/*
 * Copyright 1982 UniSoft Corporation
 * Use of this material is subject to your disclosure agreement with
 * AT&T, Western Electric and UniSoft Corporation.
 *
 * VT100 emulator
 * Called with each character destined for the console.
 * Processes control sequences and keeps track of terminal state.
 * Calls into bitmap.c actually do the I/O
 */

/* SENSESCRN resets the contrast on screen output (via the console device
 * driver) as if a key was hit.
 */

#include "sys/types.h"
#include "sys/l2.h"

#define FAST
#define SENSESCRN

#define	MAXVT_N		255	/* maximum value of any numeric parameter */
#define	MAXPARAMS	10	/* maximum number of numeric parameters */

short vt_n[MAXPARAMS];		/* numeric parameters of \E[ commands */
char vt_mparam;
char vt_tabset[88] = { 0 };
extern char bmbck, bmcolor, bmnormal;
extern char *bmscrn;
extern char kb_altkp;
short vt_maxrow = 38;
short vt_maxcol = 88;
short vt_row, vt_col;		/* cursor location (0-vt_maxrow, 0-vt_maxcol) */
short vtrow_ofs = 1;
short vtcol_ofs = 1;		/* row and column offsets */
short vt_winscrl = 1;		/* lines to scroll each time */

/* This routine interprets the characters destined for the console and
 * performs like a VT100 .  It is implemented in terms of primitives
 * defined in bitmap.c
 */

#define CBKSP	1
#define CCR	2
#define CLF	3
#define CHTAB	4
#define CESC	5
#define CBELL	6
#define CGARB	7
#define CCHAR	8

char vt_keytype[] = {
	CGARB, CGARB, CGARB, CGARB,	CGARB, CGARB, CGARB, CBELL,
	CBKSP, CHTAB, CLF,   CLF,	CLF,   CCR,   CGARB, CGARB,
	CGARB, CGARB, CGARB, CGARB,	CGARB, CGARB, CGARB, CGARB,
	CGARB, CGARB, CGARB,  CESC,	CGARB, CGARB, CGARB, CGARB,

	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,
	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,
	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,
	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,

	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,
	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,
	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,
	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,

	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,
	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,
	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CCHAR,
	CCHAR, CCHAR, CCHAR, CCHAR,	CCHAR, CCHAR, CCHAR, CGARB,
};

vt_putc (c)
register char c;
{
	extern int (*te_putc)();
	int vt_esc();
	int x;

	extern time_t lbolt;

	l2_dtrap = lbolt + l2_dtime;
	if (l2_dimmed) l2undim();

	if (c >= ' ') {
		bmputc(vt_row+vtrow_ofs,vt_col+vtcol_ofs,c);
		vt_advance();
		bminvert (vt_row+vtrow_ofs, vt_col+vtcol_ofs);
		return;
	}
	bminvert (vt_row+vtrow_ofs, vt_col+vtcol_ofs);
	switch (vt_keytype[c]) {
		case CBKSP:	
			if (vt_col > 0) 
				vt_col--; 
			break;
		case CCR:	
			vt_col = 0;
			 break;
		case CLF:	
			if (++vt_row >= vt_maxrow) {
				blt(bmscrn+90*9,bmscrn+90*9*2,9*90*38);
					vt_row -= vt_winscrl;
			}
			break;
		case CHTAB:
			for ( x = vt_col+1; x < vt_maxcol-1 ; x++ )
				if ( vt_tabset[x] == 1 )
					break;
			vt_col = x;
			break;
		case CESC:	
			te_putc = vt_esc;
			break;
		case CBELL:	
			beep();
			break;
		case CGARB:					
			break;
	}
	bminvert(vt_row+vtrow_ofs,vt_col+vtcol_ofs);
}

/* 
 * Process the escape sequences to the terminal
 */
vt_esc(c)				/* after ESC key hit */
register char c;
{
	extern int (*te_putc)();
	int vt_brck(), vt_putc();

	switch (c) {
		case '[':
			te_putc = vt_brck;	/* check E[ sequence */
			return;
		case '>':		/* disable alternate keypad */
			kb_altkp = 0;
			break;	
		case '=':		/* enable alternate keypad */
			kb_altkp = 1;
			break;	
		case 'M':		/* reverse scroll */
			
			bminvert(vt_row+vtrow_ofs,vt_col+vtcol_ofs);
			bmrscrl();
			bminvert(vt_row+vtrow_ofs,vt_col+vtcol_ofs);

			break;
		case 'H':
			vt_tabset[vt_col]=1;
			break;
	}
	te_putc = vt_putc;
	return;
}

vt_brck(c)					/* \E[ sequence checked here */
register char c;
{
	extern int (*te_putc)();
	int vt_param(), vt_attrb();

	vt_mparam = 0;
	vt_n[0] = vt_n[1] = 0;
	if (c == ';') {		/* missing 1st number - look for 2nd */
		te_putc = vt_param;
		vt_mparam++;
		return;
	}
	if (c >= '0' && c <= '9' ) {
		vt_n[0] = c - '0';
		te_putc = vt_param;
		return;
	}
	if (c == '?') {
		te_putc = vt_attrb;
		return;
	}
	vt_cmd(c);
}

vt_param(c)
register char c;
{
	register tmp;
	int vt_putc();

	if( c >= '0' && c <= '9' ) {
		tmp = (vt_n[vt_mparam] * 10) + (c - '0');
		vt_n[vt_mparam] = (tmp > MAXVT_N) ? MAXVT_N : tmp;
		return;
	}
	if ( c == ';' ) {
		if (++vt_mparam >= MAXPARAMS) {	/* too many parameters */
			te_putc = vt_putc;
			return;
		}
		vt_n[vt_mparam] = 0;
		return;
	}
	vt_cmd(c);
}

vt_cmd(c)		/* now have last char of esc sequence */
register char c;
{
	extern int (*te_putc)();
	register vt_n1 = vt_n[0];
	register vt_n2 = vt_n[1];
	register int x, y;
	int vt_putc();

	if (c == 'f')	c = 'H';
	if ((c >= 'A') && (c <= 'Z')) {
		bminvert (vt_row+vtrow_ofs, vt_col+vtcol_ofs);
		switch (c) {
		case 'A':	/* move cursor up */
			if (vt_n1 == 0)
				vt_n1 = 1;
			vt_row = (vt_n1 < vt_row) ? (vt_row - vt_n1) : 0;
			break;
		case 'B':	/* move cursor down */
			if (vt_n1 == 0)
				vt_n1 = 1;
			y = vt_row + vt_n1;
			vt_row = (y < vt_maxrow) ? y : vt_maxrow-1;
			break;
		case 'C':	/* move cursor right */
			if (vt_n1 == 0)
				vt_n1 = 1;
			y = vt_col + vt_n1;
			vt_col = (y < vt_maxcol) ? y : vt_maxcol-1;
			break;
		case 'D':	/* move cursor left */
			if (vt_n1 == 0)
				vt_n1 = 1;
			vt_col = (vt_n1 < vt_col) ? (vt_col - vt_n1) : 0;
			break;
		case 'H':	/* move cursor home */
			if (vt_n1 == 0)
				vt_row = 0;
			else if ((vt_row = vt_n1-1) >= vt_maxrow)
				vt_row = vt_maxrow - 1;
			if (vt_n2 == 0)
				vt_col = 0;
			else if ((vt_col = vt_n2-1) >= vt_maxcol)
				vt_col = vt_maxcol - 1;
			break;
		case 'J':	/* clear screen */
			if (vt_n1 == 0)
				if ((vt_row == 0) && (vt_col == 0))
					vt_n1 = 2;
			switch (vt_n1) {
			case 0:	/* clear from cursor to end */
				for (y = vt_col ; y < vt_maxcol ; y++ )
					bmputc(vt_row+vtrow_ofs,y+vtcol_ofs,' ');
				for (x = vt_row+1; x < vt_maxrow ; x++ )
					bmblank(x+vtrow_ofs);
				break;
			case 1:	/* clear from beginning to cursor */
				for (x = 0; x < vt_row ; x++ )
					bmblank(x+vtrow_ofs);
				for (y = 0; y <= vt_col ; y++ )
					bmputc(vt_row+vtrow_ofs,y+vtcol_ofs,' ');
				break;
			case 2:	/* clear entire screen */
				bmclear();
			}
			break;
		case 'K':	/* clear line */
			switch (vt_n1) {
			case 0:	/* clear from cursor to end */
				for (y = vt_col ; y < vt_maxcol ; y++ )
					bmputc(vt_row+vtrow_ofs,y+vtcol_ofs,' ');
				break;
			case 1:	/* clear from beginning to cursor */
				for (y = 0 ; y <= vt_col ; y++ )
					bmputc(vt_row+vtrow_ofs,y+vtcol_ofs,' ');
				break;
			case 2:	/* clear entire line */
				bmblank(vt_row+vtrow_ofs);
			}
			break;
		case 'L':	/* insert line(s) */
			if (vt_n1 == 0)
				vt_n1 = 1;
			if (vt_n1 > vt_maxrow - vt_row)
				vt_n1 = vt_maxrow - vt_row;
			for (x=vt_maxrow-1, y=vt_maxrow-vt_n1-1; y >= vt_row; x--, y--)
				bmcpl(x+vtrow_ofs, y+vtrow_ofs);
			for ( ; x >= vt_row ; x-- )
				bmblank(x+vtrow_ofs);
			break;
		case 'M':	/* delete line(s) */
			if (vt_n1 == 0)
				vt_n1 = 1;
			if (vt_n1 > vt_maxrow - vt_row)
				vt_n1 = vt_maxrow - vt_row;
			for (x=vt_row, y=vt_row+vt_n1; y < vt_maxrow; x++, y++)
				bmcpl(x+vtrow_ofs, y+vtrow_ofs);
			for ( ; x < vt_maxrow ; x++ )
				bmblank(x+vtrow_ofs);
			break;
		case 'P':	/* delete character(s) */
			if (vt_n1 == 0)
				vt_n1 = 1;
			if (vt_n1 > vt_maxcol - vt_col)
				vt_n1 = vt_maxcol - vt_col;
			for (x=vt_col, y=vt_col+vt_n1; y < vt_maxcol; x++, y++)
				bmmvc(vt_row+vtrow_ofs, x+vtcol_ofs,
					vt_row+vtrow_ofs, y+vtcol_ofs);
			for ( ; x < vt_maxcol ; x++ )
				bmputc(vt_row+vtrow_ofs,x+vtcol_ofs,' ');
			break;
		}
		bminvert (vt_row+vtrow_ofs, vt_col+vtcol_ofs);
	} else {
		switch (c) {
		case 'g':
			if (vt_n1 == 0)
				vt_tabset[vt_col] = 0;
			else if (vt_n1 == 3)
				for (x = 0 ; x < vt_maxcol ; x++ )
					vt_tabset[x] = 0;
			break;
		case 'm':	/* set normal display or reverse video */
			for (x = 0; x <= vt_mparam; x++)
				switch (vt_n[x]) {
				case 0:	/* turn underline off, set normal background */
					if (bmbck != bmnormal) {
						bmswitch();	/* invert font table */
						bmbck = bmnormal;
					}
					bmcolor = bmbck;	/* underline off */
					break;
				case 1: case 7:	/* set reverse image */
					if (bmbck == bmnormal) {
						bmswitch();	/* invert font table */
						bmbck = bmnormal ? 0 : -1; 
					}
					break;
				case 4:	/* set underline */
					bmcolor = bmbck ? 0 : -1; 
				}
			break;
		}
	}
	te_putc = vt_putc;
}

vt_attrb(c)		/* \E[? */
char c;
{
	int vt_atrb(), vt_putc();

	if(c >= '0' && c <= '9')
		te_putc = vt_atrb;
	else
		te_putc = vt_putc;
}

vt_atrb()
{
	int vt_putc();

	te_putc = vt_putc;
}

vt_advance()
{
	if (++vt_col >= vt_maxcol) {		/* wraps around */
		vt_col = 0;
		if (++vt_row >= vt_maxrow) {	/* on last line */
			blt(bmscrn+90*9,bmscrn+90*9*2,9*90*38);
			vt_row -= vt_winscrl;
		}
	}
}
