git: 174337b9eca0 - stable/13 - sdiff: Fix --expand-tabs and --tabsize.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 01 Aug 2024 16:46:56 UTC
The branch stable/13 has been updated by des:
URL: https://cgit.FreeBSD.org/src/commit/?id=174337b9eca0d28b96f2749b44ff4e29d201c144
commit 174337b9eca0d28b96f2749b44ff4e29d201c144
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-08-01 16:46:18 +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
(cherry picked from commit a834edfccd14a8c0f152a3b0078469af8e05f3fd)
sdiff: Fix binary case.
MFC after: 1 week
Sponsored by: Klara, Inc.
Reviewed by: markj
Differential Revision: https://reviews.freebsd.org/D43942
(cherry picked from commit ad7bef8b890768e68a48bbfa6b92ebf635068504)
sdiff: Fix usage message.
The `--ignore-all-space` option was incorrectly documented as
`--ignore-all-spaces`.
MFC after: 3 days
Sponsored by: Klara, Inc.
Reviewed by: 0mp, markj
Differential Revision: https://reviews.freebsd.org/D46161
(cherry picked from commit ca75b7dac886de66fc06fd31facfa2c561f7567e)
---
usr.bin/sdiff/sdiff.1 | 4 +-
usr.bin/sdiff/sdiff.c | 134 ++++++++++++++++++++++----------------
usr.bin/sdiff/tests/sdiff_test.sh | 36 ++++++++++
3 files changed, 116 insertions(+), 58 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 3dcf18caed0c..daa0f43e0b0e 100644
--- a/usr.bin/sdiff/sdiff.c
+++ b/usr.bin/sdiff/sdiff.c
@@ -51,7 +51,7 @@ static void astrcat(char **, const char *);
static void enqueue(char *, char, char *);
static char *mktmpcpy(const char *);
static int istextfile(FILE *);
-static void binexec(char *, char *, char *) __dead2;
+static int bindiff(FILE *, char *, FILE *, char *);
static void freediff(struct diffline *);
static void int_usage(void);
static int parsecmd(FILE *, FILE *, FILE *);
@@ -72,6 +72,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 */
@@ -127,8 +129,8 @@ 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-W, --ignore-all-spaces: ignore all spaces.",
+ "\t-t, --expand-tabs: expand tabs to spaces.",
+ "\t-W, --ignore-all-space: ignore all whitespace.",
"\t--speed-large-files: assume large file with scattered changes.",
"\t--strip-trailing-cr: strip trailing carriage return.",
"\t--ignore-file-name-case: ignore case of file names.",
@@ -208,7 +210,7 @@ main(int argc, char **argv)
{
FILE *diffpipe, *file1, *file2;
size_t diffargc = 0, flagc = 0, wval = WIDTH;
- int ch, fd[2], i, status;
+ int ch, fd[2], i, ret, status;
pid_t pid;
const char *errstr, *outfile = NULL;
char **diffargv, *diffprog = diff_path, *flagv;
@@ -247,7 +249,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 */
@@ -257,7 +258,6 @@ main(int argc, char **argv)
case 'd':
case 'E':
case 'i':
- case 't':
case 'W':
flagc++;
flagv = realloc(flagv, flagc + 2);
@@ -287,6 +287,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);
@@ -298,6 +301,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;
@@ -348,6 +356,15 @@ main(int argc, char **argv)
filename2 = tmp2;
}
+ if ((file1 = fopen(filename1, "r")) == NULL)
+ err(2, "could not open %s", filename1);
+ if ((file2 = fopen(filename2, "r")) == NULL)
+ err(2, "could not open %s", filename2);
+ if (!istextfile(file1) || !istextfile(file2)) {
+ ret = bindiff(file1, filename1, file2, filename2);
+ goto done;
+ }
+
diffargv[diffargc++] = filename1;
diffargv[diffargc++] = filename2;
/* Add NULL to end of array to indicate end of array. */
@@ -385,26 +402,6 @@ main(int argc, char **argv)
if ((diffpipe = fdopen(fd[0], "r")) == NULL)
err(2, "could not open diff pipe");
- if ((file1 = fopen(filename1, "r")) == NULL)
- err(2, "could not open %s", filename1);
- if ((file2 = fopen(filename2, "r")) == NULL)
- err(2, "could not open %s", filename2);
- if (!istextfile(file1) || !istextfile(file2)) {
- /* Close open files and pipe, delete temps */
- fclose(file1);
- fclose(file2);
- if (diffpipe != NULL)
- fclose(diffpipe);
- if (tmp1)
- if (unlink(tmp1))
- warn("Error deleting %s.", tmp1);
- if (tmp2)
- if (unlink(tmp2))
- warn("Error deleting %s.", tmp2);
- free(tmp1);
- free(tmp2);
- binexec(diffprog, filename1, filename2);
- }
/* Line numbers start at one. */
file1ln = file2ln = 1;
@@ -416,20 +413,10 @@ main(int argc, char **argv)
/* Wait for diff to exit. */
if (waitpid(pid, &status, 0) == -1 || !WIFEXITED(status) ||
WEXITSTATUS(status) >= 2)
- err(2, "diff exited abnormally.");
+ errx(2, "diff exited abnormally");
+ ret = WEXITSTATUS(status);
- /* Delete and free unneeded temporary files. */
- if (tmp1)
- if (unlink(tmp1))
- warn("Error deleting %s.", tmp1);
- if (tmp2)
- if (unlink(tmp2))
- warn("Error deleting %s.", tmp2);
- free(tmp1);
- free(tmp2);
- filename1 = filename2 = tmp1 = tmp2 = NULL;
-
- /* No more diffs, so print common lines. */
+ /* No more diffs, so enqueue common lines. */
if (lflag)
while ((s1 = xfgets(file1)))
enqueue(s1, ' ', NULL);
@@ -447,26 +434,55 @@ main(int argc, char **argv)
/* Process unmodified lines. */
processq();
+done:
+ /* Delete and free unneeded temporary files. */
+ if (tmp1 != NULL) {
+ if (unlink(tmp1) != 0)
+ warn("failed to delete %s", tmp1);
+ free(tmp1);
+ }
+ if (tmp2 != NULL) {
+ if (unlink(tmp2) != 0)
+ warn("failed to delete %s", tmp2);
+ free(tmp2);
+ }
+
/* Return diff exit status. */
free(diffargv);
if (flagc > 0)
free(flagv);
- return (WEXITSTATUS(status));
+ return (ret);
}
/*
- * When sdiff detects a binary file as input, executes them with
- * diff to maintain the same behavior as GNU sdiff with binary input.
+ * When sdiff detects a binary file as input.
*/
-static void
-binexec(char *diffprog, char *f1, char *f2)
+static int
+bindiff(FILE *f1, char *fn1, FILE *f2, char *fn2)
{
-
- char *args[] = {diffprog, f1, f2, (char *) 0};
- execv(diffprog, args);
-
- /* If execv() fails, sdiff's execution will continue below. */
- errx(1, "could not execute diff process");
+ int ch1, ch2;
+
+ flockfile(f1);
+ flockfile(f2);
+ do {
+ ch1 = getc_unlocked(f1);
+ ch2 = getc_unlocked(f2);
+ } while (ch1 != EOF && ch2 != EOF && ch1 == ch2);
+ funlockfile(f2);
+ funlockfile(f1);
+ if (ferror(f1)) {
+ warn("%s", fn1);
+ return (2);
+ }
+ if (ferror(f2)) {
+ warn("%s", fn2);
+ return (2);
+ }
+ if (ch1 != EOF || ch2 != EOF) {
+ printf("Binary files %s and %s differ\n", fn1, fn2);
+ return (1);
+ }
+ return (0);
}
/*
@@ -512,11 +528,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
@@ -524,12 +540,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..83ed93503f18 100755
--- a/usr.bin/sdiff/tests/sdiff_test.sh
+++ b/usr.bin/sdiff/tests/sdiff_test.sh
@@ -191,6 +191,40 @@ 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_test_case binary
+binary_head()
+{
+ atf_set "descr" "Checks binary file handling"
+}
+binary_body()
+{
+ printf "a\0\n" >a
+ printf "b\0\n" >b
+ atf_check -o empty sdiff a a
+ atf_check -o empty sdiff a - <a
+ atf_check -s exit:1 -o match:"Binary files .* differ" \
+ sdiff a b
+ atf_check -s exit:1 -o match:"Binary files .* differ" \
+ sdiff a - <b
+}
+
atf_init_test_cases()
{
atf_add_test_case flags
@@ -203,4 +237,6 @@ atf_init_test_cases()
atf_add_test_case dot
atf_add_test_case stdin
atf_add_test_case short
+ atf_add_test_case tflag
+ atf_add_test_case binary
}