How can I tell whether there's a character waiting on a filehandle?

The very first thing you should do is look into getting the Term::ReadKey extension from CPAN. As we mentioned earlier, it now even has limited support for non-portable (read: not open systems, closed, proprietary, not POSIX, not Unix, etc) systems.

You should also check out the Frequently Asked Questions list in comp.unix.* for things like this: the answer is essentially the same. It's very system dependent. Here's one solution that works on BSD systems:

    sub key_ready {
	my($rin, $nfd);
	vec($rin, fileno(STDIN), 1) = 1;
	return $nfd = select($rin,undef,undef,0);
    }
If you want to find out how many characters are waiting, there's also the FIONREAD ioctl call to be looked at. The h2ph tool that comes with Perl tries to convert C include files to Perl code, which can be required. FIONREAD ends up defined as a function in the sys/ioctl.ph file:

    require 'sys/ioctl.ph';
    $size = pack("L", 0);
    ioctl(FH, FIONREAD(), $size)    or die "Couldn't call ioctl: $!\n";
    $size = unpack("L", $size);
If h2ph wasn't installed or doesn't work for you, you can grep the include files by hand:

    % grep FIONREAD /usr/include/*/*
    /usr/include/asm/ioctls.h:#define FIONREAD      0x541B
Or write a small C program using the editor of champions:

    % cat > fionread.c
    #include <sys/ioctl.h>
    main() {
        printf("%#08x\n", FIONREAD);
    }
    ^D
    % cc -o fionread fionread.c
    % ./fionread
    0x4004667f
And then hard code it, leaving porting as an exercise to your successor.

    $FIONREAD = 0x4004667f;         # XXX: opsys dependent
    $size = pack("L", 0);
    ioctl(FH, $FIONREAD, $size)     or die "Couldn't call ioctl: $!\n";
    $size = unpack("L", $size);
FIONREAD requires a filehandle connected to a stream, meaning that sockets, pipes, and tty devices work, but not files.
Back to perlfaq5