sbase

suckless unix tools
git clone git://git.2f30.org/sbase.git
Log | Files | Refs | README | LICENSE

commit 443de0a85990ab38011ba8b176266f53b1315ca5
parent c8f2b068f6639369f1dc329499194b4cbffa77c2
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Tue Mar  3 10:52:34 +0100

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.

Diffstat:
Makefile | 1+
README | 1+
col.1 | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
col.c | 227+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 319 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile @@ -82,6 +82,7 @@ BIN =\ cksum\ cmp\ cols\ + col\ comm\ cp\ cron\ diff --git a/README b/README @@ -19,6 +19,7 @@ The following tools are implemented ('*' == finished, '#' == UTF-8 support, =* cksum yes none =* cmp yes none #* cols non-posix none + col yes none =* comm yes none =*| cp yes none (-i) =* cron non-posix none diff --git a/col.1 b/col.1 @@ -0,0 +1,90 @@ +.TH COL 1 col +.SH NAME +col - filter reverse line-feeds +.SH SYPNOSIS +.B col +.RB [ \-p ] +.RB [ \-b ] +.RB [ \-f ] +.RB [ \-x ] +.RB [ \-l +.IR num ] +.SH DESCRIPTION +.PP +The +.B col +utility filter all the reverse (and half reverse) line feeds, +as they are produced by nroff with .2C of ms(6) or by tbl(1). +.B col +also replaces spaces by tabs when it is possible. +The control sequences managed by +.B col +are: +.TP +.B ESC-7 +reverse line-feed +.TP +.B ESC-8 +reverse half-line-feed +.TP +.B ESC-9 +forward half-line-feed +.TP +.B VT +vertical-tab +.TP +.B SP +Space +.TP +.B TAB +horizontal tab +.TP +.B RETURN +Carriage return +.TP +.B NL +New line +.PP +All the other control codes and escape sequences are removed. +.B Col +transform all the spaces into tabulators. +.SH OPTIONS +.TP +.B \-p +Print unknown escape sequences to the output. +.TP +.B \-b +Do not print backspaces in output, +and Print only the last overstriked character in the output. +.TP +.B \-f +Allow forward half line feeds in the output. +.TP +.B \-x +Do not convert spaces in tabulators. +.TP +.BI \-l " num" +Increment to +.I num +the number of lines buffered for +.B col. +.SH BUGS +.PP +.B Col +only process text with a maximum of 256 lines with 800 characteres per line, +although the number of lines can be modified with +.B \-l +option. +When the number of lines is bigger, +the buffer is flushed to the output, +so new reverse line feeds can not operate in the flushed lines. +This implementation ignores SI and SO selection character sets, +because it is supposed it will work only with UTF-8 strings, +although the UTF-8 support is missed. +.SH SEE ALSO +.BR nroff (1), +.BR ms (6), +.BR tbl(1). + + + diff --git a/col.c b/col.c @@ -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; +}