Test If Stdin Has Input for C++ (Windows And/Or Linux)

Test if stdin has input for C++ (windows and/or linux)

Here's a solution for POSIX (Linux): I'm not sure what's the equivalent of poll() on Windows. On Unix, The file descriptor with number 0 is the standard input.

#include <stdio.h>
#include <sys/poll.h>

int main(void)
{
struct pollfd fds;
int ret;
fds.fd = 0; /* this is STDIN */
fds.events = POLLIN;
ret = poll(&fds, 1, 0);
if(ret == 1)
printf("Yep\n");
else if(ret == 0)
printf("No\n");
else
printf("Error\n");
return 0;
}

Testing:

$ ./stdin
No
$ echo "foo" | ./stdin
Yep

How to determine if stdin is empty

It sounds like you want to run your program based on arguments either provided on the command line or piped into it from a file. If so, you should check whether the arguments have been provided on the command line first:

if (argc > 1) {
//parse argv
}

Then, check whether stdin is empty, and if not read the arguments in from stdin:

else if ((fseek(stdin, 0, SEEK_END), ftell(stdin)) > 0)
{
rewind(stdin);
char buffer[1024];
fgets(buffer, 1024 , stdin);
//parse args read in from stdin
}
else
{
//no redirection
}

Detect if stdin is a terminal or pipe?

Use isatty:

#include <stdio.h>
#include <io.h>
...
if (isatty(fileno(stdin)))
printf( "stdin is a terminal\n" );
else
printf( "stdin is a file or a pipe\n");

(On windows they're prefixed with underscores: _isatty, _fileno)

Checking the stdin buffer if it's empty

There are several soutions:

poll or select with timeout of 0 - these would return immediately and result is either -1 with errno EAGAIN if no data available or number of descriptors with data (one, since you're checking only stdin).

ioctl is a swiss army knife of using descriptors. The request you need is I_NREAD:

if (ioctl(0, I_NREAD, &n) == 0 && n > 0)
// we have exactly n bytes to read

However the correct solution is to read everything you got (using scanf) as a line, then process the result - and this works good enough with sscanf:

char buf[80]; // large enough
scanf("%79s", buf); // read everything we have in stdin
if (sscanf(buf, "%d", &number) == 1)
// we have a number

... as long as you properly handle re-reading, strings that are longer than your buffer, and other real-life complications.

How can I detect if there is input waiting on stdin on windows?

As stated in the ReadConsoleInput() documentation:

A process can specify a console input buffer handle in one of the wait functions to determine when there is unread console input. When the input buffer is not empty, the state of a console input buffer handle is signaled.

To determine the number of unread input records in a console's input buffer, use the GetNumberOfConsoleInputEvents function. To read input records from a console input buffer without affecting the number of unread records, use the PeekConsoleInput function. To discard all unread records in a console's input buffer, use the FlushConsoleInputBuffer function.

You can use GetStdHandle() to get a handle to STDIN for use in the above functions.

How do I check if stdin has some data?

On Unix systems you can do the following:

import sys
import select

if select.select([sys.stdin, ], [], [], 0.0)[0]:
print("Have data!")
else:
print("No data")

On Windows the select module may only be used with sockets though so you'd need to use an alternative mechanism.

How to check if stdin is still opened without blocking?

select() does exactly what you want: signal that an operation (read, in this case) on a file descriptor (file, socket, whatever) will not block.

#include <stdio.h>
#include <sys/select.h>

int is_ready(int fd) {
fd_set fdset;
struct timeval timeout;
int ret;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
timeout.tv_sec = 0;
timeout.tv_usec = 1;
//int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
return select(fd+1, &fdset, NULL, NULL, &timeout) == 1 ? 1 : 0;
}

You can now check a file descriptor before use, for instance in order to empty the file descriptor:

void empty_fd(int fd) {
char buffer[1024];
while (is_ready(fd)) {
read(fd, buffer, sizeof(buffer));
}
}

In your case, use fileno(stdin) to get the file descriptor of stdin:

if (is_ready(fileno(stdin))) {
/* read stuff from stdin will not block */
}


Related Topics



Leave a reply



Submit