Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!cs.utexas.edu!uunet!sparky!kent From: lwall@netlabs.com (Larry Wall) Newsgroups: comp.sources.misc Subject: v18i052: perl - The perl programming language, Part34/36 Message-ID: <1991Apr19.014951.5142@sparky.IMD.Sterling.COM> Date: 19 Apr 91 01:49:51 GMT Sender: kent@sparky.IMD.Sterling.COM (Kent Landfield) Organization: NetLabs, Inc. Lines: 1965 Approved: kent@sparky.imd.sterling.com X-Checksum-Snefru: 9ec7af2a 039d76e1 a016c771 32513094 Submitted-by: Larry Wall Posting-number: Volume 18, Issue 52 Archive-name: perl/part34 [There are 36 kits for perl version 4.0.] #! /bin/sh # Make a new directory for the perl sources, cd to it, and run kits 1 # thru 36 through sh. When all 36 kits have been run, read README. echo "This is perl 4.0 kit 34 (of 36). If kit 34 is complete, the line" echo '"'"End of kit 34 (of 36)"'" will echo at the end.' echo "" export PATH || (echo "You didn't use sh, you clunch." ; kill $$) mkdir eg eg/g eg/scan eg/van h2pl h2pl/eg h2pl/eg/sys lib msdos os2 os2/eg t t/comp t/op usub x2p 2>/dev/null echo Extracting os2/dir.h sed >os2/dir.h <<'!STUFFY!FUNK!' -e 's/X//' X/* X * @(#) dir.h 1.4 87/11/06 Public Domain. X * X * A public domain implementation of BSD directory routines for X * MS-DOS. Written by Michael Rendell ({uunet,utai}michael@garfield), X * August 1987 X * X * Enhanced and ported to OS/2 by Kai Uwe Rommel; added scandir() prototype X * December 1989, February 1990 X * Change of MAXPATHLEN for HPFS, October 1990 X */ X X X#define MAXNAMLEN 256 X#define MAXPATHLEN 256 X X#define A_RONLY 0x01 X#define A_HIDDEN 0x02 X#define A_SYSTEM 0x04 X#define A_LABEL 0x08 X#define A_DIR 0x10 X#define A_ARCHIVE 0x20 X X Xstruct direct X{ X ino_t d_ino; /* a bit of a farce */ X int d_reclen; /* more farce */ X int d_namlen; /* length of d_name */ X char d_name[MAXNAMLEN + 1]; /* null terminated */ X /* nonstandard fields */ X long d_size; /* size in bytes */ X unsigned d_mode; /* DOS or OS/2 file attributes */ X unsigned d_time; X unsigned d_date; X}; X X/* The fields d_size and d_mode are extensions by me (Kai Uwe Rommel). X * The find_first and find_next calls deliver this data without any extra cost. X * If this data is needed, these fields save a lot of extra calls to stat() X * (each stat() again performs a find_first call !). X */ X Xstruct _dircontents X{ X char *_d_entry; X long _d_size; X unsigned _d_mode, _d_time, _d_date; X struct _dircontents *_d_next; X}; X Xtypedef struct _dirdesc X{ X int dd_id; /* uniquely identify each open directory */ X long dd_loc; /* where we are in directory entry is this */ X struct _dircontents *dd_contents; /* pointer to contents of dir */ X struct _dircontents *dd_cp; /* pointer to current position */ X} XDIR; X X Xextern int attributes; X Xextern DIR *opendir(char *); Xextern struct direct *readdir(DIR *); Xextern void seekdir(DIR *, long); Xextern long telldir(DIR *); Xextern void closedir(DIR *); X#define rewinddir(dirp) seekdir(dirp, 0L) X Xextern int scandir(char *, struct direct ***, X int (*)(struct direct *), X int (*)(struct direct *, struct direct *)); X Xextern int getfmode(char *); Xextern int setfmode(char *, unsigned); !STUFFY!FUNK! echo Extracting os2/eg/os2.pl sed >os2/eg/os2.pl <<'!STUFFY!FUNK!' -e 's/X//' Xextproc C:\binp\misc\perl.exe -S X#!perl X X# os2.pl: Demonstrates the OS/2 system calls and shows off some of the X# features in common with the UNIX version. X Xdo "syscalls.pl" || die "Cannot load syscalls.pl ($!)"; X X# OS/2 version number. X X $version = " "; syscall($OS2_GetVersion,$version); X ($minor, $major) = unpack("CC", $version); X print "You are using OS/2 version ", int($major/10), X ".", int($minor/10), "\n\n"; X X# Process ID. X print "This process ID is $$ and its parent's ID is ", X getppid(), "\n\n"; X X# Priority. X X printf "Current priority is %x\n", getpriority(0,0); X print "Changing priority by +5\n"; X print "Failed!\n" unless setpriority(0,0,+5); X printf "Priority is now %x\n\n", getpriority(0,0); X X# Beep. X print "Here is an A440.\n\n"; X syscall($OS2_Beep,440,50); X X# Pipes. Unlike MS-DOS, OS/2 supports true asynchronous pipes. X open(ROT13, '|perl -pe y/a-zA-Z/n-za-mN-ZA-M/') || die; X select(ROT13); $|=1; select(STDOUT); X print "Type two lines of stuff, and I'll ROT13 it while you wait.\n". X "If you type fast, you might be able to type both of your\n". X "lines before I get a chance to translate the first line.\n"; X $_ = ; print ROT13 $_; X $_ = ; print ROT13 $_; X close(ROT13); X print "Thanks.\n\n"; X X# Inspecting the disks. X print "Let's look at the disks you have installed...\n\n"; X X $x = "\0\0"; X syscall($OS2_Config, $x, 2); X print "You have ", unpack("S", $x), " floppy disks,\n"; X X $x = " "; X syscall($OS2_PhysicalDisk, 1, $x, 2, 0, 0); X ($numdisks) = unpack("S", $x); X X print "and $numdisks partitionable disks.\n\n"; X for ($i = 1; $i <= $numdisks; $i++) { X $disk = $i . ":"; X $handle = " "; X syscall($OS2_PhysicalDisk, 2, $handle, 2, $disk, 3); X ($numhandle) = unpack("S", $handle); X $zero = pack("C", 0); X $parmblock = " " x 16; X syscall($OS2_IOCtl, $parmblock, $zero, 0x63, 9, $numhandle); X ($x, $cylinders, $heads, $sect) = unpack("SSSS", $parmblock); X print "Hard drive #$i:\n"; X print " cylinders: $cylinders\n"; X print " heads: $heads\n"; X print " sect/trk: $sect\n"; X syscall($OS2_PhysicalDisk, 3, 0, 0, $handle, 2); X } X X# I won't bother with the other stuff. You get the idea. X !STUFFY!FUNK! echo Extracting t/op/write.t sed >t/op/write.t <<'!STUFFY!FUNK!' -e 's/X//' X#!./perl X X# $Header: write.t,v 4.0 91/03/20 01:55:34 lwall Locked $ X Xprint "1..3\n"; X Xformat OUT = Xthe quick brown @<< X$fox Xjumped X@* X$multiline X^<<<<<<<<< X$foo X^<<<<<<<<< X$foo X^<<<<<<... X$foo Xnow @<>>> for all@|||||men to come @<<<< X'i' . 's', "time\n", $good, 'to' X. X Xopen(OUT, '>Op.write.tmp') || die "Can't create Op.write.tmp"; X X$fox = 'foxiness'; X$good = 'good'; X$multiline = "forescore\nand\nseven years\n"; X$foo = 'when in the course of human events it becomes necessary'; Xwrite(OUT); Xclose OUT; X X$right = X"the quick brown fox Xjumped Xforescore Xand Xseven years Xwhen in Xthe course Xof huma... Xnow is the time for all good men to come to\n"; X Xif (`cat Op.write.tmp` eq $right) X { print "ok 1\n"; unlink 'Op.write.tmp'; } Xelse X { print "not ok 1\n"; } X Xformat OUT2 = Xthe quick brown @<< X$fox Xjumped X@* X$multiline X^<<<<<<<<< ~~ X$foo Xnow @<>>> for all@|||||men to come @<<<< X'i' . 's', "time\n", $good, 'to' X. X Xopen(OUT2, '>Op.write.tmp') || die "Can't create Op.write.tmp"; X X$fox = 'foxiness'; X$good = 'good'; X$multiline = "forescore\nand\nseven years\n"; X$foo = 'when in the course of human events it becomes necessary'; Xwrite(OUT2); Xclose OUT2; X X$right = X"the quick brown fox Xjumped Xforescore Xand Xseven years Xwhen in Xthe course Xof human Xevents it Xbecomes Xnecessary Xnow is the time for all good men to come to\n"; X Xif (`cat Op.write.tmp` eq $right) X { print "ok 2\n"; unlink 'Op.write.tmp'; } Xelse X { print "not ok 2\n"; } X Xeval <<'EOFORMAT'; Xformat OUT2 = Xthe brown quick @<< X$fox Xjumped X@* X$multiline X^<<<<<<<<< ~~ X$foo Xnow @<>>> for all@|||||men to come @<<<< X'i' . 's', "time\n", $good, 'to' X. XEOFORMAT X Xopen(OUT2, '>Op.write.tmp') || die "Can't create Op.write.tmp"; X X$fox = 'foxiness'; X$good = 'good'; X$multiline = "forescore\nand\nseven years\n"; X$foo = 'when in the course of human events it becomes necessary'; Xwrite(OUT2); Xclose OUT2; X X$right = X"the brown quick fox Xjumped Xforescore Xand Xseven years Xwhen in Xthe course Xof human Xevents it Xbecomes Xnecessary Xnow is the time for all good men to come to\n"; X Xif (`cat Op.write.tmp` eq $right) X { print "ok 3\n"; unlink 'Op.write.tmp'; } Xelse X { print "not ok 3\n"; } X !STUFFY!FUNK! echo Extracting lib/complete.pl sed >lib/complete.pl <<'!STUFFY!FUNK!' -e 's/X//' X;# X;# @(#)complete.pl 1.0 (sun!waynet) 11/11/88 X;# X;# Author: Wayne Thompson X;# X;# Description: X;# This routine provides word completion. X;# (TAB) attempts word completion. X;# (^D) prints completion list. X;# (These may be changed by setting $Complete'complete, etc.) X;# X;# Diagnostics: X;# Bell when word completion fails. X;# X;# Dependencies: X;# The tty driver is put into raw mode. X;# X;# Bugs: X;# X;# Usage: X;# $input = do Complete('prompt_string', @completion_list); X;# X XCONFIG: { X package Complete; X X $complete = "\004"; X $kill = "\025"; X $erase1 = "\177"; X $erase2 = "\010"; X} X Xsub Complete { X package Complete; X X local ($prompt) = shift (@_); X local ($c, $cmp, $l, $r, $ret, $return, $test); X @_cmp_lst = sort @_; X local($[) = 0; X system 'stty raw -echo'; X loop: { X print $prompt, $return; X while (($c = getc(stdin)) ne "\r") { X if ($c eq "\t") { # (TAB) attempt completion X @_match = (); X foreach $cmp (@_cmp_lst) { X push (@_match, $cmp) if $cmp =~ /^$return/; X } X $test = $_match[0]; X $l = length ($test); X unless ($#_match == 0) { X shift (@_match); X foreach $cmp (@_match) { X until (substr ($cmp, 0, $l) eq substr ($test, 0, $l)) { X $l--; X } X } X print "\007"; X } X print $test = substr ($test, $r, $l - $r); X $r = length ($return .= $test); X } X elsif ($c eq $complete) { # (^D) completion list X print "\r\n"; X foreach $cmp (@_cmp_lst) { X print "$cmp\r\n" if $cmp =~ /^$return/; X } X redo loop; X } X elsif ($c eq $kill && $r) { # (^U) kill X $return = ''; X $r = 0; X print "\r\n"; X redo loop; X } X # (DEL) || (BS) erase X elsif ($c eq $erase1 || $c eq $erase2) { X if($r) { X print "\b \b"; X chop ($return); X $r--; X } X } X elsif ($c =~ /\S/) { # printable char X $return .= $c; X $r++; X print $c; X } X } X } X system 'stty -raw echo'; X print "\n"; X $return; X} X X1; !STUFFY!FUNK! echo Extracting eg/scan/scanner sed >eg/scan/scanner <<'!STUFFY!FUNK!' -e 's/X//' X#!/usr/bin/perl X X# $Header: scanner,v 4.0 91/03/20 01:14:11 lwall Locked $ X X# This runs all the scan_* routines on all the machines in /etc/ghosts. X# We run this every morning at about 6 am: X X# !/bin/sh X# cd /usr/adm/private X# decrypt scanner | perl >scan.out 2>&1 X# mail admin = 0) { X @scanlist = @ARGV; X} else { X @scanlist = split(/[ \t\n]+/,`echo scan_*`); X} X Xscan: while ($scan = shift(@scanlist)) { X print "\n********** $scan **********\n"; X $showhost++; X X $systype = 'all'; X X open(ghosts, '/etc/ghosts') || die 'No /etc/ghosts file'; X X $one_of_these = ":$systype:"; X if ($systype =~ s/\+/[+]/g) { X $one_of_these =~ s/\+/:/g; X } X X line: while () { X s/[ \t]*\n//; X if (!$_ || /^#/) { X next line; X } X if (/^([a-zA-Z_0-9]+)=(.+)/) { X $name = $1; $repl = $2; X $repl =~ s/\+/:/g; X $one_of_these =~ s/:$name:/:$repl:/; X next line; X } X @gh = split; X $host = $gh[0]; X if ($showhost) { $showhost = "$host:\t"; } X class: while ($class = pop(gh)) { X if (index($one_of_these,":$class:") >=0) { X $iter = 0; X `exec crypt -inquire <$scan >.x 2>/dev/null`; X unless (open(scan,'.x')) { X print "Can't run $scan: $!\n"; X next scan; X } X $cmd = ; X unless ($cmd =~ s/#!(.*)\n/$1/) { X $cmd = '/usr/bin/perl'; X } X close(scan); X if (open(PIPE,"exec rsh $host '$cmd' <.x|")) { X sleep(5); X unlink '.x'; X while () { X last if $iter++ > 1000; # must be looping X next if /^[0-9.]+u [0-9.]+s/; X print $showhost,$_; X } X close(PIPE); X } else { X print "(Can't execute rsh: $!)\n"; X } X last class; X } X } X } X} !STUFFY!FUNK! echo Extracting eg/g/gcp.man sed >eg/g/gcp.man <<'!STUFFY!FUNK!' -e 's/X//' X.\" $Header: gcp.man,v 4.0 91/03/20 01:10:13 lwall Locked $ X.TH GCP 1C "13 May 1988" X.SH NAME Xgcp \- global file copy X.SH SYNOPSIS X.B gcp Xfile1 file2 X.br X.B gcp X[ X.B \-r X] file ... directory X.SH DESCRIPTION X.I gcp Xworks just like rcp(1C) except that you may specify a set of hosts to copy files Xfrom or to. XThe host sets are defined in the file /etc/ghosts. X(An individual host name can be used as a set containing one member.) XYou can give a command like X X gcp /etc/motd sun: X Xto copy your /etc/motd file to /etc/motd on all the Suns. XIf, on the other hand, you say X X gcp /a/foo /b/bar sun:/tmp X Xthen your files will be copied to /tmp on all the Suns. XThe general rule is that if you don't specify the destination directory, Xfiles go to the same directory they are in currently. X.P XYou may specify the union of two or more sets by using + as follows: X X gcp /a/foo /b/bar 750+mc: X Xwhich will copy /a/foo to /a/foo on all 750's and Masscomps, and then copy X/b/bar to /b/bar on all 750's and Masscomps. X.P XCommonly used sets should be defined in /etc/ghosts. XFor example, you could add a line that says X X pep=manny+moe+jack X XAnother way to do that would be to add the word "pep" after each of the host Xentries: X X manny sun3 pep X.br X moe sun3 pep X.br X jack sun3 pep X XHosts and sets of host can also be excluded: X X foo=sun-sun2 X XAny host so excluded will never be included, even if a subsequent set on the Xline includes it: X X foo=abc+def X.br X bar=xyz-abc+foo X Xcomes out to xyz+def. X XYou can define private host sets by creating .ghosts in your current directory Xwith entries just like /etc/ghosts. XAlso, if there is a file .grem, it defines "rem" to be the remaining hosts Xfrom the last gsh or gcp that didn't succeed everywhere. X.PP XInterrupting with a SIGINT will cause the rcp to the current host to be skipped Xand execution resumed with the next host. XTo stop completely, send a SIGQUIT. X.SH SEE ALSO Xrcp(1C) X.SH BUGS XAll the bugs of rcp, since it calls rcp. !STUFFY!FUNK! echo Extracting t/TEST sed >t/TEST <<'!STUFFY!FUNK!' -e 's/X//' X#!./perl X X# $Header: TEST,v 4.0 91/03/20 01:40:22 lwall Locked $ X X# This is written in a peculiar style, since we're trying to avoid X# most of the constructs we'll be testing for. X X$| = 1; X Xif ($ARGV[0] eq '-v') { X $verbose = 1; X shift; X} X Xchdir 't' if -f 't/TEST'; X Xif ($ARGV[0] eq '') { X @ARGV = split(/[ \n]/, X `echo base/*.t comp/*.t cmd/*.t io/*.t; echo op/*.t lib/*.t`); X} X Xopen(CONFIG,"../config.sh"); Xwhile () { X if (/sharpbang='(.*)'/) { X $sharpbang = ($1 eq '#!'); X last; X } X} X$bad = 0; Xwhile ($test = shift) { X if ($test =~ /^$/) { X next; X } X $te = $test; X chop($te); X print "$te" . '.' x (15 - length($te)); X if ($sharpbang) { X open(results,"./$test|") || (print "can't run.\n"); X } else { X open(script,"$test") || die "Can't run $test.\n"; X $_ =