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