diff --git a/text-utils/column.1 b/text-utils/column.1 index 18696954b..86886f3bf 100644 --- a/text-utils/column.1 +++ b/text-utils/column.1 @@ -82,6 +82,10 @@ Table output is useful for pretty-printing. .IP "\fB\-N, \-\-table-columns\fP \fInames\fP" Specify the columns names by comma separated list of names. The names are used for the table header or to address column in option arguments. +.IP "\fB\-l, \-\-table-columns-limit\fP \fInumber\fP" +Specify maximal number of the input columns. +The last column will contain all remaining line data if the limit is smaller +than the number of the columns in the input data. .IP "\fB\-R, \-\-table-right\fP \fIcolumns\fP" Right align text in the specified columns. .IP "\fB\-T, \-\-table-truncate\fP \fIcolumns\fP" diff --git a/text-utils/column.c b/text-utils/column.c index 33c7f1f55..238dbab41 100644 --- a/text-utils/column.c +++ b/text-utils/column.c @@ -91,6 +91,7 @@ struct column_control { wchar_t **ents; /* input entries */ size_t nents; /* number of entries */ size_t maxlength; /* longest input record (line) */ + size_t maxncols; /* maximal numer of input columns */ unsigned int greedy :1, json :1, @@ -427,18 +428,24 @@ static void modify_table(struct column_control *ctl) } -static int add_line_to_table(struct column_control *ctl, wchar_t *wcs) +static int add_line_to_table(struct column_control *ctl, wchar_t *wcs0) { - wchar_t *wcdata, *sv = NULL; - size_t n = 0; + wchar_t *wcdata, *sv = NULL, *wcs = wcs0; + size_t n = 0, nchars = 0; struct libscols_line *ln = NULL; if (!ctl->tab) init_table(ctl); - - while ((wcdata = local_wcstok(ctl, wcs, &sv))) { + do { char *data; + if (ctl->maxncols && n + 1 == ctl->maxncols) + wcdata = wcs0 + nchars; + else + wcdata = local_wcstok(ctl, wcs, &sv); + + if (!wcdata) + break; if (scols_table_get_ncols(ctl->tab) < n + 1) { if (scols_table_is_json(ctl->tab)) errx(EXIT_FAILURE, _("line %zu: for JSON the name of the " @@ -453,6 +460,8 @@ static int add_line_to_table(struct column_control *ctl, wchar_t *wcs) err(EXIT_FAILURE, _("failed to allocate output line")); } + nchars += wcslen(wcdata) + 1; + data = wcs_to_mbs(wcdata); if (!data) err(EXIT_FAILURE, _("failed to allocate output data")); @@ -460,7 +469,9 @@ static int add_line_to_table(struct column_control *ctl, wchar_t *wcs) err(EXIT_FAILURE, _("failed to add output data")); n++; wcs = NULL; - } + if (ctl->maxncols && n == ctl->maxncols) + break; + } while (1); return 0; } @@ -633,6 +644,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -n, --table-name table name for JSON output\n"), out); fputs(_(" -O, --table-order specify order of output columns\n"), out); fputs(_(" -N, --table-columns comma separated columns names\n"), out); + fputs(_(" -l, --table-columns-limit maximal number of input columns\n"), out); fputs(_(" -E, --table-noextreme don't count long text from the columns to column width\n"), out); fputs(_(" -d, --table-noheadings don't print header\n"), out); fputs(_(" -e, --table-header-repeat repeat header for each page\n"), out); @@ -684,6 +696,7 @@ int main(int argc, char **argv) { "separator", required_argument, NULL, 's' }, { "table", no_argument, NULL, 't' }, { "table-columns", required_argument, NULL, 'N' }, + { "table-columns-limit", required_argument, NULL, 'l' }, { "table-hide", required_argument, NULL, 'H' }, { "table-name", required_argument, NULL, 'n' }, { "table-noextreme", required_argument, NULL, 'E' }, @@ -715,7 +728,7 @@ int main(int argc, char **argv) ctl.output_separator = " "; ctl.input_separator = mbs_to_wcs("\t "); - while ((c = getopt_long(argc, argv, "c:dE:eH:hi:JLN:n:O:o:p:R:r:s:T:tVW:x", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "c:dE:eH:hi:Jl:LN:n:O:o:p:R:r:s:T:tVW:x", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@ -745,6 +758,11 @@ int main(int argc, char **argv) case 'L': ctl.tab_empty_lines = 1; break; + case 'l': + ctl.maxncols = strtou32_or_err(optarg, _("invalid columns limit argument")); + if (ctl.maxncols == 0) + errx(EXIT_FAILURE, _("columns limit must be greater than zero")); + break; case 'N': ctl.tab_colnames = split_or_error(optarg, _("failed to parse column names")); break;