296 lines
3.8 KiB
C
296 lines
3.8 KiB
C
/* 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);
|
|
}
|
|
}
|