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!"