/*
 * The functions in this file negotiate with the operating system for
 * characters, and write characters in a barely buffered fashion on the display.
 * All operating systems.
 */

#include	<sys/types.h>    /* 1.13 */

#ifdef UNIX    /* System V */

#include    <stdio.h>
#include    <signal.h>
#ifdef BSD
#include    <sys/ioctl.h>
#else
#include    <termio.h>
#endif /* BSD */
#include    <errno.h>
#include    <fcntl.h>
#include    "def.h"
int kbdflgs;            /* saved keyboard fd flags  */
int kbdpoll;            /* in O_NDELAY mode         */
int kbdqp;          /* there is a char in kbdq  */
char kbdq;          /* char we've already read  */

#ifdef BSD
struct	sgttyb	otermb;
struct	sgttyb	ntermb;
#else
struct  termio  otermio;    /* original terminal characteristics */
struct  termio  ntermio;    /* charactoristics to use inside */
#endif /* BSD */
extern	errno; /* System error number -- Necessary when compiling in BSD 1.13 */

int     nrow;                   /* Terminal size, rows.         */
int     ncol;                   /* Terminal size, columns.      */

/*
 * This function is called once to set up the terminal device streams.
 * On VMS, it translates TT until it finds the terminal, then assigns
 * a channel to it and sets it raw. On CPM it is a no-op.
 */

void ttopen()
{
#ifdef BSD
#ifdef ULTRIX
	struct winsize ttysize;
#else
	struct ttysize ttysize;
#endif

	ioctl(0, TIOCGETP, &otermb);	/* save settings	*/
	ntermb = otermb;			/* setup new settings	*/
	ntermb.sg_flags &= ~ECHO;
	ntermb.sg_flags |= RAW;
	ioctl(0, TIOCSETP, &ntermb); 	/* and activate them	*/
	kbdpoll = FALSE;

	/* on all screens we are not sure of the initial position
       of the cursor                    */
	ttrow = 999;
	ttcol = 999;
#if ULTRIX
	if (ioctl(0, TIOCGWINSZ, &ttysize) == 0) {
		nrow = ttysize.ws_row;
		ncol = ttysize.ws_col;
#else
		if (ioctl(0, TIOCGSIZE, &ttysize) == 0) {
			nrow = ttysize.ts_lines;
			ncol = ttysize.ts_cols;
#endif
		} else {
			nrow = NROW;
			ncol = NCOL;
		}
#else
		ioctl(0, TCGETA, &otermio); /* save old settings */
		ntermio.c_iflag = 0;        /* setup new settings */
		ntermio.c_oflag = 0;
		ntermio.c_cflag = otermio.c_cflag;
		ntermio.c_lflag = 0;
		ntermio.c_line = otermio.c_line;
		ntermio.c_cc[VMIN] = 1;
		ntermio.c_cc[VTIME] = 0;
		ioctl(0, TCSETAW, &ntermio); /* and activate them */
		kbdflgs = fcntl( 0, F_GETFL, 0 );
		kbdpoll = FALSE;
		/* on all screens we are not sure of the initial position
       of the cursor                    */
		ttrow = 999;
		ttcol = 999;
		nrow = NROW;
		ncol = NCOL;
#endif 
	}

	/*
 * This function gets called just before we go back home to the command
 * interpreter. On VMS it puts the terminal back in a reasonable state.
 * Another no-operation on CPM.
 */
	void  ttclose()
	    {
#ifdef BSD
		if (ioctl(0, TIOCSETP, &otermb) == -1) /* restore terminal settings */
			printf ("closing ioctl on dev 0 failure, error = %d\n", errno);
#else
		if (ioctl(0, TCSETAW, &otermio) == -1) /* restore terminal settings */
			printf ("closing ioctl on dev 0 failure, error = %d\n", errno);
		if (fcntl(0, F_SETFL, kbdflgs) == -1)
			printf ("closing fcntl on dev 0 failure, error = %d\n", errno);
#endif

	}

	/*
 * Write a character to the display. On VMS, terminal output is buffered, and
 * we just put the characters in the big array, after checking for overflow.
 * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
 * MS-DOS (use the very very raw console output routine).
 */
	void ttputc(c)
	    {
		fputc(c, stdout);
	}

	/*
 * Flush terminal buffer. Does real work where the terminal output is buffered
 * up. A no-operation on systems where byte at a time terminal I/O is done.
 */
	void ttflush()
	    {
		fflush(stdout);
	}

	/*
 * Read a character from the terminal, performing no editing and doing no echo
 * at all. More complex in VMS that almost anyplace else, which figures. Very
 * simple on CPM, because the system can do exactly what you want.
 */
	ttgetc()
	    {
		if( kbdqp )
			kbdqp = FALSE;
		else
		{
#ifdef BSD
			int count;

			if (kbdpoll && (ioctl(0, FIONREAD, &count), count == 0))
				return FALSE;
			read(0, &kbdq, 1);
#else
			if( kbdpoll && fcntl( 0, F_SETFL, kbdflgs ) < 0 )
				return FALSE;
			kbdpoll = FALSE;
			while (read(0, &kbdq, 1) != 1)
				;
#endif
		}
		return ( kbdq & 127 );
	}

	/* typahead():    Check to see if any characters are already in the
        keyboard buffer
*/
	ttkeyready ()
	    {
		if( !kbdqp )
		{
#ifdef BSD
			int count;

			if (!kbdpoll && (ioctl(0, FIONREAD, &count), count == 0))
				return FALSE;
			kbdpoll = TRUE;    /*  fix in 1.13 */
			kbdqp = TRUE;
#else
			if( !kbdpoll && fcntl( 0, F_SETFL, kbdflgs | O_NDELAY ) < 0 )
				return(FALSE);
			kbdpoll = TRUE;    /*  fix in 1.13 */
			kbdqp = (1 == read( 0, &kbdq, 1 ));
#endif

		}
		return ( kbdqp );
	}
#endif
