/* Special Raw console I/O for BDSC			Steve Ward 1/81
 *
 * Provides a reasonably flexible, device-independent interface:
 *
 *	ch = getchar()		Read a character
 *
 *	putchar(ch)		write a character
 *
 *	kbhit()			true iff input character waiting
 *
 *	old = TTYMode(m)	Sets tty mode bits to m, returning old
 *				 value.  Mode bits:
 *		1	Echo mode: chars echoed as read.
 *		2	Quit: ^C causes an exit.
 *		4	Flow: ^S, ^Q flow control.
 *		8	Strip: input characters stripped to 7 bits.
 *		16	Expand: expand \n, \t on output.
 *
 * Hence for REALLY raw I/O, do TTYMode(0).
 *
 * NOTE: Program using CIO.C are NOT PORTABLE to systems lacking a C compiler!
 *	 If you really must use CIO, then compile this once (to get CIO.CRL)
 *	 and link your programs by saying:
 *
 *		A>clink main <other CRL files> DEFF CIO <cr>
 *
 */

#include "bdscio.h"			/* Make sure BDSCIO.H has been
					   customized for your system!   */

/* Device-specific definitions...	   Input status flag:		*/
#define	ISTAT	((CIMASK & inp(CSTAT)) == (CAHI ? CIMASK : 0))
					/* character output status:	*/
#define	OSTAT	((COMASK & inp(CSTAT)) == (CAHI ? COMASK : 0))

/* Internal static definitions.						*/
#define	Freeze	(static[1])		/* true if output frozen (^S) */
#define	Pending	(static[2])		/* true if input char waiting */
#define	PendCh	(static[3])		/* the pending input char     */
#define	Mode	(static[4])		/* input mode bits:	     */
#define	M_echo	1			/* echo mode bit		*/
#define	M_quit	2			/* ^C (quit) mode bit		*/
#define	M_flow	4			/* ^S/^Q flow control		*/
#define	M_strip	8			/* strip to 7-bits		*/
#define	M_expan	16			/* Expand \n on output.		*/

#define	QuitC	(static[5])


putchar(c) {  rawio(1, c); }

getchar() { return rawio(2); }

kbhit() { return rawio(3); }

TTYMode(mode) { return rawio(4, mode); } /* set mode bits, returns prev. */

rawio(key, arg)
 {	char ch, *static, mode;
	static = "Nonsense!";

	if (*static == 'N')		/* Initialization ...	*/
	 { *static = Freeze = Pending = 0;
	   Mode = M_echo | M_quit | M_flow | M_strip | M_expan;
	   QuitC = 3; }

Again:	if (ISTAT)		/* check for input pending.	*/
	 { ch = inp(CDATA);
	   if ((mode=Mode) & M_strip) ch &= 0x7F;
	   if ((mode & M_quit) && (ch == QuitC)) exit();
	   else if (mode & M_flow)
		{ if (ch == ('S'-64)) { Freeze=1; goto brk; }
		  if (ch == ('Q'-64)) { Freeze=0; goto brk; }}
	   if (!Pending)
		{ Pending = 1;
		  PendCh = ch;
		  if (mode & M_echo) outp(CDATA, ch); }}

brk:	switch(key)
	 { case 0:	return;
	   case 1:	if (Freeze || !OSTAT) goto Again;  /* putchar(arg) */
			outp(CDATA, arg);
			if ((arg == '\n') && (Mode & M_expan))
				putchar('\r');
			return arg;
	   case 2:	if (!Pending) goto Again;
			Pending = 0; return PendCh;
	   case 3:	return Pending;
	   case 4:	mode = Mode; Mode = arg;
			if (!(arg & M_flow)) Freeze = 0;
			return mode;
	   default:	return;
	 }
 }

