/*
 * Jeffrey Friedl
 * Omron Corporation			オムロン（株）
 * Nagaokakyoshi, Japan			〒617長岡京下海印寺
 *
 * jfriedl@nff.ncl.omron.co.jp
 *
 * This work is placed under the terms of the GNU General Purpose License
 * (the "GNU Copyleft").
 */

/*
 * This file might be compiled directly, or included from another file.
 * It might be compiled by an ANSI or traditional compiler.
 *
 * If it's an ANSI compile, we'll only compile if we think that the system
 * include files we use have been properly ANSIfied. Otherwise, we'll compile
 * everything.
 */
#include "config.h"

/*
 * If we've been told in config.h that the the system headers haven't been
 * ANSIfied, we may as well note that we'll not compile now if we're doing
 * a STDC compile.
 */
#ifdef __STDC__
#  ifdef NON_ANSIFIED_IOCTL
#    define NO_COMPILE
#  endif
#endif

/*
 * If we are compiling (so far as we know), include the appropriate system
 * headers for the ioctl we'll be using.
 */
#ifndef NO_COMPILE
#  include "system.h"
#  ifdef _HAVE_SYS_TERMIO_H_
#    include <sys/termio.h>
#  else
#    include <sgtty.h>
#  endif
#endif

/*
 * If we're compiling (so far as we know) and it's a STDC compile,
 * make a couple of checks to see if we can guess about the ANSIfication
 * of the header files. This is all very non-portable, but the best
 * I can think of to automate this stuff....
 */
#ifndef NO_COMPILE
#  ifdef __STDC__
#    ifdef _IO
#      ifdef TIOCEXCL
#        if _IO('x', 13) == TIOCEXCL
#          define NO_COMPILE
#        endif
#      endif /* TIOCEXCL */
#      ifdef TCSBRK
#        if _IO('x', 5) == TCSBRK 
#          define NO_COMPILE
#        endif
#      endif /* TCGETA */ 
#    endif /* _IO */
#  endif /* __STDC__ */
#endif

#ifndef NO_COMPILE
#  ifdef __STDC__
#    define NO_ARGS void
#  else
#    define NO_ARGS /*empty*/
#  endif

#  include <stdio.h>
#  define DIE(note)                                                          \
   {                                                                         \
     write(fileno(stderr), note, sizeof(note));                              \
     exit(2);                                                                \
   }

#ifdef __GNUC__
#  if __GNUC > 1
#      ifndef __STDC__
#        warning integer overflow OK for this file.
#      endif
#  endif
#endif

#  ifndef _HAVE_SYS_TERMIO_H_

	static struct sgttyb original, new;

	void set_tty_state_to_cbreak(NO_ARGS)
	{
	    if (original.sg_flags == 0)
	    {
		if (ioctl(fileno(stdin), TIOCGETP, (char*)&original) < 0)
		    DIE("ioctl TIOCGETP error\n");

		new = original;
		new.sg_flags |= CBREAK;		/* turn cbreak on */
		new.sg_flags &= ~ECHO;		/* turn echo off */
	    }
	    /* don't worry about "integer overflow" warnings on next line */
	    if (ioctl(fileno(stdin), TIOCSETP, (char*)&new) < 0)
		DIE("ioctl TIOCSETP error\n");
	}

	void reset_tty_state(NO_ARGS)
	{
	    /* don't worry about "integer overflow" warnings on next lines */
	    if (original.sg_flags)
		ioctl(fileno(stdin), TIOCSETP, (char*)&original);
	}

#  else /* _HAVE_SYS_TERMIO_H_ */

	static struct termio original, new;

	void set_tty_state_to_cbreak(NO_ARGS)
	{
	    if (original.c_cflag == 0)
	    {
		if (ioctl(fileno(stdin), TCGETA, &original) < 0)
		    DIE("ioctl TCGETA error\n");
		new = original;
#               ifdef ISTRIP
		    new.c_iflag &= ~ISTRIP;
#		endif
		new.c_lflag &= ~(ECHO|ICANON);
		new.c_cc[VMIN] = 1; /* Input should wait for at least 1 char */
		new.c_cc[VTIME] = 0; /* no matter how long that takes.  */
	    }
	    if (ioctl(fileno(stdin), TCSETA, &new) < 0)
		DIE("ioctl TCSETA error\n");
	}

	void reset_tty_state(NO_ARGS)
	{
	    if (original.c_cflag)
	    {
#if USE_LOCAL_INPUT	        
		ensure_blocking_input();
#endif
		ioctl(fileno(stdin), TCSETA, &original);
	    }
        }

#  endif /* _HAVE_SYS_TERMIO_H_ */
#endif /* NO_COMPILE */
