diff options
author | Russ Cox <rsc@swtch.com> | 2014-10-20 20:41:41 -0400 |
---|---|---|
committer | Russ Cox <rsc@swtch.com> | 2014-10-20 20:41:41 -0400 |
commit | 72197f89d47444e3c62e1aa0df8bd7059c29104d (patch) | |
tree | e3d8ea98b35c26053c3aa46d505e53740054baff /src/cmd/col.c | |
parent | fd3496d3ef1b3f27c670c25278cbb0304f74a706 (diff) | |
download | plan9port-72197f89d47444e3c62e1aa0df8bd7059c29104d.tar.gz plan9port-72197f89d47444e3c62e1aa0df8bd7059c29104d.tar.bz2 plan9port-72197f89d47444e3c62e1aa0df8bd7059c29104d.zip |
col: import from plan 9, by popular demand
TBR=rsc
https://codereview.appspot.com/158240043
Diffstat (limited to 'src/cmd/col.c')
-rw-r--r-- | src/cmd/col.c | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/src/cmd/col.c b/src/cmd/col.c new file mode 100644 index 00000000..5897e17c --- /dev/null +++ b/src/cmd/col.c @@ -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); + } +} |