Audit cols(1)

1) Refactor manpage.
2) De-globalize local values.
3) update usage().
4) sort local variable declarations.
5) fix wrong argument in strtonum (3 -> 1).
6) argc-argv style, boolean style.
7) check bytes > 0 before accessing b.lines[i][bytes - 1]
   relying on len only makes sense but let's not push it.
7) don't break on maxlen > (chars - 1) / 2. This didn't even
   make sense.
8) _correctly_ calculate cols and rows in a readable way.
9) Rewrite loop over rows and cols in a readable way and
   using putchar in a loop instead of printf-magic or fputs
   where not necessary.
This commit is contained in:
FRIGN 2015-03-08 19:33:46 +01:00
parent 78187474cf
commit f140403fca
3 changed files with 43 additions and 52 deletions

2
README
View File

@ -18,7 +18,7 @@ The following tools are implemented ('*' == finished, '#' == UTF-8 support,
=*| chroot non-posix none
=* cksum yes none
=* cmp yes none
#* cols non-posix none
#*| cols non-posix none
col yes none
=* comm yes none
=*| cp yes none (-i)

19
cols.1
View File

@ -1,4 +1,4 @@
.Dd February 19, 2015
.Dd March 8, 2015
.Dt COLS 1
.Os sbase
.Sh NAME
@ -15,7 +15,8 @@ reads each
in sequence and writes them to stdout, in as many vertical
columns as will fit in
.Ar num
character columns. If no
character columns.
If no
.Ar file
is given,
.Nm
@ -27,17 +28,15 @@ tries to figure out the width of the output
device. If that fails, it defaults to 65 chars.
.Sh OPTIONS
.Bl -tag -width Ds
.It Fl c Ar chars
Set the maximum number of character columns to use
(unless the input contains lines longer than
.Ar num
characters).
.It Fl c Ar num
Set maximum number of character columns to
.Ar num ,
unless input lines exceed this limit.
.El
.Sh ENVIRONMENT
.Bl -tag -width COLUMNS
.Bl -tag -width Ds
.It COLUMNS
If this variable is set, the value is used as the
width of the output device.
The width of the output device.
.El
.Sh HISTORY
.Nm

74
cols.c
View File

@ -12,82 +12,74 @@
#include "utf.h"
#include "util.h"
static size_t chars = 65;
static int cflag;
static struct linebuf b = EMPTY_LINEBUF;
static size_t n_columns;
static size_t n_rows;
static void
usage(void)
{
eprintf("usage: %s [-c chars] [file ...]\n", argv0);
eprintf("usage: %s [-c num] [file ...]\n", argv0);
}
int
main(int argc, char *argv[])
{
size_t i, l, col, len, bytes, maxlen = 0;
struct winsize w;
FILE *fp;
struct winsize w;
struct linebuf b = EMPTY_LINEBUF;
size_t chars = 65, maxlen = 0, i, j, k, len, bytes, cols, rows;
int cflag = 0;
char *p;
ARGBEGIN {
case 'c':
cflag = 1;
chars = estrtonum(EARGF(usage()), 3, MIN(LLONG_MAX, SIZE_MAX));
chars = estrtonum(EARGF(usage()), 1, MIN(LLONG_MAX, SIZE_MAX));
break;
default:
usage();
} ARGEND;
if (cflag == 0) {
if (!cflag) {
if ((p = getenv("COLUMNS")))
chars = estrtonum(p, 1, MIN(LLONG_MAX, SIZE_MAX));
else if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) && w.ws_col > 0)
chars = w.ws_col;
}
if (argc == 0) {
if (!argc) {
getlines(stdin, &b);
} else for (; argc > 0; argc--, argv++) {
if (!(fp = fopen(argv[0], "r")))
eprintf("fopen %s:", argv[0]);
getlines(fp, &b);
fclose(fp);
} else {
for (; *argv; argc--, argv++) {
if (!(fp = fopen(*argv, "r"))) {
weprintf("fopen %s:", *argv);
continue;
}
getlines(fp, &b);
fclose(fp);
}
}
for (l = 0; l < b.nlines; ++l) {
len = utflen(b.lines[l]);
bytes = strlen(b.lines[l]);
if (len > 0 && b.lines[l][bytes - 1] == '\n') {
b.lines[l][bytes - 1] = '\0';
--len;
for (i = 0; i < b.nlines; i++) {
len = utflen(b.lines[i]);
bytes = strlen(b.lines[i]);
if (len && bytes && b.lines[i][bytes - 1] == '\n') {
b.lines[i][bytes - 1] = '\0';
len--;
}
if (len > maxlen)
maxlen = len;
if (maxlen > (chars - 1) / 2)
break;
}
n_columns = (chars + 1) / (maxlen + 1);
if (n_columns <= 1) {
for (l = 0; l < b.nlines; ++l) {
fputs(b.lines[l], stdout);
}
return 0;
}
for (cols = 1; (cols + 1) * maxlen + cols <= chars; cols++);
rows = b.nlines / cols + (b.nlines % cols > 0);
n_rows = (b.nlines + (n_columns - 1)) / n_columns;
for (i = 0; i < n_rows; ++i) {
for (l = i, col = 1; l < b.nlines; l += n_rows, ++col) {
len = utflen(b.lines[l]);
fputs(b.lines[l], stdout);
if (col < n_columns)
printf("%*s", (int)(maxlen + 1 - len), "");
for (i = 0; i < rows; i++) {
for (j = 0; j < cols && i + j * rows < b.nlines; j++) {
len = utflen(b.lines[i + j * rows]);
fputs(b.lines[i + j * rows], stdout);
if (j < cols - 1)
for (k = len; k < maxlen + 1; k++)
putchar(' ');
}
fputs("\n", stdout);
putchar('\n');
}
return 0;