/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include "util.h" #define NLINES 256 #define NCOLS 800 static char **buff; static int obackspace, onotabs, ohalfline, oescape; static unsigned nline, ncol, nchar, nspaces, maxline, bs; static size_t pagsize = NLINES; static void flush(void) { int c; unsigned i, j; for (i = 0; i < maxline; ++i) { for (j = 0; j < NCOLS && (c = buff[i][j]) != '\0'; ++j) putchar(c); putchar('\n'); } bs = nchar = nline = ncol = 0; } static void forward(unsigned n) { unsigned lim; for (lim = ncol + n; ncol != lim && nchar < NCOLS-1; ++nchar) { switch (buff[nline][nchar]) { case '\b': --ncol; break; case '\0': buff[nline][nchar] = ' '; /* FALLTHROUGH */ default: ++ncol; break; } } } static void linefeed(int up, int rcarriage) { unsigned oncol = ncol; nspaces = 0; if (up > 0) { if (nline == pagsize-1) { flush(); } else { if (++nline > maxline) maxline = nline; } } else { if (nline > 0) --nline; } bs = 0; if (rcarriage) { forward(oncol); nchar = ncol = 0; } } static void newchar(int c) { char *cp; forward(nspaces); nspaces = 0; switch (c) { case ' ': forward(1); break; case '\r': nchar = ncol = 0; break; case '\t': forward(8 - ncol%8); break; case '\b': if (ncol > 0) --ncol; if (nchar > 0) --nchar; bs = 1; break; default: cp = &buff[nline][nchar]; if (*cp != '\0' && *cp != ' ' && bs && !obackspace) { if (nchar != NCOLS-3) { memmove(cp + 3, cp + 1, NCOLS - nchar - 2); cp[1] = '\b'; nchar += 2; } } if (nchar != NCOLS-1) { for (cp = buff[nline]; cp < &buff[nline][nchar]; ++cp) { if (*cp == '\0') *cp = ' '; } buff[nline][nchar++] = c; ++ncol; } bs = 0; } } static void col(void) { int c; while ((c = getchar()) != EOF) { switch (c) { case '\x1b': switch (c = getchar()) { case '8': /* reverse half-line-feed */ case '7': /* reverse line-feed */ linefeed(-1, 0); continue; case '9': /* forward half-line-feed */ if (ohalfline) break; linefeed(1, 0); continue; } if (!oescape) continue; newchar('\x1b'); if (c != EOF) newchar(c); break; case '\v': linefeed(-1, 0); break; case ' ': if (!onotabs) { if (++nspaces != 8) continue; c = '\t'; nspaces = 0; } /* FALLTHROUGH */ case '\r': case '\b': case '\t': newchar(c); break; case '\n': linefeed(1, 1); break; default: if (!iscntrl(c)) newchar(c); break; } } } static void allocbuf(void) { char **bp; buff = emallocarray(pagsize, sizeof(*buff)); for (bp = buff; bp < &buff[pagsize]; ++bp) *bp = emalloc(NCOLS); } static void usage(void) { enprintf(2, "usage: %s [-p][-l num][-b][-f][-x]\n", argv0); } int main(int argc, char *argv[]) { ARGBEGIN { case 'b': obackspace = 1; break; case 'f': ohalfline = 1; break; case 'l': pagsize = estrtonum(EARGF(usage()), 0, SIZE_MAX); break; case 'p': oescape = 1; break; case 'x': onotabs = 1; break; default: usage(); } ARGEND; if (argc > 0) usage(); allocbuf(); col(); flush(); if (ferror(stdin)) enprintf(1, "error reading input"); if (ferror(stdout)) enprintf(2, "error writing output"); return 0; }