Stop only if some key is pressed in C - c

If I had a while loop that I wanted to stop only if the q key is pressed how would I do that.
However, I do NOT want it to quite the program
#define TRUE 1
#define FALSE 0
typedef int boolean;
int main(int argc,char* argv[]){
char *script = malloc(MAXPATH);
script = "ls";
boolean a;
a = TRUE;
while(a){ //this is the while loop i want to break incase of a keypress
system(script);
}
do something else
something else....
This will be running on Mac OS X.
both getchar() and getc() pause for a response which makes loop stop

you can use select() mechanism in UNIX-LIKE OS.
all in one function:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
fd_set readfds;
struct timeval tv;
int ch;
int bool, ret;
FD_ZERO(&readfds);
bool = 1;
while (bool) {
FD_SET(STDIN_FILENO, &readfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
/* int select(int nfds, fd_set *readfds, fd_set *writefds,
* fd_set *exceptfds, struct timeval *timeout); */
ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);
if (ret < 0) {
perror("select error");
exit(1);
} else if (ret == 0) {
/* timeout */
} else if (FD_ISSET(STDIN_FILENO, &readfds)) {
ch = fgetc(stdin);
if (ch == 'q') {
bool = 0;
}
}
sleep(1);
fprintf(stderr, ".");
}
return 0;
}

native functions in C with which i can detect a keypress are :
getchar() and getc()
kbhit() is a function returns integer value whenever the key is pressed
you can use the above functions
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <time.h>
int main()
{
int m;
clrscr();
do
{
if(kbhit())
{
if((m=getch())==97)
{
printf("Key a is pressed....\n");
}
}
} while(1);
getch();
return 0;
}

I'm glad of alexchandel's answer. I had never heard of poll()
poll() is a good answer for POSIX style systems like the questioner's platform
_kbhit() is the simplest answer on MS Windows. Their Poll() is different of course
The 1 means just one descriptor block in my list, the 100 is milliseconds timout
my file handle is { 0, for stdin
read the man page for the many events you can interrogate, I only wanted POLLIN
#include <stdio.h>
#include <poll.h>
#include <errno.h>
static struct pollfd attention = { 0, POLLIN } ;
int main()
{
int x, y;
for (;;)
{
x = poll(&attention, 1, 100);
if (x < 0)
{
printf("problem %d\n", errno);
break;
}
else if (x)
{
printf("you rang %x ?", x);
y = getc(stdin);
printf(" %c of course\n", y);
if (y == '.') break;
}
}
return 0;
}

You could make the computation run in a pthread while the main loop reads char on stdin. SDL library has better input controls if you don't just want to read char from stdin. gtk also has events that the window receives. The command "xev" is a xlib program for linux that works similarly. It opens a blank window and it reads key events as they come.

Related

Why simple read string from non blocking IO in C behaves oddly in loop?

I have just encountered a problem which I couldn't found the reason. The code works as Below:
There is a while loop which does a lot of stuff in the middle (Does not even written), and has a non-blocking IO to receive the end process command (which is a string).
At any time, a user could come and wants to finish the process. He/She would press some keys and then press the [Enter] button.
After select find out there is an input, it uses the input string and evaluates with the EXIT string and end the process.
Now the problem is when I use the exitFlag string as the termination key it just don't accept it and keeps writing <the printf() statement> until i hit cntrl+c.
I have tried scanf(), fputs(), fread() to recieve input string from stdin and also used fflush(stdin) and fflush(stdout) to clear the std buffers.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
fd_set s;
struct timeval timeout;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
char exitFlag[10];
int sFlag;
printf("Enter \"EXIT\" to End the Process\n");
while (1)
{
fflush(stdin); fflush(stdout);
FD_ZERO(&s);
FD_SET(STDIN_FILENO, &s);
timeout.tv_sec = 3; timeout.tv_usec = 0;
sFlag = select(STDIN_FILENO+1, &s, NULL, NULL, &timeout);
printf("%d: ", sFlag);
if (sFlag < 0) _exit(0);
else if (sFlag == 0)
{
printf("-\n");
fflush(stdin); fflush(stdout);
}
else
{
fflush(stdin); fflush(stdout);
scanf("%[^\n]s", &exitFlag); // fgets( exitFlag, 10, stdin); // fread( exitFlag, 10, 1 ,stdin);
printf("You have Pressed %s, Enter \"EXIT\" to End the Process: ", exitFlag);
printf("%s\n", exitFlag);
if ( memcmp(&exitFlag, "EXIT", 4) == 0 ) break;
}
}
return 0;
}
Ironically, I don't encounter similar problem when using char as the termination key input rather than string.
I would be very thankful if someone explains where I made mistake in the IO or any other place.
I have also reviewed prior questions carefully but they had seemed to work with a single keyboard press which was not safe for common use!
include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
fd_set s;
struct timeval timeout;
timeout.tv_sec = 3;
timeout.tv_usec = 0;
char exitFlag;
int sFlag;
while (1)
{
fflush(stdout);
FD_ZERO(&s);
FD_SET(STDIN_FILENO, &s);
timeout.tv_sec = 3; timeout.tv_usec = 0;
sFlag = select(STDIN_FILENO+1, &s, NULL, NULL, &timeout);
if (sFlag < 0) _exit(0);
else if (sFlag == 0)
{
fflush(stdout);
printf("-\n");
}
else
{
fflush(stdin);
scanf("%c", &exitFlag);
printf("You have Pressed %c, Press E to exit: ", exitFlag);
printf("%c\n", exitFlag);
fflush(stdout);
if ( exitFlag =='E' ) break;
}
}
return 0;
}

How to use select() correctly inside a loop?

I am trying to modify an example I found.
The example:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0 // file descriptor for standard input
int main(void)
{
struct timeval tv;
fd_set readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
FD_ZERO(&readfds);
FD_SET(STDIN, &readfds);
// don't care about writefds and exceptfds:
select(STDIN+1, &readfds, NULL, NULL, &tv);
if (FD_ISSET(STDIN, &readfds))
printf("A key was pressed!\n");
else
printf("Timed out.\n");
return 0;
}
Which print time out if 2.5 seconds has passed without sending a message, otherwise printing a key was pressed.
I tried to put it inside a while loop:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0 // file descriptor for standard input
int main(void)
{
fd_set readfds, temp;
struct timeval tv;
FD_ZERO(&readfds);
FD_ZERO(&temp);
FD_SET(STDIN, &readfds);
while(1){
temp = readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
// don't care about writefds and exceptfds:
if (select(STDIN+1, &temp, NULL, NULL, &tv) == -1)
printf("err");
if (FD_ISSET(STDIN, &temp))
{
printf("A key was pressed!\n");
}
else
printf("Timed out.\n");
}
return 0;
}
In this code when I enter a key it keeps printing a key was pressed forever.
I read online the I have to set tv variable every time but still no help.
Do i need a temp fd_set
? what am I wrong ?
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
// Note: STDIN_FILENO, or fileno(stdin)
#define STDIN 0 // file descriptor for standard input
int main(void)
{
fd_set readfds, temp;
struct timeval tv;
int ret,ch;
FD_ZERO(&readfds);
FD_ZERO(&temp);
FD_SET(STDIN, &readfds);
while(1){
temp = readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
// don't care about writefds and exceptfds:
ret = select(STDIN+1, &temp, NULL, NULL, &tv) ;
if (ret == -1) {
if (errno == EAGAIN) continue; // These are NOT Errors, but natural occuring events
if (errno == EINTR) continue; // The are reported to avoid your select() to block for too long
perror("erreur");
break;
}
else if (ret ==0) {
printf("Timed out.\n");
continue;
}
// Ok: select has returned > 0; there must be something to read
if (FD_ISSET(STDIN, &temp)) {
ch = getc(stdin); // Lookout: stdin is line-buffered
printf("A key was pressed: %d!\n", ch);
}
}
return 0;
}

pthread_kill() gives segmentation fault when called from second thread

I am trying to manually interrupt the main thread of a program when it is blocked on a read() system call. I do this in a second thread with a call to pthread_kill() however a segmentation fault occurs. However if I place the call to read() in the scond thread, i.e. NOT the main thread and call pthread_kill() from the main thread then all works as expected.
For example, the following code results in a segmentation fault, where I call pthread_kill() in the second thread, approximatelt 2 seconds after it is started. It uses the pthread_t of the main thread obtained by a call (in the main thread) to pthread_self():
Example 1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
static int fd = 0;
unsigned char buf[255];
static pthread_t s;
void sigHandler(int sig){
printf("Signal handler called.\n");
}
void * closeFD(void *arg){
printf("Second thread started.\n");
sleep(2);
int r = pthread_kill(s, SIGUSR1);
}
int main(char *argv[], int argc){
struct termios newtio;
pthread_t t1;
unsigned char buf[255];
void *res;
struct sigaction int_handler = {.sa_handler=sigHandler};
sigaction(SIGUSR1,&int_handler,0);
s = pthread_self();
printf("Process id is: %d.\n", getpid());
fd = open("/dev/ttyS0", O_RDONLY | O_NOCTTY);
if (fd != -1){
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = B2400 | CS7 | CLOCAL | CREAD ;
newtio.c_iflag = ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ~ICANON;
newtio.c_cc[VMIN] = 14;
tcsetattr(fd,TCSANOW,&newtio);
pthread_create(&t1, NULL, closeFD, NULL);
printf("Reading ..\n");
read(fd,buf,255);
close(fd);
}
return 0;
}
The following code is the same except I place the call to read() in the second thread (in closeFD()) and works as expected. The second thread unblocks and terminates while the main thread waits for it to exit then exits itself.
Example 2:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
static int fd = 0;
unsigned char buf[255];
static pthread_t s;
void sigHandler(int sig){
printf("Signal handler called.\n");
}
void * closeFD(void *arg){
printf("Second thread started.\n");
read(fd,buf,255);
printf("Read interrupted.\n");
}
int main(char *argv[], int argc){
struct termios newtio;
pthread_t t1;
unsigned char buf[255];
void *res;
struct sigaction int_handler = {.sa_handler=sigHandler};
sigaction(SIGUSR1,&int_handler,0);
s = pthread_self();
printf("Process id is: %d.\n", getpid());
fd = open("/dev/ttyS0", O_RDONLY | O_NOCTTY);
if (fd != -1){
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = B2400 | CS7 | CLOCAL | CREAD ;
newtio.c_iflag = ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ~ICANON;
newtio.c_cc[VMIN] = 14;
tcsetattr(fd,TCSANOW,&newtio);
pthread_create(&t1, NULL, closeFD, NULL);
sleep(2);
int r = pthread_kill(t1, SIGUSR1);
pthread_join(t1, &res);
close(fd);
}
return 0;
}
So far I have not been able to find a specific reference stating that terminating the main thread from a second (within the same process) is an illegal operation, so is there something I am doing wrong?
UPDATE #1
Thanks for all those that have replied, however I should make a few points clear:
I am aware that using printf in the signal handler is unsafe however this is an example and it's not the cause of the segmentation fault, though it is a valid point. Taking the printf() out of the signal handler still results in a segmentation fault. Example 2 works with printf() either in or out of the signal handler.
I know sending a SIGUSR will not terminate the program. However by using the pthread_kill(pthread_t thread, int signal) it WILL send a signal to the thread thread and it will unblock (if indeed it is blocked). This is the action I desire, this is what actually happens in Example 2 and this is what I understand should happen in either example, but does not in example 1.
When describing example 1, I used the term 'method' when I meant 'thread', where I mention the call to pthread_kill().
Further, quoting from 'Programming with POSIX Threads', David R. Butenhof, section 6.6.3 p217 'pthread_kill':
Within a process, one thread can send a signal to a specific thread
(including itself) by calling pthread_kill.
With that said, the following example ALSO gives a segmentation fault:
Example 3
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <signal.h>
static pthread_t s;
int value = 0;
void sigHandler(int sig){
value = 1;
}
int main(char *argv[], int argc){
struct sigaction int_handler = {.sa_handler=sigHandler};
sigaction(SIGUSR1,&int_handler,0);
s = pthread_self();
printf("The value of 'value' is %d.\n", value);
printf("Process id is: %d.\n", getpid());
int r = pthread_kill(s, SIGUSR1);
printf("The value of 'value' is %d.\n", value);
return 0;
}
This also fails if instead of a call to sigaction() is replaced by the (non-portable) call to signal(). With the third example in mind, which is very simple, I am not able to find any documentation that expressly states it is an illegal action. In fact the quoted reference indicates it's allowable!
You forgot to #include <pthread.h>. That fixes your segfault for me in example #3 on a recent Linux system.
--- pthread_kill-self.c.orig 2015-01-06 14:08:54.949000690 -0600
+++ pthread_kill-self.c 2015-01-06 14:08:59.820998965 -0600
## -1,6 +1,6 ##
#include <stdio.h>
#include <string.h>
-#include <string.h>
+#include <pthread.h>
#include <signal.h>
and then...
$:- gcc -o pthread_kill-self pthread_kill-self.c -pthread
$:- ./pthread_kill-self
The value of 'value' is 0.
Process id is: 3152.
The value of 'value' is 1.
You're using printf(), which is not async-signal safe, and you're not initializing your struct sigaction properly (in particular, the signal mask is left undefined).
Third, sending a SIGUSR1 signal, with a handler installed, does not and should not terminate the main thread. You're just sending it a signal, that's all.
As Jens Gustedt mentioned in his comment to the original question, both of the programs have undefined behaviour. Therefore, I'm not going to try and guess exactly what part of the undefined behaviour causes the segmentation fault (in the first program).
Instead, I'll show you a working example.
For debugging/testing purposes, I like to start with async-signal safe output functions, based on write(2):
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <termios.h>
#include <pthread.h>
#include <errno.h>
#include <time.h>
#define MYSIGNAL SIGUSR1
#define SECONDS 10
static int wrstr(const int descriptor, const char *p, const char *const q)
{
while (p < q) {
ssize_t n;
n = write(descriptor, p, (size_t)(q - p));
if (n > (ssize_t)0)
p += n;
else
if (n != (ssize_t)-1)
return EIO;
else
if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)
return errno;
}
return 0;
}
static const char *ends(const char *s)
{
if (s)
while (*s != '\0')
s++;
return s;
}
static int wrout(const char *const p)
{
if (p != NULL && *p != '\0') {
int saved_errno, result;
saved_errno = errno;
result = wrstr(STDOUT_FILENO, p, ends(p));
errno = saved_errno;
return result;
} else
return 0;
}
static int wrouti(const int value)
{
char buffer[32];
char *p = buffer + sizeof buffer;
unsigned int u;
if (value < 0)
u = -(long)value;
else
u = value;
do {
*(--p) = '0' + (u % 10U);
u /= 10U;
} while (u > 0U);
if (value < 0)
*(--p) = '-';
return wrstr(STDOUT_FILENO, p, buffer + sizeof buffer);
}
static int wrerr(const char *const p)
{
if (p != NULL && *p != '\0') {
int saved_errno, result;
saved_errno = errno;
result = wrstr(STDERR_FILENO, p, ends(p));
errno = saved_errno;
return result;
} else
return 0;
}
The above functions are async-signal safe, and therefore okay to use in a signal handler. wrout() and wrerr() also retain errno unchanged, which is useful. Saving and restoring errno in a signal handler is usually omitted, by the way, although I do believe there are some odd corner cases it might matter. The wrouti() is just a crude decimal signed integer printer, also async-signal-safe, but it does not retain errno unchanged.
Next, let's define the signal handler itself, and an installer function for it. (I like to do it this way, to make the main() simpler.)
static volatile sig_atomic_t handled = 0;
static void handler(int signum)
{
wrerr("Signal received.\n");
handled = signum;
}
static int install_handler(const int signum)
{
struct sigaction act;
/* memset(&act, 0, sizeof act); */
sigemptyset(&act.sa_mask);
act.sa_handler = handler;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL))
return errno;
return 0;
}
The commented-out memset is recommended, but not required for proper operation. The sigemptyset(), however, is required, to clear the set of blocked signals.
Next, let's look at the thread function. You shouldn't use sleep(), as that interacts with signals; use POSIX.1-2001 nanosleep() instead.
static void *worker(void *target)
{
struct timespec duration, left;
int retval;
wrout("Worker started. Sleeping ");
wrouti((int)SECONDS);
wrout(" seconds...\n");
duration.tv_sec = SECONDS;
duration.tv_nsec = 0;
left.tv_sec = 0;
left.tv_nsec = 0;
while (1) {
retval = nanosleep(&duration, &left);
if (retval == 0)
break;
if (left.tv_sec <= 0 ||
(left.tv_sec == 0 && left.tv_nsec <= 0))
break;
duration = left;
left.tv_sec = 0;
left.tv_nsec = 0;
}
wrout("Sleep complete.\n");
if (target) {
wrout("Sending signal...\n");
retval = pthread_kill(*(pthread_t *)target, MYSIGNAL);
if (retval == 0)
wrout("Signal sent successfully.\n");
else {
const char *const errmsg = strerror(retval);
wrout("Failed to send signal: ");
wrout(errmsg);
wrout(".\n");
}
}
wrout("Thread done.\n");
return NULL;
}
The pointer given to the thread function should point to the thread identifier (pthread_t) the signal is directed to.
Note that above, nanosleep() can be interrupted by a signal delivery, if the signal is delivered to or caught by this particular thread. If that occurs, nanosleep() tells us how much time was left to sleep. The loop above shows how to make sure you sleep at least the specified time, even if interrupted by signal delivery.
Finally, the main(). Instead of opening a specific device, I use standard input. To reproduce OP's program, redirect standard input from /dev/ttyUSB0, i.e. ./program < /dev/ttyUSB0, when executing it.
int main(void)
{
pthread_t main_thread, worker_thread;
pthread_attr_t attrs;
struct termios original, settings;
int result;
if (!isatty(STDIN_FILENO)) {
wrerr("Standard input is not a terminal.\n");
return EXIT_FAILURE;
}
if (tcgetattr(STDIN_FILENO, &original) != 0 ||
tcgetattr(STDIN_FILENO, &settings) != 0) {
const char *const errmsg = strerror(errno);
wrerr("Cannot get terminal settings: ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
settings.c_lflag = ~ICANON;
settings.c_cc[VMIN] = 14;
if (tcsetattr(STDIN_FILENO, TCSANOW, &settings) != 0) {
const char *const errmsg = strerror(errno);
tcsetattr(STDIN_FILENO, TCSAFLUSH, &original);
wrerr("Cannot set terminal settings: ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
wrout("Terminal is now in raw mode.\n");
if (install_handler(MYSIGNAL)) {
const char *const errmsg = strerror(errno);
wrerr("Cannot install signal handler: ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
main_thread = pthread_self();
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, 65536);
result = pthread_create(&worker_thread, &attrs, worker, &main_thread);
if (result != 0) {
const char *const errmsg = strerror(errno);
tcsetattr(STDIN_FILENO, TCSAFLUSH, &original);
wrerr("Cannot create a worker thread: ");
wrerr(errmsg);
wrerr(".\n");
return EXIT_FAILURE;
}
pthread_attr_destroy(&attrs);
wrout("Waiting for input...\n");
while (1) {
char buffer[256];
ssize_t n;
if (handled) {
wrout("Because signal was received, no more input is read.\n");
break;
}
n = read(STDIN_FILENO, buffer, sizeof buffer);
if (n > (ssize_t)0) {
wrout("Read ");
wrouti((int)n);
wrout(" bytes.\n");
continue;
} else
if (n == (ssize_t)0) {
wrout("End of input.\n");
break;
} else
if (n != (ssize_t)-1) {
wrout("read() returned an invalid value.\n");
break;
} else {
result = errno;
wrout("read() == -1, errno == ");
wrouti(result);
wrout(": ");
wrout(strerror(result));
wrout(".\n");
break;
}
}
wrout("Reaping the worker thread..\n");
result = pthread_join(worker_thread, NULL);
if (result != 0) {
wrout("Failed to reap worker thread: ");
wrout(strerror(result));
wrout(".\n");
} else
wrout("Worker thread reaped successfully.\n");
tcsetattr(STDIN_FILENO, TCSAFLUSH, &original);
wrout("Terminal reverted back to original mode.\n");
return EXIT_SUCCESS;
}
Because it's much more fun to test using the terminal, the above tries hard to restore the terminal to its original state before returning.
Note that since the VMIN field in the termios structure is set to 14, the read() blocks until at least 14 bytes are available in the buffer. If a signal is delivered, a short count is returned if there is at least one byte in the buffer. Therefore, you cannot expect the read() to always return 14 bytes, and you cannot expect it to return -1 with errno == EINTR whenever a signal is delivered! Experimenting with this program is very useful, to clarify these in your mind.
I don't remember whether the USB serial drivers in Linux ever produce EPIPE or raise SIGPIPE, but that can definitely occur when using pipes. When using pipes, the most common reason is trying to read after read has already returned zero (end of input). Unless ignored or caught with a signal handler, the process dies much like in a segmentation fault, except that the cause is SIGPIPE signal instead of SIGSEGV. With terminal-like character devices, it depends on the driver, I seem to recall.
Finally, I wrote the above code under the weather (flu), so there might be bugs in tharrr. It should be POSIX.1 C99 code, and gcc -Wall -pedantic does not complain, but having a stuffed head, I'm not making any promises here. Fixes are more than welcome!
Questions? Comments?

Wait only 5 second for user input

I want to write a simple c program in turbo c++ 4.5 editor such that in only wait 5 seconds for user input. As an example,
#include <stdio.h>
void main()
{
int value = 0;
printf("Enter a non-zero number: ");
// wait only 5 seconds for user input
scanf("%d",&value);
if(value != 0) {
printf("User input a number");
} else {
printf("User dont give input");
}
}
So, what will be the code for 5 seconds wait for 'scanf' functionality and otherwise execute if-else part.
Try a select(2) loop: https://www.mirbsd.org/man2/select on stdin (fd#0) with a timeout of 5 seconds; run the scanf(3) only if select returns indicating there is data. (See the c_read() function in the mksh source code for an example.)
Other functions, like poll(2), are also possible. Nonblocking I/O is a bit overkill.
OK, here’s a working (on MirBSD) example using select:
#include <sys/types.h>
#include <sys/time.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int
main(void)
{
int value = 0;
struct timeval tmo;
fd_set readfds;
printf("Enter a non-zero number: ");
fflush(stdout);
/* wait only 5 seconds for user input */
FD_ZERO(&readfds);
FD_SET(0, &readfds);
tmo.tv_sec = 5;
tmo.tv_usec = 0;
switch (select(1, &readfds, NULL, NULL, &tmo)) {
case -1:
err(1, "select");
break;
case 0:
printf("User dont give input");
return (1);
}
scanf("%d", &value);
if (value != 0) {
printf("User input a number");
} else {
printf("User dont give input");
}
return (0);
}
You might want to play with the exit codes a bit and sprinkle a few \n throughout the code. The fflush(stdout); is important so that the prompt is shown in the first place…
#include <stdio.h>
#include <signal.h>
void handler(int signo)
{
return;
}
int main()
{
int x;
struct sigaction sa;
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL);
alarm(5);
if (scanf("%d", &x) == 1)
{
printf("%d\n", x);
alarm(0); // cancel the alarm
}
else
{
printf("timedout\n");
}
return 0;
}
well you can use the halfdelay() function from the curses library

Exit a for loop if not input is entered after some time

So I want a method to controlling the amount of time the input prompt will wait for the user to enter something.
For example in the following code:
#include <stdio.h>
int main(void){
int i, value;
for (i=0;i<10;i++){
scanf(" %d", &value);
}
}
How can I make the program to break the for loop if the user doesn't enter any input after 5 seconds?
You can implement what you want using select (monitor stdin for some time to check if the input is available for reading), fgets (safely read input data to the buffer) and strtol (convert the buffer string to the long integer if possible).
Sample code is given below (check man pages e.g. to extend error handling):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[])
{
fd_set rfds;
struct timeval tv;
int i, val, retval;
char *endptr, buff[255];
for (i=0;i<10;i++){
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
if (retval == -1){
perror("select()");
exit(EXIT_FAILURE);
}
else if (retval){
/* FD_ISSET(0, &rfds) is true so input is available now. */
/* Read data from stdin using fgets. */
fgets(buff, sizeof(buff), stdin);
/* Convert data stored in the buffer to long int. */
errno = 0;
val = strtol(buff, &endptr, 10);
/* First, check for various possible errors. */
if (errno != 0 && val == 0) {
perror("strtol()");
exit(EXIT_FAILURE);
}
if (endptr == buff) {
fprintf(stderr, "No digits were found.\n");
exit(EXIT_FAILURE);
}
/* If we got here, strtol successfully parsed a number. */
printf("%d was read from stdin.\n", val);
}
else{
printf("No data within five seconds.\n");
break;
}
}
exit(EXIT_SUCCESS);
}
Here is a general purpose version of scanf, sync_scanf, witch should wait for seconds you choose or will return -2 as timeout:
int sync_scanf(time_t sec, const char *format, ...);
example:
#include <stdio.h>
#include <stdarg.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int sync_scanf(time_t sec, const char *format, ...);
int main(int argc, char **argv) {
int i;
int value;
int ret;
for (i = 0 ; i < 10 ; i++ ) {
ret = sync_scanf(3, "%d", &value);
if( ret > 0 ) {
printf("OK %d\n", value);
} else if( ret == -2 ) {
printf("3 seconds passed and you typed nothing!\n");
break;
} else {
printf("No enough arguments\n");
break;
}
}
return 0;
}
int sync_scanf(time_t sec, const char *format, ...) {
int re;
va_list arg;
fd_set readfds;
struct timeval timeout = {0};
timeout.tv_sec = sec;
FD_ZERO(&readfds);
FD_SET(0, &readfds);
re = select(1, &readfds, NULL, NULL, &timeout);
if( re == -1 ) {
perror("Error");
return -1;
}
else if( re == 0 ) {
return -2;
}
va_start(arg, format);
re = vfscanf(stdin, format, arg);
va_end(arg);
return re;
}
demo:
$ gcc -Wall sample.c
$ ./a.out
232
OK 232
3 seconds passed and you typed nothing!
$ ./a.out
32
OK 32
fewf
No enough arguments
$
It works as scanf but you pass the timeout first in seconds:
int sync_scanf(time_t sec, const char *format, ...);
It returns:
-1 on failure.
-2 on timeout.
Other than that it returns as scanf would does.
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
int flag;
static sigjmp_buf jmpbuf;
static void sig_arm(int signo)
{
if(flag == -1)
return;
else if(flag == 0)
siglongjmp(jmpbuf,1);
}
int main(void){
int i, value;
signal(SIGALRM,sig_arm);
for (i=0;i<10;i++){
if(sigsetjmp(jmpbuf,0) == 0)
{
flag = 0;
alarm(5);
scanf(" %d", &value);
flag = 1;
}
if(flag == 0) // 5 second out
break;
}
flag = -1;
alarm(0);
}

Resources