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
This commit is contained in:
+10
-1
@@ -25,7 +25,7 @@
|
|||||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.Dd July 29, 2004
|
.Dd May 13, 2025
|
||||||
.Dt COLUMN 1
|
.Dt COLUMN 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
.Nm
|
.Nm
|
||||||
.Op Fl tx
|
.Op Fl tx
|
||||||
.Op Fl c Ar columns
|
.Op Fl c Ar columns
|
||||||
|
.Op Fl l Ar tblcols
|
||||||
.Op Fl s Ar sep
|
.Op Fl s Ar sep
|
||||||
.Op Ar
|
.Op Ar
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
@@ -53,6 +54,14 @@ The options are as follows:
|
|||||||
Output is formatted for a display
|
Output is formatted for a display
|
||||||
.Ar columns
|
.Ar columns
|
||||||
wide.
|
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
|
.It Fl s
|
||||||
Specify a set of characters to be used to delimit columns for the
|
Specify a set of characters to be used to delimit columns for the
|
||||||
.Fl t
|
.Fl t
|
||||||
|
|||||||
+35
-10
@@ -54,6 +54,7 @@ static void usage(void);
|
|||||||
static int width(const wchar_t *);
|
static int width(const wchar_t *);
|
||||||
|
|
||||||
static int termwidth = 80; /* default terminal width */
|
static int termwidth = 80; /* default terminal width */
|
||||||
|
static int tblcols; /* number of table columns for -t */
|
||||||
|
|
||||||
static int entries; /* number of records */
|
static int entries; /* number of records */
|
||||||
static int eval; /* exit value */
|
static int eval; /* exit value */
|
||||||
@@ -68,7 +69,7 @@ main(int argc, char **argv)
|
|||||||
FILE *fp;
|
FILE *fp;
|
||||||
int ch, tflag, xflag;
|
int ch, tflag, xflag;
|
||||||
char *p;
|
char *p;
|
||||||
const char *src;
|
const char *errstr, *src;
|
||||||
wchar_t *newsep;
|
wchar_t *newsep;
|
||||||
size_t seplen;
|
size_t seplen;
|
||||||
|
|
||||||
@@ -81,17 +82,26 @@ main(int argc, char **argv)
|
|||||||
termwidth = win.ws_col;
|
termwidth = win.ws_col;
|
||||||
|
|
||||||
tflag = xflag = 0;
|
tflag = xflag = 0;
|
||||||
while ((ch = getopt(argc, argv, "c:s:tx")) != -1)
|
while ((ch = getopt(argc, argv, "c:l:s:tx")) != -1)
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
case 'c':
|
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;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
src = optarg;
|
src = optarg;
|
||||||
seplen = mbsrtowcs(NULL, &src, 0, NULL);
|
seplen = mbsrtowcs(NULL, &src, 0, NULL);
|
||||||
if (seplen == (size_t)-1)
|
if (seplen == (size_t)-1)
|
||||||
err(1, "bad separator");
|
err(1, "bad separator");
|
||||||
newsep = malloc((seplen + 1) * sizeof(wchar_t));
|
newsep = calloc(seplen + 1, sizeof(wchar_t));
|
||||||
if (newsep == NULL)
|
if (newsep == NULL)
|
||||||
err(1, NULL);
|
err(1, NULL);
|
||||||
mbsrtowcs(newsep, &src, seplen + 1, NULL);
|
mbsrtowcs(newsep, &src, seplen + 1, NULL);
|
||||||
@@ -110,6 +120,9 @@ main(int argc, char **argv)
|
|||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
|
|
||||||
|
if (tblcols && !tflag)
|
||||||
|
errx(1, "the -l flag cannot be used without the -t flag");
|
||||||
|
|
||||||
if (!*argv)
|
if (!*argv)
|
||||||
input(stdin);
|
input(stdin);
|
||||||
else for (; *argv; ++argv)
|
else for (; *argv; ++argv)
|
||||||
@@ -217,7 +230,7 @@ maketbl(void)
|
|||||||
int *lens, maxcols;
|
int *lens, maxcols;
|
||||||
TBL *tbl;
|
TBL *tbl;
|
||||||
wchar_t **cols;
|
wchar_t **cols;
|
||||||
wchar_t *last;
|
wchar_t *s;
|
||||||
|
|
||||||
if ((t = tbl = calloc(entries, sizeof(TBL))) == NULL)
|
if ((t = tbl = calloc(entries, sizeof(TBL))) == NULL)
|
||||||
err(1, NULL);
|
err(1, NULL);
|
||||||
@@ -226,9 +239,11 @@ maketbl(void)
|
|||||||
if ((lens = calloc(maxcols, sizeof(int))) == NULL)
|
if ((lens = calloc(maxcols, sizeof(int))) == NULL)
|
||||||
err(1, NULL);
|
err(1, NULL);
|
||||||
for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) {
|
for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) {
|
||||||
for (coloff = 0, p = *lp;
|
for (p = *lp; wcschr(separator, *p); ++p)
|
||||||
(cols[coloff] = wcstok(p, separator, &last));
|
/* nothing */ ;
|
||||||
p = NULL)
|
for (coloff = 0; *p;) {
|
||||||
|
cols[coloff] = p;
|
||||||
|
|
||||||
if (++coloff == maxcols) {
|
if (++coloff == maxcols) {
|
||||||
if (!(cols = realloc(cols, ((u_int)maxcols +
|
if (!(cols = realloc(cols, ((u_int)maxcols +
|
||||||
DEFCOLS) * sizeof(wchar_t *))) ||
|
DEFCOLS) * sizeof(wchar_t *))) ||
|
||||||
@@ -239,6 +254,16 @@ maketbl(void)
|
|||||||
0, DEFCOLS * sizeof(int));
|
0, DEFCOLS * sizeof(int));
|
||||||
maxcols += DEFCOLS;
|
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)
|
if ((t->list = calloc(coloff, sizeof(*t->list))) == NULL)
|
||||||
err(1, NULL);
|
err(1, NULL);
|
||||||
if ((t->len = calloc(coloff, sizeof(int))) == NULL)
|
if ((t->len = calloc(coloff, sizeof(int))) == NULL)
|
||||||
@@ -319,8 +344,8 @@ width(const wchar_t *wcs)
|
|||||||
static void
|
static void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
(void)fprintf(stderr,
|
(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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ seven.:eight.:nine
|
|||||||
::zwei
|
::zwei
|
||||||
drei..
|
drei..
|
||||||
vier:
|
vier:
|
||||||
|
:
|
||||||
|
|
||||||
END
|
END
|
||||||
|
|
||||||
@@ -161,10 +162,39 @@ END
|
|||||||
atf_check diff expected output
|
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_init_test_cases()
|
||||||
{
|
{
|
||||||
atf_add_test_case basic
|
atf_add_test_case basic
|
||||||
atf_add_test_case rows
|
atf_add_test_case rows
|
||||||
atf_add_test_case basic_table
|
atf_add_test_case basic_table
|
||||||
atf_add_test_case colonic_table
|
atf_add_test_case colonic_table
|
||||||
|
atf_add_test_case ncols
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user