diff --git a/usr.bin/column/column.1 b/usr.bin/column/column.1 --- 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 February 18, 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 @@ 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 --- a/usr.bin/column/column.c +++ b/usr.bin/column/column.c @@ -54,6 +54,7 @@ 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 @@ FILE *fp; int ch, tflag, xflag; char *p; - const char *src; + const char *src, *errstr; wchar_t *newsep; size_t seplen; @@ -81,10 +82,19 @@ 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; @@ -110,6 +120,9 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 --- a/usr.bin/column/tests/column.sh +++ b/usr.bin/column/tests/column.sh @@ -144,6 +144,7 @@ ::zwei drei.. vier: +: END @@ -161,10 +162,39 @@ 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 <expected <