Add col command

col is used to display troff documents in ttys, removing the reverse
line feeds generated by .2C in ms. This implementation keeps the limit
of 256 lines of 800 characteres of the original implementation.
This commit is contained in:
Roberto E. Vargas Caballero
2015-03-03 10:52:34 +01:00
committed by sin
parent c8f2b068f6
commit 443de0a859
4 changed files with 319 additions and 0 deletions

227
col.c Normal file
View File

@@ -0,0 +1,227 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "util.h"
#define NLINES 256
#define NCOLS 800
char **buff;
int obackspace, onotabs, ohalfline, oescape;
unsigned nline, ncol, nchar, nspaces, maxline, bs;
size_t pagsize = NLINES;
static void
usage(void)
{
enprintf(2, "usage: %s [-p][-l num][-b][-f][-x]\n", argv0);
}
static void
flush(void)
{
int c;
unsigned i, j;
for (i = 0; i < maxline; ++i) {
for (j = 0; j < NCOLS && (c = buff[i][j]) != '\0'; ++j)
putchar(c);
putchar('\n');
}
bs = nchar = nline = ncol = 0;
}
static void
forward(unsigned n)
{
unsigned lim;
for (lim = ncol + n; ncol != lim && nchar < NCOLS-1; ++nchar) {
switch (buff[nline][nchar]) {
case '\b':
--ncol;
break;
case '\0':
buff[nline][nchar] = ' ';
/* FALLTHROUGH */
default:
++ncol;
break;
}
}
}
static void
linefeed(int up, int rcarriage)
{
unsigned oncol = ncol;
nspaces = 0;
if (up > 0) {
if (nline == pagsize-1) {
flush();
} else {
if (++nline > maxline)
maxline = nline;
}
} else {
if (nline > 0)
--nline;
}
bs = 0;
if (rcarriage) {
forward(oncol);
nchar = ncol = 0;
}
}
static void
newchar(int c)
{
char *cp;
forward(nspaces);
nspaces = 0;
switch (c) {
case ' ':
forward(1);
break;
case '\r':
nchar = ncol = 0;
break;
case '\t':
forward(8 - ncol%8);
break;
case '\b':
if (ncol > 0)
--ncol;
if (nchar > 0)
--nchar;
bs = 1;
break;
default:
cp = &buff[nline][nchar];
if (*cp != '\0' && *cp != ' ' && bs && !obackspace) {
if (nchar != NCOLS-3) {
memmove(cp + 3, cp + 1, NCOLS - nchar - 2);
cp[1] = '\b';
nchar += 2;
}
}
if (nchar != NCOLS-1) {
for (cp = buff[nline]; cp < &buff[nline][nchar]; ++cp) {
if (*cp == '\0')
*cp = ' ';
}
buff[nline][nchar++] = c;
++ncol;
}
bs = 0;
}
}
static void
col(void)
{
int c;
while ((c = getchar()) != EOF) {
switch (c) {
case '\x1b':
switch (c = getchar()) {
case '8': /* reverse half-line-feed */
case '7': /* reverse line-feed */
linefeed(-1, 0);
continue;
case '9': /* forward half-line-feed */
if (ohalfline)
break;
linefeed(1, 0);
continue;
}
if (!oescape)
continue;
newchar('\x1b');
if (c != EOF)
newchar(c);
break;
case '\v':
linefeed(-1, 0);
break;
case ' ':
if (!onotabs) {
if (++nspaces != 8)
continue;
c = '\t';
nspaces = 0;
}
/* FALLTHROUGH */
case '\r':
case '\b':
case '\t':
newchar(c);
break;
case '\n':
linefeed(1, 1);
break;
default:
if (!iscntrl(c))
newchar(c);
break;
}
}
}
static void
allocbuf(void)
{
char **bp;
buff = emalloc(sizeof(*buff) * pagsize);
for (bp = buff; bp < &buff[pagsize]; ++bp)
*bp = emalloc(NCOLS);
}
int
main(int argc, char *argv[])
{
ARGBEGIN {
case 'b':
obackspace = 1;
break;
case 'f':
ohalfline = 1;
break;
case 'l':
pagsize = estrtonum(EARGF(usage()), 0, SIZE_MAX);
break;
case 'p':
oescape = 1;
break;
case 'x':
onotabs = 1;
break;
default:
usage();
} ARGEND;
if (argc > 0)
usage();
allocbuf();
col();
flush();
if (ferror(stdin))
enprintf(1, "error reading input");
if (ferror(stdout))
enprintf(2, "error writing output");
return 0;
}