{"thread":{"id":"23311","subject":"[PATCH 0/6] Add tab-in-indent whitespace rule","startedAt":"2010-04-02T23:36:50Z","lastAt":"2010-04-03T10:02:26Z","messageCount":8,"participants":["Chris Webb","Martin Mares"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"138472","messageId":"cover.1270250437.git.chris@arachsys.com","threadId":"23311","inReplyTo":null,"subject":"[PATCH 0/6] Add tab-in-indent whitespace rule","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2010-04-02T23:36:50Z","receivedAt":"2010-04-02T23:36:50Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"This patch set introduces a new whitespace error/fix class for projects and\nlanguages with a coding style where no tab character is used to indent the\nlines.\n\nTo implement this feature, we need to rework ws_fix_copy() to append to a\nstrbuf rather than write into a fixed-size output buffer, because tabs may\nbe expanded into multiple spaces when tab-in-indent is applied. We also have\nto change the \"catch all errors known to git\" to exclude tab-in-indent,\nwhich directly conflicts with the existing indent-with-non-tab rule.\n\n\nJunio C Hamano (1):\n  whitespace: we cannot \"catch all errors known to git\" anymore\n\nChris Webb (5):\n  whitespace: add tab-in-indent error class\n  whitespace: tests for git-diff --check with tab-in-indent error class\n  whitespace: replumb ws_fix_copy to take a strbuf *dst instead of char *dst\n  whitespace: add tab-in-indent support for --whitespace=fix\n  whitespace: tests for git-apply --whitespace=fix with tab-in-indent\n\n Documentation/config.txt   |    2 +\n builtin/apply.c            |   81 +++++++++++++++++++++-----------------------\n cache.h                    |    3 +-\n t/t4015-diff-whitespace.sh |   42 +++++++++++++++++++++++\n t/t4124-apply-ws-rule.sh   |   53 ++++++++++++++++-------------\n ws.c                       |   73 ++++++++++++++++++++++++++++-----------\n 6 files changed, 166 insertions(+), 88 deletions(-)\n"},{"id":"138476","messageId":"d2d764a408f3e9c9223c699ba77dba39ba118bac.1270250437.git.chris@arachsys.com","threadId":"23311","inReplyTo":"cover.1270250437.git.chris@arachsys.com","subject":"[PATCH 1/6] whitespace: we cannot \"catch all errors known to git\" anymore","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2010-04-02T23:37:00Z","receivedAt":"2010-04-02T23:37:00Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"From: Junio C Hamano <gitster@pobox.com>\n\nTraditionally, \"*.txt whitespace\" in .gitattributes file has been an\ninstruction to catch _all_ classes of whitespace errors known to git.\n\nThis has to change, however, in order to introduce \"tab-in-indent\" which\nis inherently incompatible with \"indent-with-non-tab\".  As we do not want\nto break configuration of existing users, add a mechanism to allow marking\nselected rules to be excluded from \"all rules known to git\".\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Chris Webb <chris@arachsys.com>\n---\n ws.c |    6 ++++--\n 1 files changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/ws.c b/ws.c\nindex c089338..f4afcdd 100644\n--- a/ws.c\n+++ b/ws.c\n@@ -10,7 +10,8 @@\n static struct whitespace_rule {\n \tconst char *rule_name;\n \tunsigned rule_bits;\n-\tunsigned loosens_error;\n+\tunsigned loosens_error:1,\n+\t\texclude_default:1;\n } whitespace_rule_names[] = {\n \t{ \"trailing-space\", WS_TRAILING_SPACE, 0 },\n \t{ \"space-before-tab\", WS_SPACE_BEFORE_TAB, 0 },\n@@ -82,7 +83,8 @@ unsigned whitespace_rule(const char *pathname)\n \t\t\tunsigned all_rule = 0;\n \t\t\tint i;\n \t\t\tfor (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++)\n-\t\t\t\tif (!whitespace_rule_names[i].loosens_error)\n+\t\t\t\tif (!whitespace_rule_names[i].loosens_error &&\n+\t\t\t\t    !whitespace_rule_names[i].exclude_default)\n \t\t\t\t\tall_rule |= whitespace_rule_names[i].rule_bits;\n \t\t\treturn all_rule;\n \t\t} else if (ATTR_FALSE(value)) {\n-- \n1.7.0.3\n"},{"id":"138473","messageId":"c2612b53dc7105805a2455a4188667552b1ee606.1270250437.git.chris@arachsys.com","threadId":"23311","inReplyTo":"cover.1270250437.git.chris@arachsys.com","subject":"[PATCH 2/6] whitespace: add tab-in-indent error class","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2010-04-02T23:37:08Z","receivedAt":"2010-04-02T23:37:08Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Some projects and languages use coding style where no tab character is used to\nindent the lines.\n\nThis only adds support and documentation for \"apply --whitespace=warn\" and\n\"diff --check\"; later patches add \"apply --whitespace=fix\" and tests.\n\nSigned-off-by: Chris Webb <chris@arachsys.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/config.txt |    2 ++\n cache.h                  |    1 +\n ws.c                     |   27 ++++++++++++++++++++++-----\n 3 files changed, 25 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 06b2f82..9bb8f3d 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -481,6 +481,8 @@ core.whitespace::\n   error (enabled by default).\n * `indent-with-non-tab` treats a line that is indented with 8 or more\n   space characters as an error (not enabled by default).\n+* `tab-in-indent` treats a tab character in the initial indent part of\n+  the line as an error (not enabled by default).\n * `blank-at-eof` treats blank lines added at the end of file as an error\n   (enabled by default).\n * `trailing-space` is a short-hand to cover both `blank-at-eol` and\ndiff --git a/cache.h b/cache.h\nindex 6dcb100..030af32 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1040,6 +1040,7 @@ void shift_tree_by(const unsigned char *, const unsigned char *, unsigned char *\n #define WS_INDENT_WITH_NON_TAB\t04\n #define WS_CR_AT_EOL           010\n #define WS_BLANK_AT_EOF        020\n+#define WS_TAB_IN_INDENT       040\n #define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)\n #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)\n extern unsigned whitespace_rule_cfg;\ndiff --git a/ws.c b/ws.c\nindex f4afcdd..0302ef5 100644\n--- a/ws.c\n+++ b/ws.c\n@@ -19,6 +19,7 @@ static struct whitespace_rule {\n \t{ \"cr-at-eol\", WS_CR_AT_EOL, 1 },\n \t{ \"blank-at-eol\", WS_BLANK_AT_EOL, 0 },\n \t{ \"blank-at-eof\", WS_BLANK_AT_EOF, 0 },\n+\t{ \"tab-in-indent\", WS_TAB_IN_INDENT, 0, 1 },\n };\n \n unsigned parse_whitespace_rule(const char *string)\n@@ -57,6 +58,9 @@ unsigned parse_whitespace_rule(const char *string)\n \t\t}\n \t\tstring = ep;\n \t}\n+\n+\tif (rule & WS_TAB_IN_INDENT && rule & WS_INDENT_WITH_NON_TAB)\n+\t\tdie(\"cannot enforce both tab-in-indent and indent-with-non-tab\");\n \treturn rule;\n }\n \n@@ -127,6 +131,11 @@ char *whitespace_error_string(unsigned ws)\n \t\t\tstrbuf_addstr(&err, \", \");\n \t\tstrbuf_addstr(&err, \"indent with spaces\");\n \t}\n+\tif (ws & WS_TAB_IN_INDENT) {\n+\t\tif (err.len)\n+\t\t\tstrbuf_addstr(&err, \", \");\n+\t\tstrbuf_addstr(&err, \"tab in indent\");\n+\t}\n \treturn strbuf_detach(&err, NULL);\n }\n \n@@ -165,7 +174,7 @@ static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule,\n \t\t}\n \t}\n \n-\t/* Check for space before tab in initial indent. */\n+\t/* Check indentation */\n \tfor (i = 0; i < len; i++) {\n \t\tif (line[i] == ' ')\n \t\t\tcontinue;\n@@ -177,11 +186,19 @@ static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule,\n \t\t\t\tfputs(ws, stream);\n \t\t\t\tfwrite(line + written, i - written, 1, stream);\n \t\t\t\tfputs(reset, stream);\n+\t\t\t\tfwrite(line + i, 1, 1, stream);\n \t\t\t}\n-\t\t} else if (stream)\n-\t\t\tfwrite(line + written, i - written, 1, stream);\n-\t\tif (stream)\n-\t\t\tfwrite(line + i, 1, 1, stream);\n+\t\t} else if (ws_rule & WS_TAB_IN_INDENT) {\n+\t\t\tresult |= WS_TAB_IN_INDENT;\n+\t\t\tif (stream) {\n+\t\t\t\tfwrite(line + written, i - written, 1, stream);\n+\t\t\t\tfputs(ws, stream);\n+\t\t\t\tfwrite(line + i, 1, 1, stream);\n+\t\t\t\tfputs(reset, stream);\n+\t\t\t}\n+\t\t} else if (stream) {\n+\t\t\tfwrite(line + written, i - written + 1, 1, stream);\n+\t\t}\n \t\twritten = i + 1;\n \t}\n \n-- \n1.7.0.3\n"},{"id":"138475","messageId":"7a8a7a4054abc1f478c1d0faf025b033c598e812.1270250437.git.chris@arachsys.com","threadId":"23311","inReplyTo":"cover.1270250437.git.chris@arachsys.com","subject":"[PATCH 3/6] whitespace: tests for git-diff --check with tab-in-indent error class","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2010-04-02T23:37:15Z","receivedAt":"2010-04-02T23:37:15Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Signed-off-by: Chris Webb <chris@arachsys.com>\n---\n t/t4015-diff-whitespace.sh |   42 ++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 42 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh\nindex 90f3342..9e57f80 100755\n--- a/t/t4015-diff-whitespace.sh\n+++ b/t/t4015-diff-whitespace.sh\n@@ -352,6 +352,48 @@ test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab:\n \n '\n \n+test_expect_success 'check tabs as indentation (tab-in-indent: off)' '\n+\n+\tgit config core.whitespace \"-tab-in-indent\"\n+\techo \"\tfoo ();\" > x &&\n+\tgit diff --check\n+\n+'\n+\n+test_expect_success 'check tabs as indentation (tab-in-indent: on)' '\n+\n+\tgit config core.whitespace \"tab-in-indent\" &&\n+\techo \"\tfoo ();\" > x &&\n+\ttest_must_fail git diff --check\n+\n+'\n+\n+test_expect_success 'check tabs and spaces as indentation (tab-in-indent: on)' '\n+\n+\tgit config core.whitespace \"tab-in-indent\" &&\n+\techo \"\t                foo ();\" > x &&\n+\ttest_must_fail git diff --check\n+\n+'\n+\n+test_expect_success 'check tab-in-indent and indent-with-non-tab conflict' '\n+\n+\tgit config core.whitespace \"tab-in-indent,indent-with-non-tab\"\n+\techo \"foo ();\" > x &&\n+\ttest_must_fail git diff --check\n+\n+'\n+\n+test_expect_success 'check tab-in-indent excluded from wildcard whitespace attribute' '\n+\n+\tgit config --unset core.whitespace\n+\techo \"x whitespace\" > .gitattributes &&\n+\techo \"\t  foo ();\" > x &&\n+\tgit diff --check &&\n+\trm -f .gitattributes\n+\n+'\n+\n test_expect_success 'line numbers in --check output are correct' '\n \n \techo \"\" > x &&\n-- \n1.7.0.3\n"},{"id":"138477","messageId":"7608421896a8d149a3f0746d84eafd38441083d5.1270250437.git.chris@arachsys.com","threadId":"23311","inReplyTo":"cover.1270250437.git.chris@arachsys.com","subject":"[PATCH 4/6] whitespace: replumb ws_fix_copy to take a strbuf *dst instead of char *dst","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2010-04-02T23:37:23Z","receivedAt":"2010-04-02T23:37:23Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"To implement --whitespace=fix for tab-in-indent, we have to allow for the\npossibility that whitespace can increase in size when it is fixed, expanding\ntabs to to multiple spaces in the initial indent.\n\nSigned-off-by: Chris Webb <chris@arachsys.com>\n---\n builtin/apply.c |   81 ++++++++++++++++++++++++++----------------------------\n cache.h         |    2 +-\n ws.c            |   19 +++++-------\n 3 files changed, 48 insertions(+), 54 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex 7ca9047..db9cbdd 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -1854,6 +1854,8 @@ static int match_fragment(struct image *img,\n {\n \tint i;\n \tchar *fixed_buf, *buf, *orig, *target;\n+\tstruct strbuf fixed;\n+\tsize_t fixed_len;\n \tint preimage_limit;\n \n \tif (preimage->nr + try_lno <= img->nr) {\n@@ -1977,12 +1979,12 @@ static int match_fragment(struct image *img,\n \t\t * use the whitespace from the preimage.\n \t\t */\n \t\textra_chars = preimage_end - preimage_eof;\n-\t\tfixed_buf = xmalloc(imgoff + extra_chars);\n-\t\tmemcpy(fixed_buf, img->buf + try, imgoff);\n-\t\tmemcpy(fixed_buf + imgoff, preimage_eof, extra_chars);\n-\t\timgoff += extra_chars;\n+\t\tstrbuf_init(&fixed, imgoff + extra_chars);\n+\t\tstrbuf_add(&fixed, img->buf + try, imgoff);\n+\t\tstrbuf_add(&fixed, preimage_eof, extra_chars);\n+\t\tfixed_buf = strbuf_detach(&fixed, &fixed_len);\n \t\tupdate_pre_post_images(preimage, postimage,\n-\t\t\t\tfixed_buf, imgoff, postlen);\n+\t\t\t\tfixed_buf, fixed_len, postlen);\n \t\treturn 1;\n \t}\n \n@@ -1999,27 +2001,22 @@ static int match_fragment(struct image *img,\n \t * but in this loop we will only handle the part of the\n \t * preimage that falls within the file.\n \t */\n-\tfixed_buf = xmalloc(preimage->len + 1);\n-\tbuf = fixed_buf;\n+\tstrbuf_init(&fixed, preimage->len + 1);\n \torig = preimage->buf;\n \ttarget = img->buf + try;\n \tfor (i = 0; i < preimage_limit; i++) {\n-\t\tsize_t fixlen; /* length after fixing the preimage */\n \t\tsize_t oldlen = preimage->line[i].len;\n \t\tsize_t tgtlen = img->line[try_lno + i].len;\n-\t\tsize_t tgtfixlen; /* length after fixing the target line */\n-\t\tchar tgtfixbuf[1024], *tgtfix;\n+\t\tsize_t fixstart = fixed.len;\n+\t\tstruct strbuf tgtfix;\n \t\tint match;\n \n \t\t/* Try fixing the line in the preimage */\n-\t\tfixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);\n+\t\tws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);\n \n \t\t/* Try fixing the line in the target */\n-\t\tif (sizeof(tgtfixbuf) > tgtlen)\n-\t\t\ttgtfix = tgtfixbuf;\n-\t\telse\n-\t\t\ttgtfix = xmalloc(tgtlen);\n-\t\ttgtfixlen = ws_fix_copy(tgtfix, target, tgtlen, ws_rule, NULL);\n+\t\tstrbuf_init(&tgtfix, tgtlen);\n+\t\tws_fix_copy(&tgtfix, target, tgtlen, ws_rule, NULL);\n \n \t\t/*\n \t\t * If they match, either the preimage was based on\n@@ -2031,15 +2028,15 @@ static int match_fragment(struct image *img,\n \t\t * so we might as well take the fix together with their\n \t\t * real change.\n \t\t */\n-\t\tmatch = (tgtfixlen == fixlen && !memcmp(tgtfix, buf, fixlen));\n+\t\tmatch = (tgtfix.len == fixed.len - fixstart &&\n+\t\t\t !memcmp(tgtfix.buf, fixed.buf + fixstart,\n+\t\t\t\t\t     fixed.len - fixstart));\n \n-\t\tif (tgtfix != tgtfixbuf)\n-\t\t\tfree(tgtfix);\n+\t\tstrbuf_release(&tgtfix);\n \t\tif (!match)\n \t\t\tgoto unmatch_exit;\n \n \t\torig += oldlen;\n-\t\tbuf += fixlen;\n \t\ttarget += tgtlen;\n \t}\n \n@@ -2051,19 +2048,18 @@ static int match_fragment(struct image *img,\n \t * false).\n \t */\n \tfor ( ; i < preimage->nr; i++) {\n-\t\tsize_t fixlen; /* length after fixing the preimage */\n+\t\tsize_t fixstart = fixed.len; /* start of the fixed preimage */\n \t\tsize_t oldlen = preimage->line[i].len;\n \t\tint j;\n \n \t\t/* Try fixing the line in the preimage */\n-\t\tfixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);\n+\t\tws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);\n \n-\t\tfor (j = 0; j < fixlen; j++)\n-\t\t\tif (!isspace(buf[j]))\n+\t\tfor (j = fixstart; j < fixed.len; j++)\n+\t\t\tif (!isspace(fixed.buf[j]))\n \t\t\t\tgoto unmatch_exit;\n \n \t\torig += oldlen;\n-\t\tbuf += fixlen;\n \t}\n \n \t/*\n@@ -2071,12 +2067,13 @@ static int match_fragment(struct image *img,\n \t * has whitespace breakages unfixed, and fixing them makes the\n \t * hunk match.  Update the context lines in the postimage.\n \t */\n+\tfixed_buf = strbuf_detach(&fixed, &fixed_len);\n \tupdate_pre_post_images(preimage, postimage,\n-\t\t\t       fixed_buf, buf - fixed_buf, 0);\n+\t\t\t       fixed_buf, fixed_len, 0);\n \treturn 1;\n \n  unmatch_exit:\n-\tfree(fixed_buf);\n+\tstrbuf_release(&fixed);\n \treturn 0;\n }\n \n@@ -2244,7 +2241,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,\n \tint match_beginning, match_end;\n \tconst char *patch = frag->patch;\n \tint size = frag->size;\n-\tchar *old, *new, *oldlines, *newlines;\n+\tchar *old, *oldlines;\n+\tstruct strbuf newlines;\n \tint new_blank_lines_at_end = 0;\n \tunsigned long leading, trailing;\n \tint pos, applied_pos;\n@@ -2254,16 +2252,16 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,\n \tmemset(&preimage, 0, sizeof(preimage));\n \tmemset(&postimage, 0, sizeof(postimage));\n \toldlines = xmalloc(size);\n-\tnewlines = xmalloc(size);\n+\tstrbuf_init(&newlines, size);\n \n \told = oldlines;\n-\tnew = newlines;\n \twhile (size > 0) {\n \t\tchar first;\n \t\tint len = linelen(patch, size);\n-\t\tint plen, added;\n+\t\tint plen;\n \t\tint added_blank_line = 0;\n \t\tint is_blank_context = 0;\n+\t\tsize_t start;\n \n \t\tif (!len)\n \t\t\tbreak;\n@@ -2293,7 +2291,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,\n \t\t\t\t/* ... followed by '\\No newline'; nothing */\n \t\t\t\tbreak;\n \t\t\t*old++ = '\\n';\n-\t\t\t*new++ = '\\n';\n+\t\t\tstrbuf_addch(&newlines, '\\n');\n \t\t\tadd_line_info(&preimage, \"\\n\", 1, LINE_COMMON);\n \t\t\tadd_line_info(&postimage, \"\\n\", 1, LINE_COMMON);\n \t\t\tis_blank_context = 1;\n@@ -2315,18 +2313,17 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,\n \t\t\tif (first == '+' && no_add)\n \t\t\t\tbreak;\n \n+\t\t\tstart = newlines.len;\n \t\t\tif (first != '+' ||\n \t\t\t    !whitespace_error ||\n \t\t\t    ws_error_action != correct_ws_error) {\n-\t\t\t\tmemcpy(new, patch + 1, plen);\n-\t\t\t\tadded = plen;\n+\t\t\t\tstrbuf_add(&newlines, patch + 1, plen);\n \t\t\t}\n \t\t\telse {\n-\t\t\t\tadded = ws_fix_copy(new, patch + 1, plen, ws_rule, &applied_after_fixing_ws);\n+\t\t\t\tws_fix_copy(&newlines, patch + 1, plen, ws_rule, &applied_after_fixing_ws);\n \t\t\t}\n-\t\t\tadd_line_info(&postimage, new, added,\n+\t\t\tadd_line_info(&postimage, newlines.buf + start, newlines.len - start,\n \t\t\t\t      (first == '+' ? 0 : LINE_COMMON));\n-\t\t\tnew += added;\n \t\t\tif (first == '+' &&\n \t\t\t    (ws_rule & WS_BLANK_AT_EOF) &&\n \t\t\t    ws_blank_line(patch + 1, plen, ws_rule))\n@@ -2351,9 +2348,9 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,\n \t}\n \tif (inaccurate_eof &&\n \t    old > oldlines && old[-1] == '\\n' &&\n-\t    new > newlines && new[-1] == '\\n') {\n+\t    newlines.len > 0 && newlines.buf[newlines.len - 1] == '\\n') {\n \t\told--;\n-\t\tnew--;\n+\t\tstrbuf_setlen(&newlines, newlines.len - 1);\n \t}\n \n \tleading = frag->leading;\n@@ -2385,8 +2382,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,\n \tpos = frag->newpos ? (frag->newpos - 1) : 0;\n \tpreimage.buf = oldlines;\n \tpreimage.len = old - oldlines;\n-\tpostimage.buf = newlines;\n-\tpostimage.len = new - newlines;\n+\tpostimage.buf = newlines.buf;\n+\tpostimage.len = newlines.len;\n \tpreimage.line = preimage.line_allocated;\n \tpostimage.line = postimage.line_allocated;\n \n@@ -2462,7 +2459,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,\n \t}\n \n \tfree(oldlines);\n-\tfree(newlines);\n+\tstrbuf_release(&newlines);\n \tfree(preimage.line_allocated);\n \tfree(postimage.line_allocated);\n \ndiff --git a/cache.h b/cache.h\nindex 030af32..3b7f3b0 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1049,7 +1049,7 @@ extern unsigned parse_whitespace_rule(const char *);\n extern unsigned ws_check(const char *line, int len, unsigned ws_rule);\n extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);\n extern char *whitespace_error_string(unsigned ws);\n-extern int ws_fix_copy(char *, const char *, int, unsigned, int *);\n+extern void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);\n extern int ws_blank_line(const char *line, int len, unsigned ws_rule);\n \n /* ls-files */\ndiff --git a/ws.c b/ws.c\nindex 0302ef5..897ff56 100644\n--- a/ws.c\n+++ b/ws.c\n@@ -271,8 +271,8 @@ int ws_blank_line(const char *line, int len, unsigned ws_rule)\n \treturn 1;\n }\n \n-/* Copy the line to the buffer while fixing whitespaces */\n-int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *error_count)\n+/* Copy the line onto the end of the strbuf while fixing whitespaces */\n+void ws_fix_copy(struct strbuf *dst, const char *src, int len, unsigned ws_rule, int *error_count)\n {\n \t/*\n \t * len is number of bytes to be copied from src, starting\n@@ -286,7 +286,6 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro\n \tint last_tab_in_indent = -1;\n \tint last_space_in_indent = -1;\n \tint need_fix_leading_space = 0;\n-\tchar *buf;\n \n \t/*\n \t * Strip trailing whitespace\n@@ -326,7 +325,6 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro\n \t\t\tbreak;\n \t}\n \n-\tbuf = dst;\n \tif (need_fix_leading_space) {\n \t\t/* Process indent ourselves */\n \t\tint consecutive_spaces = 0;\n@@ -348,28 +346,27 @@ int ws_fix_copy(char *dst, const char *src, int len, unsigned ws_rule, int *erro\n \t\t\tchar ch = src[i];\n \t\t\tif (ch != ' ') {\n \t\t\t\tconsecutive_spaces = 0;\n-\t\t\t\t*dst++ = ch;\n+\t\t\t\tstrbuf_addch(dst, ch);\n \t\t\t} else {\n \t\t\t\tconsecutive_spaces++;\n \t\t\t\tif (consecutive_spaces == 8) {\n-\t\t\t\t\t*dst++ = '\\t';\n+\t\t\t\t\tstrbuf_addch(dst, '\\t');\n \t\t\t\t\tconsecutive_spaces = 0;\n \t\t\t\t}\n \t\t\t}\n \t\t}\n \t\twhile (0 < consecutive_spaces--)\n-\t\t\t*dst++ = ' ';\n+\t\t\tstrbuf_addch(dst, ' ');\n \t\tlen -= last;\n \t\tsrc += last;\n \t\tfixed = 1;\n \t}\n \n-\tmemcpy(dst, src, len);\n+\tstrbuf_add(dst, src, len);\n \tif (add_cr_to_tail)\n-\t\tdst[len++] = '\\r';\n+\t\tstrbuf_addch(dst, '\\r');\n \tif (add_nl_to_tail)\n-\t\tdst[len++] = '\\n';\n+\t\tstrbuf_addch(dst, '\\n');\n \tif (fixed && error_count)\n \t\t(*error_count)++;\n-\treturn dst + len - buf;\n }\n-- \n1.7.0.3\n"},{"id":"138474","messageId":"3edb43ab524b6b2ee883c25cfa80bc6012a4abd4.1270250437.git.chris@arachsys.com","threadId":"23311","inReplyTo":"cover.1270250437.git.chris@arachsys.com","subject":"[PATCH 5/6] whitespace: add tab-in-indent support for --whitespace=fix","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2010-04-02T23:37:30Z","receivedAt":"2010-04-02T23:37:30Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"If tab-in-indent is set, --whitespace=fix will ensure that any stray tabs in\nthe initial indent are expanded to the correct number of space characters.\n\nSigned-off-by: Chris Webb <chris@arachsys.com>\n---\n ws.c |   21 ++++++++++++++++++---\n 1 files changed, 18 insertions(+), 3 deletions(-)\n\ndiff --git a/ws.c b/ws.c\nindex 897ff56..e581535 100644\n--- a/ws.c\n+++ b/ws.c\n@@ -313,8 +313,9 @@ void ws_fix_copy(struct strbuf *dst, const char *src, int len, unsigned ws_rule,\n \t\tchar ch = src[i];\n \t\tif (ch == '\\t') {\n \t\t\tlast_tab_in_indent = i;\n-\t\t\tif ((ws_rule & WS_SPACE_BEFORE_TAB) &&\n-\t\t\t    0 <= last_space_in_indent)\n+\t\t\tif ((ws_rule & WS_TAB_IN_INDENT) ||\n+\t\t\t    ((ws_rule & WS_SPACE_BEFORE_TAB) &&\n+\t\t\t     0 <= last_space_in_indent))\n \t\t\t    need_fix_leading_space = 1;\n \t\t} else if (ch == ' ') {\n \t\t\tlast_space_in_indent = i;\n@@ -325,7 +326,21 @@ void ws_fix_copy(struct strbuf *dst, const char *src, int len, unsigned ws_rule,\n \t\t\tbreak;\n \t}\n \n-\tif (need_fix_leading_space) {\n+\tif ((ws_rule & WS_TAB_IN_INDENT) && last_tab_in_indent >= 0) {\n+\t\t/* Expand tabs into spaces */\n+\t\tint last = last_tab_in_indent + 1;\n+\t\tfor (i = 0; i < last; i++) {\n+\t\t\tif (src[i] == '\\t')\n+\t\t\t\tdo {\n+\t\t\t\t\tstrbuf_addch(dst, ' ');\n+\t\t\t\t} while (dst->len % 8);\n+\t\t\telse\n+\t\t\t\tstrbuf_addch(dst, src[i]);\n+\t\t}\n+\t\tlen -= last;\n+\t\tsrc += last;\n+\t\tfixed = 1;\n+\t} else if (need_fix_leading_space) {\n \t\t/* Process indent ourselves */\n \t\tint consecutive_spaces = 0;\n \t\tint last = last_tab_in_indent + 1;\n-- \n1.7.0.3\n"},{"id":"138478","messageId":"0efb5aca7f738403283ec97ad53c645d8f7240eb.1270250437.git.chris@arachsys.com","threadId":"23311","inReplyTo":"cover.1270250437.git.chris@arachsys.com","subject":"[PATCH 6/6] whitespace: tests for git-apply --whitespace=fix with tab-in-indent","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2010-04-02T23:37:37Z","receivedAt":"2010-04-02T23:37:37Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Signed-off-by: Chris Webb <chris@arachsys.com>\n---\n t/t4124-apply-ws-rule.sh |   53 +++++++++++++++++++++++++--------------------\n 1 files changed, 29 insertions(+), 24 deletions(-)\n\ndiff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh\nindex fb9ad24..8d46df6 100755\n--- a/t/t4124-apply-ws-rule.sh\n+++ b/t/t4124-apply-ws-rule.sh\n@@ -11,21 +11,22 @@ prepare_test_file () {\n \t#   \t!  trailing-space\n \t#   \t@  space-before-tab\n \t#   \t#  indent-with-non-tab\n+\t#   \t%  tab-in-indent\n \tsed -e \"s/_/ /g\" -e \"s/>/\t/\" <<-\\EOF\n \t\tAn_SP in an ordinary line>and a HT.\n-\t\t>A HT.\n-\t\t_>A SP and a HT (@).\n-\t\t_>_A SP, a HT and a SP (@).\n+\t\t>A HT (%).\n+\t\t_>A SP and a HT (@%).\n+\t\t_>_A SP, a HT and a SP (@%).\n \t\t_______Seven SP.\n \t\t________Eight SP (#).\n-\t\t_______>Seven SP and a HT (@).\n-\t\t________>Eight SP and a HT (@#).\n-\t\t_______>_Seven SP, a HT and a SP (@).\n-\t\t________>_Eight SP, a HT and a SP (@#).\n+\t\t_______>Seven SP and a HT (@%).\n+\t\t________>Eight SP and a HT (@#%).\n+\t\t_______>_Seven SP, a HT and a SP (@%).\n+\t\t________>_Eight SP, a HT and a SP (@#%).\n \t\t_______________Fifteen SP (#).\n-\t\t_______________>Fifteen SP and a HT (@#).\n+\t\t_______________>Fifteen SP and a HT (@#%).\n \t\t________________Sixteen SP (#).\n-\t\t________________>Sixteen SP and a HT (@#).\n+\t\t________________>Sixteen SP and a HT (@#%).\n \t\t_____a__Five SP, a non WS, two SP.\n \t\tA line with a (!) trailing SP_\n \t\tA line with a (!) trailing HT>\n@@ -39,7 +40,6 @@ apply_patch () {\n }\n \n test_fix () {\n-\n \t# fix should not barf\n \tapply_patch --whitespace=fix || return 1\n \n@@ -130,20 +130,25 @@ do\n \t\tfor i in - ''\n \t\tdo\n \t\t\tcase \"$i\" in '') ti='#' ;; *) ti= ;; esac\n-\t\t\trule=${t}trailing,${s}space,${i}indent\n-\n-\t\t\trm -f .gitattributes\n-\t\t\ttest_expect_success \"rule=$rule\" '\n-\t\t\t\tgit config core.whitespace \"$rule\" &&\n-\t\t\t\ttest_fix \"$tt$ts$ti\"\n-\t\t\t'\n-\n-\t\t\ttest_expect_success \"rule=$rule (attributes)\" '\n-\t\t\t\tgit config --unset core.whitespace &&\n-\t\t\t\techo \"target whitespace=$rule\" >.gitattributes &&\n-\t\t\t\ttest_fix \"$tt$ts$ti\"\n-\t\t\t'\n-\n+\t\t\tfor h in - ''\n+\t\t\tdo\n+\t\t\t\t[ -z \"$h$i\" ] && continue\n+\t\t\t\tcase \"$h\" in '') th='%' ;; *) th= ;; esac\n+\t\t\t\trule=${t}trailing,${s}space,${i}indent,${h}tab\n+\n+\t\t\t\trm -f .gitattributes\n+\t\t\t\ttest_expect_success \"rule=$rule\" '\n+\t\t\t\t\tgit config core.whitespace \"$rule\" &&\n+\t\t\t\t\ttest_fix \"$tt$ts$ti$th\"\n+\t\t\t\t'\n+\n+\t\t\t\ttest_expect_success \"rule=$rule (attributes)\" '\n+\t\t\t\t\tgit config --unset core.whitespace &&\n+\t\t\t\t\techo \"target whitespace=$rule\" >.gitattributes &&\n+\t\t\t\t\ttest_fix \"$tt$ts$ti$th\"\n+\t\t\t\t'\n+\n+\t\t\tdone\n \t\tdone\n \tdone\n done\n-- \n1.7.0.3\n"},{"id":"138496","messageId":"mj+md-20100403.100104.14382.nikam@ucw.cz","threadId":"23311","inReplyTo":"c2612b53dc7105805a2455a4188667552b1ee606.1270250437.git.chris@arachsys.com","subject":"Re: [PATCH 2/6] whitespace: add tab-in-indent error class","fromName":"Martin Mares","fromEmail":"mj@ucw.cz","sentAt":"2010-04-03T10:02:26Z","receivedAt":"2010-04-03T10:02:26Z","isPatch":true,"sender":{"key":"mj@ucw.cz","avatar":null},"body":"Hello!\n\n> +\tif (rule & WS_TAB_IN_INDENT && rule & WS_INDENT_WITH_NON_TAB)\n> +\t\tdie(\"cannot enforce both tab-in-indent and indent-with-non-tab\");\n\nWell, it would forbid any indented lines, which could possible make\nsense for some file formats.\n\n\t\t\t\tHave a nice fortnight\n-- \nMartin `MJ' Mares                          <mj@ucw.cz>   http://mj.ucw.cz/\nFaculty of Math and Physics, Charles University, Prague, Czech Rep., Earth\n\"This is an object-oriented system. If we change anything, the users object.\"\n"}]}