git: a834edfccd14 - main - sdiff: Fix --expand-tabs and --tabsize.

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Sun, 18 Feb 2024 17:41:39 UTC
The branch main has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=a834edfccd14a8c0f152a3b0078469af8e05f3fd

commit a834edfccd14a8c0f152a3b0078469af8e05f3fd
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2024-02-18 17:39:28 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2024-02-18 17:39:50 +0000

    sdiff: Fix --expand-tabs and --tabsize.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Reviewed by:    markj
    Differential Revision:  https://reviews.freebsd.org/D43941
---
 usr.bin/sdiff/sdiff.1             |  4 +---
 usr.bin/sdiff/sdiff.c             | 32 ++++++++++++++++++++++++--------
 usr.bin/sdiff/tests/sdiff_test.sh | 18 ++++++++++++++++++
 3 files changed, 43 insertions(+), 11 deletions(-)

diff --git a/usr.bin/sdiff/sdiff.1 b/usr.bin/sdiff/sdiff.1
index ef9bb95a0990..ca6594c6479a 100644
--- a/usr.bin/sdiff/sdiff.1
+++ b/usr.bin/sdiff/sdiff.1
@@ -3,7 +3,7 @@
 .\" Written by Raymond Lai <ray@cyth.net>.
 .\" Public domain.
 .\"
-.Dd April 8, 2017
+.Dd February 16, 2024
 .Dt SDIFF 1
 .Os
 .Sh NAME
@@ -117,8 +117,6 @@ Ignore all spaces.
 Ignore blank lines.
 .It Fl E -ignore-tab-expansion
 Treat tabs and eight spaces as the same.
-.It Fl t -ignore-tabs
-Ignore tabs.
 .It Fl H -speed-large-files
 Assume scattered small changes in a large file.
 .It Fl -ignore-file-name-case
diff --git a/usr.bin/sdiff/sdiff.c b/usr.bin/sdiff/sdiff.c
index c6a4c5f9c477..41284d54f869 100644
--- a/usr.bin/sdiff/sdiff.c
+++ b/usr.bin/sdiff/sdiff.c
@@ -71,6 +71,8 @@ static size_t file1ln, file2ln;	/* line number of file1 and file2 */
 static bool Iflag;		/* ignore sets matching regexp */
 static bool lflag;		/* print only left column for identical lines */
 static bool sflag;		/* skip identical lines */
+static bool tflag;		/* expand tabs */
+static int tabsize = 8;		/* tab size */
 FILE *outfp;			/* file to save changes to */
 const char *tmpdir;		/* TMPDIR or /tmp */
 
@@ -126,7 +128,7 @@ static const char *help_msg[] = {
 	"\t-d, --minimal: minimize diff size.",
 	"\t-I RE, --ignore-matching-lines=RE: ignore changes whose line matches RE.",
 	"\t-i, --ignore-case: do a case-insensitive comparison.",
-	"\t-t, --expand-tabs: sxpand tabs to spaces.",
+	"\t-t, --expand-tabs: expand tabs to spaces.",
 	"\t-W, --ignore-all-spaces: ignore all spaces.",
 	"\t--speed-large-files: assume large file with scattered changes.",
 	"\t--strip-trailing-cr: strip trailing carriage return.",
@@ -246,7 +248,6 @@ main(int argc, char **argv)
 		case FCASE_IGNORE_OPT:
 		case FCASE_SENSITIVE_OPT:
 		case STRIPCR_OPT:
-		case TSIZE_OPT:
 		case 'S':
 		break;
 		/* combine no-arg single switches */
@@ -256,7 +257,6 @@ main(int argc, char **argv)
 		case 'd':
 		case 'E':
 		case 'i':
-		case 't':
 		case 'W':
 			flagc++;
 			flagv = realloc(flagv, flagc + 2);
@@ -286,6 +286,9 @@ main(int argc, char **argv)
 		case 's':
 			sflag = true;
 			break;
+		case 't':
+			tflag = true;
+			break;
 		case 'w':
 			wval = strtonum(optarg, WIDTH_MIN,
 			    INT_MAX, &errstr);
@@ -297,6 +300,11 @@ main(int argc, char **argv)
 				printf("%s\n", help_msg[i]);
 			exit(0);
 			break;
+		case TSIZE_OPT:
+			tabsize = strtonum(optarg, 1, INT_MAX, &errstr);
+			if (errstr)
+				errx(2, "tabsize is %s: %s", errstr, optarg);
+			break;
 		default:
 			usage();
 			break;
@@ -511,11 +519,11 @@ printcol(const char *s, size_t *col, const size_t col_max)
 			 * If rounding to next multiple of eight causes
 			 * an integer overflow, just return.
 			 */
-			if (*col > SIZE_MAX - 8)
+			if (*col > SIZE_MAX - tabsize)
 				return;
 
 			/* Round to next multiple of eight. */
-			new_col = (*col / 8 + 1) * 8;
+			new_col = (*col / tabsize + 1) * tabsize;
 
 			/*
 			 * If printing the tab goes past the column
@@ -523,12 +531,20 @@ printcol(const char *s, size_t *col, const size_t col_max)
 			 */
 			if (new_col > col_max)
 				return;
-			*col = new_col;
+
+			if (tflag) {
+				do {
+					putchar(' ');
+				} while (++*col < new_col);
+			} else {
+				putchar(*s);
+				*col = new_col;
+			}
 			break;
 		default:
-			++(*col);
+			++*col;
+			putchar(*s);
 		}
-		putchar(*s);
 	}
 }
 
diff --git a/usr.bin/sdiff/tests/sdiff_test.sh b/usr.bin/sdiff/tests/sdiff_test.sh
index 100fa1b123b0..c701c1704d3c 100755
--- a/usr.bin/sdiff/tests/sdiff_test.sh
+++ b/usr.bin/sdiff/tests/sdiff_test.sh
@@ -191,6 +191,23 @@ short_body()
 $(atf_get_srcdir)/d_input2 >/dev/null ; cat merge.out"
 }
 
+atf_test_case tflag
+tflag_head()
+{
+	atf_set "descr" "Checks tab expansion"
+}
+tflag_body()
+{
+	printf "a\tb\n" >a
+	printf "b\ta\n" >b
+	atf_check -s exit:1 -o match:$'a\tb' \
+		  sdiff a b
+	atf_check -s exit:1 -o match:"a {7}b" \
+		  sdiff -t a b
+	atf_check -s exit:1 -o match:"a {3}b" \
+		  sdiff -t --tabsize 4 a b
+}
+
 atf_init_test_cases()
 {
 	atf_add_test_case flags
@@ -203,4 +220,5 @@ atf_init_test_cases()
 	atf_add_test_case dot
 	atf_add_test_case stdin
 	atf_add_test_case short
+	atf_add_test_case tflag
 }