col: import from plan 9, by popular demand
TBR=rsc https://codereview.appspot.com/158240043
This commit is contained in:
parent
fd3496d3ef
commit
72197f89d4
2 changed files with 352 additions and 0 deletions
57
man/man1/col.1
Normal file
57
man/man1/col.1
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
.TH COL 1
|
||||||
|
.SH NAME
|
||||||
|
col \- column alignment
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B col
|
||||||
|
[
|
||||||
|
.B -bfx
|
||||||
|
]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.I Col
|
||||||
|
overlays lines to expunge reverse line feeds
|
||||||
|
(ESC-7)
|
||||||
|
and half line feeds (ESC-9 and ESC-8)
|
||||||
|
as produced by
|
||||||
|
.I nroff
|
||||||
|
for .2C in
|
||||||
|
.IR ms (6)
|
||||||
|
or
|
||||||
|
.IR man (6)
|
||||||
|
and for
|
||||||
|
.IR tbl (1).
|
||||||
|
.I Col
|
||||||
|
is a pure filter.
|
||||||
|
It normally emits only full line feeds;
|
||||||
|
option
|
||||||
|
.B -f
|
||||||
|
(fine) allows half line feeds too.
|
||||||
|
Option
|
||||||
|
.B -b
|
||||||
|
removes backspaces, printing just one of each pile of overstruck
|
||||||
|
characters.
|
||||||
|
.I Col
|
||||||
|
normally converts white space to tabs;
|
||||||
|
option
|
||||||
|
.B -x
|
||||||
|
overrides this feature.
|
||||||
|
Other escaped characters and non-printing characters are ignored.
|
||||||
|
.SH EXAMPLES
|
||||||
|
.TP
|
||||||
|
.L
|
||||||
|
tbl file | nroff -ms | col | p
|
||||||
|
Format some tables for printing on typewriters;
|
||||||
|
use
|
||||||
|
.I col
|
||||||
|
to remove reverse line feeds, and
|
||||||
|
paginate the output.
|
||||||
|
.SH SOURCE
|
||||||
|
.B \*9/src/cmd/col.c
|
||||||
|
.SH SEE ALSO
|
||||||
|
.IR pr (1)
|
||||||
|
.SH BUGS
|
||||||
|
.I Col
|
||||||
|
can't back up more than 128 lines or
|
||||||
|
handle more than 800 characters per line,
|
||||||
|
and understands
|
||||||
|
.L VT
|
||||||
|
(013) as reverse line feed.
|
||||||
295
src/cmd/col.c
Normal file
295
src/cmd/col.c
Normal file
|
|
@ -0,0 +1,295 @@
|
||||||
|
/* col - eliminate reverse line feeds */
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ESC = '\033',
|
||||||
|
RLF = '\013',
|
||||||
|
|
||||||
|
PL = 256,
|
||||||
|
LINELN = 800,
|
||||||
|
|
||||||
|
Tabstop = 8, /* must be power of 2 */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int bflag, xflag, fflag;
|
||||||
|
static int cp, lp;
|
||||||
|
static int half;
|
||||||
|
static int ll, llh, mustwr;
|
||||||
|
static int pcp = 0;
|
||||||
|
|
||||||
|
static char *page[PL];
|
||||||
|
static char *line;
|
||||||
|
static char lbuff[LINELN];
|
||||||
|
static Biobuf bin, bout;
|
||||||
|
|
||||||
|
void emit(char *s, int lineno);
|
||||||
|
void incr(void), decr(void);
|
||||||
|
void outc(Rune);
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: %s [-bfx]\n", argv0);
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i, lno;
|
||||||
|
long ch;
|
||||||
|
Rune c;
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'b':
|
||||||
|
bflag++;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
fflag++;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
xflag++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}ARGEND;
|
||||||
|
|
||||||
|
for (ll=0; ll < PL; ll++)
|
||||||
|
page[ll] = nil;
|
||||||
|
|
||||||
|
cp = 0;
|
||||||
|
ll = 0;
|
||||||
|
mustwr = PL;
|
||||||
|
line = lbuff;
|
||||||
|
|
||||||
|
Binit(&bin, 0, OREAD);
|
||||||
|
Binit(&bout, 1, OWRITE);
|
||||||
|
while ((ch = Bgetrune(&bin)) != Beof) {
|
||||||
|
c = ch;
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
incr();
|
||||||
|
incr();
|
||||||
|
cp = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\0':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ESC:
|
||||||
|
c = Bgetrune(&bin);
|
||||||
|
switch (c) {
|
||||||
|
case '7': /* reverse full line feed */
|
||||||
|
decr();
|
||||||
|
decr();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '8': /* reverse half line feed */
|
||||||
|
if (fflag)
|
||||||
|
decr();
|
||||||
|
else
|
||||||
|
if (--half < -1) {
|
||||||
|
decr();
|
||||||
|
decr();
|
||||||
|
half += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '9': /* forward half line feed */
|
||||||
|
if (fflag)
|
||||||
|
incr();
|
||||||
|
else
|
||||||
|
if (++half > 0) {
|
||||||
|
incr();
|
||||||
|
incr();
|
||||||
|
half -= 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RLF:
|
||||||
|
decr();
|
||||||
|
decr();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
cp = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\t':
|
||||||
|
cp = (cp + Tabstop) & -Tabstop;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\b':
|
||||||
|
if (cp > 0)
|
||||||
|
cp--;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ' ':
|
||||||
|
cp++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (!isascii(c) || isprint(c)) {
|
||||||
|
outc(c);
|
||||||
|
cp++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i < PL; i++) {
|
||||||
|
lno = (mustwr+i) % PL;
|
||||||
|
if (page[lno] != 0)
|
||||||
|
emit(page[lno], mustwr+i-PL);
|
||||||
|
}
|
||||||
|
emit(" ", (llh + 1) & -2);
|
||||||
|
exits(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
outc(Rune c)
|
||||||
|
{
|
||||||
|
if (lp > cp) {
|
||||||
|
line = lbuff;
|
||||||
|
lp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (lp < cp) {
|
||||||
|
switch (*line) {
|
||||||
|
case '\0':
|
||||||
|
*line = ' ';
|
||||||
|
lp++;
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
lp--;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lp++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
line++;
|
||||||
|
}
|
||||||
|
while (*line == '\b')
|
||||||
|
line += 2;
|
||||||
|
if (bflag || *line == '\0' || *line == ' ')
|
||||||
|
cp += runetochar(line, &c) - 1;
|
||||||
|
else {
|
||||||
|
char c1, c2, c3;
|
||||||
|
|
||||||
|
c1 = *++line;
|
||||||
|
*line++ = '\b';
|
||||||
|
c2 = *line;
|
||||||
|
*line++ = c;
|
||||||
|
while (c1) {
|
||||||
|
c3 = *line;
|
||||||
|
*line++ = c1;
|
||||||
|
c1 = c2;
|
||||||
|
c2 = c3;
|
||||||
|
}
|
||||||
|
lp = 0;
|
||||||
|
line = lbuff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
store(int lno)
|
||||||
|
{
|
||||||
|
lno %= PL;
|
||||||
|
if (page[lno] != nil)
|
||||||
|
free(page[lno]);
|
||||||
|
page[lno] = malloc((unsigned)strlen(lbuff) + 2);
|
||||||
|
if (page[lno] == nil)
|
||||||
|
sysfatal("out of memory");
|
||||||
|
strcpy(page[lno], lbuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fetch(int lno)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
lno %= PL;
|
||||||
|
p = lbuff;
|
||||||
|
while (*p)
|
||||||
|
*p++ = '\0';
|
||||||
|
line = lbuff;
|
||||||
|
lp = 0;
|
||||||
|
if (page[lno])
|
||||||
|
strcpy(line, page[lno]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
emit(char *s, int lineno)
|
||||||
|
{
|
||||||
|
int ncp;
|
||||||
|
char *p;
|
||||||
|
static int cline = 0;
|
||||||
|
|
||||||
|
if (*s) {
|
||||||
|
while (cline < lineno - 1) {
|
||||||
|
Bputc(&bout, '\n');
|
||||||
|
pcp = 0;
|
||||||
|
cline += 2;
|
||||||
|
}
|
||||||
|
if (cline != lineno) {
|
||||||
|
Bputc(&bout, ESC);
|
||||||
|
Bputc(&bout, '9');
|
||||||
|
cline++;
|
||||||
|
}
|
||||||
|
if (pcp)
|
||||||
|
Bputc(&bout, '\r');
|
||||||
|
pcp = 0;
|
||||||
|
p = s;
|
||||||
|
while (*p) {
|
||||||
|
ncp = pcp;
|
||||||
|
while (*p++ == ' ')
|
||||||
|
if ((++ncp & 7) == 0 && !xflag) {
|
||||||
|
pcp = ncp;
|
||||||
|
Bputc(&bout, '\t');
|
||||||
|
}
|
||||||
|
if (!*--p)
|
||||||
|
break;
|
||||||
|
while (pcp < ncp) {
|
||||||
|
Bputc(&bout, ' ');
|
||||||
|
pcp++;
|
||||||
|
}
|
||||||
|
Bputc(&bout, *p);
|
||||||
|
if (*p++ == '\b')
|
||||||
|
pcp--;
|
||||||
|
else
|
||||||
|
pcp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
incr(void)
|
||||||
|
{
|
||||||
|
int lno;
|
||||||
|
|
||||||
|
store(ll++);
|
||||||
|
if (ll > llh)
|
||||||
|
llh = ll;
|
||||||
|
lno = ll % PL;
|
||||||
|
if (ll >= mustwr && page[lno]) {
|
||||||
|
emit(page[lno], ll - PL);
|
||||||
|
mustwr++;
|
||||||
|
free(page[lno]);
|
||||||
|
page[lno] = nil;
|
||||||
|
}
|
||||||
|
fetch(ll);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
decr(void)
|
||||||
|
{
|
||||||
|
if (ll > mustwr - PL) {
|
||||||
|
store(ll--);
|
||||||
|
fetch(ll);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue