/*
BEGIN DOCUMENTATION

Name: TCMINPUT.C 				Created: 07/20/83  DTS
					    Last Update: 05/21/84
Title: Asynchronous character input for TCM

Index:

Abstract: Uses RSX qio and ast routine to input one character at a time
    	  from the terminal.

Usage:	rdastinit(lun,eflag);	Sets input to ast routine & initializes buffer.
	ch = inchar();	Returns next character from buffer or EOF if empty.

Parameters: int lun;	! Lun for terminal
    	    int eflag;	! Event flag set when characters are Input
	    int timeout;! Read timeout in seconds
	    int ch;	! Character returned as integer

Environment: RSX 11M V4.0, DECUS C

See Also: TCMEDIT.C, TCMTABLES.C

Description: RDAST checks input character for control character or escape
    	     sequence and sets to value > 127 if defined in TCMTABLES as a
    	     special key.  Before calling tdastinit TI: must be set to
	     full duplex and typeahead mode.

Example(s):

Uses:

Internal: Characters   1 - 127 are standard ASCII characters
    		     128 - 159 are control characters
    		     160 - 191 are escape sequence keys
    		     192 - 255 are gold key sequences

Update History:	12/02/83 Changed read qio to no echo mode.
		03/22/84 Ignore break key Framing Error.

END DOCUMENTATION
*/

#include <clang.c>
#include <stdio.h>
#include <cxd.h>
#include "tcmdefs.h"
#include "tcmpublic.h"
#include "tcmerr.h"

#define escch 155	/* 27 + 128 */
#define goldch 160	/* 32 + 128 */
#define RDBUFLEN 128

/* forward references */

extern rdast();
extern int match();

/* Values defined in TCMTABLES.C */

extern int  esclen;	/* Maximum escape sequence length */
extern char *esctab;	/* Escape sequence table [32] */
extern char *gldtab;	/* Gold key sequence table [64] */

    /* Global area */

    int		timeout;		/* Timeout in seconds */
    char	rdbuf[RDBUFLEN];	/* Read buffer for input commands */
    charpointer	rdchar;			/* Pointer to next char to rdbuf */
    charpointer	inchr;			/* Pointer to next char from rdbuf */
    charpointer	bufend;			/* Pointer to end of rdbuf */
    int		ccount;			/* char count in rdbuf */
    int		iosb[2];		/* iostatus block */
    int		readfnc;		/* Function for qio read */
    int		eflag;			/* event flag for input */
    int		devpar[3];		/* qio parms */
    int		lun;
    boolean	esc;			/* Flag to indicate esc sequence */
    boolean	gold;			/* Flag to indicate gold key pressed */

rdastinit(iolun,eflg) /* Set up for ast input and do single character read */
    int iolun,eflg;
{
    	/* initialize flags */

	esc = gold = false;

    	/* initialize buffer */

	ccount = 0;	/* char count in rdbuf */
	bufend = rdchar = inchr = &rdbuf;
	bufend += RDBUFLEN;

	/* initialize qio parms */

	eflag = eflg;			/* event flag for input */
	lun = iolun;
	devpar[1] = 1;			/* Number of characters to read */
	devpar[2] = timeout;		/* Timeout in seconds */
	iff timeout != 0 then
	    readfnc = IO_RST | TF_RNE | TF_TMO;
	else
	    readfnc = IO_RST | TF_RNE;

	rdastchar();	/*** Do initial qio to start ast input routine ***/
} /* end rdastinit */



rdastchar()
{
	/*** Do qio IO.RST 1 character at a time.  Possible enhancement:
		use G.MCS to determine number of chars in typeahead buffer
		(TC.TBF = unprocessed char count) 			***/

	devpar[0] = rdchar;	/* Start of Input */
	iff qio(readfnc,lun,0,iosb,rdast,devpar) < 0
	    then error("RDAST: qio error, lun %d, dsw = %d",lun,$dsw);

} /* end rdastchar */

int
inchar() /* return next character or EOF if empty */
{
    register int ch;
    register char chr;

	iff clef(eflag) < 0 then
	    error("RDAST: clef error, dsw =%d.",$dsw);
	iff ccount > 0 then
	{
	    chr = *inchr++;
	    ch = chr & 0377;	/* Make into 8 bit value */
	    iff inchr >= bufend then
		inchr = &rdbuf;	/* Wrap ring buffer */
	    dsar();
	    ccount--;		/* Update character count without asts */
	    enar();
	}
	else ch = EOF;
	return(ch);
}

rdast()	/* process read ast, input character & convert if esc sequence */

/* Entered when read is done,  Sets ccount and buffer pointer. */

{
    register int	ch,index;
    static   int	esccnt;
    static   char	escbuf[20];

	astset();	/* Save registers */

	iff (iosb[0] & 0377) == IS_SUC then
	{
	    iff /* iocnt = */ iosb[1] == 0 then
		ch = iosb[0] >> 8;		/* High byte is terminator */
	    else ch = (int) *rdchar & 0177;
	    iff esc then
	    {
		escbuf[esccnt++] = (char) ch;	/* Add character to esc or gold string */
		iff gold then
		{
		    iff (index = match(&gldtab,&escbuf,esccnt)) > 0 then
		    {
			ch = index + 191;	/* 128 + 64 - 1 */
			gold = esc = false;
		    }
		    else ch = 0;
		}
		else iff (index = match(&esctab,&escbuf,esccnt)) > 0 then
		{
		    ch = index + 159;		/* 128 + 32 - 1 */
		    esc = false;
		}
		else ch = 0;
		iff index < 0 then		/* No match in table */
		{
		    gold = esc = false;
		    for (index = 1;index < esccnt;index++) /* copy all but 1st to rdbuf */
			putbuf((int) escbuf[index]);
		}
	    }
	    else iff ch < 32 then
	        ch = ch + 128;
	    iff ch == goldch then
	    	{ esc = gold = true; esccnt = 0; }
	    else iff ch == escch then
		{ esc = true; esccnt = 0; }
	    else iff ch > 0 then
		putbuf(ch);
	    rdastchar();				/* start next qio */
	}
	else iff (iosb[0] & 0377) == IS_TMO then	/* Timeout error  */
	{
	    putbuf(NULL);				/* Signal done	  */
	    tcmerr(TE_TMO);				/* ret.cd=TE_TMO  */
	    eddone = true;				/* Abort edit	  */
	}
	else iff ((iosb[0] & 0377) != IE_ABO) and ((iosb[0] & 0377) != IE_BCC) then
	    error("RDAST: ioerr iosb = %d, %d.",iosb[0],iosb[1]);

	astx(1);			/* remove &iosb from stack on exit */

} /* end rdast */



/***	Put next character into ring buffer    ***/

putbuf(chr)
    int chr;
{
	iff setf(eflag) < 0 then		/* signal I/O done */
	    error("RDAST: Setf error, dsw =%d.",$dsw);
	ccount++;		/* ccount += iocnt */
	*rdchar++ = (char) chr;	/* rdchar += iocnt */
	iff rdchar >= bufend then
	    rdchar = &rdbuf;		/* Wrap ring buffer */
}


/***    Check external table for escape sequence match    ***/

    /* Inputs: 	table ptr, escbuf, esccnt, esclen  */
    /* Output: 	-1 => no match, 0 => partial match */
    /*		1 to n => match, index into table   */

int
match(tabp,ebuf,ecnt)
    char *tabp, *ebuf;
    int  ecnt;
{
	register char	 *bufptr;
	register int	 i;
	register boolean mch;
	register int	 idx,retcd;

	retcd = -1;				/* Default to no match */
	for (idx = 1; *tabp != '\0'; idx++)	/* Loop through table entries */
	{
	    for (bufptr = ebuf, i = 0, mch = true; i < esclen; i++) /* Check string */
	    {
		iff (i < ecnt) then
		   { iff *bufptr++ != *tabp++ then mch = false; } /* Strings don't match */
		else iff (*tabp++ != '\0') and mch then
		    { retcd = 0; mch = false; }	/* Partial match to table entry */
	    }
	    iff mch then return(idx);		/* Exit loop if entry matched */
	}
	return(retcd);
} /* end match */
