Permalink
Browse files

Split the terminal emulation into its own source file.

Also: Make ansi-sequence problems fatal, and render unknown control
chars as '?'
  • Loading branch information...
bsdphk committed Jan 12, 2018
1 parent 086a141 commit 909ce71834084299f38ef8225c00392e0fd0c359
Showing with 257 additions and 204 deletions.
  1. +1 −0 bin/varnishtest/Makefile.am
  2. +1 −1 bin/varnishtest/tests/u00000.vtc
  3. +5 −0 bin/varnishtest/vtc.h
  4. +6 −203 bin/varnishtest/vtc_process.c
  5. +244 −0 bin/varnishtest/vtc_term.c
@@ -48,6 +48,7 @@ varnishtest_SOURCES = \
vtc_proxy.c \
vtc_server.c \
vtc_subr.c \
vtc_term.c \
vtc_varnish.c
varnishtest_LDADD = \
@@ -28,6 +28,6 @@ process p4 -hexdump "cat" -start
process p4 -writeln "b\001z"
delay 0.5
process p4 -kill TERM
process p4 -wait
process p4 -wait -screen_dump
process p5 "stty -a ; sleep 1" -run -screen_dump
View
@@ -137,3 +137,8 @@ void b64_settings(const struct http *hp, const char *s);
struct vsb *vtc_hex_to_bin(struct vtclog *vl, const char *arg);
void vtc_expect(struct vtclog *, const char *, const char *, const char *,
const char *, const char *);
/* vtc_term.c */
struct term *Term_New(struct vtclog *);
void Term_Feed(struct term *, const char *, const char *);
void Term_Dump(const struct term *);
@@ -81,14 +81,8 @@ struct process {
unsigned hasthread;
int status;
unsigned term_state;
#define NTERMARG 10
int term_arg[NTERMARG];
int *term_ap;
#define NLINES 24
#define NCOLS 80
char *term_c[NLINES];
int term_x, term_y;
struct term *term;
};
static VTAILQ_HEAD(, process) processes =
@@ -113,7 +107,6 @@ process_new(const char *name)
struct process *p;
struct vsb *vsb;
char buf[1024];
int i;
ALLOC_OBJ(p, PROCESS_MAGIC);
AN(p);
@@ -134,12 +127,8 @@ process_new(const char *name)
p->fd_term = -1;
VTAILQ_INSERT_TAIL(&processes, p, list);
for (i = 0; i < NLINES; i++) {
p->term_c[i] = malloc(NCOLS + 1);
AN(p->term_c[i]);
memset(p->term_c[i], ' ', NCOLS);
p->term_c[i][NCOLS] = '\0';
}
p->term = Term_New(p->vl);
AN(p->term);
return (p);
}
@@ -181,192 +170,6 @@ process_undef(const struct process *p)
macro_undef(p->vl, p->name, "err");
}
/**********************************************************************
* Terminal emulation
*/
static void
process_term_clear(const struct process *p)
{
int i;
for (i = 0; i < NLINES; i++) {
memset(p->term_c[i], ' ', NCOLS);
p->term_c[i][NCOLS] = '\0';
}
}
static void
process_screen_dump(const struct process *p)
{
int i;
for (i = 0; i < NLINES; i++)
vtc_dump(p->vl, 3, "screen", p->term_c[i], NCOLS);
}
static void
process_escape(struct process *p, int c, int n)
{
int i;
for (i = 0; i < NTERMARG; i++)
if (!p->term_arg[i])
p->term_arg[i] = 1;
switch(c) {
case 'h':
if (p->term_arg[0] <= NLINES && p->term_arg[1] <= NCOLS) {
p->term_y = p->term_arg[0] - 1;
p->term_x = p->term_arg[1] - 1;
} else {
vtc_log(p->vl, 4, "ANSI H %d %d WRONG",
p->term_arg[0], p->term_arg[1]);
}
break;
case 'j':
if (p->term_arg[0] == 2) {
process_term_clear(p);
} else {
vtc_log(p->vl, 4, "ANSI J %d", p->term_arg[0]);
}
break;
default:
for (i = 0; i < n; i++)
vtc_log(p->vl, 4, "ANSI arg %d",
p->term_arg[i]);
vtc_log(p->vl, 4, "ANSI unk '%c'", c);
break;
}
}
static void
process_scroll(struct process *p)
{
int i;
char *l;
l = p->term_c[0];
for(i = 0; i < NLINES -1; i++)
p->term_c[i] = p->term_c[i + 1];
p->term_c[i] = l;
memset(l, ' ', NCOLS);
}
static void
process_char(struct process *p, char c)
{
assert(p->term_x < NCOLS);
assert(p->term_y < NLINES);
assert(p->term_state <= 3);
switch (c) {
case 0x00:
break;
case '\b':
if (p->term_x > 0)
p->term_x--;
break;
case '\t':
while(++p->term_x % 8)
continue;
if (p->term_x >= NCOLS) {
p->term_x = 0;
process_char(p, '\n');
}
break;
case '\n':
if (p->term_y == NLINES - 1)
process_scroll(p);
else
p->term_y++;
break;
case '\r':
p->term_x = 0;
break;
default:
if (c < ' ' || c > '~')
vtc_log(p->vl, 4, "ANSI CTRL 0x%02x", c);
else {
p->term_c[p->term_y][p->term_x] = c;
if (p->term_x == NCOLS - 1) {
p->term_x = 0;
process_char(p, '\n');
} else {
p->term_x++;
}
}
}
}
static void
process_ansi(struct process *p, const char *b, const char *e)
{
while (b < e) {
assert(p->term_x < NCOLS);
assert(p->term_y < NLINES);
assert(p->term_state <= 3);
switch (p->term_state) {
case 0:
if (*b == '\x1b')
p->term_state = 1;
else if (*(const uint8_t*)b == 0x9b)
p->term_state = 2;
else
process_char(p, *b);
b++;
break;
case 1:
if (*b++ == '[') {
p->term_state = 2;
} else {
vtc_log(p->vl, 4, "ANSI not [ 0x%x", b[-1]);
p->term_state = 0;
}
break;
case 2:
p->term_ap = p->term_arg;
memset(p->term_arg, 0, sizeof p->term_arg);
p->term_state = 3;
break;
case 3:
if (p->term_ap - p->term_arg >= NTERMARG) {
vtc_log(p->vl, 4, "ANSI too many ;");
p->term_state = 0;
b++;
continue;
}
if (isdigit(*b)) {
*p->term_ap *= 10;
*p->term_ap += *b++ - '0';
continue;
}
if (*b == ';') {
p->term_ap++;
p->term_state = 3;
b++;
continue;
}
if (islower(*b)) {
process_escape(p, *b++,
p->term_ap - p->term_arg);
p->term_state = 2;
} else if (isupper(*b)) {
process_escape(p, tolower(*b++),
p->term_ap - p->term_arg);
p->term_ap = p->term_arg;
p->term_state = 0;
} else {
vtc_log(p->vl, 4, "ANSI non-letter %c", *b);
p->term_state = 0;
b++;
}
break;
default:
WRONG("Wrong ansi state");
}
}
}
/**********************************************************************
* Data stream handling
*/
@@ -402,7 +205,7 @@ process_stdout(const struct vev *ev, int what)
else if (p->log == 3)
vtc_hexdump(p->vl, 4, "stdout", buf, i);
(void)write(p->f_stdout, buf, i);
process_ansi(p, buf, buf + i);
Term_Feed(p->term, buf, buf + i);
return (0);
}
@@ -895,7 +698,7 @@ cmd_process(CMD_ARGS)
continue;
}
if (!strcmp(*av, "-screen_dump")) {
process_screen_dump(p);
Term_Dump(p->term);
continue;
}
if (!strcmp(*av, "-close")) {
Oops, something went wrong.

0 comments on commit 909ce71

Please sign in to comment.