/*
 * TTY setup routines. These are the TERMIOS-style (POSIX) routines.
 */

static struct termios _raw_tty, _original_tty;

/*
 * current raw state
 */
static short _inraw = 0;

/*
 *  Set up the tty driver
 *
 * Args: state -- which state to put it in. 1 means go into raw (cbreak),
 *                0 out of raw.
 *
 * Result: returns 0 if successful and -1 if not.
 */
int
Raw(state)
int state;
{
    /** state is either ON or OFF, as indicated by call **/
    /* Check return code only on first call. If it fails we're done for and
       if it goes OK the others will probably go OK too. */

    if(state == 0 && _inraw){
        /*----- restore state to original -----*/
	if(tcsetattr(STDIN_FD, TCSADRAIN, &_original_tty) < 0)
	  return -1;

        _inraw = 0;
    }
    else if(state == 1 && ! _inraw){
        /*----- Go into raw mode (cbreak actually) ----*/
	if(tcgetattr(STDIN_FD, &_original_tty) < 0)
	  return -1;

	tcgetattr(STDIN_FD, &_raw_tty);
	_raw_tty.c_lflag &= ~(ICANON | ECHO | IEXTEN); /* noecho raw mode    */
 	_raw_tty.c_lflag &= ~ISIG;		/* disable signals           */
 	_raw_tty.c_iflag &= ~ICRNL;		/* turn off CR->NL on input  */
 	_raw_tty.c_oflag &= ~ONLCR;		/* turn off NL->CR on output */

	_raw_tty.c_cc[VMIN]  = '\01';		/* min # of chars to queue  */
	_raw_tty.c_cc[VTIME] = '\0';		/* min time to wait for input*/
	_raw_tty.c_cc[VINTR] = ctrl('C');	/* make it our special char */
	_raw_tty.c_cc[VQUIT] = 0;
	_raw_tty.c_cc[VSUSP] = 0;
	tcsetattr(STDIN_FD, TCSADRAIN, &_raw_tty);
	_inraw = 1;
    }

    return(0);
}


/*
 *  Set up the tty driver to use XON/XOFF flow control
 *
 * Args: state -- True to make sure XON/XOFF turned on, FALSE off.
 *
 * Result: none.
 */
void
xonxoff_proc(state)
int state;
{
    if(_inraw){
	if(state){
	    if(!(_raw_tty.c_iflag & IXON)){
		_raw_tty.c_iflag |= IXON;
		tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
	    }
	}
	else{
	    if(_raw_tty.c_iflag & IXON){
		_raw_tty.c_iflag &= ~IXON;	/* turn off ^S/^Q on input   */
		tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
	    }
	}
    }
}


/*
 *  Set up the tty driver to do LF->CR translation
 *
 * Args: state -- True to turn on translation, false to write raw LF's
 *
 * Result: none.
 */
void
crlf_proc(state)
int state;
{
    if(_inraw){
	if(state){				/* turn ON NL->CR on output */
	    if(!(_raw_tty.c_oflag & ONLCR)){
		_raw_tty.c_oflag |= ONLCR;
		tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
	    }
	}
	else{					/* turn OFF NL-CR on output */
	    if(_raw_tty.c_oflag & ONLCR){
		_raw_tty.c_oflag &= ~ONLCR;
		tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
	    }
	}
    }
}


/*
 *  Set up the tty driver to hanle interrupt char
 *
 * Args: state -- True to turn on interrupt char, false to not
 *
 * Result: tty driver that'll send us SIGINT or not
 */
void
intr_proc(state)
int state;
{
    if(_inraw){
	if(state){
	    _raw_tty.c_lflag |= ISIG;		/* enable signals */
	    tcsetattr(STDIN_FD, TCSADRAIN, &_raw_tty);
	}
	else{
	    _raw_tty.c_lflag &= ~ISIG;		/* disable signals */
	    tcsetattr(STDIN_FD, TCSADRAIN, &_raw_tty);
	}
    }
}


/*
 * Discard any pending input characters
 *
 * Args:  none
 *
 * Result: pending input buffer flushed
 */
void
flush_input()
{
    tcflush(STDIN_FD, TCIFLUSH);
}


/*
 * Turn off hi bit stripping
 */
void
bit_strip_off()
{
    _raw_tty.c_iflag &= ~ISTRIP;
    tcsetattr(STDIN_FD, TCSADRAIN, &_raw_tty);
}


/*
 * Turn off quit character (^\) if possible
 */
void
quit_char_off()
{
}


/*
 * Returns TRUE if tty is < 4800, 0 otherwise.
 */
int
ttisslow()
{
    return(cfgetospeed(&_raw_tty) < B4800);
}


