diff: fix side-by-side output with tabbed input

The previous logic conflated some things... in this block:
- j: input characters rendered so far
- nc: number of characters in the line
- col: columns rendered so far
- hw: column width ((h)ard (w)idth?)

Comparing j to hw or col to nc are naturally wrong, as col and hw are
limits on their respective counters and nc is already brought down to hw
if the input line should be truncated to start with.

Right now, we end up easily truncating lines with tabs in them as we
count each tab for $tabwidth lines in the input line, but we really
should only be accounting for them in the column count.  The problem is
most easily demonstrated by the two input files added for the tests,
the two tabbed lines lose at least a word or two even though there's
plenty of space left in the row for each side.

Reviewed by:	bapt, pstef
Sponsored by:	Klara, Inc.
Differential Revision:	https://reviews.freebsd.org/D37676
This commit is contained in:
Kyle Evans 2022-12-13 19:31:21 -06:00
parent 1656007e4c
commit 8bf187f35b
5 changed files with 35 additions and 8 deletions

View file

@ -1247,7 +1247,8 @@ fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags)
printf(" ");
}
col = 0;
for (j = 0, lastc = '\0'; j < nc; j++, lastc = c) {
for (j = 0, lastc = '\0'; j < nc && (hw == 0 || col < hw);
j++, lastc = c) {
c = getc(lb);
if (flags & D_STRIPCR && c == '\r') {
if ((c = getc(lb)) == '\n')
@ -1274,19 +1275,16 @@ fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags)
if (flags & D_EXPANDTABS) {
newcol = ((col / tabsize) + 1) * tabsize;
do {
if (diff_format == D_SIDEBYSIDE)
j++;
printf(" ");
} while (++col < newcol && j < nc);
} while (++col < newcol && col < hw);
} else {
if (diff_format == D_SIDEBYSIDE) {
if ((j + tabsize) > nc) {
printf("%*s", nc - j, "");
j = col = nc;
if ((col + tabsize) > hw) {
printf("%*s", hw - col, "");
col = hw;
} else {
printf("\t");
col += tabsize - 1;
j += tabsize - 1;
}
} else {
printf("\t");

View file

@ -12,6 +12,8 @@ ${PACKAGE}FILES+= \
input2.in \
input_c1.in \
input_c2.in \
side_by_side_tabbed_a.in \
side_by_side_tabbed_b.in \
simple.out \
simple_e.out \
simple_n.out \

View file

@ -7,6 +7,7 @@ atf_test_case header_ns
atf_test_case ifdef
atf_test_case group_format
atf_test_case side_by_side
atf_test_case side_by_side_tabbed
atf_test_case brief_format
atf_test_case b230049
atf_test_case stripcr_o
@ -145,6 +146,23 @@ side_by_side_body()
diff -W 65 -y --suppress-common-lines A B
}
side_by_side_tabbed_body()
{
file_a=$(atf_get_srcdir)/side_by_side_tabbed_a.in
file_b=$(atf_get_srcdir)/side_by_side_tabbed_b.in
atf_check -o save:diffout -s not-exit:0 \
diff -y ${file_a} ${file_b}
atf_check -o save:diffout_expanded -s not-exit:0 \
diff -yt ${file_a} ${file_b}
atf_check -o not-empty grep -Ee 'file A.+file B' diffout
atf_check -o not-empty grep -Ee 'file A.+file B' diffout_expanded
atf_check -o not-empty grep -Ee 'tabs.+tabs' diffout
atf_check -o not-empty grep -Ee 'tabs.+tabs' diffout_expanded
}
brief_format_body()
{
atf_check mkdir A B
@ -343,6 +361,7 @@ atf_init_test_cases()
atf_add_test_case ifdef
atf_add_test_case group_format
atf_add_test_case side_by_side
atf_add_test_case side_by_side_tabbed
atf_add_test_case brief_format
atf_add_test_case b230049
atf_add_test_case stripcr_o

View file

@ -0,0 +1,4 @@
This
is my test file A
it has tabs
Thanks

View file

@ -0,0 +1,4 @@
This
is my test file B
it has tabs
Thanks