{"thread":{"id":"5658","subject":"[PATCH 2/2] git-apply: second war on whitespace.","startedAt":"2006-09-23T07:47:49Z","lastAt":"2006-09-23T07:47:49Z","messageCount":1,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"27451","messageId":"7vac4rvxay.fsf@assigned-by-dhcp.cox.net","threadId":"5658","inReplyTo":null,"subject":"[PATCH 2/2] git-apply: second war on whitespace.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-09-23T07:47:49Z","receivedAt":"2006-09-23T07:47:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This makes --whitespace={warn,error,strip} option to also notice\nthe leading whitespace errors in addition to the trailing\nwhitespace errors.  Spaces that are followed by a tab in indent\nare detected as errors, and --whitespace=strip option fixes them.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n builtin-apply.c |  122 ++++++++++++++++++++++++++++++++++++++++++++-----------\n 1 files changed, 97 insertions(+), 25 deletions(-)\n\ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex 25e90d8..de5f855 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -854,6 +854,49 @@ static int find_header(char *line, unsig\n \treturn -1;\n }\n \n+static void check_whitespace(const char *line, int len)\n+{\n+\tconst char *err = \"Adds trailing whitespace\";\n+\tint seen_space = 0;\n+\tint i;\n+\n+\t/*\n+\t * We know len is at least two, since we have a '+' and we\n+\t * checked that the last character was a '\\n' before calling\n+\t * this function.  That is, an addition of an empty line would\n+\t * check the '+' here.  Sneaky...\n+\t */\n+\tif (isspace(line[len-2]))\n+\t\tgoto error;\n+\n+\t/*\n+\t * Make sure that there is no space followed by a tab in\n+\t * indentation.\n+\t */\n+\terr = \"Space in indent is followed by a tab\";\n+\tfor (i = 1; i < len; i++) {\n+\t\tif (line[i] == '\\t') {\n+\t\t\tif (seen_space)\n+\t\t\t\tgoto error;\n+\t\t}\n+\t\telse if (line[i] == ' ')\n+\t\t\tseen_space = 1;\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\treturn;\n+\n+ error:\n+\twhitespace_error++;\n+\tif (squelch_whitespace_errors &&\n+\t    squelch_whitespace_errors < whitespace_error)\n+\t\t;\n+\telse\n+\t\tfprintf(stderr, \"%s.\\n%s:%d:%.*s\\n\",\n+\t\t\terr, patch_input_file, linenr, len-2, line+1);\n+}\n+\n+\n /*\n  * Parse a unified diff. Note that this really needs to parse each\n  * fragment separately, since the only way to know the difference\n@@ -904,25 +947,8 @@ static int parse_fragment(char *line, un\n \t\t\ttrailing = 0;\n \t\t\tbreak;\n \t\tcase '+':\n-\t\t\t/*\n-\t\t\t * We know len is at least two, since we have a '+' and\n-\t\t\t * we checked that the last character was a '\\n' above.\n-\t\t\t * That is, an addition of an empty line would check\n-\t\t\t * the '+' here.  Sneaky...\n-\t\t\t */\n-\t\t\tif ((new_whitespace != nowarn_whitespace) &&\n-\t\t\t    isspace(line[len-2])) {\n-\t\t\t\twhitespace_error++;\n-\t\t\t\tif (squelch_whitespace_errors &&\n-\t\t\t\t    squelch_whitespace_errors <\n-\t\t\t\t    whitespace_error)\n-\t\t\t\t\t;\n-\t\t\t\telse {\n-\t\t\t\t\tfprintf(stderr, \"Adds trailing whitespace.\\n%s:%d:%.*s\\n\",\n-\t\t\t\t\t\tpatch_input_file,\n-\t\t\t\t\t\tlinenr, len-2, line+1);\n-\t\t\t\t}\n-\t\t\t}\n+\t\t\tif (new_whitespace != nowarn_whitespace)\n+\t\t\t\tcheck_whitespace(line, len);\n \t\t\tadded++;\n \t\t\tnewlines--;\n \t\t\ttrailing = 0;\n@@ -1494,22 +1520,68 @@ static int apply_line(char *output, cons\n {\n \t/* plen is number of bytes to be copied from patch,\n \t * starting at patch+1 (patch[0] is '+').  Typically\n-\t * patch[plen] is '\\n'.\n+\t * patch[plen] is '\\n', unless this is the incomplete\n+\t * last line.\n \t */\n+\tint i;\n \tint add_nl_to_tail = 0;\n-\tif ((new_whitespace == strip_whitespace) &&\n-\t    1 < plen && isspace(patch[plen-1])) {\n+\tint fixed = 0;\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+\tif ((new_whitespace != strip_whitespace) || !whitespace_error) {\n+\t\tmemcpy(output, patch + 1, plen);\n+\t\treturn plen;\n+\t}\n+\n+\tif (1 < plen && isspace(patch[plen-1])) {\n \t\tif (patch[plen] == '\\n')\n \t\t\tadd_nl_to_tail = 1;\n \t\tplen--;\n \t\twhile (0 < plen && isspace(patch[plen]))\n \t\t\tplen--;\n-\t\tapplied_after_stripping++;\n+\t\tfixed = 1;\n \t}\n-\tmemcpy(output, patch + 1, plen);\n+\n+\tfor (i = 1; i < plen; i++) {\n+\t\tchar ch = patch[i];\n+\t\tif (ch == '\\t') {\n+\t\t\tlast_tab_in_indent = i;\n+\t\t\tif (0 <= last_space_in_indent)\n+\t\t\t\tneed_fix_leading_space = 1;\n+\t\t}\n+\t\telse if (ch == ' ')\n+\t\t\tlast_space_in_indent = i;\n+\t\telse\n+\t\t\tbreak;\n+\t}\n+\n+\tbuf = output;\n+\tif (need_fix_leading_space) {\n+\t\t/* between patch[1..last_tab_in_indent] strip the\n+\t\t * funny spaces, updating them to tab as needed.\n+\t\t */\n+\t\tfor (i = 1; i < last_tab_in_indent; i++, plen--) {\n+\t\t\tchar ch = patch[i];\n+\t\t\tif (ch != ' ')\n+\t\t\t\t*output++ = ch;\n+\t\t\telse if ((i % 8) == 0)\n+\t\t\t\t*output++ = '\\t';\n+\t\t}\n+\t\tfixed = 1;\n+\t\ti = last_tab_in_indent;\n+\t}\n+\telse\n+\t\ti = 1;\n+\n+\tmemcpy(output, patch + i, plen);\n \tif (add_nl_to_tail)\n \t\toutput[plen++] = '\\n';\n-\treturn plen;\n+\tif (fixed)\n+\t\tapplied_after_stripping++;\n+\treturn output + plen - buf;\n }\n \n static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, int inaccurate_eof)\n-- \n1.4.2.1.gf2bba\n"}]}