Files
sbase/col.c
T

222 lines
3.3 KiB
C
Raw Normal View History

2015-03-03 13:36:25 +00:00
/* See LICENSE file for copyright and license details. */
2015-03-22 21:43:59 +01:00
#include <limits.h>
2015-03-03 10:52:34 +01:00
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
2015-03-22 21:43:59 +01:00
#include "utf.h"
2015-03-03 10:52:34 +01:00
#include "util.h"
2015-03-30 21:48:26 +02:00
#define NLINES 128
2015-03-03 10:52:34 +01:00
#define NCOLS 800
2015-03-22 21:43:59 +01:00
static Rune **buf;
2015-03-03 10:52:34 +01:00
2015-03-22 21:43:59 +01:00
static int backspace, notabs, halfline, escape;
static size_t nline, ncol, nchar, nspaces, maxline, bs, pagesize = NLINES;
2015-03-03 10:52:34 +01:00
static void
flush(void)
{
2015-03-22 21:43:59 +01:00
Rune c;
size_t i, j;
2015-03-03 10:52:34 +01:00
for (i = 0; i < maxline; ++i) {
2015-03-22 21:43:59 +01:00
for (j = 0; j < NCOLS && (c = buf[i][j]); ++j)
efputrune(&c, stdout, "<stdout>");
2015-03-03 10:52:34 +01:00
putchar('\n');
}
bs = nchar = nline = ncol = 0;
}
static void
2015-03-22 21:43:59 +01:00
forward(size_t n)
2015-03-03 10:52:34 +01:00
{
2015-03-22 21:43:59 +01:00
size_t lim;
2015-03-03 10:52:34 +01:00
2015-03-22 21:43:59 +01:00
for (lim = ncol + n; ncol != lim && nchar < NCOLS - 1; ++nchar) {
switch (buf[nline][nchar]) {
2015-03-03 10:52:34 +01:00
case '\b':
--ncol;
break;
case '\0':
2015-03-22 21:43:59 +01:00
buf[nline][nchar] = ' ';
2015-03-03 10:52:34 +01:00
/* FALLTHROUGH */
default:
++ncol;
break;
}
}
}
static void
linefeed(int up, int rcarriage)
{
2015-03-22 21:43:59 +01:00
size_t oncol = ncol;
2015-03-03 10:52:34 +01:00
nspaces = 0;
if (up > 0) {
2015-03-22 21:43:59 +01:00
if (nline == pagesize - 1) {
2015-03-03 10:52:34 +01:00
flush();
} else {
if (++nline > maxline)
maxline = nline;
}
2015-03-22 21:43:59 +01:00
} else if (nline > 0) {
--nline;
2015-03-03 10:52:34 +01:00
}
bs = 0;
if (rcarriage) {
forward(oncol);
2015-03-22 21:43:59 +01:00
nchar = ncol = 0;
2015-03-03 10:52:34 +01:00
}
}
static void
2015-03-22 21:43:59 +01:00
newchar(Rune c)
2015-03-03 10:52:34 +01:00
{
2015-03-22 21:43:59 +01:00
Rune *cp;
2015-03-03 10:52:34 +01:00
forward(nspaces);
nspaces = 0;
switch (c) {
case ' ':
forward(1);
break;
case '\r':
nchar = ncol = 0;
break;
case '\t':
2015-03-22 21:43:59 +01:00
forward(8 - ncol % 8);
2015-03-03 10:52:34 +01:00
break;
case '\b':
if (ncol > 0)
--ncol;
if (nchar > 0)
--nchar;
bs = 1;
break;
default:
2015-03-22 21:43:59 +01:00
cp = &buf[nline][nchar];
if (*cp && *cp != ' ' && bs && !backspace && nchar != NCOLS - 3) {
memmove(cp + 3, cp + 1, (NCOLS - nchar - 2) * sizeof(*cp));
cp[1] = '\b';
nchar += 2;
2015-03-03 10:52:34 +01:00
}
2015-03-22 21:43:59 +01:00
if (nchar != NCOLS - 1) {
for (cp = buf[nline]; cp < &buf[nline][nchar]; ++cp) {
2015-03-03 10:52:34 +01:00
if (*cp == '\0')
*cp = ' ';
}
2015-03-22 21:43:59 +01:00
buf[nline][nchar++] = c;
2015-03-03 10:52:34 +01:00
++ncol;
}
bs = 0;
}
}
static void
col(void)
{
2015-03-22 21:43:59 +01:00
Rune r;
int ret;
2015-03-03 10:52:34 +01:00
2015-03-22 21:43:59 +01:00
while (efgetrune(&r, stdin, "<stdin>")) {
switch (r) {
2015-03-03 10:52:34 +01:00
case '\x1b':
2015-03-22 21:43:59 +01:00
ret = efgetrune(&r, stdin, "<stdin>");
switch (r) {
2015-03-03 10:52:34 +01:00
case '8': /* reverse half-line-feed */
case '7': /* reverse line-feed */
linefeed(-1, 0);
continue;
case '9': /* forward half-line-feed */
2015-03-22 21:43:59 +01:00
if (halfline)
2015-03-03 10:52:34 +01:00
break;
linefeed(1, 0);
continue;
}
2015-03-22 21:43:59 +01:00
if (!escape)
2015-03-03 10:52:34 +01:00
continue;
newchar('\x1b');
2015-03-22 21:43:59 +01:00
if (ret)
newchar(r);
2015-03-03 10:52:34 +01:00
break;
case '\v':
linefeed(-1, 0);
break;
case ' ':
2015-03-22 21:43:59 +01:00
if (!notabs) {
2015-03-03 10:52:34 +01:00
if (++nspaces != 8)
continue;
2015-03-22 21:43:59 +01:00
r = '\t';
2015-03-03 10:52:34 +01:00
nspaces = 0;
}
/* FALLTHROUGH */
case '\r':
case '\b':
case '\t':
2015-03-22 21:43:59 +01:00
newchar(r);
2015-03-03 10:52:34 +01:00
break;
case '\n':
linefeed(1, 1);
break;
default:
2015-03-22 21:43:59 +01:00
if (!iscntrlrune(r))
newchar(r);
2015-03-03 10:52:34 +01:00
break;
}
}
}
static void
allocbuf(void)
{
2015-03-22 21:43:59 +01:00
Rune **bp;
2015-03-03 10:52:34 +01:00
2015-03-22 21:43:59 +01:00
buf = ereallocarray(NULL, pagesize, sizeof(*buf));
for (bp = buf; bp < buf + pagesize; ++bp)
*bp = ereallocarray(NULL, NCOLS, sizeof(**buf));
2015-03-03 10:52:34 +01:00
}
2015-03-03 13:37:15 +00:00
static void
usage(void)
{
2015-03-30 21:49:04 +02:00
eprintf("usage: %s [-pbfx] [-l num]\n", argv0);
2015-03-03 13:37:15 +00:00
}
2015-03-03 10:52:34 +01:00
int
main(int argc, char *argv[])
{
ARGBEGIN {
case 'b':
2015-03-22 21:43:59 +01:00
backspace = 1;
2015-03-03 10:52:34 +01:00
break;
case 'f':
2015-03-22 21:43:59 +01:00
halfline = 1;
2015-03-03 10:52:34 +01:00
break;
case 'l':
2015-03-30 21:49:33 +02:00
pagesize = estrtonum(EARGF(usage()), 1, MIN(SIZE_MAX, LLONG_MAX));
2015-03-03 10:52:34 +01:00
break;
case 'p':
2015-03-22 21:43:59 +01:00
escape = 1;
2015-03-03 10:52:34 +01:00
break;
case 'x':
2015-03-22 21:43:59 +01:00
notabs = 1;
2015-03-03 10:52:34 +01:00
break;
default:
usage();
} ARGEND;
2015-03-22 21:43:59 +01:00
if (argc)
2015-03-03 10:52:34 +01:00
usage();
allocbuf();
col();
flush();
return 0;
}