diff options
Diffstat (limited to 'text-utils')
-rw-r--r-- | text-utils/Makefile.am | 2 | ||||
-rw-r--r-- | text-utils/column.c | 214 |
2 files changed, 120 insertions, 96 deletions
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); -} |