/*
 * Readch
 *
 * Reads a single character from stdin, with a timeout.
 *
 * compile with: cc readch.c -o readch
 *
 * usage: readch <timeout>
 *
 * The exit value of this code will be ASCII value of the key pressed;
 * In the event of a timeout, the value 1 will be returned.  The only
 * problem may be that you can't tell a null from a timeout.
 * Don't use null for things.
 * If the timeout isn't given, or can't be read, or is zero, the system
 * will wait forever, ie: there will be no timeout.
 * Timeouts are in seconds.
 *
 * Copyright (C) 1999 Louis W. Erickson.  Feel free, folks.
 *
 */

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>

void SignalHandler(int);
int main(int, char **);

int isSetup = 0;
struct termios term;

/* catch signals */
/* All of the signals this program catches are handled by returning
   the terminal to it's normal output, and then exiting, returning
   the error code of 0 for the timeout value. */
void SignalHandler(int sig)
{
	sig = sig;

	/* If we managed to save a mode, restore it */
	if(isSetup)
	{
		tcsetattr(fileno(stdin), TCSANOW, &term);
	}

	/* Return our error value */
	exit(0);
}

int main(int argc, char *argv[])
{
	int ch;
	int delay = 0;
	struct termios newMode;

	/* read the command line */
	if(argc > 1)
	{
		delay = atoi(argv[1]);
	}

	/* Move to raw mode */
	/* Get the current mode */
	tcgetattr(fileno(stdin), &term);
	/* make a copy of the current mode */
	newMode = term;
	/* Convert the mode to RAW */
	cfmakeraw(&newMode);
	/* Set RAW mode */
	tcsetattr(fileno(stdin), TCSANOW, &newMode);
	/* Note that we set raw mode */
	isSetup = 1;

	/* Set the signal handler, and the alarm */
	signal(SIGALRM, SignalHandler);
	if(delay)
	{
		alarm(delay);
	}

	/* read a character */
	ch = getc(stdin);

	/* Stop the alarm handling */
	signal(SIGALRM, SIG_IGN);

	/* Restore the old mode */
	tcsetattr(fileno(stdin), TCSANOW, &term);

	/* Return the value typed */
	exit(ch);
}
