tcol: import from plan 9, by popular demand - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 72197f89d47444e3c62e1aa0df8bd7059c29104d
 (DIR) parent fd3496d3ef1b3f27c670c25278cbb0304f74a706
 (HTM) Author: Russ Cox <rsc@swtch.com>
       Date:   Mon, 20 Oct 2014 20:41:41 -0400
       
       col: import from plan 9, by popular demand
       
       TBR=rsc
       https://codereview.appspot.com/158240043
       
       Diffstat:
         A man/man1/col.1                      |      57 +++++++++++++++++++++++++++++++
         A src/cmd/col.c                       |     295 ++++++++++++++++++++++++++++++
       
       2 files changed, 352 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/man/man1/col.1 b/man/man1/col.1
       t@@ -0,0 +1,57 @@
       +.TH COL 1
       +.SH NAME
       +col \- column alignment
       +.SH SYNOPSIS
       +.B col
       +[
       +.B -bfx 
       +]
       +.SH DESCRIPTION
       +.I Col
       +overlays lines to expunge reverse line feeds
       +(ESC-7)
       +and half line feeds (ESC-9 and ESC-8)
       +as produced by
       +.I nroff
       +for .2C in
       +.IR ms (6)
       +or
       +.IR man (6)
       +and for 
       +.IR tbl (1).
       +.I Col
       +is a pure filter.
       +It normally emits only full line feeds;
       +option 
       +.B -f
       +(fine) allows half line feeds too.
       +Option 
       +.B -b
       +removes backspaces, printing just one of each pile of overstruck
       +characters.
       +.I Col
       +normally converts white space to tabs;
       +option
       +.B -x
       +overrides this feature.
       +Other escaped characters and non-printing characters are ignored.
       +.SH EXAMPLES
       +.TP
       +.L
       +tbl file | nroff -ms | col | p
       +Format some tables for printing on typewriters;
       +use
       +.I col
       +to remove reverse line feeds, and 
       +paginate the output.
       +.SH SOURCE
       +.B \*9/src/cmd/col.c
       +.SH SEE ALSO
       +.IR pr (1)
       +.SH BUGS
       +.I Col
       +can't back up more than 128 lines or
       +handle more than 800 characters per line,
       +and understands
       +.L VT
       +(013) as reverse line feed.
 (DIR) diff --git a/src/cmd/col.c b/src/cmd/col.c
       t@@ -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);
       +        }
       +}