From nobody Mon Mar 11 12:35:06 2024 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Ttbp26FDxz5CtrK; Mon, 11 Mar 2024 12:35:06 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Ttbp25b8Xz4CSB; Mon, 11 Mar 2024 12:35:06 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1710160506; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=GtWfp9ybd0ohk61HD6gQrRV2asXQiC2HgrELwjoG9lo=; b=rwYILAqopR86W7YESFTq7KGlov7M8KSTqE/U15aZZc0a9GdbxFEVvS9wOOV5+273cX6qZE wDSYjtSEiEDE9wnXhSZpGbp8o/aBGkA+3g99u1JRk/chf16WFnVVK0Vcdc+Oi22WnvhD9Z Y1C4oom5ONXlqFx8FlAkEDE+SrB3CrXnAs5KK37nW8RTO3IxAy4HmGTVbTLyY3xLHFxfal e1UehWbdU2QLetHpV/bl2QdgGk3Yk6MPYLT1MeQsmjT4spTaalLvPqzRg93YCna9s1g2eY rQ975cbTryQAcmz7f3DQ/NsobGORfx7MjOt1gQ6nrCyyRD37hS4bLksnxh+2tQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1710160506; a=rsa-sha256; cv=none; b=iBsol+XKhEjQWfqfLF0N/TepF/zg+ZLV+sTty5nJlffl+/ZtTr8IblcXEMhEJnDdOqjcBS K294t+MdUZT7dx6nk9oxLqtZzbk4GkmSZPsl4hOmS8qIVYzWxak0X+6sIooewjUjp+LRde SDO22U0at9hrYp7ZFo5u4iGDLGcZ/Aq2oFcI9wDV3R6/kNVShB4bjqnsgurTzQcOCLJ0QI qHoCPzkbgSw0rsEHNYm8sD6/q2YZbwcl80wPE8NZ3+If7WJZBysN+tbL5YmPrbmDYvkOLq 07W6yhU2phTROoTkyLxARv5q0rRlwfiuZFee7mNqryMLaAhcYjm1gFR1gYSSwg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1710160506; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=GtWfp9ybd0ohk61HD6gQrRV2asXQiC2HgrELwjoG9lo=; b=gfpOt+meEwIqz1b8wSrvsKapiUAHhO/DTG5EopS+P653+UtFpeDR1MJQechQDuNV0B3nB/ 5tDxR2iSyJnGQ5RnR3lKA6VuOd5U4olWyEyGrae0rlQGIxYmqzkc9dNVTkndR5LpzOrOny vx/xRCRM7a2VVxCVYXKXD8cyfwtESTdTLZdOZIM3iNwO5F01jmoWLZrJR3B8+5EXCj7u1I kkOR8sepurEpTPSe5tixhwrTG7a6lYnHSjAvsGru/eSOfmprouPrNI/4hECLcbUY+8MbCI e+uZAThCWl5SxIit/KPorXxnUPK/RXuLVc2/r6mRtvQ3b7C1pwSQ5Ew1QuWv+Q== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Ttbp24tL0zVk2; Mon, 11 Mar 2024 12:35:06 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 42BCZ60p028901; Mon, 11 Mar 2024 12:35:06 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 42BCZ6Tf028898; Mon, 11 Mar 2024 12:35:06 GMT (envelope-from git) Date: Mon, 11 Mar 2024 12:35:06 GMT Message-Id: <202403111235.42BCZ6Tf028898@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Dag-Erling =?utf-8?Q?Sm=C3=B8rgrav?= Subject: git: da2905289748 - stable/14 - diff: Fix --expand-tabs and --side-by-side. List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: da290528974846d3ed49138ca0f2de7fff02eaf6 Auto-Submitted: auto-generated The branch stable/14 has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=da290528974846d3ed49138ca0f2de7fff02eaf6 commit da290528974846d3ed49138ca0f2de7fff02eaf6 Author: Dag-Erling Smørgrav AuthorDate: 2024-02-26 18:08:06 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2024-03-11 12:19:06 +0000 diff: Fix --expand-tabs and --side-by-side. * Overhaul column width and padding calculation. * Rewrite print_space() so it is now a) correct and b) understandable. * Rewrite tab expansion in fetch() for the same reason. This brings us in line with GNU diff for all cases I could think of. Sponsored by: Klara, Inc. Reviewed by: imp Differential Revision: https://reviews.freebsd.org/D44014 (cherry picked from commit 53de23f4d140becc3166e87665b0064f215a220e) diff: Bump manual page date. Sponsored by: Klara, Inc. (cherry picked from commit 312b1076c6b0aff9bbcaff058b93385eaf607685) --- usr.bin/diff/diff.1 | 11 ++++- usr.bin/diff/diff.c | 12 ++---- usr.bin/diff/diffreg.c | 113 ++++++++++++++++++++++++++++--------------------- 3 files changed, 79 insertions(+), 57 deletions(-) diff --git a/usr.bin/diff/diff.1 b/usr.bin/diff/diff.1 index e04aeb5d6d67..d3978158d1d1 100644 --- a/usr.bin/diff/diff.1 +++ b/usr.bin/diff/diff.1 @@ -29,7 +29,7 @@ .\" .\" @(#)diff.1 8.1 (Berkeley) 6/30/93 .\" -.Dd March 10, 2022 +.Dd February 26, 2024 .Dt DIFF 1 .Os .Sh NAME @@ -429,6 +429,15 @@ Output at most .Ar number columns when using side by side format. The default value is 130. +Note that unless +.It Fl t +was specified, +.Nm +will always align the second column to a tab stop, so values of +.Fl -width +smaller than approximately five times the value of +.Fl -tabsize +may yield surprising results. .It Fl -changed-group-format Ar GFMT Format input groups in the provided .Pp diff --git a/usr.bin/diff/diff.c b/usr.bin/diff/diff.c index 03eb363fc323..d947c1e01705 100644 --- a/usr.bin/diff/diff.c +++ b/usr.bin/diff/diff.c @@ -276,10 +276,8 @@ main(int argc, char **argv) break; case 'W': width = (int) strtonum(optarg, 1, INT_MAX, &errstr); - if (errstr) { - warnx("Invalid argument for width"); - usage(); - } + if (errstr) + errx(1, "width is %s: %s", errstr, optarg); break; case 'X': read_excludes_file(optarg); @@ -317,10 +315,8 @@ main(int argc, char **argv) break; case OPT_TSIZE: tabsize = (int) strtonum(optarg, 1, INT_MAX, &errstr); - if (errstr) { - warnx("Invalid argument for tabsize"); - usage(); - } + if (errstr) + errx(1, "tabsize is %s: %s", errstr, optarg); break; case OPT_STRIPCR: dflags |= D_STRIPCR; diff --git a/usr.bin/diff/diffreg.c b/usr.bin/diff/diffreg.c index 11aefb73cda6..8042003cd836 100644 --- a/usr.bin/diff/diffreg.c +++ b/usr.bin/diff/diffreg.c @@ -169,7 +169,6 @@ struct context_vec { enum readhash { RH_BINARY, RH_OK, RH_EOF }; -#define MIN_PAD 1 static FILE *opentemp(const char *); static void output(char *, FILE *, char *, FILE *, int); static void check(FILE *, FILE *, int); @@ -209,7 +208,7 @@ static int len[2]; static int pref, suff; /* length of prefix and suffix */ static int slen[2]; static int anychange; -static int hw, padding; /* half width and padding */ +static int hw, lpad, rpad; /* half width and padding */ static int edoffset; static long *ixnew; /* will be overlaid on file[1] */ static long *ixold; /* will be overlaid on klist */ @@ -254,21 +253,44 @@ diffreg(char *file1, char *file2, int flags, int capsicum) lastline = 0; lastmatchline = 0; - /* - * hw excludes padding and make sure when -t is not used, - * the second column always starts from the closest tab stop - */ + /* + * In side-by-side mode, we need to print the left column, a + * change marker surrounded by padding, and the right column. + * + * If expanding tabs, we don't care about alignment, so we simply + * subtract 3 from the width and divide by two. + * + * If not expanding tabs, we need to ensure that the right column + * is aligned to a tab stop. We start with the same formula, then + * decrement until we reach a size that lets us tab-align the + * right column. We then adjust the width down if necessary for + * the padding calculation to work. + * + * Left padding is half the space left over, rounded down; right + * padding is whatever is needed to match the width. + */ if (diff_format == D_SIDEBYSIDE) { - hw = width >> 1; - padding = tabsize - (hw % tabsize); - if ((flags & D_EXPANDTABS) != 0 || (padding % tabsize == 0)) - padding = MIN_PAD; - - hw = (width >> 1) - - ((padding == MIN_PAD) ? (padding << 1) : padding) - 1; + if (flags & D_EXPANDTABS) { + if (width > 3) { + hw = (width - 3) / 2; + } else { + /* not enough space */ + hw = 0; + } + } else if (width <= 3 || width <= tabsize) { + /* not enough space */ + hw = 0; + } else { + hw = (width - 3) / 2; + while (hw > 0 && roundup(hw + 3, tabsize) + hw > width) + hw--; + if (width - (roundup(hw + 3, tabsize) + hw) < tabsize) + width = roundup(hw + 3, tabsize) + hw; + } + lpad = (width - hw * 2 - 1) / 2; + rpad = (width - hw * 2 - 1) - lpad; } - if (flags & D_IGNORECASE) chrtran = cup2low; else @@ -869,7 +891,7 @@ output(char *file1, FILE *f1, char *file2, FILE *f2, int flags) while (i0 <= m && J[i0] == J[i0 - 1] + 1) { if (diff_format == D_SIDEBYSIDE && suppress_common != 1) { nc = fetch(ixold, i0, i0, f1, '\0', 1, flags); - print_space(nc, (hw - nc) + (padding << 1) + 1, flags); + print_space(nc, hw - nc + lpad + 1 + rpad, flags); fetch(ixnew, J[i0], J[i0], f2, '\0', 0, flags); printf("\n"); } @@ -1147,10 +1169,10 @@ proceed: else if (color && c > d) printf("\033[%sm", del_code); if (a > b) { - print_space(0, hw + padding , *pflags); + print_space(0, hw + lpad, *pflags); } else { nc = fetch(ixold, a, b, f1, '\0', 1, *pflags); - print_space(nc, hw - nc + padding, *pflags); + print_space(nc, hw - nc + lpad, *pflags); } if (color && a > b) printf("\033[%sm", add_code); @@ -1159,7 +1181,7 @@ proceed: printf("%c", (a > b) ? '>' : ((c > d) ? '<' : '|')); if (color && c > d) printf("\033[m"); - print_space(hw + padding + 1 , padding, *pflags); + print_space(hw + lpad + 1, rpad, *pflags); fetch(ixnew, c, d, f2, '\0', 0, *pflags); printf("\n"); } @@ -1265,30 +1287,24 @@ fetch(long *f, int a, int b, FILE *lb, int ch, int oldfile, int flags) printf("\n\\ No newline at end of file\n"); return (col); } - /* - * when using --side-by-side, col needs to be increased - * in any case to keep the columns aligned - */ if (c == '\t') { - if (flags & D_EXPANDTABS) { - newcol = ((col / tabsize) + 1) * tabsize; - do { - printf(" "); - } while (++col < newcol && col < hw); + /* + * Calculate where the tab would bring us. + * If it would take us to the end of the + * column, either clip it (if expanding + * tabs) or return right away (if not). + */ + newcol = roundup(col + 1, tabsize); + if ((flags & D_EXPANDTABS) == 0) { + if (hw > 0 && newcol >= hw) + return (col); + printf("\t"); } else { - if (diff_format == D_SIDEBYSIDE) { - if ((col + tabsize) > hw) { - printf("%*s", hw - col, ""); - col = hw; - } else { - printf("\t"); - col += tabsize - 1; - } - } else { - printf("\t"); - col++; - } + if (hw > 0 && newcol > hw) + newcol = hw; + printf("%*s", newcol - col, ""); } + col = newcol; } else { if (diff_format == D_EDIT && j == 1 && c == '\n' && lastc == '.') { @@ -1668,18 +1684,19 @@ print_header(const char *file1, const char *file2) * nc is the preceding number of characters */ static void -print_space(int nc, int n, int flags) { - int i, col; +print_space(int nc, int n, int flags) +{ + int col, newcol, tabstop; - col = n; + col = nc; + newcol = nc + n; + /* first, use tabs if allowed */ if ((flags & D_EXPANDTABS) == 0) { - /* first tabstop may be closer than tabsize */ - i = tabsize - (nc % tabsize); - while (col >= tabsize) { + while ((tabstop = roundup(col + 1, tabsize)) <= newcol) { printf("\t"); - col -= i; - i = tabsize; + col = tabstop; } } - printf("%*s", col, ""); + /* finish with spaces */ + printf("%*s", newcol - col, ""); }