| /* 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); | 
 | 	} | 
 | } |