aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/col.c
diff options
context:
space:
mode:
authorRuss Cox <rsc@swtch.com>2014-10-20 20:41:41 -0400
committerRuss Cox <rsc@swtch.com>2014-10-20 20:41:41 -0400
commit72197f89d47444e3c62e1aa0df8bd7059c29104d (patch)
treee3d8ea98b35c26053c3aa46d505e53740054baff /src/cmd/col.c
parentfd3496d3ef1b3f27c670c25278cbb0304f74a706 (diff)
downloadplan9port-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.c295
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);
+ }
+}