[comp.lang.perl] makelib and beyond

tchrist@convex.COM (Tom Christiansen) (02/15/90)

In article <5319@convex.convex.com> I myself write:
>I once posted the scripts I use to massage (pound?) .h files from makelib
>into .pl files in a posting to perl-users before this newsgroup was 
>created.  It should be in the archives at Ohio State, but if there's
>demand for it, mail me and I'll send you a copy.  If enough people
>ask me I'll repost it.

I've gotten three requests already, so I guess I'll repost.  Note that
there's a bug fix to makelib here that hasn't (to my knowledge) made
it into any of the patches yet you'll need to apply. (patch 9 Larry?)

The .h version will be more safely portable, because if something
isn't defined on the new system, like &TIOCGETP, then you'll get
a fatal run-time error on the system lacking that function.  Using
the .pl version means that the subsequent scripts will give you a 0 
$TIOCGETP and God only knows what may then happen.   Still, I 
like the .pl stuff because they're faster to load.  

I notice that Larry's man page example of the socket stuff uses the .h form,
but the ioctl example uses $TIOCSETP not &TIOCSETP even though it includes 
the .h form, which is a trifle inconsistent.


--tom

[PS: To the patholically pedantic, yes, I've trimmed some verbiage from 
     the original posting.]

Date:         Tue, 07 Nov 89 14:37:57 CST
From:         Tom Christiansen <tchrist>
Subject:      a sojourn into the land of makelib; plus bug reports
To:           uunet!virginia.edu!perl-users

I have been playing with makelib to translate some C include
files into perl ones, and I find that this
	
    makelib sys/ioctl.h

makes a file that has things like in it:

    eval 'sub TIOCM_RTS {0004;}';
    eval 'sub TIOCM_ST {0010;}';
    eval 'sub TIOCM_SR {0020;}';
    eval 'sub TIOCM_CTS {0040;}';
    eval 'sub TIOCM_CAR {0100;}';

rather than what Larry's ioctl.pl from the perl source dir has, 
which is:

    $TIOCM_RTS = 0004;
    $TIOCM_ST = 0010;
    $TIOCM_SR = 0020;
    $TIOCM_CTS = 0040;
    $TIOCM_CAR = 0100;

I've been sitting here trying to trying to find out how to 
convert these into what Larry had, since he seems to have
done so automagically, so I wrote a script to basically 
eval all the defined simple subroutines.  It worked on the
simple ones, including all of simple files like <sysexits.h>
and <sys/errno.h> but not on these:

    eval 'sub TIOCGSIZE {&TIOCGWINSZ;}';
    eval 'sub TIOCGWINSZ {&_IOR("t", 104, \'struct winsize\');}';
    eval 'sub TIOCSETD {&_IOW("t", 1, \'int\');}';
    eval 'sub TIOCGETP {&_IOR("t", 8,\'struct sgttyb\');}';

The _IO[RW] routines use a %sizeof array, which (presumably) 
is keyed on the type name with the value being the size in 
bytes.  Well, the long and the short of it is that I finally
got something to automatically convert stuff like ioctl.h
into Larry's ioctl.pl, and I'll include that at the end of this
note, but in doing so I came up with several "irregularities"
that may well be bugs.  

First of all, the makelib program can generate things like this
	$X & $Y
    or sans spaces:
	$X&$Y
but if $Y were a subroutine, you'd have
	$X & &Y
    or sans spaces:
	$X&&Y

which is pretty clearly wrong, as perl will see this as 
	($X)&&(Y)
and give you a syntax error.  

To fix this, you have to change line #157 of makelib from 
	    $new .= '&' . $id;
to 
	    $new .= "(&$id)";

and this gets better.   

I discovered this while using the perl debugger.   I had a simple
program:
    #!/usr/bin/perl -d
    do 'sys/ioctl.h';
    printf "TIOCGSIZE = %x\n", &TIOCGSIZE;
That under the debugger caused the aforementioned syntax error.
Nonetheless, it would not let me say 'l TIOCGSIZE' to see what
was afoot.  I tried 

    #!/usr/bin/perl -Pd
    #include "/usr/local/lib/perl/sys/ioctl.h"
    printf "TIOCGSIZE = %x\n", &TIOCGSIZE;

but I found it got really confused about line numbers then, and 
even when I set break-points past the included stuff, and it had
eval'd the TIOCGSIZE function, it still wouldn't show it to me.  
I would call these "irregularities" more than bugs, if for no
other reason that they'd be VERY hard to fix.  Oh well.

Here are the scripts I've used to convert what makelib 
generates.  The basic one is 'mkvars'.  I ran it this
way:
	mkvars sys/ioctl.h > ioctl2.pl
	mkvars sys/errno.h > errno.pl
	mkvars sysexits.h  > sysexits.pl



===================== mkvars ===========================================
#!/usr/bin/perl
$sizes = 'sizeof.h';
do $sizes || die "couldn't do $sizes";
$LIB = '/usr/local/lib/perl';

foreach $include (@ARGV) {
    printf stderr "including %s\n", $include;
    do $include;
    warn "sourcing $inlcude: $@\n" if ($@);
    if (!open (include,"$LIB/$include")) {
	warn "can't open $LIB/$include: $!\n"; 
	next; 
    } 
    while (<include>) {
	chop;
	if (/^\s*eval\s+'sub\s+(\w+)\s.*[^{]$/ || /^\s*sub\s+(\w+)\s.*[^{]$/) {
	    $var = $1;
	    $val = eval "&$var;";
	    if ($@) { warn "$@: $_"; next; } 
	    ( $nval = sprintf ("%x",$val ) ) =~ tr/a-z/A-Z/;
	    printf "\$%s = 0x%s;\n", $var, $nval; # %X hates me in perl3
	} 
    }
} 
===========================================================================


Ah, you say, what is this "sizeof.h" thing?   Yes, that's the gotcha.  
You need to figure out the sizes.  Here's a script, mksizes, that is
fed a list of types one per line like this:

================= sizes ===================================================
char
int
long
struct arpreq
struct ifconf
struct ifreq
struct ltchars
struct pcntl
struct rtentry
struct sgttyb
struct tchars
struct ttychars
struct winsize
===========================================================================

and fed into mksizes, produces output like this to stick in sizeof.h:

================ output from "mksizes < sizes" ============================
$sizeof{'char'} = 1;
$sizeof{'int'} = 4;
$sizeof{'long'} = 4;
$sizeof{'struct arpreq'} = 36;
$sizeof{'struct ifconf'} = 8;
$sizeof{'struct ifreq'} = 32;
$sizeof{'struct ltchars'} = 6;
$sizeof{'struct pcntl'} = 116;
$sizeof{'struct rtentry'} = 52;
$sizeof{'struct sgttyb'} = 6;
$sizeof{'struct tchars'} = 6;
$sizeof{'struct ttychars'} = 14;
$sizeof{'struct winsize'} = 8;
===========================================================================

I pulled out this set of vars with this script:

============== getioctlsizes ==============================================
#!/usr/bin/perl
open (ioctls,'/usr/include/sys/ioctl.h') || die "ioctl open failed";
while (<ioctls>) {
    if (/^\s*#\s*define\s+\w+\s+_IO(R|W|WR)\(\w+,\s*\w+,\s*([^)]+)/) {
	$need{$2}++;
    } 
}
foreach $key ( sort keys %need ) {
    print $key,"\n";
} 
===========================================================================

and here at long last is mksizes.  You'll probably have to hack the set
of include files for non-BSD hosts.    Maybe lwall could talk 
config into doing this for us; it would sem an appropriate use
for it.


================ mksizes ==================================================
#!/usr/bin/perl

($iam = $0) =~ s%.*/%%;
$tmp = "$iam.$$";
open (code,">$tmp.c") || die "$iam: cannot create $tmp.c: $!\n";
$mask = 'printf ("$sizeof{\'%s\'} = %d;\n"'; 

# write C program
select(code);
print <<EO_C_PROGRAM
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <net/route.h>
#include <sys/ioctl.h>

main() {
EO_C_PROGRAM
;

while ( <> ) {
    chop;
    printf "\t%s, \n\t\t\"%s\", sizeof(%s));\n", $mask, $_,$_;
}

print "\n}\n";
close code;

# compile C program
select(stdout);
system "cc $tmp.c -o $tmp";
die "couldn't compile $tmp.c" if $?;
system "./$tmp"; 	   
die "couldn't run $tmp" if $?;
unlink "$tmp.c", $tmp;
===========================================================================

If this stuff is portable enough I think it or its functional
equivalent should really be someday included in the perl distribution.
On the other had, I can't really blame him for not doing so.  They're
more than somewhat convoluted.  I still haven't figured out how Larry
got some to come out in octal and others in hex, but besides that
it seems to work.

The one overwhelming thing I learned from reading the makelib and
perldb code is that while this should come as no surprise, Larry
Wall knows a googolplex more about perl than I may ever come to 
understand in this life.

--tom

--

    Tom Christiansen                       {uunet,uiucdcs,sun}!convex!tchrist 
    Convex Computer Corporation                            tchrist@convex.COM
		 "EMACS belongs in <sys/errno.h>: Editor too big!"