home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-13 | 49.3 KB | 1,735 lines |
- Newsgroups: comp.sources.misc
- From: lwall@netlabs.com (Larry Wall)
- Subject: v25i061: perl - The perl programming language, Patch12
- Message-ID: <1991Nov13.214221.3565@sparky.imd.sterling.com>
- X-Md4-Signature: f2b6a10dc4714b35af7826f02964e4ac
- Date: Wed, 13 Nov 1991 21:42:21 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: lwall@netlabs.com (Larry Wall)
- Posting-number: Volume 25, Issue 61
- Archive-name: perl/patch12
- Environment: UNIX, MS-DOS, OS2
- Patch-To: perl: Volume 18, Issue 19-54
-
- System: perl version 4.0
- Patch #: 12
- Priority: MED-HIGH
- Subject: patch #11, continued
-
- Description:
- See patch #11.
-
- Fix: From rn, say "| patch -p -N -d DIR", where DIR is your perl source
- directory. Outside of rn, say "cd DIR; patch -p -N <thisarticle".
- If you don't have the patch program, apply the following by hand,
- or get patch (version 2.0, latest patchlevel).
-
- After patching:
- *** DO NOTHING--INSTALL ALL PATCHES UP THROUGH #18 FIRST ***
-
- If patch indicates that patchlevel is the wrong version, you may need
- to apply one or more previous patches, or the patch may already
- have been applied. See the patchlevel.h file to find out what has or
- has not been applied. In any event, don't continue with the patch.
-
- If you are missing previous patches they can be obtained from me:
-
- Larry Wall
- lwall@netlabs.com
-
- If you send a mail message of the following form it will greatly speed
- processing:
-
- Subject: Command
- @SH mailpatch PATH perl 4.0 LIST
- ^ note the c
-
- where PATH is a return path FROM ME TO YOU either in Internet notation,
- or in bang notation from some well-known host, and LIST is the number
- of one or more patches you need, separated by spaces, commas, and/or
- hyphens. Saying 35- says everything from 35 to the end.
-
-
- Index: patchlevel.h
- Prereq: 11
- 1c1
- < #define PATCHLEVEL 11
- ---
- > #define PATCHLEVEL 12
-
- Index: c2ph.SH
- *** c2ph.SH.old Tue Nov 5 19:25:34 1991
- --- c2ph.SH Tue Nov 5 19:25:34 1991
- ***************
- *** 0 ****
- --- 1,1101 ----
- + case $CONFIG in
- + '')
- + if test ! -f config.sh; then
- + ln ../config.sh . || \
- + ln ../../config.sh . || \
- + ln ../../../config.sh . || \
- + (echo "Can't find config.sh."; exit 1)
- + fi
- + . config.sh
- + ;;
- + esac
- + : This forces SH files to create target in same directory as SH file.
- + : This is so that make depend always knows where to find SH derivatives.
- + case "$0" in
- + */*) cd `expr X$0 : 'X\(.*\)/'` ;;
- + esac
- + echo "Extracting c2ph (with variable substitutions)"
- + : This section of the file will have variable substitutions done on it.
- + : Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!.
- + : Protect any dollar signs and backticks that you do not want interpreted
- + : by putting a backslash in front. You may delete these comments.
- + $spitshell >c2ph <<!GROK!THIS!
- + #!$bin/perl
- + #
- + !GROK!THIS!
- +
- + : In the following dollars and backticks do not need the extra backslash.
- + $spitshell >>c2ph <<'!NO!SUBS!'
- + #
- + # c2ph (aka pstruct)
- + # Tom Christiansen, <tchrist@convex.com>
- + #
- + # As pstruct, dump C structures as generated from 'cc -g -S' stabs.
- + # As c2ph, do this PLUS generate perl code for getting at the structures.
- + #
- + # See the usage message for more. If this isn't enough, read the code.
- + #
- +
- + $RCSID = '$RCSfile: c2ph.SH,v $$Revision: 4.0.1.1 $$Date: 91/11/05 16:02:29 $';
- +
- +
- + ######################################################################
- +
- + # some handy data definitions. many of these can be reset later.
- +
- + $bitorder = 'b'; # ascending; set to B for descending bit fields
- +
- + %intrinsics =
- + %template = (
- + 'char', 'c',
- + 'unsigned char', 'C',
- + 'short', 's',
- + 'short int', 's',
- + 'unsigned short', 'S',
- + 'unsigned short int', 'S',
- + 'short unsigned int', 'S',
- + 'int', 'i',
- + 'unsigned int', 'I',
- + 'long', 'l',
- + 'long int', 'l',
- + 'unsigned long', 'L',
- + 'unsigned long', 'L',
- + 'long unsigned int', 'L',
- + 'unsigned long int', 'L',
- + 'long long', 'q',
- + 'long long int', 'q',
- + 'unsigned long long', 'Q',
- + 'unsigned long long int', 'Q',
- + 'float', 'f',
- + 'double', 'd',
- + 'pointer', 'p',
- + 'null', 'x',
- + 'neganull', 'X',
- + 'bit', $bitorder,
- + );
- +
- + &buildscrunchlist;
- + delete $intrinsics{'neganull'};
- + delete $intrinsics{'bit'};
- + delete $intrinsics{'null'};
- +
- + # use -s to recompute sizes
- + %sizeof = (
- + 'char', '1',
- + 'unsigned char', '1',
- + 'short', '2',
- + 'short int', '2',
- + 'unsigned short', '2',
- + 'unsigned short int', '2',
- + 'short unsigned int', '2',
- + 'int', '4',
- + 'unsigned int', '4',
- + 'long', '4',
- + 'long int', '4',
- + 'unsigned long', '4',
- + 'unsigned long int', '4',
- + 'long unsigned int', '4',
- + 'long long', '8',
- + 'long long int', '8',
- + 'unsigned long long', '8',
- + 'unsigned long long int', '8',
- + 'float', '4',
- + 'double', '8',
- + 'pointer', '4',
- + );
- +
- + ($type_width, $member_width, $offset_width, $size_width) = (20, 20, 6, 5);
- +
- + ($offset_fmt, $size_fmt) = ('d', 'd');
- +
- + $indent = 2;
- +
- + $CC = 'cc';
- + $CFLAGS = '-g -S';
- + $DEFINES = '';
- +
- + $perl++ if $0 =~ m#/?c2ph$#;
- +
- + require 'getopts.pl';
- +
- + eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
- +
- + &Getopts('aixdpvtnws:') || &usage(0);
- +
- + $opt_d && $debug++;
- + $opt_t && $trace++;
- + $opt_p && $perl++;
- + $opt_v && $verbose++;
- + $opt_n && ($perl = 0);
- +
- + if ($opt_w) {
- + ($type_width, $member_width, $offset_width) = (45, 35, 8);
- + }
- + if ($opt_x) {
- + ($offset_fmt, $offset_width, $size_fmt, $size_width) = ( 'x', '08', 'x', 04 );
- + }
- +
- + eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_]+=)(.*)/ && shift;
- +
- + sub PLUMBER {
- + select(STDERR);
- + print "oops, apperent pager foulup\n";
- + $isatty++;
- + &usage(1);
- + }
- +
- + sub usage {
- + local($oops) = @_;
- + unless (-t STDOUT) {
- + select(STDERR);
- + } elsif (!$oops) {
- + $isatty++;
- + $| = 1;
- + print "hit <RETURN> for further explanation: ";
- + <STDIN>;
- + open (PIPE, "|". ($ENV{PAGER} || 'more'));
- + $SIG{PIPE} = PLUMBER;
- + select(PIPE);
- + }
- +
- + print "usage: $0 [-dpnP] [var=val] [files ...]\n";
- +
- + exit unless $isatty;
- +
- + print <<EOF;
- +
- + Options:
- +
- + -w wide; short for: type_width=45 member_width=35 offset_width=8
- + -x hex; short for: offset_fmt=x offset_width=08 size_fmt=x size_width=04
- +
- + -n do not generate perl code (default when invoked as pstruct)
- + -p generate perl code (default when invoked as c2ph)
- + -v generate perl code, with C decls as comments
- +
- + -i do NOT recompute sizes for intrinsic datatypes
- + -a dump information on intrinsics also
- +
- + -t trace execution
- + -d spew reams of debugging output
- +
- + -slist give comma-separated list a structures to dump
- +
- +
- + Var Name Default Value Meaning
- +
- + EOF
- +
- + &defvar('CC', 'which_compiler to call');
- + &defvar('CFLAGS', 'how to generate *.s files with stabs');
- + &defvar('DEFINES','any extra cflags or cpp defines, like -I, -D, -U');
- +
- + print "\n";
- +
- + &defvar('type_width', 'width of type field (column 1)');
- + &defvar('member_width', 'width of member field (column 2)');
- + &defvar('offset_width', 'width of offset field (column 3)');
- + &defvar('size_width', 'width of size field (column 4)');
- +
- + print "\n";
- +
- + &defvar('offset_fmt', 'sprintf format type for offset');
- + &defvar('size_fmt', 'sprintf format type for size');
- +
- + print "\n";
- +
- + &defvar('indent', 'how far to indent each nesting level');
- +
- + print <<'EOF';
- +
- + If any *.[ch] files are given, these will be catted together into
- + a temporary *.c file and sent through:
- + $CC $CFLAGS $DEFINES
- + and the resulting *.s groped for stab information. If no files are
- + supplied, then stdin is read directly with the assumption that it
- + contains stab information. All other liens will be ignored. At
- + most one *.s file should be supplied.
- +
- + EOF
- + close PIPE;
- + exit 1;
- + }
- +
- + sub defvar {
- + local($var, $msg) = @_;
- + printf "%-16s%-15s %s\n", $var, eval "\$$var", $msg;
- + }
- +
- + $recurse = 1;
- +
- + if (@ARGV) {
- + if (grep(!/\.[csh]$/,@ARGV)) {
- + warn "Only *.[csh] files expected!\n";
- + &usage;
- + }
- + elsif (grep(/\.s$/,@ARGV)) {
- + if (@ARGV > 1) {
- + warn "Only one *.s file allowed!\n";
- + &usage;
- + }
- + }
- + elsif (@ARGV == 1 && $ARGV[0] =~ /\.c$/) {
- + local($dir, $file) = $ARGV[0] =~ m#(.*/)?(.*)$#;
- + $chdir = "cd $dir; " if $dir;
- + &system("$chdir$CC $CFLAGS $DEFINES $file") && exit 1;
- + $ARGV[0] =~ s/\.c$/.s/;
- + }
- + else {
- + $TMP = "/tmp/c2ph.$$.c";
- + &system("cat @ARGV > $TMP") && exit 1;
- + &system("cd /tmp; $CC $CFLAGS $DEFINES $TMP") && exit 1;
- + unlink $TMP;
- + $TMP =~ s/\.c$/.s/;
- + @ARGV = ($TMP);
- + }
- + }
- +
- + if ($opt_s) {
- + for (split(/[\s,]+/, $opt_s)) {
- + $interested{$_}++;
- + }
- + }
- +
- +
- + $| = 1 if $debug;
- +
- + main: {
- +
- + if ($trace) {
- + if (-t && !@ARGV) {
- + print STDERR "reading from your keyboard: ";
- + } else {
- + print STDERR "reading from " . (@ARGV ? "@ARGV" : "<STDIN>").": ";
- + }
- + }
- +
- + STAB: while (<>) {
- + if ($trace && !($. % 10)) {
- + $lineno = $..'';
- + print STDERR $lineno, "\b" x length($lineno);
- + }
- + next unless /^\s*\.stabs\s+/;
- + $line = $_;
- + s/^\s*\.stabs\s+//;
- + &stab;
- + }
- + print STDERR "$.\n" if $trace;
- + unlink $TMP if $TMP;
- +
- + &compute_intrinsics if $perl && !$opt_i;
- +
- + print STDERR "resolving types\n" if $trace;
- +
- + &resolve_types;
- + &adjust_start_addrs;
- +
- + $sum = 2 + $type_width + $member_width;
- + $pmask1 = "%-${type_width}s %-${member_width}s";
- + $pmask2 = "%-${sum}s %${offset_width}${offset_fmt}%s %${size_width}${size_fmt}%s";
- +
- + if ($perl) {
- + # resolve template -- should be in stab define order, but even this isn't enough.
- + print STDERR "\nbuilding type templates: " if $trace;
- + for $i (reverse 0..$#type) {
- + next unless defined($name = $type[$i]);
- + next unless defined $struct{$name};
- + $build_recursed = 0;
- + &build_template($name) unless defined $template{&psou($name)} ||
- + $opt_s && !$interested{$name};
- + }
- + print STDERR "\n\n" if $trace;
- + }
- +
- + print STDERR "dumping structs: " if $trace;
- +
- +
- + foreach $name (sort keys %struct) {
- + next if $opt_s && !$interested{$name};
- + print STDERR "$name " if $trace;
- +
- + undef @sizeof;
- + undef @typedef;
- + undef @offsetof;
- + undef @indices;
- + undef @typeof;
- +
- + $mname = &munge($name);
- +
- + $fname = &psou($name);
- +
- + print "# " if $perl && $verbose;
- + $pcode = '';
- + print "$fname {\n" if !$perl || $verbose;
- + $template{$fname} = &scrunch($template{$fname}) if $perl;
- + &pstruct($name,$name,0);
- + print "# " if $perl && $verbose;
- + print "}\n" if !$perl || $verbose;
- + print "\n" if $perl && $verbose;
- +
- + if ($perl) {
- + print "$pcode";
- +
- + printf("\nsub %-32s { %4d; }\n\n", "${mname}'struct", $countof{$name});
- +
- + print <<EOF;
- + sub ${mname}'typedef {
- + local(\$${mname}'index) = shift;
- + defined \$${mname}'index
- + ? \$${mname}'typedef[\$${mname}'index]
- + : \$${mname}'typedef;
- + }
- + EOF
- +
- + print <<EOF;
- + sub ${mname}'sizeof {
- + local(\$${mname}'index) = shift;
- + defined \$${mname}'index
- + ? \$${mname}'sizeof[\$${mname}'index]
- + : \$${mname}'sizeof;
- + }
- + EOF
- +
- + print <<EOF;
- + sub ${mname}'offsetof {
- + local(\$${mname}'index) = shift;
- + defined \$${mname}index
- + ? \$${mname}'offsetof[\$${mname}'index]
- + : \$${mname}'sizeof;
- + }
- + EOF
- +
- + print <<EOF;
- + sub ${mname}'typeof {
- + local(\$${mname}'index) = shift;
- + defined \$${mname}index
- + ? \$${mname}'typeof[\$${mname}'index]
- + : '$name';
- + }
- + EOF
- +
- +
- + print "\$${mname}'typedef = '" . &scrunch($template{$fname})
- + . "';\n";
- +
- + print "\$${mname}'sizeof = $sizeof{$name};\n\n";
- +
- +
- + print "\@${mname}'indices = (", &squishseq(@indices), ");\n";
- +
- + print "\n";
- +
- + print "\@${mname}'typedef[\@${mname}'indices] = (",
- + join("\n\t", '', @typedef), "\n );\n\n";
- + print "\@${mname}'sizeof[\@${mname}'indices] = (",
- + join("\n\t", '', @sizeof), "\n );\n\n";
- + print "\@${mname}'offsetof[\@${mname}'indices] = (",
- + join("\n\t", '', @offsetof), "\n );\n\n";
- + print "\@${mname}'typeof[\@${mname}'indices] = (",
- + join("\n\t", '', @typeof), "\n );\n\n";
- +
- + $template_printed{$fname}++;
- + $size_printed{$fname}++;
- + }
- + print "\n";
- + }
- +
- + print STDERR "\n" if $trace;
- +
- + unless ($perl && $opt_a) {
- + print "\n1;\n";
- + exit;
- + }
- +
- +
- +
- + foreach $name (sort bysizevalue keys %intrinsics) {
- + next if $size_printed{$name};
- + print '$',&munge($name),"'sizeof = ", $sizeof{$name}, ";\n";
- + }
- +
- + print "\n";
- +
- + sub bysizevalue { $sizeof{$a} <=> $sizeof{$b}; }
- +
- +
- + foreach $name (sort keys %intrinsics) {
- + print '$',&munge($name),"'typedef = '", $template{$name}, "';\n";
- + }
- +
- + print "\n1;\n";
- +
- + exit;
- + }
- +
- + ########################################################################################
- +
- +
- + sub stab {
- + next unless /:[\$\w]+(\(\d+,\d+\))?=[\*\$\w]+/; # (\d+,\d+) is for sun
- + s/"// || next;
- + s/",([x\d]+),([x\d]+),([x\d]+),.*// || next;
- +
- + next if /^\s*$/;
- +
- + $size = $3 if $3;
- +
- +
- + $line = $_;
- +
- + if (($name, $pdecl) = /^([\$ \w]+):[tT]((\d+)(=[rufs*](\d+))+)$/) {
- + print "$name is a typedef for some funky pointers: $pdecl\n" if $debug;
- + &pdecl($pdecl);
- + next;
- + }
- +
- +
- +
- + if (/(([ \w]+):t(\d+|\(\d+,\d+\)))=r?(\d+|\(\d+,\d+\))(;\d+;\d+;)?/) {
- + local($ident) = $2;
- + push(@intrinsics, $ident);
- + $typeno = &typeno($3);
- + $type[$typeno] = $ident;
- + print STDERR "intrinsic $ident in new type $typeno\n" if $debug;
- + next;
- + }
- +
- + if (($name, $typeordef, $typeno, $extra, $struct, $_)
- + = /^([\$ \w]+):([ustT])(\d+|\(\d+,\d+\))(=[rufs*](\d+))?(.*)$/)
- + {
- + $typeno = &typeno($typeno); # sun foolery
- + }
- + elsif (/^[\$\w]+:/) {
- + next; # variable
- + }
- + else {
- + warn "can't grok stab: <$_> in: $line " if $_;
- + next;
- + }
- +
- + #warn "got size $size for $name\n";
- + $sizeof{$name} = $size if $size;
- +
- + s/;[-\d]*;[-\d]*;$//; # we don't care about ranges
- +
- + $typenos{$name} = $typeno;
- +
- + unless (defined $type[$typeno]) {
- + &panic("type 0??") unless $typeno;
- + $type[$typeno] = $name unless defined $type[$typeno];
- + printf "new type $typeno is $name" if $debug;
- + if ($extra =~ /\*/ && defined $type[$struct]) {
- + print ", a typedef for a pointer to " , $type[$struct] if $debug;
- + }
- + } else {
- + printf "%s is type %d", $name, $typeno if $debug;
- + print ", a typedef for " , $type[$typeno] if $debug;
- + }
- + print "\n" if $debug;
- + #next unless $extra =~ /[su*]/;
- +
- + #$type[$struct] = $name;
- +
- + if ($extra =~ /[us*]/) {
- + &sou($name, $extra);
- + $_ = &sdecl($name, $_, 0);
- + }
- + elsif (/^=ar/) {
- + print "it's a bare array typedef -- that's pretty sick\n" if $debug;
- + $_ = "$typeno$_";
- + $scripts = '';
- + $_ = &adecl($_,1);
- +
- + }
- + elsif (s/((\w+):t(\d+|\(\d+,\d+\)))?=r?(;\d+;\d+;)?//) { # the ?'s are for gcc
- + push(@intrinsics, $2);
- + $typeno = &typeno($3);
- + $type[$typeno] = $2;
- + print STDERR "intrinsic $2 in new type $typeno\n" if $debug;
- + }
- + elsif (s/^=e//) { # blessed by thy compiler; mine won't do this
- + &edecl;
- + }
- + else {
- + warn "Funny remainder for $name on line $_ left in $line " if $_;
- + }
- + }
- +
- + sub typeno { # sun thinks types are (0,27) instead of just 27
- + local($_) = @_;
- + s/\(\d+,(\d+)\)/$1/;
- + $_;
- + }
- +
- + sub pstruct {
- + local($what,$prefix,$base) = @_;
- + local($field, $fieldname, $typeno, $count, $offset, $entry);
- + local($fieldtype);
- + local($type, $tname);
- + local($mytype, $mycount, $entry2);
- + local($struct_count) = 0;
- + local($pad, $revpad, $length, $prepad, $lastoffset, $lastlength, $fmt);
- + local($bits,$bytes);
- + local($template);
- +
- +
- + local($mname) = &munge($name);
- +
- + sub munge {
- + local($_) = @_;
- + s/[\s\$\.]/_/g;
- + $_;
- + }
- +
- + local($sname) = &psou($what);
- +
- + $nesting++;
- +
- + for $field (split(/;/, $struct{$what})) {
- + $pad = $prepad = 0;
- + $entry = '';
- + ($fieldname, $typeno, $count, $offset, $length) = split(/,/, $field);
- +
- + $type = $type[$typeno];
- +
- + $type =~ /([^[]*)(\[.*\])?/;
- + $mytype = $1;
- + $count .= $2;
- + $fieldtype = &psou($mytype);
- +
- + local($fname) = &psou($name);
- +
- + if ($build_templates) {
- +
- + $pad = ($offset - ($lastoffset + $lastlength))/8
- + if defined $lastoffset;
- +
- + if (! $finished_template{$sname}) {
- + if ($isaunion{$what}) {
- + $template{$sname} .= 'X' x $revpad . ' ' if $revpad;
- + } else {
- + $template{$sname} .= 'x' x $pad . ' ' if $pad;
- + }
- + }
- +
- + $template = &fetch_template($type) x
- + ($count ? &scripts2count($count) : 1);
- +
- + if (! $finished_template{$sname}) {
- + $template{$sname} .= $template;
- + }
- +
- + $revpad = $length/8 if $isaunion{$what};
- +
- + ($lastoffset, $lastlength) = ($offset, $length);
- +
- + } else {
- + print '# ' if $perl && $verbose;
- + $entry = sprintf($pmask1,
- + ' ' x ($nesting * $indent) . $fieldtype,
- + "$prefix.$fieldname" . $count);
- +
- + $entry =~ s/(\*+)( )/$2$1/;
- +
- + printf $pmask2,
- + $entry,
- + ($base+$offset)/8,
- + ($bits = ($base+$offset)%8) ? ".$bits" : " ",
- + $length/8,
- + ($bits = $length % 8) ? ".$bits": ""
- + if !$perl || $verbose;
- +
- +
- + if ($perl && $nesting == 1) {
- + $template = &scrunch(&fetch_template($type) x
- + ($count ? &scripts2count($count) : 1));
- + push(@sizeof, int($length/8) .",\t# $fieldname");
- + push(@offsetof, int($offset/8) .",\t# $fieldname");
- + push(@typedef, "'$template', \t# $fieldname");
- + $type =~ s/(struct|union) //;
- + push(@typeof, "'$type" . ($count ? $count : '') .
- + "',\t# $fieldname");
- + }
- +
- + print ' ', ' ' x $indent x $nesting, $template
- + if $perl && $verbose;
- +
- + print "\n" if !$perl || $verbose;
- +
- + }
- + if ($perl) {
- + local($mycount) = defined $struct{$mytype} ? $countof{$mytype} : 1;
- + $mycount *= &scripts2count($count) if $count;
- + if ($nesting==1 && !$build_templates) {
- + $pcode .= sprintf("sub %-32s { %4d; }\n",
- + "${mname}'${fieldname}", $struct_count);
- + push(@indices, $struct_count);
- + }
- + $struct_count += $mycount;
- + }
- +
- +
- + &pstruct($type, "$prefix.$fieldname", $base+$offset)
- + if $recurse && defined $struct{$type};
- + }
- +
- + $countof{$what} = $struct_count unless defined $countof{$whati};
- +
- + $template{$sname} .= '$' if $build_templates;
- + $finished_template{$sname}++;
- +
- + if ($build_templates && !defined $sizeof{$name}) {
- + local($fmt) = &scrunch($template{$sname});
- + print STDERR "no size for $name, punting with $fmt..." if $debug;
- + eval '$sizeof{$name} = length(pack($fmt, ()))';
- + if ($@) {
- + chop $@;
- + warn "couldn't get size for \$name: $@";
- + } else {
- + print STDERR $sizeof{$name}, "\n" if $debUg;
- + }
- + }
- +
- + --$nesting;
- + }
- +
- +
- + sub psize {
- + local($me) = @_;
- + local($amstruct) = $struct{$me} ? 'struct ' : '';
- +
- + print '$sizeof{\'', $amstruct, $me, '\'} = ';
- + printf "%d;\n", $sizeof{$me};
- + }
- +
- + sub pdecl {
- + local($pdecl) = @_;
- + local(@pdecls);
- + local($tname);
- +
- + warn "pdecl: $pdecl\n" if $debug;
- +
- + $pdecl =~ s/\(\d+,(\d+)\)/$1/g;
- + $pdecl =~ s/\*//g;
- + @pdecls = split(/=/, $pdecl);
- + $typeno = $pdecls[0];
- + $tname = pop @pdecls;
- +
- + if ($tname =~ s/^f//) { $tname = "$tname&"; }
- + #else { $tname = "$tname*"; }
- +
- + for (reverse @pdecls) {
- + $tname .= s/^f// ? "&" : "*";
- + #$tname =~ s/^f(.*)/$1&/;
- + print "type[$_] is $tname\n" if $debug;
- + $type[$_] = $tname unless defined $type[$_];
- + }
- + }
- +
- +
- +
- + sub adecl {
- + ($arraytype, $unknown, $lower, $upper) = ();
- + #local($typeno);
- + # global $typeno, @type
- + local($_, $typedef) = @_;
- +
- + while (s/^((\d+)=)?ar(\d+);//) {
- + ($arraytype, $unknown) = ($2, $3);
- + if (s/^(\d+);(\d+);//) {
- + ($lower, $upper) = ($1, $2);
- + $scripts .= '[' . ($upper+1) . ']';
- + } else {
- + warn "can't find array bounds: $_";
- + }
- + }
- + if (s/^([\d*f=]*),(\d+),(\d+);//) {
- + ($start, $length) = ($2, $3);
- + local($whatis) = $1;
- + if ($whatis =~ /^(\d+)=/) {
- + $typeno = $1;
- + &pdecl($whatis);
- + } else {
- + $typeno = $whatis;
- + }
- + } elsif (s/^(\d+)(=[*suf]\d*)//) {
- + local($whatis) = $2;
- +
- + if ($whatis =~ /[f*]/) {
- + &pdecl($whatis);
- + } elsif ($whatis =~ /[su]/) { #
- + print "$prefix.$fieldname is an array$scripts anon structs; disgusting\n"
- + if $debug;
- + #$type[$typeno] = $name unless defined $type[$typeno];
- + ##printf "new type $typeno is $name" if $debug;
- + $typeno = $1;
- + $type[$typeno] = "$prefix.$fieldname";
- + local($name) = $type[$typeno];
- + &sou($name, $whatis);
- + $_ = &sdecl($name, $_, $start+$offset);
- + 1;
- + $start = $start{$name};
- + $offset = $sizeof{$name};
- + $length = $offset;
- + } else {
- + warn "what's this? $whatis in $line ";
- + }
- + } elsif (/^\d+$/) {
- + $typeno = $_;
- + } else {
- + warn "bad array stab: $_ in $line ";
- + next STAB;
- + }
- + #local($wasdef) = defined($type[$typeno]) && $debug;
- + #if ($typedef) {
- + #print "redefining $type[$typeno] to " if $wasdef;
- + #$type[$typeno] = "$whatis$scripts"; # unless defined $type[$typeno];
- + #print "$type[$typeno]\n" if $wasdef;
- + #} else {
- + #$type[$arraytype] = $type[$typeno] unless defined $type[$arraytype];
- + #}
- + $type[$arraytype] = "$type[$typeno]$scripts" if defined $type[$typeno];
- + print "type[$arraytype] is $type[$arraytype]\n" if $debug;
- + print "$prefix.$fieldname is an array of $type[$arraytype]\n" if $debug;
- + $_;
- + }
- +
- +
- +
- + sub sdecl {
- + local($prefix, $_, $offset) = @_;
- +
- + local($fieldname, $scripts, $type, $arraytype, $unknown,
- + $whatis, $pdecl, $upper,$lower, $start,$length) = ();
- + local($typeno,$sou);
- +
- +
- + SFIELD:
- + while (/^([^;]+);/) {
- + $scripts = '';
- + warn "sdecl $_\n" if $debug;
- + if (s/^([\$\w]+)://) {
- + $fieldname = $1;
- + } elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { #
- + $typeno = &typeno($1);
- + $type[$typeno] = "$prefix.$fieldname";
- + local($name) = "$prefix.$fieldname";
- + &sou($name,$2);
- + $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
- + $start = $start{$name};
- + $offset += $sizeof{$name};
- + #print "done with anon, start is $start, offset is $offset\n";
- + #next SFIELD;
- + } else {
- + warn "weird field $_ of $line" if $debug;
- + next STAB;
- + #$fieldname = &gensym;
- + #$_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
- + }
- +
- + if (/^\d+=ar/) {
- + $_ = &adecl($_);
- + }
- + elsif (s/^(\d+|\(\d+,\d+\))?,(\d+),(\d+);//) {
- + ($start, $length) = ($2, $3);
- + &panic("no length?") unless $length;
- + $typeno = &typeno($1) if $1;
- + }
- + elsif (s/^((\d+|\(\d+,\d+\))(=[*f](\d+|\(\d+,\d+\)))+),(\d+),(\d+);//) {
- + ($pdecl, $start, $length) = ($1,$5,$6);
- + &pdecl($pdecl);
- + }
- + elsif (s/(\d+)=([us])(\d+|\(\d+,\d+\))//) { # the dratted anon struct
- + ($typeno, $sou) = ($1, $2);
- + $typeno = &typeno($typeno);
- + if (defined($type[$typeno])) {
- + warn "now how did we get type $1 in $fieldname of $line?";
- + } else {
- + print "anon type $typeno is $prefix.$fieldname\n" if $debug;
- + $type[$typeno] = "$prefix.$fieldname" unless defined $type[$typeno];
- + };
- + local($name) = "$prefix.$fieldname";
- + &sou($name,$sou);
- + print "anon ".($isastruct{$name}) ? "struct":"union"." for $prefix.$fieldname\n" if $debug;
- + $type[$typeno] = "$prefix.$fieldname";
- + $_ = &sdecl("$prefix.$fieldname", $_, $start+$offset);
- + $start = $start{$name};
- + $length = $sizeof{$name};
- + }
- + else {
- + warn "can't grok stab for $name ($_) in line $line ";
- + next STAB;
- + }
- +
- + &panic("no length for $prefix.$fieldname") unless $length;
- + $struct{$name} .= join(',', $fieldname, $typeno, $scripts, $start, $length) . ';';
- + }
- + if (s/;\d*,(\d+),(\d+);//) {
- + local($start, $size) = ($1, $2);
- + $sizeof{$prefix} = $size;
- + print "start of $prefix is $start, size of $sizeof{$prefix}\n" if $debug;
- + $start{$prefix} = $start;
- + }
- + $_;
- + }
- +
- + sub edecl {
- + s/;$//;
- + $enum{$name} = $_;
- + $_ = '';
- + }
- +
- + sub resolve_types {
- + local($sou);
- + for $i (0 .. $#type) {
- + next unless defined $type[$i];
- + $_ = $type[$i];
- + unless (/\d/) {
- + print "type[$i] $type[$i]\n" if $debug;
- + next;
- + }
- + print "type[$i] $_ ==> " if $debug;
- + s/^(\d+)(\**)\&\*(\**)/"$2($3".&type($1) . ')()'/e;
- + s/^(\d+)\&/&type($1)/e;
- + s/^(\d+)/&type($1)/e;
- + s/(\*+)([^*]+)(\*+)/$1$3$2/;
- + s/\((\*+)(\w+)(\*+)\)/$3($1$2)/;
- + s/^(\d+)([\*\[].*)/&type($1).$2/e;
- + #s/(\d+)(\*|(\[[\[\]\d\*]+]\])+)/&type($1).$2/ge;
- + $type[$i] = $_;
- + print "$_\n" if $debug;
- + }
- + }
- + sub type { &psou($type[$_[0]] || "<UNDEFINED>"); }
- +
- + sub adjust_start_addrs {
- + for (sort keys %start) {
- + ($basename = $_) =~ s/\.[^.]+$//;
- + $start{$_} += $start{$basename};
- + print "start: $_ @ $start{$_}\n" if $debug;
- + }
- + }
- +
- + sub sou {
- + local($what, $_) = @_;
- + /u/ && $isaunion{$what}++;
- + /s/ && $isastruct{$what}++;
- + }
- +
- + sub psou {
- + local($what) = @_;
- + local($prefix) = '';
- + if ($isaunion{$what}) {
- + $prefix = 'union ';
- + } elsif ($isastruct{$what}) {
- + $prefix = 'struct ';
- + }
- + $prefix . $what;
- + }
- +
- + sub scrunch {
- + local($_) = @_;
- +
- + study;
- +
- + s/\$//g;
- + s/ / /g;
- + 1 while s/(\w) \1/$1$1/g;
- +
- + # i wanna say this, but perl resists my efforts:
- + # s/(\w)(\1+)/$2 . length($1)/ge;
- +
- + &quick_scrunch;
- +
- + s/ $//;
- +
- + $_;
- + }
- +
- + sub buildscrunchlist {
- + $scrunch_code = "sub quick_scrunch {\n";
- + for (values %intrinsics) {
- + $scrunch_code .= "\ts/($_{2,})/'$_' . length(\$1)/ge;\n";
- + }
- + $scrunch_code .= "}\n";
- + print "$scrunch_code" if $debug;
- + eval $scrunch_code;
- + &panic("can't eval scrunch_code $@ \nscrunch_code") if $@;
- + }
- +
- + sub fetch_template {
- + local($mytype) = @_;
- + local($fmt);
- + local($count) = 1;
- +
- + &panic("why do you care?") unless $perl;
- +
- + if ($mytype =~ s/(\[\d+\])+$//) {
- + $count .= $1;
- + }
- +
- + if ($mytype =~ /\*/) {
- + $fmt = $template{'pointer'};
- + }
- + elsif (defined $template{$mytype}) {
- + $fmt = $template{$mytype};
- + }
- + elsif (defined $struct{$mytype}) {
- + if (!defined $template{&psou($mytype)}) {
- + &build_template($mytype) unless $mytype eq $name;
- + }
- + elsif ($template{&psou($mytype)} !~ /\$$/) {
- + #warn "incomplete template for $mytype\n";
- + }
- + $fmt = $template{&psou($mytype)} || '?';
- + }
- + else {
- + warn "unknown fmt for $mytype\n";
- + $fmt = '?';
- + }
- +
- + $fmt x $count . ' ';
- + }
- +
- + sub compute_intrinsics {
- + local($TMP) = "/tmp/c2ph-i.$$.c";
- + open (TMP, ">$TMP") || die "can't open $TMP: $!";
- + select(TMP);
- +
- + print STDERR "computing intrinsic sizes: " if $trace;
- +
- + undef %intrinsics;
- +
- + print <<'EOF';
- + main() {
- + char *mask = "%d %s\n";
- + EOF
- +
- + for $type (@intrinsics) {
- + next if $type eq 'void';
- + print <<"EOF";
- + printf(mask,sizeof($type), "$type");
- + EOF
- + }
- +
- + print <<'EOF';
- + printf(mask,sizeof(char *), "pointer");
- + exit(0);
- + }
- + EOF
- + close TMP;
- +
- + select(STDOUT);
- + open(PIPE, "cd /tmp && $CC $TMP && /tmp/a.out|");
- + while (<PIPE>) {
- + chop;
- + split(' ',$_,2);;
- + print "intrinsic $_[1] is size $_[0]\n" if $debug;
- + $sizeof{$_[1]} = $_[0];
- + $intrinsics{$_[1]} = $template{$_[0]};
- + }
- + close(PIPE) || die "couldn't read intrinsics!";
- + unlink($TMP, '/tmp/a.out');
- + print STDERR "done\n" if $trace;
- + }
- +
- + sub scripts2count {
- + local($_) = @_;
- +
- + s/^\[//;
- + s/\]$//;
- + s/\]\[/*/g;
- + $_ = eval;
- + &panic("$_: $@") if $@;
- + $_;
- + }
- +
- + sub system {
- + print STDERR "@_\n" if $trace;
- + system @_;
- + }
- +
- + sub build_template {
- + local($name) = @_;
- +
- + &panic("already got a template for $name") if defined $template{$name};
- +
- + local($build_templates) = 1;
- +
- + local($lparen) = '(' x $build_recursed;
- + local($rparen) = ')' x $build_recursed;
- +
- + print STDERR "$lparen$name$rparen " if $trace;
- + $build_recursed++;
- + &pstruct($name,$name,0);
- + print STDERR "TEMPLATE for $name is ", $template{&psou($name)}, "\n" if $debug;
- + --$build_recursed;
- + }
- +
- +
- + sub panic {
- +
- + select(STDERR);
- +
- + print "\npanic: @_\n";
- +
- + exit 1 if $] <= 4.003; # caller broken
- +
- + local($i,$_);
- + local($p,$f,$l,$s,$h,$a,@a,@sub);
- + for ($i = 0; ($p,$f,$l,$s,$h,$w) = caller($i); $i++) {
- + @a = @DB'args;
- + for (@a) {
- + if (/^StB\000/ && length($_) == length($_main{'_main'})) {
- + $_ = sprintf("%s",$_);
- + }
- + else {
- + s/'/\\'/g;
- + s/([^\0]*)/'$1'/ unless /^-?[\d.]+$/;
- + s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg;
- + s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg;
- + }
- + }
- + $w = $w ? '@ = ' : '$ = ';
- + $a = $h ? '(' . join(', ', @a) . ')' : '';
- + push(@sub, "$w&$s$a from file $f line $l\n");
- + last if $signal;
- + }
- + for ($i=0; $i <= $#sub; $i++) {
- + last if $signal;
- + print $sub[$i];
- + }
- + exit 1;
- + }
- +
- + sub squishseq {
- + local($num);
- + local($last) = -1e8;
- + local($string);
- + local($seq) = '..';
- +
- + while (defined($num = shift)) {
- + if ($num == ($last + 1)) {
- + $string .= $seq unless $inseq++;
- + $last = $num;
- + next;
- + } elsif ($inseq) {
- + $string .= $last unless $last == -1e8;
- + }
- +
- + $string .= ',' if defined $string;
- + $string .= $num;
- + $last = $num;
- + $inseq = 0;
- + }
- + $string .= $last if $inseq && $last != -e18;
- + $string;
- + }
- + !NO!SUBS!
- + $eunicefix c2ph
- + rm -f pstruct
- + ln c2ph pstruct
-
- Index: c2ph.doc
- *** c2ph.doc.old Tue Nov 5 19:25:36 1991
- --- c2ph.doc Tue Nov 5 19:25:36 1991
- ***************
- *** 0 ****
- --- 1,191 ----
- + Article 484 of comp.lang.perl:
- + Xref: netlabs comp.lang.perl:484 comp.lang.c:983 alt.sources:134
- + Path: netlabs!psinntp!iggy.GW.Vitalink.COM!lll-winken!sun-barr!cronkite.Central.Sun.COM!spdev!texsun!convex!tchrist
- + From: tchrist@convex.com (Tom Christiansen)
- + Newsgroups: comp.lang.perl,comp.lang.c,alt.sources
- + Subject: pstruct -- a C structure formatter; AKA c2ph, a C to perl header translator
- + Keywords: C perl tranlator
- + Message-ID: <1991Jul25.081021.8104@convex.com>
- + Date: 25 Jul 91 08:10:21 GMT
- + Sender: usenet@convex.com (news access account)
- + Followup-To: comp.lang.perl
- + Organization: CONVEX Computer Corporation, Richardson, Tx., USA
- + Lines: 1208
- + Nntp-Posting-Host: pixel.convex.com
- +
- + Once upon a time, I wrote a program called pstruct. It was a perl
- + program that tried to parse out C structures and display their member
- + offsets for you. This was especially useful for people looking at
- + binary dumps or poking around the kernel.
- +
- + Pstruct was not a pretty program. Neither was it particularly robust.
- + The problem, you see, was that the C compiler was much better at parsing
- + C than I could ever hope to be.
- +
- + So I got smart: I decided to be lazy and let the C compiler parse the C,
- + which would spit out debugger stabs for me to read. These were much
- + easier to parse. It's still not a pretty program, but at least it's more
- + robust.
- +
- + Pstruct takes any .c or .h files, or preferably .s ones, since that's
- + the format it is going to massage them into anyway, and spits out
- + listings like this:
- +
- + struct tty {
- + int tty.t_locker 000 4
- + int tty.t_mutex_index 004 4
- + struct tty * tty.t_tp_virt 008 4
- + struct clist tty.t_rawq 00c 20
- + int tty.t_rawq.c_cc 00c 4
- + int tty.t_rawq.c_cmax 010 4
- + int tty.t_rawq.c_cfx 014 4
- + int tty.t_rawq.c_clx 018 4
- + struct tty * tty.t_rawq.c_tp_cpu 01c 4
- + struct tty * tty.t_rawq.c_tp_iop 020 4
- + unsigned char * tty.t_rawq.c_buf_cpu 024 4
- + unsigned char * tty.t_rawq.c_buf_iop 028 4
- + struct clist tty.t_canq 02c 20
- + int tty.t_canq.c_cc 02c 4
- + int tty.t_canq.c_cmax 030 4
- + int tty.t_canq.c_cfx 034 4
- + int tty.t_canq.c_clx 038 4
- + struct tty * tty.t_canq.c_tp_cpu 03c 4
- + struct tty * tty.t_canq.c_tp_iop 040 4
- + unsigned char * tty.t_canq.c_buf_cpu 044 4
- + unsigned char * tty.t_canq.c_buf_iop 048 4
- + struct clist tty.t_outq 04c 20
- + int tty.t_outq.c_cc 04c 4
- + int tty.t_outq.c_cmax 050 4
- + int tty.t_outq.c_cfx 054 4
- + int tty.t_outq.c_clx 058 4
- + struct tty * tty.t_outq.c_tp_cpu 05c 4
- + struct tty * tty.t_outq.c_tp_iop 060 4
- + unsigned char * tty.t_outq.c_buf_cpu 064 4
- + unsigned char * tty.t_outq.c_buf_iop 068 4
- + (*int)() tty.t_oproc_cpu 06c 4
- + (*int)() tty.t_oproc_iop 070 4
- + (*int)() tty.t_stopproc_cpu 074 4
- + (*int)() tty.t_stopproc_iop 078 4
- + struct thread * tty.t_rsel 07c 4
- +
- + etc.
- +
- +
- + Actually, this was generated by a particular set of options. You can control
- + the formatting of each column, whether you prefer wide or fat, hex or decimal,
- + leading zeroes or whatever.
- +
- + All you need to be able to use this is a C compiler than generates
- + BSD/GCC-style stabs. The -g option on native BSD compilers and GCC
- + should get this for you.
- +
- + To learn more, just type a bogus option, like -\?, and a long usage message
- + will be provided. There are a fair number of possibilities.
- +
- + If you're only a C programmer, than this is the end of the message for you.
- + You can quit right now, and if you care to, save off the source and run it
- + when you feel like it. Or not.
- +
- +
- +
- + But if you're a perl programmer, then for you I have something much more
- + wondrous than just a structure offset printer.
- +
- + You see, if you call pstruct by its other incybernation, c2ph, you have a code
- + generator that translates C code into perl code! Well, structure and union
- + declarations at least, but that's quite a bit.
- +
- + Prior to this point, anyone programming in perl who wanted to interact
- + with C programs, like the kernel, was forced to guess the layouts of the C
- + strutures, and then hardwire these into his program. Of course, when you
- + took your wonderfully to a system where the sgtty structure was laid out
- + differently, you program broke. Which is a shame.
- +
- + We've had Larry's h2ph translator, which helped, but that only works on
- + cpp symbols, not real C, which was also very much needed. What I offer
- + you is a symbolic way of getting at all the C structures. I've couched
- + them in terms of packages and functions. Consider the following program:
- +
- + #!/usr/local/bin/perl
- +
- + require 'syscall.ph';
- + require 'sys/time.ph';
- + require 'sys/resource.ph';
- +
- + $ru = "\0" x &rusage'sizeof();
- +
- + syscall(&SYS_getrusage, &RUSAGE_SELF, $ru) && die "getrusage: $!";
- +
- + @ru = unpack($t = &rusage'typedef(), $ru);
- +
- + $utime = $ru[ &rusage'ru_utime + &timeval'tv_sec ]
- + + ($ru[ &rusage'ru_utime + &timeval'tv_usec ]) / 1e6;
- +
- + $stime = $ru[ &rusage'ru_stime + &timeval'tv_sec ]
- + + ($ru[ &rusage'ru_stime + &timeval'tv_usec ]) / 1e6;
- +
- + printf "you have used %8.3fs+%8.3fu seconds.\n", $utime, $stime;
- +
- +
- + As you see, the name of the package is the name of the structure. Regular
- + fields are just their own names. Plus the follwoing accessor functions are
- + provided for your convenience:
- +
- + struct This takes no arguments, and is merely the number of first-level
- + elements in the structure. You would use this for indexing
- + into arrays of structures, perhaps like this
- +
- +
- + $usec = $u[ &user'u_utimer
- + + (&ITIMER_VIRTUAL * &itimerval'struct)
- + + &itimerval'it_value
- + + &timeval'tv_usec
- + ];
- +
- + sizeof Returns the bytes in the structure, or the member if
- + you pass it an argument, such as
- +
- + &rusage'sizeof(&rusage'ru_utime)
- +
- + typedef This is the perl format definition for passing to pack and
- + unpack. If you ask for the typedef of a nothing, you get
- + the whole structure, otherwise you get that of the member
- + you ask for. Padding is taken care of, as is the magic to
- + guarantee that a union is unpacked into all its aliases.
- + Bitfields are not quite yet supported however.
- +
- + offsetof This function is the byte offset into the array of that
- + member. You may wish to use this for indexing directly
- + into the packed structure with vec() if you're too lazy
- + to unpack it.
- +
- + typeof Not to be confused with the typedef accessor function, this
- + one returns the C type of that field. This would allow
- + you to print out a nice structured pretty print of some
- + structure without knoning anything about it beforehand.
- + No args to this one is a noop. Someday I'll post such
- + a thing to dump out your u structure for you.
- +
- +
- + The way I see this being used is like basically this:
- +
- + % h2ph <some_include_file.h > /usr/lib/perl/tmp.ph
- + % c2ph some_include_file.h >> /usr/lib/perl/tmp.ph
- + % install
- +
- + It's a little tricker with c2ph because you have to get the includes right.
- + I can't know this for your system, but it's not usually too terribly difficult.
- +
- + The code isn't pretty as I mentioned -- I never thought it would be a 1000-
- + line program when I started, or I might not have begun. :-) But I would have
- + been less cavalier in how the parts of the program communicated with each
- + other, etc. It might also have helped if I didn't have to divine the makeup
- + of the stabs on the fly, and then account for micro differences between my
- + compiler and gcc.
- +
- + Anyway, here it is. Should run on perl v4 or greater. Maybe less.
- +
- +
- + --tom
- +
- +
-
- Index: cflags.SH
- *** cflags.SH.old Tue Nov 5 19:25:38 1991
- --- cflags.SH Tue Nov 5 19:25:38 1991
- ***************
- *** 6,12 ****
- ln ../../../config.sh . || \
- (echo "Can't find config.sh."; exit 1)
- fi
- ! . config.sh
- ;;
- esac
- : This forces SH files to create target in same directory as SH file.
- --- 6,12 ----
- ln ../../../config.sh . || \
- (echo "Can't find config.sh."; exit 1)
- fi
- ! . ./config.sh
- ;;
- esac
- : This forces SH files to create target in same directory as SH file.
-
- Index: lib/chat2.pl
- *** lib/chat2.pl.old Tue Nov 5 19:26:52 1991
- --- lib/chat2.pl Tue Nov 5 19:26:52 1991
- ***************
- *** 0 ****
- --- 1,333 ----
- + ## chat.pl: chat with a server
- + ## V2.01.alpha.7 91/06/16
- + ## Randal L. Schwartz
- +
- + package chat;
- +
- + $sockaddr = 'S n a4 x8';
- + chop($thishost = `hostname`); $thisaddr = (gethostbyname($thishost))[4];
- + $thisproc = pack($sockaddr, 2, 0, $thisaddr);
- +
- + # *S = symbol for current I/O, gets assigned *chatsymbol....
- + $next = "chatsymbol000000"; # next one
- + $nextpat = "^chatsymbol"; # patterns that match next++, ++, ++, ++
- +
- +
- + ## $handle = &chat'open_port("server.address",$port_number);
- + ## opens a named or numbered TCP server
- +
- + sub open_port { ## public
- + local($server, $port) = @_;
- +
- + local($serveraddr,$serverproc);
- +
- + *S = ++$next;
- + if ($server =~ /^(\d+)+\.(\d+)\.(\d+)\.(\d+)$/) {
- + $serveraddr = pack('C4', $1, $2, $3, $4);
- + } else {
- + local(@x) = gethostbyname($server);
- + return undef unless @x;
- + $serveraddr = $x[4];
- + }
- + $serverproc = pack($sockaddr, 2, $port, $serveraddr);
- + unless (socket(S, 2, 1, 6)) {
- + # XXX hardwired $AF_SOCKET, $SOCK_STREAM, 'tcp'
- + # but who the heck would change these anyway? (:-)
- + ($!) = ($!, close(S)); # close S while saving $!
- + return undef;
- + }
- + unless (bind(S, $thisproc)) {
- + ($!) = ($!, close(S)); # close S while saving $!
- + return undef;
- + }
- + unless (connect(S, $serverproc)) {
- + ($!) = ($!, close(S)); # close S while saving $!
- + return undef;
- + }
- + select((select(S), $| = 1)[0]);
- + $next; # return symbol for switcharound
- + }
- +
- + ## ($host, $port, $handle) = &chat'open_listen([$port_number]);
- + ## opens a TCP port on the current machine, ready to be listened to
- + ## if $port_number is absent or zero, pick a default port number
- + ## process must be uid 0 to listen to a low port number
- +
- + sub open_listen { ## public
- +
- + *S = ++$next;
- + local($thisport) = shift || 0;
- + local($thisproc_local) = pack($sockaddr, 2, $thisport, $thisaddr);
- + local(*NS) = "__" . time;
- + unless (socket(NS, 2, 1, 6)) {
- + # XXX hardwired $AF_SOCKET, $SOCK_STREAM, 'tcp'
- + # but who the heck would change these anyway? (:-)
- + ($!) = ($!, close(NS));
- + return undef;
- + }
- + unless (bind(NS, $thisproc_local)) {
- + ($!) = ($!, close(NS));
- + return undef;
- + }
- + unless (listen(NS, 1)) {
- + ($!) = ($!, close(NS));
- + return undef;
- + }
- + select((select(NS), $| = 1)[0]);
- + local($family, $port, @myaddr) =
- + unpack("S n C C C C x8", getsockname(NS));
- + $S{"needs_accept"} = *NS; # so expect will open it
- + (@myaddr, $port, $next); # returning this
- + }
- +
- + ## $handle = &chat'open_proc("command","arg1","arg2",...);
- + ## opens a /bin/sh on a pseudo-tty
- +
- + sub open_proc { ## public
- + local(@cmd) = @_;
- +
- + *S = ++$next;
- + local(*TTY) = "__TTY" . time;
- + local($pty,$tty) = &_getpty(S,TTY);
- + die "Cannot find a new pty" unless defined $pty;
- + local($pid) = fork;
- + die "Cannot fork: $!" unless defined $pid;
- + unless ($pid) {
- + close STDIN; close STDOUT; close STDERR;
- + setpgrp(0,$$);
- + if (open(DEVTTY, "/dev/tty")) {
- + ioctl(DEVTTY,0x20007471,0); # XXX s/b &TIOCNOTTY
- + close DEVTTY;
- + }
- + open(STDIN,"<&TTY");
- + open(STDOUT,">&TTY");
- + open(STDERR,">&STDOUT");
- + die "Oops" unless fileno(STDERR) == 2; # sanity
- + close(S);
- + exec @cmd;
- + die "Cannot exec @cmd: $!";
- + }
- + close(TTY);
- + $next; # return symbol for switcharound
- + }
- +
- + # $S is the read-ahead buffer
- +
- + ## $return = &chat'expect([$handle,] $timeout_time,
- + ## $pat1, $body1, $pat2, $body2, ... )
- + ## $handle is from previous &chat'open_*().
- + ## $timeout_time is the time (either relative to the current time, or
- + ## absolute, ala time(2)) at which a timeout event occurs.
- + ## $pat1, $pat2, and so on are regexs which are matched against the input
- + ## stream. If a match is found, the entire matched string is consumed,
- + ## and the corresponding body eval string is evaled.
- + ##
- + ## Each pat is a regular-expression (probably enclosed in single-quotes
- + ## in the invocation). ^ and $ will work, respecting the current value of $*.
- + ## If pat is 'TIMEOUT', the body is executed if the timeout is exceeded.
- + ## If pat is 'EOF', the body is executed if the process exits before
- + ## the other patterns are seen.
- + ##
- + ## Pats are scanned in the order given, so later pats can contain
- + ## general defaults that won't be examined unless the earlier pats
- + ## have failed.
- + ##
- + ## The result of eval'ing body is returned as the result of
- + ## the invocation. Recursive invocations are not thought
- + ## through, and may work only accidentally. :-)
- + ##
- + ## undef is returned if either a timeout or an eof occurs and no
- + ## corresponding body has been defined.
- + ## I/O errors of any sort are treated as eof.
- +
- + $nextsubname = "expectloop000000"; # used for subroutines
- +
- + sub expect { ## public
- + if ($_[0] =~ /$nextpat/) {
- + *S = shift;
- + }
- + local($endtime) = shift;
- +
- + local($timeout,$eof) = (1,1);
- + local($caller) = caller;
- + local($rmask, $nfound, $timeleft, $thisbuf);
- + local($cases, $pattern, $action, $subname);
- + $endtime += time if $endtime < 600_000_000;
- +
- + if (defined $S{"needs_accept"}) { # is it a listen socket?
- + local(*NS) = $S{"needs_accept"};
- + delete $S{"needs_accept"};
- + $S{"needs_close"} = *NS;
- + unless(accept(S,NS)) {
- + ($!) = ($!, close(S), close(NS));
- + return undef;
- + }
- + select((select(S), $| = 1)[0]);
- + }
- +
- + # now see whether we need to create a new sub:
- +
- + unless ($subname = $expect_subname{$caller,@_}) {
- + # nope. make a new one:
- + $expect_subname{$caller,@_} = $subname = $nextsubname++;
- +
- + $cases .= <<"EDQ"; # header is funny to make everything elsif's
- + sub $subname {
- + LOOP: {
- + if (0) { ; }
- + EDQ
- + while (@_) {
- + ($pattern,$action) = splice(@_,0,2);
- + if ($pattern =~ /^eof$/i) {
- + $cases .= <<"EDQ";
- + elsif (\$eof) {
- + package $caller;
- + $action;
- + }
- + EDQ
- + $eof = 0;
- + } elsif ($pattern =~ /^timeout$/i) {
- + $cases .= <<"EDQ";
- + elsif (\$timeout) {
- + package $caller;
- + $action;
- + }
- + EDQ
- + $timeout = 0;
- + } else {
- + $pattern =~ s#/#\\/#g;
- + $cases .= <<"EDQ";
- + elsif (\$S =~ /$pattern/) {
- + \$S = \$';
- + package $caller;
- + $action;
- + }
- + EDQ
- + }
- + }
- + $cases .= <<"EDQ" if $eof;
- + elsif (\$eof) {
- + undef;
- + }
- + EDQ
- + $cases .= <<"EDQ" if $timeout;
- + elsif (\$timeout) {
- + undef;
- + }
- + EDQ
- + $cases .= <<'ESQ';
- + else {
- + $rmask = "";
- + vec($rmask,fileno(S),1) = 1;
- + ($nfound, $rmask) =
- + select($rmask, undef, undef, $endtime - time);
- + if ($nfound) {
- + $nread = sysread(S, $thisbuf, 1024);
- + if ($nread > 0) {
- + $S .= $thisbuf;
- + } else {
- + $eof++, redo LOOP; # any error is also eof
- + }
- + } else {
- + $timeout++, redo LOOP; # timeout
- + }
- + redo LOOP;
- + }
- + }
- + }
- + ESQ
- + eval $cases; die "$cases:\n$@" if $@;
- + }
- + $eof = $timeout = 0;
- + do $subname();
- + }
- +
- + ## &chat'print([$handle,] @data)
- + ## $handle is from previous &chat'open().
- + ## like print $handle @data
- +
- + sub print { ## public
- + if ($_[0] =~ /$nextpat/) {
- + *S = shift;
- + }
- + print S @_;
- + }
- +
- + ## &chat'close([$handle,])
- + ## $handle is from previous &chat'open().
- + ## like close $handle
- +
- + sub close { ## public
- + if ($_[0] =~ /$nextpat/) {
- + *S = shift;
- + }
- + close(S);
- + if (defined $S{"needs_close"}) { # is it a listen socket?
- + local(*NS) = $S{"needs_close"};
- + delete $S{"needs_close"};
- + close(NS);
- + }
- + }
- +
- + ## @ready_handles = &chat'select($timeout, @handles)
- + ## select()'s the handles with a timeout value of $timeout seconds.
- + ## Returns an array of handles that are ready for I/O.
- + ## Both user handles and chat handles are supported (but beware of
- + ## stdio's buffering for user handles).
- +
- + sub select { ## public
- + local($timeout) = shift;
- + local(@handles) = @_;
- + local(%handlename) = ();
- + local(%ready) = ();
- + local($caller) = caller;
- + local($rmask) = "";
- + for (@handles) {
- + if (/$nextpat/o) { # one of ours... see if ready
- + local(*SYM) = $_;
- + if (length($SYM)) {
- + $timeout = 0; # we have a winner
- + $ready{$_}++;
- + }
- + $handlename{fileno($_)} = $_;
- + } else {
- + $handlename{fileno(/'/ ? $_ : "$caller\'$_")} = $_;
- + }
- + }
- + for (sort keys %handlename) {
- + vec($rmask, $_, 1) = 1;
- + }
- + select($rmask, undef, undef, $timeout);
- + for (sort keys %handlename) {
- + $ready{$handlename{$_}}++ if vec($rmask,$_,1);
- + }
- + sort keys %ready;
- + }
- +
- + # ($pty,$tty) = $chat'_getpty(PTY,TTY):
- + # internal procedure to get the next available pty.
- + # opens pty on handle PTY, and matching tty on handle TTY.
- + # returns undef if can't find a pty.
- +
- + sub _getpty { ## private
- + local($_PTY,$_TTY) = @_;
- + $_PTY =~ s/^([^']+)$/(caller)[$[]."'".$1/e;
- + $_TTY =~ s/^([^']+)$/(caller)[$[]."'".$1/e;
- + local($pty,$tty);
- + for $bank (112..127) {
- + next unless -e sprintf("/dev/pty%c0", $bank);
- + for $unit (48..57) {
- + $pty = sprintf("/dev/pty%c%c", $bank, $unit);
- + open($_PTY,"+>$pty") || next;
- + select((select($_PTY), $| = 1)[0]);
- + ($tty = $pty) =~ s/pty/tty/;
- + open($_TTY,"+>$tty") || next;
- + select((select($_TTY), $| = 1)[0]);
- + system "stty nl>$tty";
- + return ($pty,$tty);
- + }
- + }
- + undef;
- + }
- +
- + 1;
-
- *** End of Patch 12 ***
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-