/*
 * 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>
#if 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
	struct ttysize ttysize;

	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 (ioctl(0, TIOCGSIZE, &ttysize) == 0) {
		nrow = ttysize.ts_lines;
		ncol = ttysize.ts_cols;
	} 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
