[master] 909ce71 Split the terminal emulation into its own source file.

Poul-Henning Kamp phk at FreeBSD.org
Fri Jan 12 16:43:08 UTC 2018


commit 909ce71834084299f38ef8225c00392e0fd0c359
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Fri Jan 12 16:18:07 2018 +0000

    Split the terminal emulation into its own source file.
    
    Also: Make ansi-sequence problems fatal, and render unknown control
    chars as '?'

diff --git a/bin/varnishtest/Makefile.am b/bin/varnishtest/Makefile.am
index 5ffbf79..974aaf9 100644
--- a/bin/varnishtest/Makefile.am
+++ b/bin/varnishtest/Makefile.am
@@ -48,6 +48,7 @@ varnishtest_SOURCES = \
 		vtc_proxy.c \
 		vtc_server.c \
 		vtc_subr.c \
+		vtc_term.c \
 		vtc_varnish.c
 
 varnishtest_LDADD = \
diff --git a/bin/varnishtest/tests/u00000.vtc b/bin/varnishtest/tests/u00000.vtc
index ded88ab..0b33c36 100644
--- a/bin/varnishtest/tests/u00000.vtc
+++ b/bin/varnishtest/tests/u00000.vtc
@@ -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
diff --git a/bin/varnishtest/vtc.h b/bin/varnishtest/vtc.h
index af89358..6efef45 100644
--- a/bin/varnishtest/vtc.h
+++ b/bin/varnishtest/vtc.h
@@ -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 *);
diff --git a/bin/varnishtest/vtc_process.c b/bin/varnishtest/vtc_process.c
index dde798b..6d55975 100644
--- a/bin/varnishtest/vtc_process.c
+++ b/bin/varnishtest/vtc_process.c
@@ -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);
 }
 
@@ -182,192 +171,6 @@ process_undef(const struct process *p)
 }
 
 /**********************************************************************
- * 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")) {
diff --git a/bin/varnishtest/vtc_term.c b/bin/varnishtest/vtc_term.c
new file mode 100644
index 0000000..34caa30
--- /dev/null
+++ b/bin/varnishtest/vtc_term.c
@@ -0,0 +1,244 @@
+/*-
+ * Copyright (c) 2018 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * A trivial ANSI terminal emulation
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vtc.h"
+
+struct term {
+	unsigned		magic;
+#define TERM_MAGIC		0x1c258f0f
+
+	struct vtclog		*vl;
+	unsigned		state;
+#define NTERMARG		10
+	int			arg[NTERMARG];
+	int			*argp;
+	int			nlin;
+	int			ncol;
+	char			**vram;
+	int			col;
+	int			line;
+};
+
+static void
+term_clear(const struct term *tp)
+{
+	int i;
+
+	for (i = 0; i < tp->nlin; i++) {
+		memset(tp->vram[i], ' ', tp->ncol);
+		tp->vram[i][tp->ncol] = '\0';
+	}
+}
+
+void
+Term_Dump(const struct term *tp)
+{
+	int i;
+
+	for (i = 0; i < tp->nlin; i++)
+		vtc_dump(tp->vl, 3, "screen", tp->vram[i], tp->ncol);
+}
+
+static void
+term_escape(struct term *tp, int c, int n)
+{
+	int i;
+
+	c = tolower(c);
+	for (i = 0; i < NTERMARG; i++)
+		if (!tp->arg[i])
+			tp->arg[i] = 1;
+	switch(c) {
+	case 'h':
+		if (tp->arg[0] > tp->nlin || tp->arg[1] > tp->ncol)
+			vtc_fatal(tp->vl, "ANSI H[%d,%d] outside vram",
+			    tp->arg[0], tp->arg[1]);
+		tp->line = tp->arg[0] - 1;
+		tp->col = tp->arg[1] - 1;
+		break;
+	case 'j':
+		if (tp->arg[0] != 2)
+			vtc_fatal(tp->vl, "ANSI J[%d]", tp->arg[0]);
+		term_clear(tp);
+		break;
+	default:
+		for (i = 0; i < n; i++)
+			vtc_log(tp->vl, 4, "ANSI arg %d", tp->arg[i]);
+		vtc_fatal(tp->vl, "ANSI unknown (%c)", c);
+		break;
+	}
+}
+
+static void
+term_scroll(const struct term *tp)
+{
+	int i;
+	char *l;
+
+	l = tp->vram[0];
+	for(i = 0; i < tp->nlin -1; i++)
+		tp->vram[i] = tp->vram[i + 1];
+	tp->vram[i] = l;
+	memset(l, ' ', tp->ncol);
+}
+
+static void
+term_char(struct term *tp, char c)
+{
+	assert(tp->col < tp->ncol);
+	assert(tp->line < tp->nlin);
+	assert(tp->state <= 3);
+	switch (c) {
+	case 0x00:
+		break;
+	case '\b':
+		if (tp->col > 0)
+			tp->col--;
+		break;
+	case '\t':
+		while(++tp->col % 8)
+			continue;
+		if (tp->col >= tp->ncol) {
+			tp->col = 0;
+			term_char(tp, '\n');
+		}
+		break;
+	case '\n':
+		if (tp->line == tp->nlin - 1)
+			term_scroll(tp);
+		else
+			tp->line++;
+		break;
+	case '\r':
+		tp->col = 0;
+		break;
+	default:
+		if (c < ' ' || c > '~')
+			c = '?';
+		tp->vram[tp->line][tp->col] = c;
+		if (tp->col == tp->ncol - 1) {
+			tp->col = 0;
+			term_char(tp, '\n');
+		} else {
+			tp->col++;
+		}
+	}
+}
+
+void
+Term_Feed(struct term *tp, const char *b, const char *e)
+{
+
+	while (b < e) {
+		assert(tp->col < tp->ncol);
+		assert(tp->line < tp->nlin);
+		assert(tp->state <= 3);
+		switch (tp->state) {
+		case 0:
+			if (*b == '\x1b')
+				tp->state = 1;
+			else if (*(const uint8_t*)b == 0x9b)
+				tp->state = 2;
+			else
+				term_char(tp, *b);
+			b++;
+			break;
+		case 1:
+			if (*b++ != '[')
+				vtc_fatal(tp->vl, "ANSI not '[' (0x%x)",
+				    b[-1] & 0xff);
+			tp->state = 2;
+			break;
+		case 2:
+			tp->argp = tp->arg;
+			memset(tp->arg, 0, sizeof tp->arg);
+			tp->state = 3;
+			break;
+		case 3:
+			if (tp->argp - tp->arg >= NTERMARG)
+				vtc_fatal(tp->vl, "ANSI too many args");
+
+			if (isdigit(*b)) {
+				*tp->argp *= 10;
+				*tp->argp += *b++ - '0';
+				continue;
+			}
+			if (*b == ';') {
+				tp->argp++;
+				tp->state = 3;
+				b++;
+				continue;
+			}
+			if (islower(*b)) {
+				term_escape(tp, *b++, tp->argp -  tp->arg);
+				tp->state = 2;
+			} else if (isupper(*b)) {
+				term_escape(tp, *b++, tp->argp -  tp->arg);
+				tp->argp = tp->arg;
+				tp->state = 0;
+			} else {
+				vtc_fatal(tp->vl, "ANSI non-letter (0x%02x)",
+				    *b & 0xff);
+			}
+			break;
+		default:
+			WRONG("Wrong ansi state");
+		}
+	}
+}
+
+struct term *
+Term_New(struct vtclog *vl)
+{
+	struct term *tp;
+	int i;
+
+	ALLOC_OBJ(tp, TERM_MAGIC);
+	AN(tp);
+	tp->vl = vl;
+	tp->nlin = 24;
+	tp->ncol = 80;
+	tp->vram = calloc(tp->nlin, sizeof *tp->vram);
+	AN(tp->vram);
+	for (i = 0; i < tp->nlin; i++) {
+		tp->vram[i] = malloc(tp->ncol + 1L);
+		AN(tp->vram[i]);
+	}
+	term_clear(tp);
+	tp->line = tp->nlin - 1;
+	return (tp);
+}
+


More information about the varnish-commit mailing list