4  * Copyright (c) 2007 Junio C Hamano
 
  10 static struct whitespace_rule {
 
  11         const char *rule_name;
 
  13         unsigned loosens_error:1,
 
  15 } whitespace_rule_names[] = {
 
  16         { "trailing-space", WS_TRAILING_SPACE, 0 },
 
  17         { "space-before-tab", WS_SPACE_BEFORE_TAB, 0 },
 
  18         { "indent-with-non-tab", WS_INDENT_WITH_NON_TAB, 0 },
 
  19         { "cr-at-eol", WS_CR_AT_EOL, 1 },
 
  20         { "blank-at-eol", WS_BLANK_AT_EOL, 0 },
 
  21         { "blank-at-eof", WS_BLANK_AT_EOF, 0 },
 
  22         { "tab-in-indent", WS_TAB_IN_INDENT, 0, 1 },
 
  25 unsigned parse_whitespace_rule(const char *string)
 
  27         unsigned rule = WS_DEFAULT_RULE;
 
  35                 string = string + strspn(string, ", \t\n\r");
 
  36                 ep = strchr(string, ',');
 
  49                 for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++) {
 
  50                         if (strncmp(whitespace_rule_names[i].rule_name,
 
  54                                 rule &= ~whitespace_rule_names[i].rule_bits;
 
  56                                 rule |= whitespace_rule_names[i].rule_bits;
 
  62         if (rule & WS_TAB_IN_INDENT && rule & WS_INDENT_WITH_NON_TAB)
 
  63                 die("cannot enforce both tab-in-indent and indent-with-non-tab");
 
  67 static void setup_whitespace_attr_check(struct git_attr_check *check)
 
  69         static struct git_attr *attr_whitespace;
 
  72                 attr_whitespace = git_attr("whitespace");
 
  73         check[0].attr = attr_whitespace;
 
  76 unsigned whitespace_rule(const char *pathname)
 
  78         struct git_attr_check attr_whitespace_rule;
 
  80         setup_whitespace_attr_check(&attr_whitespace_rule);
 
  81         if (!git_checkattr(pathname, 1, &attr_whitespace_rule)) {
 
  84                 value = attr_whitespace_rule.value;
 
  85                 if (ATTR_TRUE(value)) {
 
  86                         /* true (whitespace) */
 
  87                         unsigned all_rule = 0;
 
  89                         for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++)
 
  90                                 if (!whitespace_rule_names[i].loosens_error &&
 
  91                                     !whitespace_rule_names[i].exclude_default)
 
  92                                         all_rule |= whitespace_rule_names[i].rule_bits;
 
  94                 } else if (ATTR_FALSE(value)) {
 
  95                         /* false (-whitespace) */
 
  97                 } else if (ATTR_UNSET(value)) {
 
  98                         /* reset to default (!whitespace) */
 
  99                         return whitespace_rule_cfg;
 
 102                         return parse_whitespace_rule(value);
 
 105                 return whitespace_rule_cfg;
 
 109 /* The returned string should be freed by the caller. */
 
 110 char *whitespace_error_string(unsigned ws)
 
 112         struct strbuf err = STRBUF_INIT;
 
 113         if ((ws & WS_TRAILING_SPACE) == WS_TRAILING_SPACE)
 
 114                 strbuf_addstr(&err, "trailing whitespace");
 
 116                 if (ws & WS_BLANK_AT_EOL)
 
 117                         strbuf_addstr(&err, "trailing whitespace");
 
 118                 if (ws & WS_BLANK_AT_EOF) {
 
 120                                 strbuf_addstr(&err, ", ");
 
 121                         strbuf_addstr(&err, "new blank line at EOF");
 
 124         if (ws & WS_SPACE_BEFORE_TAB) {
 
 126                         strbuf_addstr(&err, ", ");
 
 127                 strbuf_addstr(&err, "space before tab in indent");
 
 129         if (ws & WS_INDENT_WITH_NON_TAB) {
 
 131                         strbuf_addstr(&err, ", ");
 
 132                 strbuf_addstr(&err, "indent with spaces");
 
 134         if (ws & WS_TAB_IN_INDENT) {
 
 136                         strbuf_addstr(&err, ", ");
 
 137                 strbuf_addstr(&err, "tab in indent");
 
 139         return strbuf_detach(&err, NULL);
 
 142 /* If stream is non-NULL, emits the line after checking. */
 
 143 static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule,
 
 144                                 FILE *stream, const char *set,
 
 145                                 const char *reset, const char *ws)
 
 149         int trailing_whitespace = -1;
 
 150         int trailing_newline = 0;
 
 151         int trailing_carriage_return = 0;
 
 154         /* Logic is simpler if we temporarily ignore the trailing newline. */
 
 155         if (len > 0 && line[len - 1] == '\n') {
 
 156                 trailing_newline = 1;
 
 159         if ((ws_rule & WS_CR_AT_EOL) &&
 
 160             len > 0 && line[len - 1] == '\r') {
 
 161                 trailing_carriage_return = 1;
 
 165         /* Check for trailing whitespace. */
 
 166         if (ws_rule & WS_BLANK_AT_EOL) {
 
 167                 for (i = len - 1; i >= 0; i--) {
 
 168                         if (isspace(line[i])) {
 
 169                                 trailing_whitespace = i;
 
 170                                 result |= WS_BLANK_AT_EOL;
 
 177         /* Check indentation */
 
 178         for (i = 0; i < len; i++) {
 
 183                 if ((ws_rule & WS_SPACE_BEFORE_TAB) && written < i) {
 
 184                         result |= WS_SPACE_BEFORE_TAB;
 
 187                                 fwrite(line + written, i - written, 1, stream);
 
 188                                 fputs(reset, stream);
 
 189                                 fwrite(line + i, 1, 1, stream);
 
 191                 } else if (ws_rule & WS_TAB_IN_INDENT) {
 
 192                         result |= WS_TAB_IN_INDENT;
 
 194                                 fwrite(line + written, i - written, 1, stream);
 
 196                                 fwrite(line + i, 1, 1, stream);
 
 197                                 fputs(reset, stream);
 
 200                         fwrite(line + written, i - written + 1, 1, stream);
 
 205         /* Check for indent using non-tab. */
 
 206         if ((ws_rule & WS_INDENT_WITH_NON_TAB) && i - written >= 8) {
 
 207                 result |= WS_INDENT_WITH_NON_TAB;
 
 210                         fwrite(line + written, i - written, 1, stream);
 
 211                         fputs(reset, stream);
 
 218                  * Now the rest of the line starts at "written".
 
 219                  * The non-highlighted part ends at "trailing_whitespace".
 
 221                 if (trailing_whitespace == -1)
 
 222                         trailing_whitespace = len;
 
 224                 /* Emit non-highlighted (middle) segment. */
 
 225                 if (trailing_whitespace - written > 0) {
 
 227                         fwrite(line + written,
 
 228                             trailing_whitespace - written, 1, stream);
 
 229                         fputs(reset, stream);
 
 232                 /* Highlight errors in trailing whitespace. */
 
 233                 if (trailing_whitespace != len) {
 
 235                         fwrite(line + trailing_whitespace,
 
 236                             len - trailing_whitespace, 1, stream);
 
 237                         fputs(reset, stream);
 
 239                 if (trailing_carriage_return)
 
 241                 if (trailing_newline)
 
 247 void ws_check_emit(const char *line, int len, unsigned ws_rule,
 
 248                    FILE *stream, const char *set,
 
 249                    const char *reset, const char *ws)
 
 251         (void)ws_check_emit_1(line, len, ws_rule, stream, set, reset, ws);
 
 254 unsigned ws_check(const char *line, int len, unsigned ws_rule)
 
 256         return ws_check_emit_1(line, len, ws_rule, NULL, NULL, NULL, NULL);
 
 259 int ws_blank_line(const char *line, int len, unsigned ws_rule)
 
 262          * We _might_ want to treat CR differently from other
 
 263          * whitespace characters when ws_rule has WS_CR_AT_EOL, but
 
 264          * for now we just use this stupid definition.
 
 274 /* Copy the line onto the end of the strbuf while fixing whitespaces */
 
 275 void ws_fix_copy(struct strbuf *dst, const char *src, int len, unsigned ws_rule, int *error_count)
 
 278          * len is number of bytes to be copied from src, starting
 
 279          * at src.  Typically src[len-1] is '\n', unless this is
 
 280          * the incomplete last line.
 
 283         int add_nl_to_tail = 0;
 
 284         int add_cr_to_tail = 0;
 
 286         int last_tab_in_indent = -1;
 
 287         int last_space_in_indent = -1;
 
 288         int need_fix_leading_space = 0;
 
 291          * Strip trailing whitespace
 
 293         if (ws_rule & WS_BLANK_AT_EOL) {
 
 294                 if (0 < len && src[len - 1] == '\n') {
 
 297                         if (0 < len && src[len - 1] == '\r') {
 
 298                                 add_cr_to_tail = !!(ws_rule & WS_CR_AT_EOL);
 
 302                 if (0 < len && isspace(src[len - 1])) {
 
 303                         while (0 < len && isspace(src[len-1]))
 
 310          * Check leading whitespaces (indent)
 
 312         for (i = 0; i < len; i++) {
 
 315                         last_tab_in_indent = i;
 
 316                         if ((ws_rule & WS_SPACE_BEFORE_TAB) &&
 
 317                             0 <= last_space_in_indent)
 
 318                             need_fix_leading_space = 1;
 
 319                 } else if (ch == ' ') {
 
 320                         last_space_in_indent = i;
 
 321                         if ((ws_rule & WS_INDENT_WITH_NON_TAB) &&
 
 322                             8 <= i - last_tab_in_indent)
 
 323                                 need_fix_leading_space = 1;
 
 328         if (need_fix_leading_space) {
 
 329                 /* Process indent ourselves */
 
 330                 int consecutive_spaces = 0;
 
 331                 int last = last_tab_in_indent + 1;
 
 333                 if (ws_rule & WS_INDENT_WITH_NON_TAB) {
 
 334                         /* have "last" point at one past the indent */
 
 335                         if (last_tab_in_indent < last_space_in_indent)
 
 336                                 last = last_space_in_indent + 1;
 
 338                                 last = last_tab_in_indent + 1;
 
 342                  * between src[0..last-1], strip the funny spaces,
 
 343                  * updating them to tab as needed.
 
 345                 for (i = 0; i < last; i++) {
 
 348                                 consecutive_spaces = 0;
 
 349                                 strbuf_addch(dst, ch);
 
 351                                 consecutive_spaces++;
 
 352                                 if (consecutive_spaces == 8) {
 
 353                                         strbuf_addch(dst, '\t');
 
 354                                         consecutive_spaces = 0;
 
 358                 while (0 < consecutive_spaces--)
 
 359                         strbuf_addch(dst, ' ');
 
 363         } else if ((ws_rule & WS_TAB_IN_INDENT) && last_tab_in_indent >= 0) {
 
 364                 /* Expand tabs into spaces */
 
 365                 int last = last_tab_in_indent + 1;
 
 366                 for (i = 0; i < last; i++) {
 
 369                                         strbuf_addch(dst, ' ');
 
 370                                 } while (dst->len % 8);
 
 372                                 strbuf_addch(dst, src[i]);
 
 379         strbuf_add(dst, src, len);
 
 381                 strbuf_addch(dst, '\r');
 
 383                 strbuf_addch(dst, '\n');
 
 384         if (fixed && error_count)