1/* See LICENSE file for copyright and license details. */
2
3#include <sys/ioctl.h>
4
5#include <limits.h>
6#include <stdint.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11
12#include "text.h"
13#include "util.h"
14
15static void
16usage(void)
17{
18 eprintf("usage: %s [-c num] [file ...]\n", argv0);
19}
20
21// ?man cols: format columns
22// ?man arguments: file ...
23// ?man format standard input into vertical columns
24int
25main(int argc, char *argv[])
26{
27 FILE *fp;
28 struct winsize w;
29 struct linebuf b = EMPTY_LINEBUF;
30 size_t chars = 65, maxlen = 0, i, j, k, len, cols, rows;
31 int cflag = 0, ret = 0;
32 char *p;
33
34 ARGBEGIN
35 {
36 // ?man -c:num: print count or perform stdout action
37 case 'c':
38 cflag = 1;
39 chars = estrtonum(
40 EARGF(usage()), 1, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX)
41 );
42 break;
43 default:
44 usage();
45 }
46 ARGEND
47
48 if (!cflag) {
49 if ((p = getenv("COLUMNS")))
50 chars = estrtonum(p, 1, MIN((unsigned long long)LLONG_MAX, (unsigned long long)SIZE_MAX));
51 else if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) && w.ws_col > 0)
52 chars = w.ws_col;
53 }
54
55 if (!argc) {
56 getlines(stdin, &b);
57 } else {
58 for (; *argv; argc--, argv++) {
59 if (!strcmp(*argv, "-")) {
60 *argv = "<stdin>";
61 fp = stdin;
62 } else if (!(fp = fopen(*argv, "r"))) {
63 weprintf("fopen %s:", *argv);
64 ret = 1;
65 continue;
66 }
67 getlines(fp, &b);
68 if (fp != stdin && fshut(fp, *argv))
69 ret = 1;
70 }
71 }
72
73 for (i = 0; i < b.nlines; i++) {
74 for (j = 0, len = 0; j < b.lines[i].len; j++) {
75 if (UTF8_POINT(b.lines[i].data[j]))
76 len++;
77 }
78 if (len && b.lines[i].data[b.lines[i].len - 1] == '\n') {
79 b.lines[i].data[--(b.lines[i].len)] = '\0';
80 len--;
81 }
82 if (len > maxlen)
83 maxlen = len;
84 }
85
86 for (cols = 1; (cols + 1) * maxlen + cols <= chars; cols++)
87 ;
88 rows = b.nlines / cols + (b.nlines % cols > 0);
89
90 for (i = 0; i < rows; i++) {
91 for (j = 0; j < cols && i + j * rows < b.nlines; j++) {
92 for (k = 0, len = 0; k < b.lines[i + j * rows].len; k++) {
93 if (UTF8_POINT(b.lines[i + j * rows].data[k]))
94 len++;
95 }
96 fwrite(b.lines[i + j * rows].data, 1, b.lines[i + j * rows].len, stdout);
97 if (j < cols - 1)
98 for (k = len; k < maxlen + 1; k++)
99 putchar(' ');
100 }
101 putchar('\n');
102 }
103
104 ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>");
105
106 return ret;
107}