summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/commands.sh.in1
-rw-r--r--tests/diff/column/fillrow0
-rw-r--r--tests/diff/column/separator_table0
-rw-r--r--tests/expected/column/fillrow4
-rw-r--r--tests/expected/column/separator_table10
-rwxr-xr-xtests/ts/column/fillrow29
-rw-r--r--tests/ts/column/input10
-rwxr-xr-xtests/ts/column/separator_table29
-rw-r--r--text-utils/Makefile.am2
-rw-r--r--text-utils/column.c214
10 files changed, 203 insertions, 96 deletions
diff --git a/tests/commands.sh.in b/tests/commands.sh.in
index 0318046d7..0fc86404d 100644
--- a/tests/commands.sh.in
+++ b/tests/commands.sh.in
@@ -47,6 +47,7 @@ TS_CMD_FSCKMINIX=${TS_CMD_FSCKMINIX:-"$top_builddir/disk-utils/fsck.minix"}
TS_CMD_IPCS=${TS_CMD_IPCS:-"$top_builddir/sys-utils/ipcs"}
TS_CMD_COL=${TS_CMD_COL:-"$top_builddir/text-utils/col"}
+TS_CMD_COLUMN=${TS_CMD_COLUMN:-"$top_builddir/text-utils/column"}
TS_CMD_NAMEI=${TS_CMD_NAMEI-"$top_builddir/misc-utils/namei"}
TS_CMD_LOOK=${TS_CMD_LOOK-"$top_builddir/misc-utils/look"}
diff --git a/tests/diff/column/fillrow b/tests/diff/column/fillrow
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/diff/column/fillrow
diff --git a/tests/diff/column/separator_table b/tests/diff/column/separator_table
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/diff/column/separator_table
diff --git a/tests/expected/column/fillrow b/tests/expected/column/fillrow
new file mode 100644
index 000000000..07f99520f
--- /dev/null
+++ b/tests/expected/column/fillrow
@@ -0,0 +1,4 @@
+0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5
+0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5
+0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5
+0 1 2 3 4 5
diff --git a/tests/expected/column/separator_table b/tests/expected/column/separator_table
new file mode 100644
index 000000000..bf974c338
--- /dev/null
+++ b/tests/expected/column/separator_table
@@ -0,0 +1,10 @@
+0 1 3 4 5
+0 1 3 4 5
+0 1 3 4 5
+0 1 3 4 5
+0 1 3 4 5
+0 1 3 4 5
+0 1 3 4 5
+0 1 3 4 5
+0 1 3 4 5
+0 1 3 4 5
diff --git a/tests/ts/column/fillrow b/tests/ts/column/fillrow
new file mode 100755
index 000000000..172e8587f
--- /dev/null
+++ b/tests/ts/column/fillrow
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+#
+# Copyright (C) 2011 Sami Kerola <kerolasa@iki.fi>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="$(dirname $0)/../.."
+TS_DESC="fill row"
+
+. $TS_TOPDIR/functions.sh
+ts_init "$*"
+
+cd $TS_OUTDIR
+
+$TS_CMD_COLUMN -x -c 50 $TS_SELF/input >> $TS_OUTPUT 2>&1
+
+ts_finalize
+
diff --git a/tests/ts/column/input b/tests/ts/column/input
new file mode 100644
index 000000000..d3ea4a8f6
--- /dev/null
+++ b/tests/ts/column/input
@@ -0,0 +1,10 @@
+0 1 2 3 4 5
+0 1 2 3 4 5
+0 1 2 3 4 5
+0 1 2 3 4 5
+0 1 2 3 4 5
+0 1 2 3 4 5
+0 1 2 3 4 5
+0 1 2 3 4 5
+0 1 2 3 4 5
+0 1 2 3 4 5
diff --git a/tests/ts/column/separator_table b/tests/ts/column/separator_table
new file mode 100755
index 000000000..fe6f83c0a
--- /dev/null
+++ b/tests/ts/column/separator_table
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+#
+# Copyright (C) 2011 Sami Kerola <kerolasa@iki.fi>
+#
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+TS_TOPDIR="$(dirname $0)/../.."
+TS_DESC="separator & table"
+
+. $TS_TOPDIR/functions.sh
+ts_init "$*"
+
+cd $TS_OUTDIR
+
+$TS_CMD_COLUMN -s 2 -t $TS_SELF/input >> $TS_OUTPUT 2>&1
+
+ts_finalize
+
diff --git a/text-utils/Makefile.am b/text-utils/Makefile.am
index 513f1c367..cc4b8b66d 100644
--- a/text-utils/Makefile.am
+++ b/text-utils/Makefile.am
@@ -4,6 +4,8 @@ EXTRA_DIST = README.clear README.col
usrbin_exec_PROGRAMS = col colcrt colrm column hexdump rev line tailf
+column_SOURCES = column.c $(top_srcdir)/lib/strutils.c
+
hexdump_SOURCES = hexdump.c conv.c display.c hexsyntax.c parse.c \
hexdump.h $(top_srcdir)/lib/strutils.c
diff --git a/text-utils/column.c b/text-utils/column.c
index ffc91df65..bb6147cf9 100644
--- a/text-utils/column.c
+++ b/text-utils/column.c
@@ -54,6 +54,7 @@
#include "widechar.h"
#include "c.h"
#include "xalloc.h"
+#include "strutils.h"
#ifdef HAVE_WIDECHAR
#define wcs_width(s) wcswidth(s,wcslen(s))
@@ -70,37 +71,17 @@ static char *mtsafe_strtok(char *, const char *, char **);
#define DEFNUM 1000
#define MAXLINELEN (LINE_MAX + 1)
-static void c_columnate __P((void));
-static void *emalloc __P((int));
-static void input __P((FILE *));
-static void maketbl __P((void));
-static void print __P((void));
-static void r_columnate __P((void));
+static int input(FILE *fp, int *maxlength, wchar_t ***list, int *entries);
+static void c_columnate(int maxlength, long termwidth, wchar_t **list, int entries);
+static void r_columnate(int maxlength, long termwidth, wchar_t **list, int entries);
+static void maketbl(wchar_t **list, int entries, wchar_t *separator);
+static void print(wchar_t **list, int entries);
typedef struct _tbl {
wchar_t **list;
int cols, *len;
} TBL;
-int termwidth = 80; /* default terminal width */
-
-int entries; /* number of records */
-int eval; /* exit value */
-int maxlength; /* longest record */
-wchar_t **list; /* array of pointers to records */
-wchar_t default_separator[] = { '\t', ' ', 0 };
-wchar_t *separator = default_separator; /* field separator for table option */
-
-static const struct option longopts[] =
-{
- { "help", 0, 0, 'h' },
- { "columns", 0, 0, 'c' },
- { "table", 0, 0, 't' },
- { "separator", 0, 0, 's' },
- { "fillrows", 0, 0, 'x' },
- { NULL, 0, 0, 0 },
-};
-
static void __attribute__((__noreturn__)) usage(int rc)
{
FILE *out = rc == EXIT_FAILURE ? stderr : stdout;
@@ -111,6 +92,7 @@ static void __attribute__((__noreturn__)) usage(int rc)
fprintf(out, _(
" -h, --help displays this help text\n"
+ " -V, --version output version information and exit\n"
" -c, --columns <width> width of output in number of characters\n"
" -t, --table create a table\n"
" -s, --separator <string> table delimeter\n"
@@ -119,33 +101,61 @@ static void __attribute__((__noreturn__)) usage(int rc)
fprintf(out, _("\nFor more information see column(1).\n"));
exit(rc);
}
-int
-main(int argc, char **argv)
+
+int main(int argc, char **argv)
{
struct winsize win;
FILE *fp;
int ch, tflag, xflag;
char *p;
+ long termwidth;
+ int entries = 0; /* number of records */
+ unsigned int eval = 0; /* exit value */
+ int maxlength; /* longest record */
+ wchar_t **list = NULL; /* array of pointers to records */
+ /* field separator for table option */
+ wchar_t default_separator[] = { '\t', ' ', 0 };
+ wchar_t *separator = default_separator;
+
+ static const struct option longopts[] =
+ {
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'V' },
+ { "columns", 0, 0, 'c' },
+ { "table", 0, 0, 't' },
+ { "separator", 0, 0, 's' },
+ { "fillrows", 0, 0, 'x' },
+ { NULL, 0, 0, 0 },
+ };
+
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
if ((p = getenv("COLUMNS")) != NULL)
- termwidth = atoi(p);
+ termwidth = strtol_or_err(p,
+ _("terminal environment COLUMNS failed"));
} else
termwidth = win.ws_col;
tflag = xflag = 0;
- while ((ch = getopt_long(argc, argv, "h?c:s:tx", longopts, NULL)) != -1)
+ while ((ch = getopt_long(argc, argv, "hVc:s:tx", longopts, NULL)) != -1)
switch(ch) {
case 'h':
- case '?':
usage(EXIT_SUCCESS);
break;
+ case 'V':
+ printf(_("%s from %s\n"), program_invocation_short_name,
+ PACKAGE_STRING);
+ return EXIT_SUCCESS;
case 'c':
- termwidth = atoi(optarg);
+ termwidth = strtol_or_err(optarg,
+ _("bad columns width value"));
+ if (termwidth < 1)
+ errx(EXIT_FAILURE,
+ _("-%c positive integer expected as an argument"), ch);
break;
case 's':
separator = mbs_to_wcs(optarg);
@@ -158,42 +168,49 @@ main(int argc, char **argv)
break;
default:
usage(EXIT_FAILURE);
- }
+ }
argc -= optind;
argv += optind;
if (!*argv)
- input(stdin);
- else {
+ eval += input(stdin, &maxlength, &list, &entries);
+ else
for (; *argv; ++argv) {
if ((fp = fopen(*argv, "r")) != NULL) {
- input(fp);
- (void)fclose(fp);
+ eval += input(fp, &maxlength, &list, &entries);
+ fclose(fp);
} else {
warn("%s", *argv);
- eval = EXIT_FAILURE;
+ eval += EXIT_FAILURE;
}
}
- }
if (!entries)
exit(eval);
if (tflag)
- maketbl();
+ maketbl(list, entries, separator);
else if (maxlength >= termwidth)
- print();
+ print(list, entries);
else if (xflag)
- c_columnate();
+ c_columnate(maxlength, termwidth, list, entries);
else
- r_columnate();
+ r_columnate(maxlength, termwidth, list, entries);
+
+ for (int i = 0; i < entries; i++)
+ free(list[i]);
+ free(list);
+
if (ferror(stdout) || fclose(stdout))
- eval = EXIT_FAILURE;
- exit(eval);
+ eval += EXIT_FAILURE;
+
+ if (eval == 0)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
}
-static void
-c_columnate()
+static void c_columnate(int maxlength, long termwidth, wchar_t **list, int entries)
{
int chcnt, col, cnt, endcol, numcols;
wchar_t **lp;
@@ -222,8 +239,7 @@ c_columnate()
putwchar('\n');
}
-static void
-r_columnate()
+static void r_columnate(int maxlength, long termwidth, wchar_t **list, int entries)
{
int base, chcnt, cnt, col, endcol, numcols, numrows, row;
@@ -252,8 +268,7 @@ r_columnate()
}
}
-static void
-print()
+static void print(wchar_t **list, int entries)
{
int cnt;
wchar_t **lp;
@@ -264,36 +279,37 @@ print()
}
}
-static void
-maketbl()
+static void maketbl(wchar_t **list, int entries, wchar_t *separator)
{
TBL *t;
- int coloff, cnt, i;
+ int cnt, i;
wchar_t *p, **lp;
- int *lens, maxcols;
+ ssize_t *lens;
+ ssize_t maxcols = DEFCOLS, coloff;
TBL *tbl;
wchar_t **cols;
wchar_t *wcstok_state;
- t = tbl = emalloc(entries * sizeof(TBL));
- cols = emalloc((maxcols = DEFCOLS) * sizeof(wchar_t *));
- lens = emalloc(maxcols * sizeof(int));
- for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) {
- for (coloff = 0, p = *lp;
- (cols[coloff] = wcstok(p, separator, &wcstok_state)) != NULL;
- p = NULL) {
+ t = tbl = xcalloc(entries, sizeof(TBL));
+ cols = xcalloc(maxcols, sizeof(wchar_t *));
+ lens = xcalloc(maxcols, sizeof(ssize_t));
+
+ for (lp = list, cnt = 0; cnt < entries; ++cnt, ++lp, ++t) {
+ coloff = 0;
+ p = *lp;
+ while ((cols[coloff] = wcstok(p, separator, &wcstok_state)) != NULL) {
if (++coloff == maxcols) {
- cols = xrealloc(cols, ((u_int)maxcols + DEFCOLS)
- * sizeof(wchar_t *));
- lens = xrealloc(lens, ((u_int)maxcols + DEFCOLS)
- * sizeof(int));
- memset((char *)lens + maxcols * sizeof(int),
- 0, DEFCOLS * sizeof(int));
maxcols += DEFCOLS;
+ cols = xrealloc(cols, maxcols * sizeof(wchar_t *));
+ lens = xrealloc(lens, maxcols * sizeof(ssize_t));
+ /* zero fill only new memory */
+ memset(lens + ((maxcols - DEFCOLS) * sizeof(ssize_t)), 0,
+ DEFCOLS * sizeof(int));
}
+ p = NULL;
}
- t->list = emalloc(coloff * sizeof(wchar_t *));
- t->len = emalloc(coloff * sizeof(int));
+ t->list = xcalloc(coloff, sizeof(wchar_t *));
+ t->len = xcalloc(coloff, sizeof(int));
for (t->cols = coloff; --coloff >= 0;) {
t->list[coloff] = cols[coloff];
t->len[coloff] = wcs_width(cols[coloff]);
@@ -301,7 +317,8 @@ maketbl()
lens[coloff] = t->len[coloff];
}
}
- for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) {
+
+ for (t = tbl, cnt = 0; cnt < entries; ++cnt, ++t) {
for (coloff = 0; coloff < t->cols - 1; ++coloff) {
fputws(t->list[coloff], stdout);
for (i = lens[coloff] - t->len[coloff] + 2; i > 0; i--)
@@ -312,20 +329,30 @@ maketbl()
putwchar('\n');
}
}
+
+ for (cnt = 0; cnt < entries; ++cnt) {
+ free((tbl+cnt)->list);
+ free((tbl+cnt)->len);
+ }
+ free(cols);
+ free(lens);
+ free(tbl);
}
-static void
-input(fp)
- FILE *fp;
+static int input(FILE *fp, int *maxlength, wchar_t ***list, int *entries)
{
- static int maxentry;
- int len, lineno = 1, reportedline = 0;
+ static int maxentry = DEFNUM;
+ int len, lineno = 1, reportedline = 0, eval = 0;
wchar_t *p, buf[MAXLINELEN];
+ wchar_t **local_list;
+ int local_entries = *entries;
+
+ if (!local_list)
+ local_list = xcalloc(maxentry, sizeof(wchar_t *));
- if (!list)
- list = emalloc((maxentry = DEFNUM) * sizeof(wchar_t *));
while (fgetws(buf, MAXLINELEN, fp)) {
- for (p = buf; *p && iswspace(*p); ++p);
+ for (p = buf; *p && iswspace(*p); ++p)
+ ;
if (!*p)
continue;
if (!(p = wcschr(p, '\n')) && !feof(fp)) {
@@ -334,21 +361,27 @@ input(fp)
lineno);
reportedline = lineno;
}
- eval = EXIT_FAILURE;
+ eval = 1;
continue;
}
lineno++;
if (!feof(fp))
*p = '\0';
len = wcs_width(buf); /* len = p - buf; */
- if (maxlength < len)
- maxlength = len;
- if (entries == maxentry) {
+ if (*maxlength < len)
+ *maxlength = len;
+ if (local_entries == maxentry) {
maxentry += DEFNUM;
- list = xrealloc(list, (u_int)maxentry * sizeof(wchar_t *));
+ local_list = xrealloc(local_list,
+ (u_int)maxentry * sizeof(wchar_t *));
}
- list[entries++] = wcsdup(buf);
+ local_list[local_entries++] = wcsdup(buf);
}
+
+ *list = local_list;
+ *entries = local_entries;
+
+ return eval;
}
#ifdef HAVE_WIDECHAR
@@ -393,14 +426,3 @@ static char *mtsafe_strtok(char *str, const char *delim, char **ptr)
}
}
#endif
-
-static void *
-emalloc(size)
- int size;
-{
- char *p;
-
- p = xmalloc(size);
- memset(p, 0, size);
- return (p);
-}