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 }