From nobody Mon May 19 09:30:48 2025 X-Original-To: dev-commits-src-all@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 4b1C951b9lz5wqFf; Mon, 19 May 2025 09:30:49 +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 "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4b1C945zmyz3K2G; Mon, 19 May 2025 09:30:48 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1747647048; 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=OTTJNygpler3+lvfmI53ALZpUW8/OhxBEbiyJrch3+I=; b=gce0LChZ9OWwsJGZ3pnFJKMwhUVyGyAmvTLdfsxTFWew+SZRWUPZ0VkAtNp5fvxmynTANN q3+WRxHb8xItMFlx7Sh3DOmzPJxc/08QzZ4vSaUe4Ihnc/SLO8D+I632HbM1gF6hZ250CF i+ygwnzS5DYWGVroXHa2U2o1HxQWG5xdROOxMw1hmrCo2wtSTx+FC8otVU7uJkBY8AVP/p lobUCQc2/PgEupr5GXz4zpnZpfMJsziKKl8iO23GNivaij7pqWiJZIsaiEJ7kLdy0GB5I2 FQbkAhkzFJ13jxN1a20V9yZHo+EONwsnu4NSsBfPhmnCCwgMHAbqFIdw+k2esQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1747647048; 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=OTTJNygpler3+lvfmI53ALZpUW8/OhxBEbiyJrch3+I=; b=nGJx5jNAqSJZiPYr/iPfzMAQMGDGioFCSpl1RwtUJT8jDcDKY0kEMdTgdvZghMeUNxyQwv 4d6FdDSgTXx9aT6Kyqn0Y8M/2b7dEWUeY5u36dJRfm3gSmUl/nExA6c8DqUBD2O41/0CU+ kEXF8+aUlAREfiHjrMeAg1AeK57qT0DF6/XYGrTXjYlVNxCEevM8CGrCXdCGRuxgPbAaCa sDt2Zy62/EuiGyFm2eAK6pb1gzhuNcVpJWX7hcoJEEVyWvlUy4QqB2jCQrm9am/M0uBNr/ wGIfDJOwA5eDeOJvKY7nZoEVRQZHMcxCc+YzxNsqGmQYR9+q4uvsmnlgwtDu5Q== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1747647048; a=rsa-sha256; cv=none; b=lCYmiYXJD0rFQcoHsxcae7xdtahUPkDTBNnBLW3vYy1Zc055ZC7NBu2toPxyTC1nuf/Bpp oA2RbmQem3OKCX3cJrPwQX4hcGHFNnwKjFiBPa4+0oXeJpY0DjuVfI5pbaVtNRH2efv4Yk +amtTC6so+iT22Ua4mN5VSr6mXpmAJoUD8w/rLwais/U24nG7UYVXMV3qn3+IKklosY7rZ ovtVD5S4U67otODaM0DG8uQEfOdbOk754EI3eLSOVTWjZFyiSrRxynm93LwvuyyZnWirzS SHWQZc3hrHx3rpyY/OdOET6OyaHUdL9lKzPDbR4uYP/Ccodr/cdYzxcUHvzmDQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none 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 4b1C945b1wzyK0; Mon, 19 May 2025 09:30:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 54J9Um8X023152; Mon, 19 May 2025 09:30:48 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 54J9Umo8023149; Mon, 19 May 2025 09:30:48 GMT (envelope-from git) Date: Mon, 19 May 2025 09:30:48 GMT Message-Id: <202505190930.54J9Umo8023149@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Lexi Winter Subject: git: e5081477e6b3 - stable/14 - column(1): add tests and -l flag List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: ivy X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: e5081477e6b3a7f9533c57b2bf68b6ee305614b2 Auto-Submitted: auto-generated The branch stable/14 has been updated by ivy: URL: https://cgit.FreeBSD.org/src/commit/?id=e5081477e6b3a7f9533c57b2bf68b6ee305614b2 commit e5081477e6b3a7f9533c57b2bf68b6ee305614b2 Author: Lexi Winter AuthorDate: 2025-05-07 09:27:20 +0000 Commit: Lexi Winter CommitDate: 2025-05-19 09:29:55 +0000 column(1): add tests and -l flag column(1): add tests Reviewed by: des Approved by: des (mentor) Differential Revision: https://reviews.freebsd.org/D49911 (cherry picked from commit 6f2b1b56ac3dd154bd98f5a7ea075abcb4356560) column(1): add -l flag the '-l ' flag limits the number of columns that column(1) will produce in -t mode. this is syntax-compatible with the same option in util-linux's column(1), but due to existing differences between the two implementations, it's not semantically compatible. as a side-effect, fix a pre-existing bug where empty fields could cause incorrect output: % echo ':' | column -ts: (null) while here, also fix a couple of minor existing issues. Reviewed by: des Approved by: des (mentor) Differential Revision: https://reviews.freebsd.org/D50290 (cherry picked from commit 313713b24c6d2a3061972c4f431515c4f1b01c77) --- etc/mtree/BSD.tests.dist | 2 + usr.bin/column/Makefile | 4 + usr.bin/column/column.1 | 11 ++- usr.bin/column/column.c | 45 +++++++--- usr.bin/column/tests/Makefile | 3 + usr.bin/column/tests/column.sh | 200 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 254 insertions(+), 11 deletions(-) diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index a6b2eed725b8..2159b24978c0 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -1041,6 +1041,8 @@ .. cmp .. + column + .. compress .. cpio diff --git a/usr.bin/column/Makefile b/usr.bin/column/Makefile index 1c304e2b3927..23933d9ef96f 100644 --- a/usr.bin/column/Makefile +++ b/usr.bin/column/Makefile @@ -1,5 +1,9 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 +.include PROG= column +HAS_TESTS= +SUBDIR.${MK_TESTS}= tests + .include diff --git a/usr.bin/column/column.1 b/usr.bin/column/column.1 index f9b05ccf2210..c9dff361cc9c 100644 --- a/usr.bin/column/column.1 +++ b/usr.bin/column/column.1 @@ -27,7 +27,7 @@ .\" .\" @(#)column.1 8.1 (Berkeley) 6/6/93 .\" -.Dd July 29, 2004 +.Dd May 13, 2025 .Dt COLUMN 1 .Os .Sh NAME @@ -37,6 +37,7 @@ .Nm .Op Fl tx .Op Fl c Ar columns +.Op Fl l Ar tblcols .Op Fl s Ar sep .Op Ar .Sh DESCRIPTION @@ -55,6 +56,14 @@ The options are as follows: Output is formatted for a display .Ar columns wide. +.It Fl l +When used with +.Fl t , +limit the table to +.Ar tblcols +columns in width. +The last column will contain the rest of the line, +including any delimiters. .It Fl s Specify a set of characters to be used to delimit columns for the .Fl t diff --git a/usr.bin/column/column.c b/usr.bin/column/column.c index a808113649bc..97fc83e6b589 100644 --- a/usr.bin/column/column.c +++ b/usr.bin/column/column.c @@ -67,6 +67,7 @@ static void usage(void); static int width(const wchar_t *); static int termwidth = 80; /* default terminal width */ +static int tblcols; /* number of table columns for -t */ static int entries; /* number of records */ static int eval; /* exit value */ @@ -81,7 +82,7 @@ main(int argc, char **argv) FILE *fp; int ch, tflag, xflag; char *p; - const char *src; + const char *errstr, *src; wchar_t *newsep; size_t seplen; @@ -94,17 +95,26 @@ main(int argc, char **argv) termwidth = win.ws_col; tflag = xflag = 0; - while ((ch = getopt(argc, argv, "c:s:tx")) != -1) + while ((ch = getopt(argc, argv, "c:l:s:tx")) != -1) switch(ch) { case 'c': - termwidth = atoi(optarg); + termwidth = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) + errx(1, "invalid terminal width \"%s\": %s", + optarg, errstr); + break; + case 'l': + tblcols = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) + errx(1, "invalid max width \"%s\": %s", + optarg, errstr); break; case 's': src = optarg; seplen = mbsrtowcs(NULL, &src, 0, NULL); if (seplen == (size_t)-1) err(1, "bad separator"); - newsep = malloc((seplen + 1) * sizeof(wchar_t)); + newsep = calloc(seplen + 1, sizeof(wchar_t)); if (newsep == NULL) err(1, NULL); mbsrtowcs(newsep, &src, seplen + 1, NULL); @@ -123,6 +133,9 @@ main(int argc, char **argv) argc -= optind; argv += optind; + if (tblcols && !tflag) + errx(1, "the -l flag cannot be used without the -t flag"); + if (!*argv) input(stdin); else for (; *argv; ++argv) @@ -230,7 +243,7 @@ maketbl(void) int *lens, maxcols; TBL *tbl; wchar_t **cols; - wchar_t *last; + wchar_t *s; if ((t = tbl = calloc(entries, sizeof(TBL))) == NULL) err(1, NULL); @@ -239,9 +252,11 @@ maketbl(void) if ((lens = calloc(maxcols, sizeof(int))) == NULL) err(1, NULL); for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) { - for (coloff = 0, p = *lp; - (cols[coloff] = wcstok(p, separator, &last)); - p = NULL) + for (p = *lp; wcschr(separator, *p); ++p) + /* nothing */ ; + for (coloff = 0; *p;) { + cols[coloff] = p; + if (++coloff == maxcols) { if (!(cols = realloc(cols, ((u_int)maxcols + DEFCOLS) * sizeof(wchar_t *))) || @@ -252,6 +267,16 @@ maketbl(void) 0, DEFCOLS * sizeof(int)); maxcols += DEFCOLS; } + + if ((!tblcols || coloff < tblcols) && + (s = wcspbrk(p, separator))) { + *s++ = L'\0'; + while (*s && wcschr(separator, *s)) + ++s; + p = s; + } else + break; + } if ((t->list = calloc(coloff, sizeof(*t->list))) == NULL) err(1, NULL); if ((t->len = calloc(coloff, sizeof(int))) == NULL) @@ -332,8 +357,8 @@ width(const wchar_t *wcs) static void usage(void) { - (void)fprintf(stderr, - "usage: column [-tx] [-c columns] [-s sep] [file ...]\n"); + "usage: column [-tx] [-c columns] [-l tblcols]" + " [-s sep] [file ...]\n"); exit(1); } diff --git a/usr.bin/column/tests/Makefile b/usr.bin/column/tests/Makefile new file mode 100644 index 000000000000..40a7767f0dc0 --- /dev/null +++ b/usr.bin/column/tests/Makefile @@ -0,0 +1,3 @@ +ATF_TESTS_SH= column + +.include diff --git a/usr.bin/column/tests/column.sh b/usr.bin/column/tests/column.sh new file mode 100644 index 000000000000..283dc88bff1a --- /dev/null +++ b/usr.bin/column/tests/column.sh @@ -0,0 +1,200 @@ +# SPDX-License-Identifier: ISC +# +# Copyright (c) 2025 Lexi Winter +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +atf_test_case "basic" +basic_head() +{ + atf_set descr "Basic column(1) with default options" +} + +basic_body() +{ + cat >input.1 <input.2 <input.3 <expected <input.1 <input.2 <input.3 <expected <input.1 <input.2 <input.3 <expected <input <expected <input <expected <