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
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