master xplshn/aruu / cmd / pseudo / cols.c
  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}