Determining the Number of Unread Bytes (Perl Cookbook, 2nd Edition)

## 7.21. Determining the Number of Unread Bytes

### 7.21.1. Problem

You want to know how many unread bytes are available for reading from a filehandle.

### 7.21.2. Solution

Use the `FIONREAD` ioctl call:

>     $size = pack("L", 0);
>     ioctl(FH, $FIONREAD, $size)     or die "Couldn't call ioctl: $!\n";
>     $size = unpack("L", $size);

>     # $size bytes can be read

Make sure the input filehandle is unbuffered (because you've used an I/O layer like `:unix` on it), or use only `sysread`.

### 7.21.3. Discussion

The Perl `ioctl` function is a direct interface to the operating system's ioctl(2) system call. If your system doesn't have the `FIONREAD` request or the ioctl(2) call, you can't use this recipe. `FIONREAD` and the other ioctl(2) requests are numeric values normally found lurking in C include files.

Perl's h2ph tool tries to convert C include files to Perl code, which can be `require` d. `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 manually grep the include files:

>     % grep FIONREAD /usr/include/*/*
>     /usr/include/asm/ioctls.h:#define FIONREAD      0x541B

If you install Inline::C from CPAN, you can write a C subroutine to obtain the constant for you:

>     use Inline C;

>     $FIONREAD = get_FIONREAD( );
>     # ...

>     _ _END_ _
>     _ _C_ _
>     #include <sys/ioctl.h>

>     int get_FIONREAD( ) {
>       return FIONREAD;
>     }

If all else fails, 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

Then hardcode 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, which means sockets, pipes, and tty devices all work, but regular files don't.

If this is too much system programming for you, try to think outside the problem. Read from the filehandle in non-blocking mode (see Recipe 7.20). Then, if you manage to read something, that's how much was there waiting to be read. If you couldn't read anything, you know there was nothing to be read. This might get you in trouble with other users (or other processes) who are using the same system, though— because it uses busy-wait I/O, it's a drain on system resources.

### 7.21.4. See Also

Recipe 7.20; your system's ioctl(2) manpage; the `ioctl` function in perlfunc(1) and in Chapter 29 of Programming Perl; the documentation for the Inline::C module from CPAN

Copyright © 2003 O'Reilly & Associates. All rights reserved.