/*
 *  tread -- read with timeout
 *
 *  revision history
 *	0.1: Dec.  8, 2016 by Dai ISHIJIMA
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#define YES 1
#define NO 0

char *prog;
#define shift --argc; ++argv

static struct termios keyorg, keynew;	/* キーボード (stdin) の状態を保持 */


/* キーボード (stdin) を「生」モード<STRIKE>、エコーなし</STRIKE>に */
void kbdinit(int echo)
{
    if (isatty(fileno(stdin))) {
	tcgetattr(fileno(stdin), &keyorg);
	memcpy(&keynew, &keyorg, sizeof(struct termios));
	cfmakeraw(&keynew);
	/* keynew.c_lflag &= ~ECHO; */
	if (echo > 0) {			/* -e 正の数 -> エコーあり */
	    keynew.c_lflag |= ECHO;
	}
	if (echo < 0) {			/* -e 負の数 -> エコーなし */
	    keynew.c_lflag &= ~ECHO;
	}
	tcsetattr(fileno(stdin), TCSANOW, &keynew);
    }
}


/* キーボード (stdin) の設定を元に戻す */
void kbdrestore()
{
    if (isatty(fileno(stdin))) {
	tcsetattr(fileno(stdin), TCSANOW, &keyorg);
    }
}


/* 入力があるまで待つ */
int waitfor(long seconds, int echo)
{
    int nfds;
    fd_set readfds;
    struct timeval timeout;
    int status = 0;
    
    kbdinit(echo);
    FD_ZERO(&readfds);
    FD_SET(fileno(stdin), &readfds);
    timeout.tv_sec = seconds;
    timeout.tv_usec = 0;
    nfds = select(fileno(stdin) + 1, &readfds, NULL, NULL, &timeout);
    if ((nfds < 0) && (errno != EINTR)) {
	fprintf(stderr, "%s: select failed\n", prog);
	status = -1;
    }
    if ((nfds > 0) && (FD_ISSET(fileno(stdin), &readfds))) {
	/* キーボード入力あり */
	status = 1;
    }
    kbdrestore();
    return(status);
}


/* 使い方の簡易説明 */
void usage()
{
    fprintf(stderr, "Usage: %s [option...]\n", prog);
    fprintf(stderr, "    options:\n");
    fprintf(stderr, "\t-t #: set timeout\n");
    fprintf(stderr, "\t-p #: set prompt\n");
    fprintf(stderr, "\t-e #: set echo mode\n");
}

/* メイン */
int main(int argc, char *argv[])
{
    long seconds=10;
    char value[BUFSIZ];
    char prompt[BUFSIZ];
    int  echo = 0;
    
    prog = *argv;
    shift;
    prompt[0] = '\0';
    while ((argc > 0) && (argv[0][0] == '-')) {
	if ((argv[0][1] == 't') && (argc > 1)) {	/* タイムアウト */
	    shift;
	    seconds = atoi(*argv);
	}
	else if ((argv[0][1] == 'p') && (argc > 1)) {	/* プロンプト */
	    shift;
	    strncpy(prompt, *argv, BUFSIZ);
	}
	else if ((argv[0][1] == 'e') && (argc > 1)) {	/* ECHO */
	    shift;
	    echo = atoi(*argv);
	}
	else {
	    usage();
	    exit(1);
	}
	shift;
    }
    fputs(prompt, stderr);
    if (waitfor(seconds, echo) > 0) {
	fgets(value, BUFSIZ, stdin);
	fputs(value, stdout);
	exit(0);
    }
    exit(1);
}

/* Local Variables: */
/* compile-command:"cc -Wall -o tread tread.c" */
/* End: */
