#include #include #include #ifndef _WIN32_WCE #include #include #include #include #include #endif #include #include // For gettimeofday(); #include // for wait3() on sparc_solaris #include #include #include "termio.h" /* * This routine will run the program specified with the arguments * specified. It is NOT POSSIBLE to send parameters with embedded spaces. * This routine closes all open file descriptors except for stdout and * stderr on the child so that it can't hang and cause them to remain open. * It returns the PID of the child process on success and -1 on failure. */ int run_program(const char * program, const char * args) { int loop; int pid; /* Child's process ID */ if ( (pid = fork()) == -1) { fprintf(stderr,"run_program: cannot fork().\n"); return -1; } if (pid == 0) { /* CHILD */ int ret; int num_descriptors;/* Number of available file descr */ char command[600]; /* Command passed to system() call */ /* Close all files except stdout and stderr. */ /* This prevents a hung child from keeping devices open */ num_descriptors = getdtablesize(); for (loop = 0; loop < num_descriptors; loop++) { if ( (loop != 1) && (loop != 2) ) { close(loop); } } sprintf(command,"%s %s",program, args); ret = system(command); if ( (ret == 127) || (ret == -1) ) { fprintf(stderr, "run_program: system() failed !!!!!\n"); perror("Error"); fprintf(stderr, "Attempted command was: '%s'\n", command); exit(-1); /* This should never occur */ } exit(0); } else { /* PARENT */ return pid; } } enum STATE { state_initial, state_number, state_numletter }; int noblock_read_character(void) { int c; // See if there is one or more characters available // on stdin. If so, then get the next one. If not, // return zero. Wait up to 1ms for a keypress (1000 // microseconds). struct timeval millisec = { 0 , 1000 }; fd_set read_descriptors; FD_ZERO(&read_descriptors); FD_SET(0, &read_descriptors); if (select( 16, &read_descriptors, NULL, NULL, &millisec) > 0) { return getchar(); } else { return 0; } } int main(unsigned argc, const char *argv[]) { bool done = false; int c; // Turn off line-buffered input so that we can get characters as // soon as the user types them and will time out if none are pressed. //system("stty -icanon time 1"); system("/bin/stty raw opost onlcr -echo"); // Keep getting characters and acting on them until someone // kills us or stdin runs out of data for us. while ( true ) { static STATE current_state = state_initial; // Get the next character (zero if there was no character). c = noblock_read_character(); // If they press '/', that means quit in any state. if (c == '/') { break; } // When a character is pressed, reset the "since_pressed" // timer to zero. While no character is pressed, count up // the time so that we can have timeouts. static struct timeval last_char_time = { 0 , 0 }; struct timeval now; gettimeofday(&now, NULL); if ( (c != 0) || ((last_char_time.tv_sec == 0) && (last_char_time.tv_usec == 0)) ) { last_char_time = now; } long secdiff = now.tv_sec - last_char_time.tv_sec; long usecdiff = now.tv_usec - last_char_time.tv_usec; double since_pressed = secdiff + 1e-6*usecdiff; // Finite state machine running to keep track of what we should // do. Switch selects which state we are in, then the state // logic within each state determines what to do next based on // key presses and timeouts. switch (current_state) { case state_initial: if (c != 0) printf("Got %d\n", c); if (since_pressed > 2) { printf("timeout\n"); last_char_time = now; break; } switch (c) { } break; default: fprintf(stderr,"Unexpected internal state\n"); current_state = state_initial; break; } } system("/bin/stty sane"); return 0; }