/*	TERM1.C		Subroutines for TERM.C, Part 1
			SIO Input / Output
			Interrupt service for SIO input, needs to link 
			with assembly routines in TERMA.M
			Keyboard,file input / Screen,file,printer output
	14 Feb 1988	A.Herrmann
	09 Mar 1988	separated SIO input buffer installation from
			interrupt install/uninstall
	10 Mar 1988	separated send,receive from s_rs232,r_rs232
*/

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


#define	BUFLEN	 1024		/* input buffer length in bytes		*/
#define	MINDIS	   64		/* distance between input,output pointer */
#define	MAXDIS	  128

#define INTVEC	0xFFD0		/* Interrupt address in BIOS	*/


extern void service();			/* Address of assembler routine	*/
					/* for interrupt service	*/

static int (*oldvec)() = &service;	/* Service routine and place for */
					/* old interrupt vector		*/

static char *p_in, *p_out;		/* input,output ptrs in ring buffer */
static char *p_beg,*p_end;		/* begin, end of buffer		 */

static int stopped = FALSE;		/* TRUE iff screen output stopped   */


void install()	/* establishes and inits the SIO input buffer	*/
{
	while ((p_beg=p_in=p_out=alloc(BUFLEN)) == NULL) {
		printf("Less than %dk for input buffer\n",BUFLEN);
		exit(1);
	}
	p_end = p_beg + BUFLEN - 1;
	bufclr = TRUE;
}


void sioswap()	/* inits the SIO and swaps the interrupt vector	*/
{
	extern void swapvec();		/* assembly language routine	*/

	i_rs232();
	swapvec(&oldvec,oldvec,INTVEC);	/* swap interrupt vectors	*/
}


void intsvc()	/* reads char from SIO input; called by interrupt	*/
		/* service assembly routine SERVICE			*/
{
	*p_in = inp(A_DATA) & mask;
	if (p_in++ == p_end)	p_in = p_beg;
	if (bufclr && space()<MINDIS) {
		stophost();
		bufclr = FALSE;
	}
}


int space()	/* returns free space left in input ring buffer	*/
{
	static int sp;

	sp = p_out-p_in;
	if (p_in >= p_out) sp += BUFLEN;
	return sp;
}


int bempty()	/* returns TRUE iff input buffer empty	*/
{
	return p_in==p_out;
}


char receive()	/* Returns character from input ring buffer		*/
		/* or NULL if none available or screen output stopped	*/
{
	static int ch;

	if (p_out == p_in || stopped)  return NULL;
	ch = *p_out;
	if (p_out++ == p_end)	p_out = p_beg;
	if (!bufclr && space()>=MAXDIS)	{
		wakehost();
		bufclr = TRUE;
	}
	return ch;
}


char send(ch)	/* Sends character ch out		*/
char ch;	/* Returns ch iff sent, else NULL 	*/
{
	if (input && !bempty()) return NULL;
	return s_rs232(ch);
}


char r_kbd()	/* Returns character read from keyboard or input file	*/
{
	static int c;

	while ( (c=gc()) == SWITCH)	setup();
	if (xonkey) {
		if (stopped) {
			stopped = (c!=_XOFF && c!=_XON);
			return NULL;
		}
		if (c==_XOFF) {
			stopped = TRUE;
			return NULL;
		}
	}
	if (input && ((c = gf(input)) == CPMEOF || c == EOF) )
		closefile(&input,IFITEM);
	if (c && echo) display(c);
	return c;
}


void display(ch)	/* displays char ch; control chars are either	*/
char ch;		/* interpreted or displayed as hex codes	*/
{
	static char str[5];
	static int i;

	if (dspctl && ch<_BLANK) {	/* display control chars as hex	*/
		sprintf(str,"<%-2X>",ch);
		for (i=0; i<4; i++)
			s_dsp(str[i]);
		if (ch==_CR) {
			s_dsp(_CR); s_dsp(_LF);
		}
	} else if (vtemul) {
		if (vt(ch)) s_dsp(ch);	/* translate VT100 (ANSI) codes	*/
	} else
		s_dsp(ch);		/* interpret control chars	*/
	return;
}



void s_dsp(ch)	/* writes character ch after possibly converting it	*/
char ch;	/* to HEX output format 				*/
{
#if FALSE
	static char str[4];
	static int i;

	if (format==HEX) {
		sprintf(str,"%-2X ",ch);
		for (i=0; i<3; i++)
			dsp(str[i]);
		if (ch==_CR) {
			dsp(_CR); dsp(_LF);
		}
	} else
#endif
		dsp(ch);
}


void dsp(ch)	/* writes char ch to screen and/or printer,output file	*/
char ch;
{
	if (output && (pf(ch) == EOF || ch == CPMEOF))
		closefile(&output,OFITEM);
	pc(ch);
	if (prtlog) pt(ch);
}
