295 lines · 3.8 KB · C
RawDownload
/* 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 voidusage(void){	fprint(2, "usage: %s [-bfx]\n", argv0);	exits("usage");} voidmain(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);} voidoutc(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;	}} voidstore(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);} voidfetch(int lno){	char *p; 	lno %= PL;	p = lbuff;	while (*p)		*p++ = '\0';	line = lbuff;	lp = 0;	if (page[lno])		strcpy(line, page[lno]);} voidemit(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++;		}	}} voidincr(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);} voiddecr(void){	if (ll > mustwr - PL) {		store(ll--);		fetch(ll);	}}