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