Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 13 May 2025 10:41:57 GMT
From:      Lexi Winter <ivy@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 313713b24c6d - main - column(1): add -l flag
Message-ID:  <202505131041.54DAfv0Y044145@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by ivy:

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

commit 313713b24c6d2a3061972c4f431515c4f1b01c77
Author:     Lexi Winter <ivy@FreeBSD.org>
AuthorDate: 2025-05-13 10:28:59 +0000
Commit:     Lexi Winter <ivy@FreeBSD.org>
CommitDate: 2025-05-13 10:33:08 +0000

    column(1): add -l flag
    
    the '-l <tblcols>' 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
---
 usr.bin/column/column.1        | 11 ++++++++++-
 usr.bin/column/column.c        | 45 ++++++++++++++++++++++++++++++++----------
 usr.bin/column/tests/column.sh | 30 ++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+), 11 deletions(-)

diff --git a/usr.bin/column/column.1 b/usr.bin/column/column.1
index 4481fccf2c3d..1baf8a916e55 100644
--- a/usr.bin/column/column.1
+++ b/usr.bin/column/column.1
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd July 29, 2004
+.Dd May 13, 2025
 .Dt COLUMN 1
 .Os
 .Sh NAME
@@ -35,6 +35,7 @@
 .Nm
 .Op Fl tx
 .Op Fl c Ar columns
+.Op Fl l Ar tblcols
 .Op Fl s Ar sep
 .Op Ar
 .Sh DESCRIPTION
@@ -53,6 +54,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 d1322312f8fa..aa9e38d560e4 100644
--- a/usr.bin/column/column.c
+++ b/usr.bin/column/column.c
@@ -54,6 +54,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 */
@@ -68,7 +69,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;
 
@@ -81,17 +82,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);
@@ -110,6 +120,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)
@@ -217,7 +230,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);
@@ -226,9 +239,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 *))) ||
@@ -239,6 +254,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)
@@ -319,8 +344,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/column.sh b/usr.bin/column/tests/column.sh
index c7c6502098d4..283dc88bff1a 100644
--- a/usr.bin/column/tests/column.sh
+++ b/usr.bin/column/tests/column.sh
@@ -144,6 +144,7 @@ seven.:eight.:nine
 ::zwei
 drei..
 vier:
+:
 
 END
 
@@ -161,10 +162,39 @@ END
 	atf_check diff expected output
 }
 
+atf_test_case "ncols"
+ncols_head()
+{
+	atf_set descr "column(1) with -t (table) and -s and -l options"
+}
+
+ncols_body()
+{
+	cat >input <<END
+now we have five columns
+here there are four
+now only three
+just two
+one
+END
+
+	cat >expected <<END
+now   we     have five columns
+here  there  are four
+now   only   three
+just  two
+one
+END
+
+	atf_check -o save:output column -tc120 -l3 input
+	atf_check diff expected output
+}
+
 atf_init_test_cases()
 {
 	atf_add_test_case basic
 	atf_add_test_case rows
 	atf_add_test_case basic_table
 	atf_add_test_case colonic_table
+	atf_add_test_case ncols
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202505131041.54DAfv0Y044145>