I want to fulfill the following things in a console application:
But the problem is the program will trap at the line of scanf() function forever to wait for an input character,
Remove the semicolon after while
.
Try using the select() function. Then you can wait for 10 seconds until you can read from stdin without blocking. If select() returns with zero, perform the default action.
I don't know if this works on windows, it's POSIX standard. If you happen to develop on unix/linux, try man select
I just wrote a working example using select:
#include <stdlib.h>
#include <stdio.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define MAXBYTES 80
int main(int argc, char *argv[])
{
fd_set readfds;
int num_readable;
struct timeval tv;
int num_bytes;
char buf[MAXBYTES];
int fd_stdin;
fd_stdin = fileno(stdin);
while(1) {
FD_ZERO(&readfds);
FD_SET(fileno(stdin), &readfds);
tv.tv_sec = 10;
tv.tv_usec = 0;
printf("Enter command: ");
fflush(stdout);
num_readable = select(fd_stdin + 1, &readfds, NULL, NULL, &tv);
if (num_readable == -1) {
fprintf(stderr, "\nError in select : %s\n", strerror(errno));
exit(1);
}
if (num_readable == 0) {
printf("\nPerforming default action after 10 seconds\n");
break; /* since I don't want to test forever */
} else {
num_bytes = read(fd_stdin, buf, MAXBYTES);
if (num_bytes < 0) {
fprintf(stderr, "\nError on read : %s\n", strerror(errno));
exit(1);
}
/* process command, maybe by sscanf */
printf("\nRead %d bytes\n", num_bytes);
break; /* to terminate loop, since I don't process anything */
}
}
return 0;
}
Note: the poll() example below is OK too, no problem. For the rest I chose to read the available bytes into a buffer (up to MAXBYTES). It can be (s)scanned afterwards. (scanf() just isn't too much my friend, but that's a personal taste matter).
As others have said, the best way to do truly async IO is with select(...)
.
But a quick and dirty way to do what you want is with getline(...)
which will return the number of bytes read every time (not hanging on IO) and returns -1 on no bytes read.
The following is from the getline(3) man page:
// The following code fragment reads lines from a file and writes them to standard output.
// The fwrite() function is used in case the line contains embedded NUL characters.
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, fp)) > 0)
fwrite(line, linelen, 1, stdout);
Try alarm(3)
#include <stdio.h>
#include <unistd.h>
int main(void)
{
char buf [10];
alarm(3);
scanf("%s", buf);
return 0;
}
Here is a working example of how to do this with poll
(probably the most 'correct' way on Linux):
#include <unistd.h>
#include <poll.h>
#include <stdio.h>
int main()
{
struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI };
char string[10];
if( poll(&mypoll, 1, 2000) )
{
scanf("%9s", string);
printf("Read string - %s\n", string);
}
else
{
puts("Read nothing");
}
return 0;
}
The timeout is the third argument to poll
and is in milliseconds - this example will wait for 2 seconds for input on stdin. Windows has WSAPoll
, which should work similarly.