Merge branch 'cw/ws-indent-with-tab'

* cw/ws-indent-with-tab:
  whitespace: tests for git-apply --whitespace=fix with tab-in-indent
  whitespace: add tab-in-indent support for --whitespace=fix
  whitespace: replumb ws_fix_copy to take a strbuf *dst instead of char *dst
  whitespace: tests for git-diff --check with tab-in-indent error class
  whitespace: add tab-in-indent error class
  whitespace: we cannot "catch all errors known to git" anymore
This commit is contained in:
Junio C Hamano 2010-05-08 22:35:35 -07:00
commit c58c5129d6
6 changed files with 159 additions and 82 deletions

View File

@ -481,6 +481,8 @@ core.whitespace::
error (enabled by default). error (enabled by default).
* `indent-with-non-tab` treats a line that is indented with 8 or more * `indent-with-non-tab` treats a line that is indented with 8 or more
space characters as an error (not enabled by default). space characters as an error (not enabled by default).
* `tab-in-indent` treats a tab character in the initial indent part of
the line as an error (not enabled by default).
* `blank-at-eof` treats blank lines added at the end of file as an error * `blank-at-eof` treats blank lines added at the end of file as an error
(enabled by default). (enabled by default).
* `trailing-space` is a short-hand to cover both `blank-at-eol` and * `trailing-space` is a short-hand to cover both `blank-at-eol` and

View File

@ -1854,6 +1854,8 @@ static int match_fragment(struct image *img,
{ {
int i; int i;
char *fixed_buf, *buf, *orig, *target; char *fixed_buf, *buf, *orig, *target;
struct strbuf fixed;
size_t fixed_len;
int preimage_limit; int preimage_limit;
if (preimage->nr + try_lno <= img->nr) { if (preimage->nr + try_lno <= img->nr) {
@ -1977,12 +1979,12 @@ static int match_fragment(struct image *img,
* use the whitespace from the preimage. * use the whitespace from the preimage.
*/ */
extra_chars = preimage_end - preimage_eof; extra_chars = preimage_end - preimage_eof;
fixed_buf = xmalloc(imgoff + extra_chars); strbuf_init(&fixed, imgoff + extra_chars);
memcpy(fixed_buf, img->buf + try, imgoff); strbuf_add(&fixed, img->buf + try, imgoff);
memcpy(fixed_buf + imgoff, preimage_eof, extra_chars); strbuf_add(&fixed, preimage_eof, extra_chars);
imgoff += extra_chars; fixed_buf = strbuf_detach(&fixed, &fixed_len);
update_pre_post_images(preimage, postimage, update_pre_post_images(preimage, postimage,
fixed_buf, imgoff, postlen); fixed_buf, fixed_len, postlen);
return 1; return 1;
} }
@ -1999,27 +2001,22 @@ static int match_fragment(struct image *img,
* but in this loop we will only handle the part of the * but in this loop we will only handle the part of the
* preimage that falls within the file. * preimage that falls within the file.
*/ */
fixed_buf = xmalloc(preimage->len + 1); strbuf_init(&fixed, preimage->len + 1);
buf = fixed_buf;
orig = preimage->buf; orig = preimage->buf;
target = img->buf + try; target = img->buf + try;
for (i = 0; i < preimage_limit; i++) { for (i = 0; i < preimage_limit; i++) {
size_t fixlen; /* length after fixing the preimage */
size_t oldlen = preimage->line[i].len; size_t oldlen = preimage->line[i].len;
size_t tgtlen = img->line[try_lno + i].len; size_t tgtlen = img->line[try_lno + i].len;
size_t tgtfixlen; /* length after fixing the target line */ size_t fixstart = fixed.len;
char tgtfixbuf[1024], *tgtfix; struct strbuf tgtfix;
int match; int match;
/* Try fixing the line in the preimage */ /* Try fixing the line in the preimage */
fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL); ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
/* Try fixing the line in the target */ /* Try fixing the line in the target */
if (sizeof(tgtfixbuf) > tgtlen) strbuf_init(&tgtfix, tgtlen);
tgtfix = tgtfixbuf; ws_fix_copy(&tgtfix, target, tgtlen, ws_rule, NULL);
else
tgtfix = xmalloc(tgtlen);
tgtfixlen = ws_fix_copy(tgtfix, target, tgtlen, ws_rule, NULL);
/* /*
* If they match, either the preimage was based on * If they match, either the preimage was based on
@ -2031,15 +2028,15 @@ static int match_fragment(struct image *img,
* so we might as well take the fix together with their * so we might as well take the fix together with their
* real change. * real change.
*/ */
match = (tgtfixlen == fixlen && !memcmp(tgtfix, buf, fixlen)); match = (tgtfix.len == fixed.len - fixstart &&
!memcmp(tgtfix.buf, fixed.buf + fixstart,
fixed.len - fixstart));
if (tgtfix != tgtfixbuf) strbuf_release(&tgtfix);
free(tgtfix);
if (!match) if (!match)
goto unmatch_exit; goto unmatch_exit;
orig += oldlen; orig += oldlen;
buf += fixlen;
target += tgtlen; target += tgtlen;
} }
@ -2051,19 +2048,18 @@ static int match_fragment(struct image *img,
* false). * false).
*/ */
for ( ; i < preimage->nr; i++) { for ( ; i < preimage->nr; i++) {
size_t fixlen; /* length after fixing the preimage */ size_t fixstart = fixed.len; /* start of the fixed preimage */
size_t oldlen = preimage->line[i].len; size_t oldlen = preimage->line[i].len;
int j; int j;
/* Try fixing the line in the preimage */ /* Try fixing the line in the preimage */
fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL); ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
for (j = 0; j < fixlen; j++) for (j = fixstart; j < fixed.len; j++)
if (!isspace(buf[j])) if (!isspace(fixed.buf[j]))
goto unmatch_exit; goto unmatch_exit;
orig += oldlen; orig += oldlen;
buf += fixlen;
} }
/* /*
@ -2071,12 +2067,13 @@ static int match_fragment(struct image *img,
* has whitespace breakages unfixed, and fixing them makes the * has whitespace breakages unfixed, and fixing them makes the
* hunk match. Update the context lines in the postimage. * hunk match. Update the context lines in the postimage.
*/ */
fixed_buf = strbuf_detach(&fixed, &fixed_len);
update_pre_post_images(preimage, postimage, update_pre_post_images(preimage, postimage,
fixed_buf, buf - fixed_buf, 0); fixed_buf, fixed_len, 0);
return 1; return 1;
unmatch_exit: unmatch_exit:
free(fixed_buf); strbuf_release(&fixed);
return 0; return 0;
} }
@ -2244,7 +2241,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
int match_beginning, match_end; int match_beginning, match_end;
const char *patch = frag->patch; const char *patch = frag->patch;
int size = frag->size; int size = frag->size;
char *old, *new, *oldlines, *newlines; char *old, *oldlines;
struct strbuf newlines;
int new_blank_lines_at_end = 0; int new_blank_lines_at_end = 0;
unsigned long leading, trailing; unsigned long leading, trailing;
int pos, applied_pos; int pos, applied_pos;
@ -2254,16 +2252,16 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
memset(&preimage, 0, sizeof(preimage)); memset(&preimage, 0, sizeof(preimage));
memset(&postimage, 0, sizeof(postimage)); memset(&postimage, 0, sizeof(postimage));
oldlines = xmalloc(size); oldlines = xmalloc(size);
newlines = xmalloc(size); strbuf_init(&newlines, size);
old = oldlines; old = oldlines;
new = newlines;
while (size > 0) { while (size > 0) {
char first; char first;
int len = linelen(patch, size); int len = linelen(patch, size);
int plen, added; int plen;
int added_blank_line = 0; int added_blank_line = 0;
int is_blank_context = 0; int is_blank_context = 0;
size_t start;
if (!len) if (!len)
break; break;
@ -2293,7 +2291,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
/* ... followed by '\No newline'; nothing */ /* ... followed by '\No newline'; nothing */
break; break;
*old++ = '\n'; *old++ = '\n';
*new++ = '\n'; strbuf_addch(&newlines, '\n');
add_line_info(&preimage, "\n", 1, LINE_COMMON); add_line_info(&preimage, "\n", 1, LINE_COMMON);
add_line_info(&postimage, "\n", 1, LINE_COMMON); add_line_info(&postimage, "\n", 1, LINE_COMMON);
is_blank_context = 1; is_blank_context = 1;
@ -2315,18 +2313,17 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
if (first == '+' && no_add) if (first == '+' && no_add)
break; break;
start = newlines.len;
if (first != '+' || if (first != '+' ||
!whitespace_error || !whitespace_error ||
ws_error_action != correct_ws_error) { ws_error_action != correct_ws_error) {
memcpy(new, patch + 1, plen); strbuf_add(&newlines, patch + 1, plen);
added = plen;
} }
else { else {
added = ws_fix_copy(new, patch + 1, plen, ws_rule, &applied_after_fixing_ws); ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
} }
add_line_info(&postimage, new, added, add_line_info(&postimage, newlines.buf + start, newlines.len - start,
(first == '+' ? 0 : LINE_COMMON)); (first == '+' ? 0 : LINE_COMMON));
new += added;
if (first == '+' && if (first == '+' &&
(ws_rule & WS_BLANK_AT_EOF) && (ws_rule & WS_BLANK_AT_EOF) &&
ws_blank_line(patch + 1, plen, ws_rule)) ws_blank_line(patch + 1, plen, ws_rule))
@ -2351,9 +2348,9 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
} }
if (inaccurate_eof && if (inaccurate_eof &&
old > oldlines && old[-1] == '\n' && old > oldlines && old[-1] == '\n' &&
new > newlines && new[-1] == '\n') { newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
old--; old--;
new--; strbuf_setlen(&newlines, newlines.len - 1);
} }
leading = frag->leading; leading = frag->leading;
@ -2385,8 +2382,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
pos = frag->newpos ? (frag->newpos - 1) : 0; pos = frag->newpos ? (frag->newpos - 1) : 0;
preimage.buf = oldlines; preimage.buf = oldlines;
preimage.len = old - oldlines; preimage.len = old - oldlines;
postimage.buf = newlines; postimage.buf = newlines.buf;
postimage.len = new - newlines; postimage.len = newlines.len;
preimage.line = preimage.line_allocated; preimage.line = preimage.line_allocated;
postimage.line = postimage.line_allocated; postimage.line = postimage.line_allocated;
@ -2462,7 +2459,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
} }
free(oldlines); free(oldlines);
free(newlines); strbuf_release(&newlines);
free(preimage.line_allocated); free(preimage.line_allocated);
free(postimage.line_allocated); free(postimage.line_allocated);

View File

@ -1042,6 +1042,7 @@ void shift_tree_by(const unsigned char *, const unsigned char *, unsigned char *
#define WS_INDENT_WITH_NON_TAB 04 #define WS_INDENT_WITH_NON_TAB 04
#define WS_CR_AT_EOL 010 #define WS_CR_AT_EOL 010
#define WS_BLANK_AT_EOF 020 #define WS_BLANK_AT_EOF 020
#define WS_TAB_IN_INDENT 040
#define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF) #define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB) #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
extern unsigned whitespace_rule_cfg; extern unsigned whitespace_rule_cfg;
@ -1050,7 +1051,7 @@ extern unsigned parse_whitespace_rule(const char *);
extern unsigned ws_check(const char *line, int len, unsigned ws_rule); extern unsigned ws_check(const char *line, int len, unsigned ws_rule);
extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws); extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
extern char *whitespace_error_string(unsigned ws); extern char *whitespace_error_string(unsigned ws);
extern int ws_fix_copy(char *, const char *, int, unsigned, int *); extern void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
extern int ws_blank_line(const char *line, int len, unsigned ws_rule); extern int ws_blank_line(const char *line, int len, unsigned ws_rule);
/* ls-files */ /* ls-files */

View File

@ -352,6 +352,48 @@ test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab:
' '
test_expect_success 'check tabs as indentation (tab-in-indent: off)' '
git config core.whitespace "-tab-in-indent" &&
echo " foo ();" > x &&
git diff --check
'
test_expect_success 'check tabs as indentation (tab-in-indent: on)' '
git config core.whitespace "tab-in-indent" &&
echo " foo ();" > x &&
test_must_fail git diff --check
'
test_expect_success 'check tabs and spaces as indentation (tab-in-indent: on)' '
git config core.whitespace "tab-in-indent" &&
echo " foo ();" > x &&
test_must_fail git diff --check
'
test_expect_success 'check tab-in-indent and indent-with-non-tab conflict' '
git config core.whitespace "tab-in-indent,indent-with-non-tab" &&
echo "foo ();" > x &&
test_must_fail git diff --check
'
test_expect_success 'check tab-in-indent excluded from wildcard whitespace attribute' '
git config --unset core.whitespace &&
echo "x whitespace" > .gitattributes &&
echo " foo ();" > x &&
git diff --check &&
rm -f .gitattributes
'
test_expect_success 'line numbers in --check output are correct' ' test_expect_success 'line numbers in --check output are correct' '
echo "" > x && echo "" > x &&

View File

@ -11,21 +11,22 @@ prepare_test_file () {
# ! trailing-space # ! trailing-space
# @ space-before-tab # @ space-before-tab
# # indent-with-non-tab # # indent-with-non-tab
# % tab-in-indent
sed -e "s/_/ /g" -e "s/>/ /" <<-\EOF sed -e "s/_/ /g" -e "s/>/ /" <<-\EOF
An_SP in an ordinary line>and a HT. An_SP in an ordinary line>and a HT.
>A HT. >A HT (%).
_>A SP and a HT (@). _>A SP and a HT (@%).
_>_A SP, a HT and a SP (@). _>_A SP, a HT and a SP (@%).
_______Seven SP. _______Seven SP.
________Eight SP (#). ________Eight SP (#).
_______>Seven SP and a HT (@). _______>Seven SP and a HT (@%).
________>Eight SP and a HT (@#). ________>Eight SP and a HT (@#%).
_______>_Seven SP, a HT and a SP (@). _______>_Seven SP, a HT and a SP (@%).
________>_Eight SP, a HT and a SP (@#). ________>_Eight SP, a HT and a SP (@#%).
_______________Fifteen SP (#). _______________Fifteen SP (#).
_______________>Fifteen SP and a HT (@#). _______________>Fifteen SP and a HT (@#%).
________________Sixteen SP (#). ________________Sixteen SP (#).
________________>Sixteen SP and a HT (@#). ________________>Sixteen SP and a HT (@#%).
_____a__Five SP, a non WS, two SP. _____a__Five SP, a non WS, two SP.
A line with a (!) trailing SP_ A line with a (!) trailing SP_
A line with a (!) trailing HT> A line with a (!) trailing HT>
@ -39,7 +40,6 @@ apply_patch () {
} }
test_fix () { test_fix () {
# fix should not barf # fix should not barf
apply_patch --whitespace=fix || return 1 apply_patch --whitespace=fix || return 1
@ -130,20 +130,25 @@ do
for i in - '' for i in - ''
do do
case "$i" in '') ti='#' ;; *) ti= ;; esac case "$i" in '') ti='#' ;; *) ti= ;; esac
rule=${t}trailing,${s}space,${i}indent for h in - ''
do
[ -z "$h$i" ] && continue
case "$h" in '') th='%' ;; *) th= ;; esac
rule=${t}trailing,${s}space,${i}indent,${h}tab
rm -f .gitattributes rm -f .gitattributes
test_expect_success "rule=$rule" ' test_expect_success "rule=$rule" '
git config core.whitespace "$rule" && git config core.whitespace "$rule" &&
test_fix "$tt$ts$ti" test_fix "$tt$ts$ti$th"
' '
test_expect_success "rule=$rule (attributes)" ' test_expect_success "rule=$rule (attributes)" '
git config --unset core.whitespace && git config --unset core.whitespace &&
echo "target whitespace=$rule" >.gitattributes && echo "target whitespace=$rule" >.gitattributes &&
test_fix "$tt$ts$ti" test_fix "$tt$ts$ti$th"
' '
done
done done
done done
done done

66
ws.c
View File

@ -10,7 +10,8 @@
static struct whitespace_rule { static struct whitespace_rule {
const char *rule_name; const char *rule_name;
unsigned rule_bits; unsigned rule_bits;
unsigned loosens_error; unsigned loosens_error:1,
exclude_default:1;
} whitespace_rule_names[] = { } whitespace_rule_names[] = {
{ "trailing-space", WS_TRAILING_SPACE, 0 }, { "trailing-space", WS_TRAILING_SPACE, 0 },
{ "space-before-tab", WS_SPACE_BEFORE_TAB, 0 }, { "space-before-tab", WS_SPACE_BEFORE_TAB, 0 },
@ -18,6 +19,7 @@ static struct whitespace_rule {
{ "cr-at-eol", WS_CR_AT_EOL, 1 }, { "cr-at-eol", WS_CR_AT_EOL, 1 },
{ "blank-at-eol", WS_BLANK_AT_EOL, 0 }, { "blank-at-eol", WS_BLANK_AT_EOL, 0 },
{ "blank-at-eof", WS_BLANK_AT_EOF, 0 }, { "blank-at-eof", WS_BLANK_AT_EOF, 0 },
{ "tab-in-indent", WS_TAB_IN_INDENT, 0, 1 },
}; };
unsigned parse_whitespace_rule(const char *string) unsigned parse_whitespace_rule(const char *string)
@ -56,6 +58,9 @@ unsigned parse_whitespace_rule(const char *string)
} }
string = ep; string = ep;
} }
if (rule & WS_TAB_IN_INDENT && rule & WS_INDENT_WITH_NON_TAB)
die("cannot enforce both tab-in-indent and indent-with-non-tab");
return rule; return rule;
} }
@ -82,7 +87,8 @@ unsigned whitespace_rule(const char *pathname)
unsigned all_rule = 0; unsigned all_rule = 0;
int i; int i;
for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++) for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++)
if (!whitespace_rule_names[i].loosens_error) if (!whitespace_rule_names[i].loosens_error &&
!whitespace_rule_names[i].exclude_default)
all_rule |= whitespace_rule_names[i].rule_bits; all_rule |= whitespace_rule_names[i].rule_bits;
return all_rule; return all_rule;
} else if (ATTR_FALSE(value)) { } else if (ATTR_FALSE(value)) {
@ -125,6 +131,11 @@ char *whitespace_error_string(unsigned ws)
strbuf_addstr(&err, ", "); strbuf_addstr(&err, ", ");
strbuf_addstr(&err, "indent with spaces"); strbuf_addstr(&err, "indent with spaces");
} }
if (ws & WS_TAB_IN_INDENT) {
if (err.len)
strbuf_addstr(&err, ", ");
strbuf_addstr(&err, "tab in indent");
}
return strbuf_detach(&err, NULL); return strbuf_detach(&err, NULL);
} }
@ -163,7 +174,7 @@ static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule,
} }
} }
/* Check for space before tab in initial indent. */ /* Check indentation */
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (line[i] == ' ') if (line[i] == ' ')
continue; continue;
@ -175,11 +186,19 @@ static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule,
fputs(ws, stream); fputs(ws, stream);
fwrite(line + written, i - written, 1, stream); fwrite(line + written, i - written, 1, stream);
fputs(reset, stream); fputs(reset, stream);
fwrite(line + i, 1, 1, stream);
} }
} else if (stream) } else if (ws_rule & WS_TAB_IN_INDENT) {
fwrite(line + written, i - written, 1, stream); result |= WS_TAB_IN_INDENT;
if (stream) if (stream) {
fwrite(line + i, 1, 1, stream); fwrite(line + written, i - written, 1, stream);
fputs(ws, stream);
fwrite(line + i, 1, 1, stream);
fputs(reset, stream);
}
} else if (stream) {
fwrite(line + written, i - written + 1, 1, stream);
}
written = i + 1; written = i + 1;
} }
@ -252,8 +271,8 @@ int ws_blank_line(const char *line, int len, unsigned ws_rule)
return 1; return 1;
} }
/* Copy the line to the buffer while fixing whitespaces */ /* Copy the line onto the end of the strbuf while fixing whitespaces */
int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *error_count) void ws_fix_copy(struct strbuf *dst, const char *src, int len, unsigned ws_rule, int *error_count)
{ {
/* /*
* len is number of bytes to be copied from src, starting * len is number of bytes to be copied from src, starting
@ -267,7 +286,6 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro
int last_tab_in_indent = -1; int last_tab_in_indent = -1;
int last_space_in_indent = -1; int last_space_in_indent = -1;
int need_fix_leading_space = 0; int need_fix_leading_space = 0;
char *buf;
/* /*
* Strip trailing whitespace * Strip trailing whitespace
@ -307,7 +325,6 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro
break; break;
} }
buf = dst;
if (need_fix_leading_space) { if (need_fix_leading_space) {
/* Process indent ourselves */ /* Process indent ourselves */
int consecutive_spaces = 0; int consecutive_spaces = 0;
@ -329,28 +346,41 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro
char ch = src[i]; char ch = src[i];
if (ch != ' ') { if (ch != ' ') {
consecutive_spaces = 0; consecutive_spaces = 0;
*dst++ = ch; strbuf_addch(dst, ch);
} else { } else {
consecutive_spaces++; consecutive_spaces++;
if (consecutive_spaces == 8) { if (consecutive_spaces == 8) {
*dst++ = '\t'; strbuf_addch(dst, '\t');
consecutive_spaces = 0; consecutive_spaces = 0;
} }
} }
} }
while (0 < consecutive_spaces--) while (0 < consecutive_spaces--)
*dst++ = ' '; strbuf_addch(dst, ' ');
len -= last;
src += last;
fixed = 1;
} else if ((ws_rule & WS_TAB_IN_INDENT) && last_tab_in_indent >= 0) {
/* Expand tabs into spaces */
int last = last_tab_in_indent + 1;
for (i = 0; i < last; i++) {
if (src[i] == '\t')
do {
strbuf_addch(dst, ' ');
} while (dst->len % 8);
else
strbuf_addch(dst, src[i]);
}
len -= last; len -= last;
src += last; src += last;
fixed = 1; fixed = 1;
} }
memcpy(dst, src, len); strbuf_add(dst, src, len);
if (add_cr_to_tail) if (add_cr_to_tail)
dst[len++] = '\r'; strbuf_addch(dst, '\r');
if (add_nl_to_tail) if (add_nl_to_tail)
dst[len++] = '\n'; strbuf_addch(dst, '\n');
if (fixed && error_count) if (fixed && error_count)
(*error_count)++; (*error_count)++;
return dst + len - buf;
} }