mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-24 11:41:58 +00:00
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…
Reference in a new issue