12.17.3. Discussion
A file whose name ends in
.ph has been created by the
h2ph tool, which translates C preprocessor
directives from C #include files into Perl. The
goal is to allow Perl code to access the same constants as C code.
h2xs is a better approach in most cases because
it provides compiled C code for your modules, not Perl code
simulating C code. However, using h2xs requires
a lot more programming savvy (at least, for accessing C code) than
h2ph does.
When h2ph's translation process works, it's
wonderful. When it doesn't, you're probably out of luck. As system
architectures and include files become more complex,
h2ph fails more frequently. If you're lucky, the
constants you need are already in the Fcntl, Socket, or POSIX
modules. The POSIX module implements constants from
sys/file.h, sys/errno.h,
and sys/wait.h, among others. It also allows
fancy tty handling, as described in Recipe 15.8.
So what can you do with these .ph files? Here
are a few examples. The first uses the pessimally non-portable
syscall function to access your operating system's
gettimeofday syscall. This implements the FineTime
module described in Recipe 12.12.
# file FineTime.pm
package main;
require "sys/syscall.ph";
die "No SYS_gettimeofday in sys/syscall.ph"
unless defined &SYS_gettimeofday;
package FineTime;
use strict;
require Exporter;
use vars qw(@ISA @EXPORT_OK);
@ISA = qw(Exporter);
@EXPORT_OK = qw(time);
sub time( ) {
my $tv = pack("LL", ( )); # presize buffer to two longs
syscall(&main::SYS_gettimeofday, $tv, undef) >= 0
or die "gettimeofday: $!";
my($seconds, $microseconds) = unpack("LL", $tv);
return $seconds + ($microseconds / 1_000_000);
}
1;
If you are forced to require an old-style
.pl or .ph file, do so from
the main package (package main
in the preceding code). These old libraries always put their symbols
in the current package, and main serves as a reasonable rendezvous
point. To use a symbol, use its fully qualified name, as we did with
main::SYS_gettimeofday.
The
sys/ioctl.ph file, if you can get it to build on
your system, is the gateway to your system's idiosyncratic I/O
functions through the ioctl function. One such
function is the TIOCSTI ioctl, shown in Example 12-1.
That abbreviation stands for "terminal I/O control, simulate terminal
input." On systems that implement this function, it will push one
character into your device stream so that the next time any process
reads from that device, it gets the character you put there.
Example 12-1. jam
#!/usr/bin/perl -w
# jam - stuff characters down STDIN's throat
require "sys/ioctl.ph";
die "no TIOCSTI" unless defined &TIOCSTI;
sub jam {
local $SIG{TTOU} = "IGNORE"; # "Stopped for tty output"
local *TTY; # make local filehandle
open(TTY, "+<", "/dev/tty") or die "no tty: $!";
for (split(//, $_[0])) {
ioctl(TTY, &TIOCSTI, $_) or die "bad TIOCSTI: $!";
}
close(TTY);
}
jam("@ARGV\n");
Since sys/ioctl.h translation is so dodgy,
you'll probably have to run this C program to get your TIOCSTI value:
% cat > tio.c << EOF && cc tio.c && a.out
#include <sys/ioctl.h>
main( ) { printf("%#08x\n", TIOCSTI); }
EOF
0x005412
Another popular use for
ioctl is for figuring out your current window size
in rows and columns, and maybe even in pixels. This is shown in Example 12-2.
Example 12-2. winsz
#!/usr/bin/perl
# winsz - find x and y for chars and pixels
require "sys/ioctl.ph";
die "no TIOCGWINSZ " unless defined &TIOCGWINSZ;
open(TTY, "+<", "/dev/tty") or die "No tty: $!";
unless (ioctl(TTY, &TIOCGWINSZ, $winsize="")) {
die sprintf "$0: ioctl TIOCGWINSZ (%08x: $!)\n", &TIOCGWINSZ;
}
($row, $col, $xpixel, $ypixel) = unpack("S4", $winsize);
print "(row,col) = ($row,$col)";
print " (xpixel,ypixel) = ($xpixel,$ypixel)" if $xpixel || $ypixel;
print "\n";
As you see, as soon as you start playing with
.ph files, unpack ing binary
data, and calling syscall and
ioctl, you need to know about the C APIs that Perl
normally hides. The only other thing that requires this much C
knowledge is using the XS interface. Some suggest you should resist
the temptation to descend into such unportable convolutions. Others
feel that the demands put upon the trenchworkers are such that they
must be forgiven these desperate measures.
Fortunately, less fragile mechanisms are increasingly available. CPAN
modules for most of these functions now exist, which should
theoretically prove more robust than sourcing
.ph files.