There are many ways to check if standard input has input available. The most portable ones are, in that order: select, fcntl and poll.
Here are some snippets on how to do it, case by case.
#include <stdio.h> /* Same old */
#include <stdlib.h> /* Same old */
#include <time.h> /* struct timeval for select() */
#include <unistd.h> /* select() */
#include <poll.h> /* poll() */
#include <sys/ioctl.h> /* FIONREAD ioctl() */
#include <termios.h> /* tcgetattr() and tcsetattr() */
#include <fcntl.h> /* fnctl() */
#define BUFF 256
int chkin_select(void);
int chkin_poll(void);
int chkin_ioctl(void);
int chkin_fcntl(void);
int chkin_termios(void);
/*
Simple loops to test various options of
nonblocking test for standard input
*/
int main(void)
{
char sin[BUFF] = "r";
printf("\nType 'q' to advance\nTesting select()\n");
while(sin[0]++ != 'q')
{
while(!chkin_select())
{
printf("nothing to read on select()\n");
sleep(2);
}
fgets(sin, BUFF, stdin);
printf("\nInput select(): %s\n", sin);
}
printf("\nType 'q' to advance\nTesting poll()\n");
while(sin[0]++ != 'q')
{
while(!chkin_poll())
{
printf("nothing to read poll()\n");
sleep(2);
}
fgets(sin, BUFF, stdin);
printf("\nInput poll(): %s\n", sin);
}
printf("\nType 'q' to advance\nTesting ioctl()\n");
while(sin[0]++ != 'q')
{
while(!chkin_ioctl())
{
printf("nothing to read ioctl()\n");
sleep(2);
}
fgets(sin, BUFF, stdin);
printf("\nInput ioctl(): %s\n", sin);
}
printf("\nType 'q' to advance\nTesting fcntl()\n");
while(sin[0]++ != 'q')
{
while(!chkin_fcntl())
{
printf("nothing to read fcntl()\n");
sleep(2);
}
fgets(sin, BUFF, stdin);
printf("\nInput fcntl: %s\n", sin);
}
printf("\nType 'q' to advance\nTesting termios()\n");
while(sin[0]++ != 'q')
{
while(!chkin_termios())
{
printf("nothing to read termios()\n");
sleep(2);
}
fgets(sin, BUFF, stdin);
printf("\nInput termios: %s\n", sin);
}
return EXIT_SUCCESS;
}
/*
select() and pselect() allow a program to monitor
multiple file descriptors, waiting until one or
more of the file descriptors become "ready" for
some class of I/O operation (e.g., input possible).
A file descriptor is considered ready if it is
possible to perform a corresponding I/O operation
(e.g., read(2) without blocking, or a
sufficiently small write(2)).
*/
int chkin_select(void)
{
fd_set rd;
struct timeval tv = {0};
int ret;
FD_ZERO(&rd);
FD_SET(STDIN_FILENO, &rd);
ret = select(1, &rd, NULL, NULL, &tv);
return (ret>0);
}
/* poll() performs a similar task to select(2): it
waits for one of a set of file descriptors to
become ready to perform I/O.
The set of file descriptors to be monitored
is specified in the fds argument, which is
an array of structures of the following form:
struct pollfd {
int fd; // File descriptor //
short events; // Requested events //
short revents; // Returned events //
};
The caller should specify the number of
items in the fds array in nfds.
*/
int chkin_poll(void)
{
int ret;
struct pollfd pfd[1] = {0};
pfd[0].fd = STDIN_FILENO;
pfd[0].events = POLLIN;
ret = poll(pfd, 1, 0);
return (ret>0);
}
/*
The ioctl(2) call for terminals and serial ports
accepts many possible command arguments. Most
require a third argument, of varying type,
here called argp or arg.
Use of ioctl makes for nonportable
programs. Use the POSIX interface
described in termios(3) whenever
possible.
*/
int chkin_ioctl(void)
{
int n;
ioctl(STDIN_FILENO, FIONREAD, &n);
return (n>0);
}
/*
fcntl() performs one of the operations described
below on the open file descriptor fd. The
operation is determined by cmd.
fcntl() can take an optional third argument.
Whether or not this argument is required is
determined by cmd. The required argument
type is indicated in parentheses after each
cmd name (in most cases, the required type
is int, and we identify the argument using
the name arg), or void is specified if the
argument is not required.
Certain of the operations below are supported
only since a particular Linux kernel version.
The preferred method of checking whether the
host kernel supports a particular operation
is to invoke fcntl() with the desired cmd
value and then test whether the call
failed with EINVAL, indicating that
the kernel does not recognize this
value.
*/
int chkin_fcntl(void)
{
int flag, ch;
flag = fcntl(STDIN_FILENO, F_GETFL, 0); /* Save old flags */
fcntl(STDIN_FILENO, F_SETFL, flag|O_NONBLOCK); /* Set non-block */
ch = ungetc(getc(stdin), stdin);
fcntl(STDIN_FILENO, F_SETFL, flag); /* Return old state */
return (ch != EOF);
}
/*
The termios functions describe a general terminal
interface that is provided to control
asynchronous communications ports.
This function doesn't wait for '\n' to return!
*/
int chkin_termios(void)
{
struct termios old, new;
int ch;
tcgetattr(STDIN_FILENO, &old); /* Save settings */
new = old;
new.c_lflag &= ~ICANON; /* Non-canonical mode: inputs
by char, not lines */
new.c_cc[VMIN] = 0; /* Wait for no bytes at all */
new.c_cc[VTIME] = 0; /* timeout */
tcsetattr(STDIN_FILENO, TCSANOW, &new); /* New settings */
ch = ungetc(getc(stdin), stdin); /* Check by reading and
puking it back */
tcsetattr(STDIN_FILENO, TCSANOW, &old); /* Restore old settings */
return (ch != EOF);
}
Try to avoid ioctl and termios; they are too specific, or too low-level. Also, you can't really use feof in a meaningful way with stdin or any FIFO for that matter. You can guarantee the pointer position, and if you try ftell or fseek you will get an error (ask perror).
References (Linux manual pages):
stdinis empty. Read a character, check the status of the operation. If status is not "OK" assumestdinis empty ...if ((c = getchar()) == EOF) /*assume stdin empty; in reality could be some other reason*/;