/*	VTERM4.C	Subroutines for TERM.C - Part 4
			Translating VT100 (ANSI) control codes
			into VIDEO80 control codes
	14 Feb 1988	A.Herrmann

This function parses character sequences following an <Esc>
until one of the implemented ANSI input sequences is recognized or
an illegal character is encountered.
Once a legal sequence has been recognized output is generated 
immediately and the function returns as its value the NULL character.
If an illegal character was encountered parsing is aborted and the
offending character is returned.


  VT100       -->  VIDEO80      Meaning  (n=ASCII-Integer)
-----------------------------------------------------------------------
  <Esc>[nA    -->  Ctrl/K       Cursor up  (Default n=1)
  <Esc>[nB    -->  Ctrl/J       Cursor down
  <Esc>[nC    -->  Ctrl/I       Cursor forward
  <Esc>[nD    -->  Ctrl/H       Cursor backward
  <Esc>[l;cH  -->  <Esc>Fyx     Cursor position (Default l,c=0)
  <Esc>[l;cf  -->  dito

  <Esc>[1m   -->   <Esc>R       Bold (Dim)
  <Esc>[4m   -->   <Esc>R       Underline (Dim)
  <Esc>[7m   -->   <Esc>R       Reverse (Dim)
  <Esc>[0m   -->   <Esc>S       All attributes off (Dim off)
  <Esc>[m    -->   <Esc>S	dito

  <Esc>[nL   -->   <Esc>\       Insert line
  <Esc>[nM   -->   <Esc>]       Delete line
  <Esc>[K    -->   <Esc>Z       Erase end of line
  <Esc>[0K   -->   <Esc>Z	dito
  <Esc>[J    -->   <Esc>[       Erase end of screen
  <Esc>[0J   -->   <Esc>[	dito
  <Esc>[2J   -->   <Esc>I	Erase entire screen

  <Esc>(x    -->		Change G0 char set (ignored for all x)
  <Esc>)x    -->		Change G1 char set (ignored for all x)

  <Esc>=     -->		Keypad mode on	(ignored)
  <Esc>>     -->		Keypad mode off	(ignored)
  <Esc><     -->		ANSI mode on	(ignored)
  <Esc>\     -->		Device control string terminator (ignored)
  <Esc>7     -->   <Esc>E	Save cursor and attributes
  <Esc>8     -->   <Esc>D	Restore cursor and attributes
  <Esc>M     -->   <Esc>\       Reverse index

*/

#include "stdio.h"
#include "term.h"
#include "term.e"

/* Control characters */
#define	CTRL_H	0x08
#define	CTRL_I	0x09
#define CTRL_J	0x0a
#define	CTRL_K	0x0b

/* Parser status */
#define	STTEXT	0	/* in text			*/
#define	STESC	1	/* after escape 		*/
#define	STLBR	2	/* after left bracket		*/
#define STLPA	3	/* after left parenthesis	*/
#define	STRPA	4	/* after right parenthesis	*/
#define	STPAR1	5	/* after first parameter	*/
#define	STPAR2	6	/* after second parameter	*/

static status;		/* status of parser		*/
static par1,par2;	/* numeric parameter values	*/


vt(ch)		/* parser for VT100 (ANSI) control sequences	*/
char ch;	/* Returns ch if char not parsable, else NULL	*/
{
	if (vtinit) {			/* parser needs to be init'ed	*/
		status=STTEXT;
		vtinit=FALSE;
	}
	switch (status) {
	case STLPA:
	case STRPA:
		status = STTEXT;
		return NULL;
	case STPAR2:
		return tr_pa2(ch);			
	case STLBR:
		return tr_lbr(ch);
	case STESC:
		return tr_esc(ch);
	case STTEXT:
		if (ch==_ESC) {
			status=STESC;
			return NULL;
		}
		return ch;
	}
	printf("vt(): Illegal status %d\n", status);
	return NULL;
}


tr_esc(ch)		/* translates after Esc				*/
char ch;		/* returns ch iff illegal sequence, else NULL	*/
{
	switch (ch) {
	case '(':
		status=STLPA;
		return NULL;
	case ')':
		status=STRPA;
		return NULL;
	case 'M':
		esc_seq('\\');
		goto texit;
	case '7':
		esc_seq('E');
		goto texit;
	case '8':
		esc_seq('D');
	case '<':
	case '=':
	case '>':
	case '\\':
texit:		status=STTEXT;
		return NULL;
	case '[':
		par1=par2=0;
		status=STLBR;
		return NULL;
	default:
		status=STTEXT;
		return ch;
	}
}


tr_lbr(ch)		/* translates after left bracket		*/
char ch;		/* returns ch iff illegal sequence, else NULL	*/
{
	if (isdigit(ch)) {			/* first parameter	*/
		par1 = 10*par1 + (ch-'0');
		return NULL;
	}
	if (ch==';') {				/* parameter delimiter	*/
		status=STPAR2;
		return NULL;
	}
	status=STTEXT;
	switch (ch) {
	case 'A':				/* Cursor up	*/
		if (par1==0) par1++;
		while (par1--) s_dsp(CTRL_K);
		return NULL;
	case 'B':				/* Cursor down	*/
		if (par1==0) par1++;
		while (par1--) s_dsp(CTRL_J);
		return NULL;
	case 'C':				/* Cursor forward */
		if (par1==0) par1++;
		while (par1--) s_dsp(CTRL_I);
		return NULL;
	case 'D':				/* Cursor backward */
		if (par1==0) par1++;
		while (par1--) s_dsp(CTRL_H);
		return NULL;
	case 'H':
	case 'f':				/* Cursor position */
		if (par1) par1--;
		if (par2) par2--;
		yx( (short)(TEHLIN+par1), (short)(TEHCOL+par2));
		return NULL;
	case 'm':				/* Screen attributes */
		switch (par1) {
		case 0:				/* All attributes off */
			esc_seq('K');			/* Inverse off	*/
			esc_seq('S');			/* Dim off	*/
			esc_seq('U');			/* Blinking off	*/
			break;
		case 1:				/* Bold intensity	*/
		case 4:				/* Underlined		*/
			esc_seq('R');			/* Dim on	*/
			break;
		case 5:				/* Blinking		*/
			esc_seq('T');			/* Blinking on	*/
			break;
		case 7:				/* Negative (reverse)	*/
			esc_seq('J');			/* Inverse on	*/
			break;
		case 22:			/* Normal intensity	*/
		case 24:			/* Not underlined	*/
			esc_seq('R');			/* Dim off	*/
			break;
		case 25:			/* Not blinking		*/
			esc_seq('U');			/* Blinking off	*/
			break;
		case 27:			/* Positive (not reverse) */
			esc_seq('K');			/* Inverse off	*/
			break;
		}
		return NULL;
	case 'L':				/* Insert line	*/
		if (par1==0) par1++;
		while (par1--) esc_seq('\\');
		return NULL;
	case 'M':				/* Delete line	*/
		if (par1==0) par1++;
		while (par1--) esc_seq(']');
		return NULL;
	case 'K':				/* Erase within line	*/
		if (par1==0) esc_seq('Z');		/* to end of line */
		return NULL;
	case 'J':				/* Erase within screen	*/
		switch (par1) {
		case 0:
			esc_seq('[');			/* to end of screen */
			break;
		case 2:
			esc_seq('I');			/* entire screen */
			break;
		}
		return NULL;
	default:				/* Unrecognized code	*/
		return ch;
	}
}


tr_pa2(ch)		/* translates after the second parameter	*/
char ch;		/* returns ch iff illegal sequence, else NULL	*/
{
	if (isdigit(ch)) {
		par2 = 10*par2 + (ch-'0');
		return NULL;
	}
	if (ch== 'H' || ch== 'f') 
		return tr_lbr(ch);
	status=STTEXT;
	return ch;
}


esc_seq(ch)	/* sends ESC followed by char ch to the display	*/
char ch;
{
	s_dsp(_ESC); s_dsp(ch);
}
