commit 6b9753d15ac98f38375c0f1b8ed4ae950a89894c
parent 6ffddc2a6352ed97d31522ff646d433248efdd19
Author: Christoph Lohmann <20h@r-36.net>
Date:   Fri,  8 Apr 2011 12:45:22 +0200
Adding test file and preliminary window support.
Diffstat:
| vt100.c | | | 360 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ | 
| vt100.h | | | 77 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- | 
| vt100test.c | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ | 
3 files changed, 452 insertions(+), 33 deletions(-)
diff --git a/vt100.c b/vt100.c
@@ -13,47 +13,211 @@
 
 #include "vt100.h"
 
-int termrows;
-int termcols;
+termwin_t *
+termwin_new(term_t *term, int r, int c, int rows, int cols)
+{
+	termwin_t *win;
+
+	win = malloc(sizeof(termwin_t));
+	if (win == NULL)
+		return NULL;
+	bzero(win, sizeof(win));
+
+	win->r = r;
+	win->c = c;
+	win->rows = rows;
+	win->cols = cols;
+	win->term = term;
+
+	if (term->first == NULL)
+		term->first = win;
+	else {
+		term->last->next = win;
+		win->prev = term->last;
+		term->last = win;
+	}
+
+	return win;
+}
+
+void
+termwin_free(term_t *term, termwin_t *win)
+{
+	if (term->first == win)
+		term->first = win->next;
+	if (term->last == win)
+		term->last = win->prev;
+	if (win->next != NULL)
+		win->next->prev = win->prev;
+	if (win->prev != NULL)
+		win->prev->next = win->next;
+
+	free(win);
+}
+
+term_t *
+term_new(void)
+{
+	term_t *term;
+
+	term = malloc(sizeof(term_t));
+	if (term == NULL)
+		return NULL;
+	bzero(term, sizeof(term));
+
+	term_init(term);
+
+	return term;
+}
 
-struct termios tioin;
-struct termios tioout;
+void
+term_free(term_t *term)
+{
+	termwin_t *win;
+
+	if (term->first != NULL) {
+		for (win = term->first; win; win = win->next)
+			termwin_free(term, win);
+	}
+
+	free(term);
+}
 
 void
 term_setpos(int row, int col)
 {
-	printf("\003[%d;%dH", row, col);
+	printf("\033[%d;%dH", row, col);
+	fflush(stdout);
+}
+
+void
+term_up(int rows)
+{
+	printf("\033[%dA", rows);
+	fflush(stdout);
+}
+
+void
+term_down(int rows)
+{
+	printf("\033[%dB", rows);
+	fflush(stdout);
+}
+
+void
+term_forward(int cols)
+{
+	printf("\033[%dC", cols);
+	fflush(stdout);
 }
 
 void
-term_erasepos(void)
+term_backward(int cols)
 {
+	printf("\033[%dD", cols);
+	fflush(stdout);
+}
+
+void
+term_erasepos(int row, int col)
+{
+	term_setpos(row, col);
 	printf("\033[OK");
+	fflush(stdout);
+}
+
+void
+term_eraserow(int row)
+{
+	term_setpos(row, 0);
+	printf("\033[K0");
+	fflush(stdout);
 }
 
 void
-term_clrscr(void)
+term_erasescreen(void)
 {
 	printf("\033[2J");
+	fflush(stdout);
+}
+
+void
+term_backspace(void)
+{
+	term_backward(2);
+}
+
+void
+term_setscrolling(int start, int end)
+{
+	printf("\x033[%d;%dr", start, end);
+	fflush(stdout);
+}
+
+void
+term_scrollup(int times)
+{
+	int i;
+
+	for (i = 0; i < times; i++) {
+		printf("\x033");
+		printf("D");
+	}
+	fflush(stdout);
+}
+
+void
+term_scrolldown(int times)
+{
+	int i;
+
+	for (i = 0; i < times; i++)
+		printf("\x033H");
+	fflush(stdout);
+}
+
+void
+term_showcursor(void)
+{
+	printf("\033[?25h");
+	fflush(stdout);
+}
+
+void
+term_hidecursor(void)
+{
+	printf("\033[?25l");
+	fflush(stdout);
 }
 
 void
-term_clrrow(int row)
+term_blinkcursor(void)
 {
-	printf("\033[%dC|\n\r", row);
+	printf("\033[?12h");
+	fflush(stdout);
 }
 
 void
-term_rst(void)
+term_staticursor(void)
 {
-	printf("\x033[?47l");
-	printf("\x033[%d;1H", termrows);
-	tcsetattr(0, TCSANOW, &tioin);
-	tcsetattr(1, TCSANOW, &tioout);
+	printf("\033[?12l");
+	fflush(stdout);
 }
 
 void
-term_init(void)
+term_reset(term_t *term)
+{
+	printf("\033[?47l");
+	printf("\033[%d;1H", term->rows);
+	fflush(stdout);
+	tcsetattr(0, TCSANOW, &term->tioin);
+	tcsetattr(1, TCSANOW, &term->tioout);
+
+	term_showcursor();
+}
+
+void
+term_init(term_t *term)
 {
 	char buf[65];
 	struct termios tio;
@@ -61,43 +225,53 @@ term_init(void)
 
 	bzero(buf, sizeof(buf));
 
-	tcgetattr(1, &tioout);
+	tcgetattr(1, &term->tioout);
 	tcgetattr(0, &tio);
-	memmove(&tioin, &tio, sizeof(tio));
+	memmove(&term->tioin, &tio, sizeof(tio));
 	cfmakeraw(&tio);
 	tcsetattr(0, TCSAFLUSH, &tio);
 	tcgetattr(1, &tio);
 	cfmakeraw(&tio);
 	tcsetattr(1, TCSADRAIN, &tio);
 
+	/* disable line wrap. */
+	printf("\033[7l");
+
 	printf("\033[18t");
+	fflush(stdout);
 	for (i = 0; read(0, &buf[i], 1) && i < sizeof(buf)-1; i++) {
-		if (buf[i] == '\t') {
+		if (buf[i] == 't') {
 			buf[i] = '\0';
 			break;
 		}
 	}
 	if (i >= sizeof(buf)-1) {
-		termrows = 24;
-		termcols = 80;
+		term->rows = 24;
+		term->cols = 80;
 	} else {
 		sscanf(&buf[4], "%d;%d", &ro, &co);
-		termrows = ro;
-		termcols = co;
+		term->rows = ro;
+		term->cols = co;
 		printf("\033[?37h");
+		fflush(stdout);
 	}
+
+	term_hidecursor();
+	term_erasescreen();
 }
 
 void
-term_error(char *fmt, ...)
+term_error(term_t *term, char *fmt, ...)
 {
 	va_list fmtargs;
 
-	printf("\033[%d:%dH", termrows, 1);
+	term_eraserow(term->rows);
+	printf("\033[%d:%dH", term->rows, 1);
 	va_start(fmtargs, fmt);
 	vfprintf(stdout, fmt, fmtargs);
 	va_end(fmtargs);
-	printf("\n\r");
+	printf("\r");
+	fflush(stdout);
 }
 
 void
@@ -110,5 +284,141 @@ term_printf(int row, int col, char *fmt, ...)
 	vfprintf(stdout, fmt, fmtargs);
 	va_end(fmtargs);
 	printf("\n\r");
+	fflush(stdout);
+}
+
+/* Bresenham's line algorithm */
+void
+term_drawline(term_t *term, int r0, int c0, int r1, int c1, char line)
+{
+	int dr, dc, sr, sc, err, err2;
+
+	dr = abs(r1 - r0);
+	dc = abs(c1 - c0);
+	sr = (r0 < r1)? 1 : -1;
+	sc = (c0 < c1)? 1 : -1;
+	err = dr - dc;
+
+	for (;;) {
+		term_printf(r0, c0, "%c", line);
+		if (r0 == r1 && c0 == c1)
+			break;
+		err2 = 2 * err;
+		if (err2 > -dc) {
+			err -= dc;
+			r0 += sr;
+		}
+		if (err2 < dr) {
+			err += dr;
+			c0 += sc;
+		}
+	}
+	fflush(stdout);
+}
+
+void
+term_drawrectangle(term_t *term, int r0, int c0, int r1, int c1,
+		char hline, char vline, char uredge, char uledge,
+		char lredge, char lledge)
+{
+	term_printf(r0, c0, "%c", uredge);
+	term_drawline(term, r0, c0+1, r0, c1-1, hline);
+	term_printf(r0, c1, "%c", uledge);
+	term_drawline(term, r0+1, c1, r1-1, c1, vline);
+	term_printf(r1, c1, "%c", lledge);
+	term_drawline(term, r1, c0+1, r1, c1-1, hline);
+	term_printf(r1, c0, "%c", lredge);
+	term_drawline(term, r0+1, c0, r1-1, c0, vline);
+}
+
+void
+term_fillrectangle(term_t *term, int r0, int c0, int r1, int c1, char fill)
+{
+	int br, be;
+
+	br = (r0 < r1)? r0 : r1;
+	be = (r0 < r1)? r1 : r0;
+	for (; br <= be; br++)
+		term_drawline(term, br, c0, br, c1, fill);
+}
+
+
+void
+termwin_setpos(termwin_t *win, int row, int col)
+{
+	if (row <= win->drows && col <= win->dcols && row > 0 && col > 0) {
+		win->cr = row;
+		win->cc = col;
+	}
+}
+
+int
+termwin_inwindow(termwin_t *win, int row, int col)
+{
+	return (row >= win->dr && row < win->dr + win->drows
+			&& col >= win->dc && col < win->dc + win->dcols);
 }
 
+void
+termwin_up(termwin_t *win, int rows)
+{
+	win->cr -= rows;
+	if (win->cr < 1)
+		win->cr = 11;
+}
+
+void
+termwin_down(termwin_t *win, int rows)
+{
+	win->cr += rows;
+	if (win->cr > win->drows)
+		win->cr = win->drows;
+}
+
+void
+termwin_forward(termwin_t *win, int cols)
+{
+	win->cc += cols;
+	if (win->cc > win->dcols)
+		win->cc = win->dcols;
+}
+
+void
+termwin_backward(termwin_t *win, int cols)
+{
+	win->cc -= cols;
+	if (win->cc < 1)
+		win->cc = 1;
+}
+
+void
+termwin_erasepos(termwin_t *win, int row, int col)
+{
+	if (termwin_inwindow(win, row, col))
+		term_printf(win->dr + row, win->dc + col, " ");
+}
+
+
+void
+termwin_eraserow(termwin_t *win, int row)
+{
+	if (row > 0 && row <= win->drows) {
+		term_drawline(win->term, win->dr + row, win->dc,
+				win->dr + row, win->dc + win->cols, ' ');
+	}
+}
+
+void
+termwin_erasewin(termwin_t *win)
+{
+	term_fillrectangle(win->term, win->dr, win->dc, win->dr + win->drows,
+			win->dc + win->dcols, ' ');
+}
+
+void
+termwin_backspace(termwin_t *win)
+{
+	termwin_backward(win, 2);
+}
+
+
diff --git a/vt100.h b/vt100.h
@@ -6,28 +6,89 @@
 #ifndef __LIBVT100_H__
 #define __LIBVT100_H__
 
-extern int termrows;
-extern int termcols;
+#include <unistd.h>
+#include <termios.h>
 
+typedef struct term_t term_t;
 typedef struct termwin_t termwin_t;
 struct termwin_t {
-	int br, bc, r, c;
+	int r, c, rows, cols;
+	int dr, dc, drows, dcols;
 	int cr, cc;
 
-	int id;
+	int scrollc1, scrollc2, scroll;
+
+	term_t *term;
 
 	termwin_t *next;
 	termwin_t *prev;
 };
 
-typedef struct termwm_t termwm_t;
-struct termwm_t {
-	int n;
+struct term_t {
+	int rows, cols;
 
+	struct termios tioin, tioout;
+
+	int n;
 	termwin_t *first;
 	termwin_t *last;
-	termwin_t *root;
 };
 
+termwin_t *termwin_new(term_t *term, int r, int c, int rows, int cols);
+void termwin_free(term_t *term, termwin_t *win);
+
+term_t *term_new(void);
+void term_free(term_t *term);
+
+void term_setpos(int row, int col);
+void term_up(int rows);
+void term_down(int rows);
+void term_forward(int cols);
+void term_backward(int cols);
+void term_erasepos(int row, int col);
+void term_eraserow(int row);
+void term_erasescreen(void);
+void term_backspace(void);
+
+void term_setscrolling(int start, int end);
+void term_scrollup(int times);
+void term_scrolldown(int times);
+
+void term_showcursor(void);
+void term_hidecursor(void);
+void term_blinkcursor(void);
+void term_staticursor(void);
+
+void term_reset(term_t *term);
+void term_init(term_t *term);
+
+void term_error(term_t *term, char *fmt, ...);
+void term_printf(int row, int col, char *fmt, ...);
+
+void term_drawline(term_t *term, int r0, int c0, int r1, int c1, char sym);
+void term_drawrectangle(term_t *term, int r0, int c0, int r1, int c1,
+		char hline, char vline, char uredge, char uledge,
+		char lredge, char lledge);
+void term_fillrectangle(term_t *term, int r0, int c0, int r1, int c1,
+		char fill);
+
+void termwin_setpos(termwin_t *win, int row, int col);
+int temwin_inwindow(termwin_t *win, int row, int col);
+void termwin_up(termwin_t *win, int rows);
+void termwin_down(termwin_t *win, int rows);
+void termwin_forward(termwin_t *win, int cols);
+void termwin_backward(termwin_t *win, int cols);
+void termwin_erasepos(termwin_t *win, int row, int col);
+void termwin_eraserow(termwin_t *win, int row);
+void termwin_erasewin(termwin_t *win);
+void termwin_backspace(termwin_t *win);
+
+void termwin_setscrolling(termwin_t *win, int start, int end);
+void termwin_scrollup(termwin_t *win, int times);
+void termwin_scrolldown(termwin_t *win, int times);
+
+void termwin_error(termwin_t *win, char *fmt, ...);
+void termwin_printf(termwin_t *win, int row, int col, char *fmt, ...);
+
 #endif
 
diff --git a/vt100test.c b/vt100test.c
@@ -0,0 +1,48 @@
+/*
+ * Copy me if you can.
+ * by 20h
+ */
+
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "vt100.h"
+
+int
+main(void)
+{
+	char *str;
+	term_t *term;
+
+	term = term_new();
+
+	term_fillrectangle(term, 1, 1, term->rows-1, term->cols-1, '.');
+
+	term_drawrectangle(term, 1, 1, term->rows-1, term->cols-1, '#', '#',
+			'#', '#', '#', '#');
+	term_drawrectangle(term, 2, 2, 20, 30, '-', '|', '+', '+', '+',
+			'+');
+	term_fillrectangle(term, 3, 3, 19, 29, ' ');
+
+	term_printf(3, 3, "Hello here ...");
+	term_printf(5, 3, "Another one ...");
+	term_error(term, "Something bad happened.");
+	term_printf(8, 3, "termrows: %d, termcols: %d", term->rows, term->cols);
+	term_printf(10, 3, "sleeping for 1s ...");
+
+	sleep(1);
+
+	term_printf(5, 3, "It changed!");
+	term_error(term, "Another bad one ...");
+	sleep(1);
+
+	term_error(term, "Oh, another one");
+	sleep(2);
+
+	term_reset(term);
+
+	return 0;
+}
+