diff: ignore tabs consistently with expanding them

* src/io.c (find_and_hash_each_line):
* src/util.c (lines_differ):
Treat '\0', '\a', '\b', '\f', '\r', '\v' consistently with how
side.c treats them when expanding them, e.g., backspacing from
column 1 is a no-op when counting tab columns.
* tests/ignore-tab-expansion: New test.
* tests/Makefile.am (TESTS): Add it.
This commit is contained in:
Paul Eggert 2023-07-05 11:01:01 -07:00
parent 6e091776f8
commit 572249e0fa
5 changed files with 62 additions and 7 deletions

4
NEWS
View File

@ -19,6 +19,10 @@ GNU diffutils NEWS -*- outline -*-
cp /proc/cmdline t; cmp -s /proc/cmdline t || echo files differ
[bug present since "the beginning"]
diff -E no longer mishandles some input lines containing '\a', '\b',
'\f', '\r', '\v', or '\0'.
[bug present since 2.8]
diff -ly no longer mishandles non-ASCII input
[bug#64461 introduced in 2.9]

View File

@ -292,7 +292,7 @@ find_and_hash_each_line (struct file_data *current)
case IGNORE_TAB_EXPANSION_AND_TRAILING_SPACE:
case IGNORE_TRAILING_SPACE:
{
intmax_t column = 0;
intmax_t tab = 0, column = 0;
for (unsigned char c; (c = *p++) != '\n'; )
{
if (ig_white_space & IGNORE_TRAILING_SPACE
@ -318,19 +318,29 @@ find_and_hash_each_line (struct file_data *current)
switch (c)
{
case '\b':
column = (column ? column : tabsize) - 1;
if (0 < column)
column--;
else if (0 < tab)
{
tab--;
column = tabsize - 1;
}
break;
case '\t':
c = ' ';
repetitions = tabsize - column % tabsize;
tab += column / tabsize + 1;
column = 0;
break;
case '\r':
column = 0;
tab = column = 0;
break;
case '\0': case '\a': case '\f': case '\v':
break;
default:
column++;
break;

View File

@ -1212,14 +1212,38 @@ lines_differ (char const *s1, char const *s2)
if (c1 != c2)
break;
}
if (c1 == '\n')
return false;
column++;
if (c1 == '\t' || column == tabsize)
switch (c1)
{
case '\n':
return false;
case '\r':
tab = column = 0;
break;
case '\b':
if (0 < column)
column--;
else if (0 < tab)
{
tab--;
column = tabsize - 1;
}
break;
case '\0': case '\a': case '\f': case '\v':
break;
default:
column++;
if (column < tabsize)
break;
FALLTHROUGH;
case '\t':
tab++;
column = 0;
break;
}
}

View File

@ -16,6 +16,7 @@ TESTS = \
invalid-re \
function-line-vs-leading-space \
ignore-matching-lines \
ignore-tab-expansion \
label-vs-func \
large-subopt \
new-file \

16
tests/ignore-tab-expansion Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
# Test ignoring tab expansion.
. "${srcdir=.}/init.sh"; path_prepend_ ../src
fail=0
for p in '\b' '\r' '\t ' '\n'; do
printf "$p"'\b\tx\n' >a || framework_failure_
printf "$p"'\b x\n' >b || framework_failure
diff -E a b >out || fail=1
compare /dev/null out || fail=1
done
Exit $fail