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