[alt.sources] perl 3.0 beta kit 10/23

lwall@jato.Jpl.Nasa.Gov (Larry Wall) (09/04/89)

#! /bin/sh

# Make a new directory for the perl sources, cd to it, and run kits 1
# thru 23 through sh.  When all 23 kits have been run, read README.

echo "This is perl 3.0 kit 10 (of 23).  If kit 10 is complete, the line"
echo '"'"End of kit 10 (of 23)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
mkdir  2>/dev/null
echo Extracting perl.man.2
sed >perl.man.2 <<'!STUFFY!FUNK!' -e 's/X//'
X''' Beginning of part 2
X''' $Header: perl.man.2,v 2.0.1.9 88/11/22 01:13:02 lwall Locked $
X'''
X''' $Log:	perl.man.2,v $
X'''
X.PP
XAlong with the literals and variables mentioned earlier,
Xthe operations in the following section can serve as terms in an expression.
XSome of these operations take a LIST as an argument.
XSuch a list can consist of any combination of scalar arguments or array values;
Xthe array values will be included in the list as if each individual element were
Xinterpolated at that point in the list, forming a longer single-dimensional
Xarray value.
XElements of the LIST should be separated by commas.
XIf an operation is listed both with and without parentheses around its
Xarguments, it means you can either use it as a unary operator or
Xas a function call.
XTo use it as a function call, the left parenthesis must immediately follow
Xthe function name with no intervening space.
XSuch a function then has highest precedence, as you would expect from
Xa function.
XIf any character other than a left parenthesis follows, then it is a
Xunary operator, with a precedence depending only on whether it is a LIST
Xoperator or not.
XLIST operators have lowest precedence.
XAll other unary operators have a precedence greater than relational operators
Xbut less than arithmetic operators.
XSee the section on Precedence.
X.Ip "/PATTERN/" 8 4
XSee m/PATTERN/.
X.Ip "?PATTERN?" 8 4
XThis is just like the /pattern/ search, except that it matches only once between
Xcalls to the
X.I reset
Xoperator.
XThis is a useful optimization when you only want to see the first occurrence of
Xsomething in each file of a set of files, for instance.
XOnly ?? patterns local to the current package are reset.
X.Ip "atan2(X,Y)" 8 2
XReturns the arctangent of X/Y in the range
X.if t \-\(*p to \(*p.
X.if n \-PI to PI.
X.Ip "chdir(EXPR)" 8 2
X.Ip "chdir EXPR" 8 2
XChanges the working directory to EXPR, if possible.
XReturns 1 upon success, 0 otherwise.
XSee example under
X.IR die .
X.Ip "chmod(LIST)" 8 2
X.Ip "chmod LIST" 8 2
XChanges the permissions of a list of files.
XThe first element of the list must be the numerical mode.
XReturns the number of files successfully changed.
X.nf
X
X.ne 2
X	$cnt = chmod 0755, \'foo\', \'bar\';
X	chmod 0755, @executables;
X
X.fi
X.Ip "chop(LIST)" 8 7
X.Ip "chop(VARIABLE)" 8
X.Ip "chop VARIABLE" 8
X.Ip "chop" 8
XChops off the last character of a string and returns the character chopped.
XIt's used primarily to remove the newline from the end of an input record,
Xbut is much more efficient than s/\en// because it neither scans nor copies
Xthe string.
XIf VARIABLE is omitted, chops $_.
XExample:
X.nf
X
X.ne 5
X	while (<>) {
X		chop;	# avoid \en on last field
X		@array = split(/:/);
X		.\|.\|.
X	}
X
X.fi
XYou can actually chop anything that's an lvalue, including an assignment:
X.nf
X
X	chop($cwd = \`pwd\`);
X	chop($answer = <STDIN>);
X
X.fi
XIf you chop a list, each element is chopped.
XOnly the value of the last chop is returned.
X.Ip "chown(LIST)" 8 2
X.Ip "chown LIST" 8 2
XChanges the owner (and group) of a list of files.
XThe first two elements of the list must be the NUMERICAL uid and gid,
Xin that order.
XReturns the number of files successfully changed.
X.nf
X
X.ne 2
X	$cnt = chown $uid, $gid, \'foo\', \'bar\';
X	chown $uid, $gid, @filenames;
X
X.fi
X.ne 23
XHere's an example of looking up non-numeric uids:
X.nf
X
X	print "User: ";
X	$user = <STDIN>;
X	chop($user);
X	print "Files: "
X	$pattern = <STDIN>;
X	chop($pattern);
X	open(pass, \'/etc/passwd\') || die "Can't open passwd: $!\n";
X	while (<pass>) {
X		($login,$pass,$uid,$gid) = split(/:/);
X		$uid{$login} = $uid;
X		$gid{$login} = $gid;
X	}
X	@ary = <$pattern>;	# get filenames
X	if ($uid{$user} eq \'\') {
X		die "$user not in passwd file";
X	}
X	else {
X		chown $uid{$user}, $gid{$user}, @ary;
X	}
X
X.fi
X.Ip "chroot(FILENAME)" 8 5
X.Ip "chroot FILENAME" 8
XDoes the same as the system call of that name.
XIf you don't know what it does, don't worry about it.
X.Ip "close(FILEHANDLE)" 8 5
X.Ip "close FILEHANDLE" 8
XCloses the file or pipe associated with the file handle.
XYou don't have to close FILEHANDLE if you are immediately going to
Xdo another open on it, since open will close it for you.
X(See
X.IR open .)
XHowever, an explicit close on an input file resets the line counter ($.), while
Xthe implicit close done by
X.I open
Xdoes not.
XAlso, closing a pipe will wait for the process executing on the pipe to complete,
Xin case you want to look at the output of the pipe afterwards.
XClosing a pipe explicitly also puts the status value of the command into $?.
XExample:
X.nf
X
X.ne 4
X	open(OUTPUT, \'|sort >foo\');	# pipe to sort
X	.\|.\|.	# print stuff to output
X	close OUTPUT;		# wait for sort to finish
X	open(INPUT, \'foo\');	# get sort's results
X
X.fi
XFILEHANDLE may be an expression whose value gives the real filehandle name.
X.Ip "cos(EXPR)" 8 6
X.Ip "cos EXPR" 8 6
XReturns the cosine of EXPR (expressed in radians).
X.Ip "crypt(PLAINTEXT,SALT)" 8 6
XEncrypts a string exactly like the crypt() function in the C library.
XUseful for checking the password file for lousy passwords.
XOnly the guys wearing white hats should do this.
X.Ip "dbmclose(ASSOC_ARRAY)" 8 6
X.Ip "dbmclose ASSOC_ARRAY" 8
XBreaks the binding between a dbm file and an associative array.
XThe values remaining in the associative array are meaningless unless
Xyou happen to want to know what was in the cache for the dbm file.
XThis function is only useful if you have ndbm.
X.Ip "dbmopen(ASSOC,DBNAME,MODE)" 8 6
XThis binds a dbm or ndbm file to an associative array.
XASSOC is the name of the associative array.
X(Unlike normal open, the first argument is NOT a filehandle, even though
Xit looks like one).
XDBNAME is the name of the database (without the .dir or .pag extension).
XIf the database does not exist, it is created with protection specified
Xby MODE (as modified by the umask).
XIf your system only supports the older dbm functions, you may only have one
Xdbmopen in your program.
XIf your system has neither dbm nor ndbm, calling dbmopen produces a fatal
Xerror.
X.Sp
XValues assigned to the associative array prior to the dbmopen are lost.
XA certain number of values from the dbm file are cached in memory.
XBy default this number is 64, but you can increase it by preallocating
Xthat number of garbage entries in the associative array before the dbmopen.
XYou can flush the cache if necessary with the reset command.
X.Sp
XIf you don't have write access to the dbm file, you can only read
Xassociative array variables, not set them.
XIf you want to test whether you can write, either use file tests or
Xtry setting a dummy array entry inside an eval, which will trap the error.
X.Sp
XNote that functions such as keys() and values() may return huge array values
Xwhen used on large dbm files.
XYou may prefer to use the each() function to iterate over large dbm files.
XExample:
X.nf
X
X.ne 6
X	# print out history file offsets
X	dbmopen(HIST,'/usr/lib/news/history',0666);
X	while (($key,$val) = each %HIST) {
X		print $key, ' = ', unpack('L',$val), "\en";
X	}
X	dbmclose(HIST);
X
X.fi
X.Ip "defined(EXPR)" 8 6
X.Ip "defined EXPR" 8
XReturns a boolean value saying whether the lvalue EXPR has a real value
Xor not.
XMany operations return the undefined value under exceptional conditions,
Xsuch as end of file, uninitialized variable, system error and such.
XThis function allows you to distinguish between an undefined null string
Xand a defined null string with operations that might return a real null
Xstring, in particular referencing elements of an array.
XYou may also check to see if arrays or subroutines exist.
XUse on predefined variables is not guaranteed to produce intuitive results.
XExamples:
X.nf
X
X.ne 7
X	print if defined $switch{'D'};
X	print "$val\en" while defined($val = pop(@ary));
X	die "Can't readlink $sym: $!"
X		unless defined($value = readlink $sym);
X	eval '@foo = ()' if defined(@foo);
X	die "No XYZ package defined" unless defined %_XYZ;
X	sub foo { defined &bar ? &bar(@_) : die "No bar"; }
X
X.fi
XSee also undef.
X.Ip "delete $ASSOC{KEY}" 8 6
XDeletes the specified value from the specified associative array.
XReturns the deleted value, or the undefined value if nothing was deleted.
XDeleting from $ENV{} modifies the environment.
XDeleting from an array bound to a dbm file deletes the entry from the dbm
Xfile.
X.Sp
XThe following deletes all the values of an associative array:
X.nf
X
X.ne 3
X	foreach $key (keys %ARRAY) {
X		delete $ARRAY{$key};
X	}
X
X.fi
X(But it would be faster to use the
X.I reset
Xcommand.
XSaying undef %ARRAY is faster yet.)
X.Ip "die(LIST)" 8
X.Ip "die LIST" 8
XPrints the value of LIST to
X.I STDERR
Xand exits with the current value of $!
X(errno).
XIf $! is 0, exits with the value of ($? >> 8) (\`command\` status).
XIf ($? >> 8) is 0, exits with 255.
XEquivalent examples:
X.nf
X
X.ne 3
X	die "Can't cd to spool: $!\en" unless chdir \'/usr/spool/news\';
X
X	chdir \'/usr/spool/news\' || die "Can't cd to spool: $!\en" 
X
X.fi
X.Sp
XIf the value of EXPR does not end in a newline, the current script line
Xnumber and input line number (if any) are also printed, and a newline is
Xsupplied.
XHint: sometimes appending \*(L", stopped\*(R" to your message will cause it to make
Xbetter sense when the string \*(L"at foo line 123\*(R" is appended.
XSuppose you are running script \*(L"canasta\*(R".
X.nf
X
X.ne 7
X	die "/etc/games is no good";
X	die "/etc/games is no good, stopped";
X
Xproduce, respectively
X
X	/etc/games is no good at canasta line 123.
X	/etc/games is no good, stopped at canasta line 123.
X
X.fi
XSee also
X.IR exit .
X.Ip "do BLOCK" 8 4
XReturns the value of the last command in the sequence of commands indicated
Xby BLOCK.
XWhen modified by a loop modifier, executes the BLOCK once before testing the
Xloop condition.
X(On other statements the loop modifiers test the conditional first.)
X.Ip "do SUBROUTINE (LIST)" 8 3
XExecutes a SUBROUTINE declared by a
X.I sub
Xdeclaration, and returns the value
Xof the last expression evaluated in SUBROUTINE.
XIf there is no subroutine by that name, returns the undefined value.
XIf you pass arrays as part of LIST you may wish to pass the length
Xof the array in front of each array.
X(See the section on subroutines later on.)
XSUBROUTINE may be a scalar variable, in which case the variable contains
Xthe name of the subroutine to execute.
XThe parentheses are required to avoid confusion with the \*(L"do EXPR\*(R"
Xform.
X.Sp
XAs an alternate form, you may call a subroutine by prefixing the name with
Xan ampersand: &foo(@args).
XIf you aren't passing any arguments, you don't have to use parentheses.
XIf you omit the parentheses, no @_ array is passed to the subroutine.
XThe & form is also used to specify subroutines to the defined and undef
Xoperators.
X.Ip "do EXPR" 8 3
XUses the value of EXPR as a filename and executes the contents of the file
Xas a
X.I perl
Xscript.
XIts primary use is to include subroutines from a
X.I perl
Xsubroutine library.
X.nf
X
X	do \'stat.pl\';
X
Xis just like
X
X	eval \`cat stat.pl\`;
X
X.fi
Xexcept that it's more efficient, more concise, keeps track of the current
Xfilename for error messages, and searches all the
X.B \-I
Xlibraries if the file
Xisn't in the current directory (see also the @INC array in Predefined Names).
XIt's the same, however, in that it does reparse the file every time you
Xcall it, so if you are going to use the file inside a loop you might prefer
Xto use \-P and #include, at the expense of a little more startup time.
X(The main problem with #include is that cpp doesn't grok # comments\*(--a
Xworkaround is to use \*(L";#\*(R" for standalone comments.)
XNote that the following are NOT equivalent:
X.nf
X
X.ne 2
X	do $foo;	# eval a file
X	do $foo();	# call a subroutine
X
X.fi
X.Ip "dump LABEL" 8 6
XThis causes an immediate core dump.
XPrimarily this is so that you can use the undump program to turn your
Xcore dump into an executable binary after having initialized all your
Xvariables at the beginning of the program.
XWhen the new binary is executed it will begin by executing a "goto LABEL"
X(with all the restrictions that goto suffers).
XThink of it as a goto with an intervening core dump and reincarnation.
XIf LABEL is omitted, restarts the program from the top.
XWARNING: any files opened at the time of the dump will NOT be open any more
Xwhen the program is reincarnated, with possible resulting confusion on the part
Xof perl.
XSee also \-u.
X.Sp
XExample:
X.nf
X
X.ne 16
X	#!/usr/bin/perl
X	do 'getopt.pl';
X	do 'stat.pl';
X	%days = (
X	    'Sun',1,
X	    'Mon',2,
X	    'Tue',3,
X	    'Wed',4,
X	    'Thu',5,
X	    'Fri',6,
X	    'Sat',7);
X
X	dump QUICKSTART if $ARGV[0] eq '-d';
X
X    QUICKSTART:
X	do Getopt('f');
X
X.fi
X.Ip "each(ASSOC_ARRAY)" 8 6
X.Ip "each ASSOC_ARRAY" 8
XReturns a 2 element array consisting of the key and value for the next
Xvalue of an associative array, so that you can iterate over it.
XEntries are returned in an apparently random order.
XWhen the array is entirely read, a null array is returned (which when
Xassigned produces a FALSE (0) value).
XThe next call to each() after that will start iterating again.
XThe iterator can be reset only by reading all the elements from the array.
XYou must not modify the array while iterating over it.
XThere is a single iterator for each associative array, shared by all
Xeach(), keys() and values() function calls in the program.
XThe following prints out your environment like the printenv program, only
Xin a different order:
X.nf
X
X.ne 3
X	while (($key,$value) = each %ENV) {
X		print "$key=$value\en";
X	}
X
X.fi
XSee also keys() and values().
X.Ip "eof(FILEHANDLE)" 8 8
X.Ip "eof()" 8
X.Ip "eof" 8
XReturns 1 if the next read on FILEHANDLE will return end of file, or if
XFILEHANDLE is not open.
XFILEHANDLE may be an expression whose value gives the real filehandle name.
XAn eof without an argument returns the eof status for the last file read.
XEmpty parentheses () may be used to indicate the pseudo file formed of the
Xfiles listed on the command line, i.e. eof() is reasonable to use inside
Xa while (<>) loop to detect the end of only the last file.
XUse eof(ARGV) or eof without the parentheses to test EACH file in a while (<>) loop.
XExamples:
X.nf
X
X.ne 7
X	# insert dashes just before last line of last file
X	while (<>) {
X		if (eof()) {
X			print "\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\|\-\en";
X		}
X		print;
X	}
X
X.ne 7
X	# reset line numbering on each input file
X	while (<>) {
X		print "$.\et$_";
X		if (eof) {	# Not eof().
X			close(ARGV);
X		}
X	}
X
X.fi
X.Ip "eval(EXPR)" 8 6
X.Ip "eval EXPR" 8 6
XEXPR is parsed and executed as if it were a little
X.I perl
Xprogram.
XIt is executed in the context of the current
X.I perl
Xprogram, so that
Xany variable settings, subroutine or format definitions remain afterwards.
XThe value returned is the value of the last expression evaluated, just
Xas with subroutines.
XIf there is a syntax error or runtime error, a null string is returned by
Xeval, and $@ is set to the error message.
XIf there was no error, $@ is null.
XIf EXPR is omitted, evaluates $_.
XThe final semicolon, if any, may be omitted from the expression.
X.Sp
XNote that, since eval traps otherwise-fatal errors, it is useful for
Xdetermining whether a particular feature
X(such as dbmopen or symlink) is implemented.
X.Ip "exec(LIST)" 8 8
X.Ip "exec LIST" 8 6
XIf there is more than one argument in LIST, or if LIST is an array with
Xmore than one value,
Xcalls execvp() with the arguments in LIST.
XIf there is only one scalar argument, the argument is checked for shell metacharacters.
XIf there are any, the entire argument is passed to \*(L"/bin/sh \-c\*(R" for parsing.
XIf there are none, the argument is split into words and passed directly to
Xexecvp(), which is more efficient.
XNote: exec (and system) do not flush your output buffer, so you may need to
Xset $| to avoid lost output.
XExamples:
X.nf
X
X	exec \'/bin/echo\', \'Your arguments are: \', @ARGV;
X	exec "sort $outfile | uniq";
X
X.fi
X.Sp
XIf you don't really want to execute the first argument, but want to lie
Xto the program you are executing about its own name, you can specify
Xthe program you actually want to run by assigning that to a variable and
Xputting the name of the variable in front of the LIST without a comma.
X(This always forces interpretation of the LIST as a multi-valued list, even
Xif there is only a single scalar in the list.)
XExample:
X.nf
X
X.ne 2
X	$shell = '/bin/csh';
X	exec $shell '-sh';		# pretend it's a login shell
X
X.fi
X.Ip "exit(EXPR)" 8 6
X.Ip "exit EXPR" 8
XEvaluates EXPR and exits immediately with that value.
XExample:
X.nf
X
X.ne 2
X	$ans = <STDIN>;
X	exit 0 \|if \|$ans \|=~ \|/\|^[Xx]\|/\|;
X
X.fi
XSee also
X.IR die .
X.Ip "exp(EXPR)" 8 3
X.Ip "exp EXPR" 8
XReturns
X.I e
Xto the power of EXPR.
X.Ip "fcntl(FILEHANDLE,FUNCTION,SCALAR)" 8 4
XImplements the fcntl(2) function.
XYou'll probably have to say
X.nf
X
X	do "fcntl.h";	# probably /usr/local/lib/perl/fcntl.h
X
X.fi
Xfirst to get the correct function definitions.
XIf fcntl.h doesn't exist or doesn't have the correct definitions
Xyou'll have to roll
Xyour own, based on your C header files such as <sys/fcntl.h>.
X(There is a perl script called makelib that comes with the perl kit
Xwhich may help you in this.)
XArgument processing works just like ioctl below.
XNote that fcntl will produce a fatal error if used on a machine that doesn't implement
Xfcntl(2).
X.Ip "fileno(FILEHANDLE)" 8 4
XReturns the file descriptor for a filehandle.
XUseful for constructing bitmaps for select().
XIf FILEHANDLE is an expression, the value is taken as the name of
Xthe filehandle.
X.Ip "flock(FILEHANDLE,OPERATION)" 8 4
XCalls flock(2) on FILEHANDLE.
XSee manual page for flock(2) for definition of OPERATION.
XWill produce a fatal error if used on a machine that doesn't implement
Xflock(2).
XHere's a mailbox appender for BSD systems.
X.nf
X
X.ne 20
X	$LOCK_SH = 1;
X	$LOCK_EX = 2;
X	$LOCK_NB = 4;
X	$LOCK_UN = 8;
X
X	sub lock {
X	    flock(MBOX,$LOCK_EX);
X	    # and, in case someone appended
X	    # while we were waiting...
X	    seek(MBOX, 0, 2);
X	}
X
X	sub unlock {
X	    flock(MBOX,$LOCK_UN);
X	}
X
X	open(MBOX, ">>/usr/spool/mail/$USER")
X		|| die "Can't open mailbox: $!";
X
X	do lock();
X	print MBOX $msg,"\en\en";
X	do unlock();
X
X.fi
X.Ip "fork" 8 4
XDoes a fork() call.
XReturns the child pid to the parent process and 0 to the child process.
XNote: unflushed buffers remain unflushed in both processes, which means
Xyou may need to set $| to avoid duplicate output.
X.Ip "getc(FILEHANDLE)" 8 4
X.Ip "getc FILEHANDLE" 8
X.Ip "getc" 8
XReturns the next character from the input file attached to FILEHANDLE, or
Xa null string at EOF.
XIf FILEHANDLE is omitted, reads from STDIN.
X.Ip "gethostbyname(NAME)" 8
X.Ip "getnetbyname(NAME)" 8
X.Ip "getprotobyname(NAME)" 8
X.Ip "getservbyname(NAME,PROTO)" 8
X.Ip "gethostbyaddr(ADDR,ADDRTYPE)" 8
X.Ip "getnetbyaddr(ADDR,ADDRTYPE)" 8
X.Ip "getprotobynumber(NUMBER)" 8
X.Ip "getservbyport(PORT,PROTO)" 8
X.Ip "gethostent()" 8
X.Ip "getnetent()" 8
X.Ip "getprotoent()" 8
X.Ip "getservent()" 8
X.Ip "sethostent(STAYOPEN)" 8
X.Ip "setnetent(STAYOPEN)" 8
X.Ip "setprotoent(STAYOPEN)" 8
X.Ip "setservent(STAYOPEN)" 8
X.Ip "endhostent()" 8
X.Ip "endnetent()" 8
X.Ip "endprotoent()" 8
X.Ip "endservent()" 8
XThese routines perform the same functions as their counterparts in the
Xsystem library.
XThe return values from the get routines are as follows:
X.nf
X
X	($name,$aliases,$addrtype,$length,@addrs) = gethost.\|.\|.
X	($name,$aliases,$addrtype,$net) = getnet.\|.\|.
X	($name,$aliases,$proto) = getproto.\|.\|.
X	($name,$aliases,$port,$proto) = getserv.\|.\|.
X
X.fi
X.Ip "getpgrp(PID)" 8 4
X.Ip "getpgrp PID" 8
XReturns the current process group for the specified PID, 0 for the current
Xprocess.
XWill produce a fatal error if used on a machine that doesn't implement
Xgetpgrp(2).
X.Ip "getppid" 8 4
XReturns the process id of the parent process.
X.Ip "getpriority(WHICH,WHO)" 8 4
XReturns the current priority for a process, a process group, or a user.
X(See getpriority(2).)
XWill produce a fatal error if used on a machine that doesn't implement
Xgetpriority(2).
X.Ip "gmtime(EXPR)" 8 4
X.Ip "gmtime EXPR" 8
XConverts a time as returned by the time function to a 9-element array with
Xthe time analyzed for the Greenwich timezone.
XTypically used as follows:
X.nf
X
X.ne 3
X    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
X
X.fi
XAll array elements are numeric, and come straight out of a struct tm.
XIn particular this means that $mon has the range 0.\|.11 and $wday has the
Xrange 0.\|.6.
X.Ip "goto LABEL" 8 6
XFinds the statement labeled with LABEL and resumes execution there.
XCurrently you may only go to statements in the main body of the program
Xthat are not nested inside a do {} construct.
XThis statement is not implemented very efficiently, and is here only to make
Xthe
X.IR sed -to- perl
Xtranslator easier.
XI may change its semantics at any time, consistent with support for translated
X.I sed
Xscripts.
XUse it at your own risk.
XBetter yet, don't use it at all.
X.Ip "grep(EXPR,LIST)" 8 4
XEvaluates EXPR for each element of LIST (locally setting $_ to each element)
Xand returns the array value consisting of those elements for which the
Xexpression evaluated to true.
X.nf
X
X	@foo = grep(!/^#/, @bar);    # weed out comments
X
X.fi
X.Ip "hex(EXPR)" 8 4
X.Ip "hex EXPR" 8
XReturns the decimal value of EXPR interpreted as an hex string.
X(To interpret strings that might start with 0 or 0x see oct().)
X.Ip "ioctl(FILEHANDLE,FUNCTION,SCALAR)" 8 4
XImplements the ioctl(2) function.
XYou'll probably have to say
X.nf
X
X	do "ioctl.h";	# probably /usr/local/lib/perl/ioctl.h
X
X.fi
Xfirst to get the correct function definitions.
XIf ioctl.h doesn't exist or doesn't have the correct definitions
Xyou'll have to roll
Xyour own, based on your C header files such as <sys/ioctl.h>.
X(There is a perl script called makelib that comes with the perl kit
Xwhich may help you in this.)
XSCALAR will be read and/or written depending on the FUNCTION\*(--a pointer
Xto the string value of SCALAR will be passed as the third argument of
Xthe actual ioctl call.
X(If SCALAR has no string value but does have a numeric value, that value
Xwill be passed rather than a pointer to the string value.
XTo guarantee this to be true, add a 0 to the scalar before using it.)
XThe pack() and unpack() functions are useful for manipulating the values
Xof structures used by ioctl().
XThe following example sets the erase character to DEL.
X.nf
X
X.ne 9
X	do 'ioctl.h';
X	$sgttyb_t = "ccccs";		# 4 chars and a short
X	if (ioctl(STDIN,$TIOCGETP,$sgttyb)) {
X		@ary = unpack($sgttyb_t,$sgttyb);
X		$ary[2] = 127;
X		$sgttyb = pack($sgttyb_t,@ary);
X		ioctl(STDIN,$TIOCSETP,$sgttyb)
X			|| die "Can't ioctl: $!";
X	}
X
X.fi
XReturns 1 on success, 0 otherwise.
X.Ip "index(STR,SUBSTR)" 8 4
XReturns the position of the first occurrence of SUBSTR in STR, based at 0, or whatever you've
Xset the $[ variable to.
XIf the substring is not found, returns one less than the base, ordinarily \-1.
X.Ip "int(EXPR)" 8 4
X.Ip "int EXPR" 8
XReturns the integer portion of EXPR.
X.Ip "join(EXPR,LIST)" 8 8
X.Ip "join(EXPR,ARRAY)" 8
XJoins the separate strings of LIST or ARRAY into a single string with fields
Xseparated by the value of EXPR, and returns the string.
XExample:
X.nf
X    
X    $_ = join(\|\':\', $login,$passwd,$uid,$gid,$gcos,$home,$shell);
X
X.fi
XSee
X.IR split .
X.Ip "keys(ASSOC_ARRAY)" 8 6
X.Ip "keys ASSOC_ARRAY" 8
XReturns a normal array consisting of all the keys of the named associative
Xarray.
XThe keys are returned in an apparently random order, but it is the same order
Xas either the values() or each() function produces (given that the associative array
Xhas not been modified).
XHere is yet another way to print your environment:
X.nf
X
X.ne 5
X	@keys = keys %ENV;
X	@values = values %ENV;
X	while ($#keys >= 0) {
X		print pop(keys), \'=\', pop(values), "\en";
X	}
X
Xor how about sorted by key:
X
X.ne 3
X	foreach $key (sort(keys %ENV)) {
X		print $key, \'=\', $ENV{$key}, "\en";
X	}
X
X.fi
X.Ip "kill(LIST)" 8 8
X.Ip "kill LIST" 8 2
XSends a signal to a list of processes.
XThe first element of the list must be the signal to send.
XReturns the number of processes successfully signaled.
X.nf
X
X	$cnt = kill 1, $child1, $child2;
X	kill 9, @goners;
X
X.fi
XIf the signal is negative, kills process groups instead of processes.
X(On System V, a negative \fIprocess\fR number will also kill process groups,
Xbut that's not portable.)
XYou may use a signal name in quotes.
X.Ip "last LABEL" 8 8
X.Ip "last" 8
XThe
X.I last
Xcommand is like the
X.I break
Xstatement in C (as used in loops); it immediately exits the loop in question.
XIf the LABEL is omitted, the command refers to the innermost enclosing loop.
XThe
X.I continue
Xblock, if any, is not executed:
X.nf
X
X.ne 4
X	line: while (<STDIN>) {
X		last line if /\|^$/;	# exit when done with header
X		.\|.\|.
X	}
X
X.fi
X.Ip "length(EXPR)" 8 4
X.Ip "length EXPR" 8
XReturns the length in characters of the value of EXPR.
X.Ip "link(OLDFILE,NEWFILE)" 8 2
XCreates a new filename linked to the old filename.
XReturns 1 for success, 0 otherwise.
X.Ip "local(LIST)" 8 4
XDeclares the listed variables to be local to the enclosing block,
Xsubroutine, eval or \*(L"do\*(R".
XAll the listed elements must be legal lvalues.
XThis operator works by saving the current values of those variables in LIST
Xon a hidden stack and restoring them upon exiting the block, subroutine or eval.
XThis means that called subroutines can also reference the local variable,
Xbut not the global one.
XThe LIST may be assigned to if desired, which allows you to initialize
Xyour local variables.
X(If no initializer is given, all scalars are initialized to the null string
Xand all arrays and associative arrays to the null array.)
XCommonly this is used to name the parameters to a subroutine.
XExamples:
X.nf
X
X.ne 13
X	sub RANGEVAL {
X		local($min, $max, $thunk) = @_;
X		local($result) = \'\';
X		local($i);
X
X		# Presumably $thunk makes reference to $i
X
X		for ($i = $min; $i < $max; $i++) {
X			$result .= eval $thunk;
X		}
X
X		$result;
X	}
X
X.ne 6
X	if ($sw eq \'-v\') {
X	    # init local array with global array
X	    local(@ARGV) = @ARGV;
X	    unshift(\'echo\',@ARGV);
X	    system @ARGV;
X	}
X	# @ARGV restored
X
X.ne 6
X	# temporarily add to digits associative array
X	if ($base12) {
X		# (NOTE: not claiming this is efficient!)
X		local(%digits) = (%digits,'t',10,'e',11);
X		do parse_num();
X	}
X
X.fi
XNote that local() is a run-time command, and so gets executed every time
Xthrough a loop, using up more stack storage each time until it's all
Xreleased at once when the loop is exited.
X.Ip "localtime(EXPR)" 8 4
X.Ip "localtime EXPR" 8
XConverts a time as returned by the time function to a 9-element array with
Xthe time analyzed for the local timezone.
XTypically used as follows:
X.nf
X
X.ne 3
X    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
X
X.fi
XAll array elements are numeric, and come straight out of a struct tm.
XIn particular this means that $mon has the range 0.\|.11 and $wday has the
Xrange 0.\|.6.
X.Ip "log(EXPR)" 8 4
X.Ip "log EXPR" 8
XReturns logarithm (base
X.IR e )
Xof EXPR.
X.Ip "m/PATTERN/io" 8 4
X.Ip "/PATTERN/io" 8
XSearches a string for a pattern match, and returns true (1) or false (\'\').
XIf no string is specified via the =~ or !~ operator,
Xthe $_ string is searched.
X(The string specified with =~ need not be an lvalue\*(--it may be the result of an expression evaluation, but remember the =~ binds rather tightly.)
XSee also the section on regular expressions.
X.Sp
XIf / is the delimiter then the initial \*(L'm\*(R' is optional.
XWith the \*(L'm\*(R' you can use any pair of characters as delimiters.
XThis is particularly useful for matching Unix path names that contain \*(L'/\*(R'.
XIf the final delimiter is followed by the optional letter \*(L'i\*(R', the matching is
Xdone in a case-insensitive manner.
XPATTERN may contain references to scalar variables, which will be interpolated
X(and the pattern recompiled) every time the pattern search is evaluated.
XIf you want such a pattern to be compiled only once, add an \*(L"o\*(R" after
Xthe trailing delimiter.
XThis avoids expensive run-time recompilations, and
Xis useful when the value you are interpolating won't change over the
Xlife of the script.
X.Sp
XIf used in a context that requires an array value, a pattern match returns an
Xarray consisting of the subexpressions matched by the parentheses in the
Xpattern,
Xi.e. ($1, $2, $3.\|.\|.).
XIt does NOT actually set $1, $2, etc. in this case, nor does it set $+, $`, $&
Xor $'.
X.Sp
XExamples:
X.nf
X
X.ne 4
X    open(tty, \'/dev/tty\');
X    <tty> \|=~ \|/\|^y\|/i \|&& \|do foo(\|);	# do foo if desired
X
X    if (/Version: \|*\|([0\-9.]*\|)\|/\|) { $version = $1; }
X
X    next if m#^/usr/spool/uucp#;
X
X.ne 5
X    # poor man's grep
X    $arg = shift;
X    while (<>) {
X	    print if /$arg/o;	# compile only once
X    }
X
X    if (($F1, $F2, $Etc) = ($foo =~ /^(\eS+)\es+(\eS+)\es*(.*)/))
X
X.fi
XThis last example splits $foo into the first two words and the remainder
Xof the line, and assigns those three fields to $F1, $F2 and $Etc.
XThe conditional is true if any variables were assigned, i.e. if the pattern
Xmatched.
X.Ip "mkdir(FILENAME,MODE)" 8 3
XCreates the directory specified by FILENAME, with permissions specified by
XMODE (as modified by umask).
XIf it succeeds it returns 1, otherwise it returns 0 and sets $! (errno).
!STUFFY!FUNK!
echo Extracting perl.y
sed >perl.y <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: perl.y,v 2.0.1.6 88/11/19 00:04:01 lwall Locked $
X *
X *    Copyright (c) 1989, Larry Wall
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the perl 3.0 kit.
X *
X * $Log:	perl.y,v $
X */
X
X%{
X#include "INTERN.h"
X#include "perl.h"
X
XSTAB *scrstab;
XARG *arg4;	/* rarely used arguments to make_op() */
XARG *arg5;
X
X%}
X
X%start prog
X
X%union {
X    int	ival;
X    char *cval;
X    ARG *arg;
X    CMD *cmdval;
X    struct compcmd compval;
X    STAB *stabval;
X    FCMD *formval;
X}
X
X%token <cval> WORD
X%token <ival> APPEND OPEN SELECT LOOPEX
X%token <ival> USING FORMAT DO SHIFT PUSH POP LVALFUN
X%token <ival> WHILE UNTIL IF UNLESS ELSE ELSIF CONTINUE SPLIT FLIST
X%token <ival> FOR FILOP FILOP2 FILOP3 FILOP4 FILOP22 FILOP25
X%token <ival> FUNC0 FUNC1 FUNC2 FUNC3 HSHFUN HSHFUN3
X%token <ival> FLIST2 SUB FILETEST LOCAL DELETE
X%token <ival> RELOP EQOP MULOP ADDOP PACKAGE AMPER LFUNC4
X%token <formval> FORMLIST
X%token <stabval> REG ARYLEN ARY HSH STAR
X%token <arg> SUBST PATTERN
X%token <arg> RSTRING TRANS
X
X%type <ival> prog decl format remember
X%type <stabval>
X%type <cmdval> block lineseq line loop cond sideff nexpr else
X%type <arg> expr sexpr cexpr csexpr term handle aryword hshword
X%type <arg> condmod loopmod
X%type <arg> texpr listop
X%type <cval> label
X%type <compval> compblock
X
X%nonassoc <ival> LISTOP
X%left ','
X%right '='
X%right '?' ':'
X%nonassoc DOTDOT
X%left OROR
X%left ANDAND
X%left '|' '^'
X%left '&'
X%nonassoc EQOP
X%nonassoc RELOP
X%nonassoc <ival> UNIOP
X%nonassoc FILETEST
X%left LS RS
X%left ADDOP
X%left MULOP
X%left MATCH NMATCH 
X%right '!' '~' UMINUS
X%right POW
X%nonassoc INC DEC
X%left '('
X
X%% /* RULES */
X
Xprog	:	lineseq
X			{ if (in_eval)
X				eval_root = block_head($1);
X			    else
X				main_root = block_head($1); }
X	;
X
Xcompblock:	block CONTINUE block
X			{ $$.comp_true = $1; $$.comp_alt = $3; }
X	|	block else
X			{ $$.comp_true = $1; $$.comp_alt = $2; }
X	;
X
Xelse	:	/* NULL */
X			{ $$ = Nullcmd; }
X	|	ELSE block
X			{ $$ = $2; }
X	|	ELSIF '(' expr ')' compblock
X			{ cmdline = $1;
X			    $$ = make_ccmd(C_ELSIF,$3,$5); }
X	;
X
Xblock	:	'{' remember lineseq '}'
X			{ $$ = block_head($3);
X			  if (savestack->ary_fill > $2)
X			    restorelist($2); }
X	;
X
Xremember:	/* NULL */	/* in case they push a package name */
X			{ $$ = savestack->ary_fill; }
X	;
X
Xlineseq	:	/* NULL */
X			{ $$ = Nullcmd; }
X	|	lineseq line
X			{ $$ = append_line($1,$2); }
X	;
X
Xline	:	decl
X			{ $$ = Nullcmd; }
X	|	label cond
X			{ $$ = add_label($1,$2); }
X	|	loop	/* loops add their own labels */
X	|	label ';'
X			{ if ($1 != Nullch) {
X			      $$ = add_label($1, make_acmd(C_EXPR, Nullstab,
X				  Nullarg, Nullarg) );
X			    } else
X			      $$ = Nullcmd; }
X	|	label sideff ';'
X			{ $$ = add_label($1,$2); }
X	;
X
Xsideff	:	error
X			{ $$ = Nullcmd; }
X	|	expr
X			{ $$ = make_acmd(C_EXPR, Nullstab, $1, Nullarg); }
X	|	expr condmod
X			{ $$ = addcond(
X			       make_acmd(C_EXPR, Nullstab, Nullarg, $1), $2); }
X	|	expr loopmod
X			{ $$ = addloop(
X			       make_acmd(C_EXPR, Nullstab, Nullarg, $1), $2); }
X	;
X
Xcond	:	IF '(' expr ')' compblock
X			{ cmdline = $1;
X			    $$ = make_icmd(C_IF,$3,$5); }
X	|	UNLESS '(' expr ')' compblock
X			{ cmdline = $1;
X			    $$ = invert(make_icmd(C_IF,$3,$5)); }
X	|	IF block compblock
X			{ cmdline = $1;
X			    $$ = make_ccmd(C_IF,cmd_to_arg($2),$3); }
X	|	UNLESS block compblock
X			{ cmdline = $1;
X			    $$ = invert(make_ccmd(C_IF,cmd_to_arg($2),$3)); }
X	;
X
Xloop	:	label WHILE '(' texpr ')' compblock
X			{ cmdline = $2;
X			    $$ = wopt(add_label($1,
X			    make_ccmd(C_WHILE,$4,$6) )); }
X	|	label UNTIL '(' expr ')' compblock
X			{ cmdline = $2;
X			    $$ = wopt(add_label($1,
X			    invert(make_ccmd(C_WHILE,$4,$6)) )); }
X	|	label WHILE block compblock
X			{ cmdline = $2;
X			    $$ = wopt(add_label($1,
X			    make_ccmd(C_WHILE, cmd_to_arg($3),$4) )); }
X	|	label UNTIL block compblock
X			{ cmdline = $2;
X			    $$ = wopt(add_label($1,
X			    invert(make_ccmd(C_WHILE, cmd_to_arg($3),$4)) )); }
X	|	label FOR REG '(' expr ')' compblock
X			{ cmdline = $2;
X			    /*
X			     * The following gobbledygook catches EXPRs that
X			     * aren't explicit array refs and translates
X			     *		foreach VAR (EXPR) {
X			     * into
X			     *		@ary = EXPR;
X			     *		foreach VAR (@ary) {
X			     * where @ary is a hidden array made by genstab().
X			     * (Note that @ary may become a local array if
X			     * it is determined that it might be called
X			     * recursively.  See cmd_tosave().)
X			     */
X			    if ($5->arg_type != O_ARRAY) {
X				scrstab = aadd(genstab());
X				$$ = append_line(
X				    make_acmd(C_EXPR, Nullstab,
X				      l(make_op(O_ASSIGN,2,
X					listish(make_op(O_ARRAY, 1,
X					  stab2arg(A_STAB,scrstab),
X					  Nullarg,Nullarg, 1)),
X					listish($5),
X					Nullarg)),
X				      Nullarg),
X				    wopt(over($3,add_label($1,
X				      make_ccmd(C_WHILE,
X					make_op(O_ARRAY, 1,
X					  stab2arg(A_STAB,scrstab),
X					  Nullarg,Nullarg ),
X					$7)))));
X			    }
X			    else {
X				$$ = wopt(over($3,add_label($1,
X				make_ccmd(C_WHILE,$5,$7) )));
X			    }
X			}
X	|	label FOR '(' expr ')' compblock
X			{ cmdline = $2;
X			    if ($4->arg_type != O_ARRAY) {
X				scrstab = aadd(genstab());
X				$$ = append_line(
X				    make_acmd(C_EXPR, Nullstab,
X				      l(make_op(O_ASSIGN,2,
X					listish(make_op(O_ARRAY, 1,
X					  stab2arg(A_STAB,scrstab),
X					  Nullarg,Nullarg, 1 )),
X					listish($4),
X					Nullarg)),
X				      Nullarg),
X				    wopt(over(defstab,add_label($1,
X				      make_ccmd(C_WHILE,
X					make_op(O_ARRAY, 1,
X					  stab2arg(A_STAB,scrstab),
X					  Nullarg,Nullarg ),
X					$6)))));
X			    }
X			    else {	/* lisp, anyone? */
X				$$ = wopt(over(defstab,add_label($1,
X				make_ccmd(C_WHILE,$4,$6) )));
X			    }
X			}
X	|	label FOR '(' nexpr ';' texpr ';' nexpr ')' block
X			/* basically fake up an initialize-while lineseq */
X			{   yyval.compval.comp_true = $10;
X			    yyval.compval.comp_alt = $8;
X			    cmdline = $2;
X			    $$ = append_line($4,wopt(add_label($1,
X				make_ccmd(C_WHILE,$6,yyval.compval) ))); }
X	|	label compblock	/* a block is a loop that happens once */
X			{ $$ = add_label($1,make_ccmd(C_BLOCK,Nullarg,$2)); }
X	;
X
Xnexpr	:	/* NULL */
X			{ $$ = Nullcmd; }
X	|	sideff
X	;
X
Xtexpr	:	/* NULL means true */
X			{ (void)scanstr("1"); $$ = yylval.arg; }
X	|	expr
X	;
X
Xlabel	:	/* empty */
X			{ $$ = Nullch; }
X	|	WORD ':'
X	;
X
Xloopmod :	WHILE expr
X			{ $$ = $2; }
X	|	UNTIL expr
X			{ $$ = make_op(O_NOT,1,$2,Nullarg,Nullarg); }
X	;
X
Xcondmod :	IF expr
X			{ $$ = $2; }
X	|	UNLESS expr
X			{ $$ = make_op(O_NOT,1,$2,Nullarg,Nullarg); }
X	;
X
Xdecl	:	format
X			{ $$ = 0; }
X	|	subrout
X			{ $$ = 0; }
X	|	package
X			{ $$ = 0; }
X	;
X
Xformat	:	FORMAT WORD '=' FORMLIST
X			{ stab_form(stabent($2,TRUE)) = $4; Safefree($2);}
X	|	FORMAT '=' FORMLIST
X			{ stab_form(stabent("STDOUT",TRUE)) = $3; }
X	;
X
Xsubrout	:	SUB WORD block
X			{ make_sub($2,$3); }
X	;
X
Xpackage :	PACKAGE WORD ';'
X			{ char tmpbuf[256];
X
X			  savehptr(&curstash);
X			  saveitem(curstname);
X			  str_set(curstname,$2);
X			  sprintf(tmpbuf,"'_%s",$2);
X			  curstash = stab_xhash(hadd(stabent(tmpbuf,TRUE)));
X			  curstash->tbl_coeffsize = 0;
X			  Safefree($2);
X			}
X	;
X
Xcexpr	:	',' expr
X			{ $$ = $2; }
X	;
X
Xexpr	:	expr ',' sexpr
X			{ $$ = make_op(O_COMMA, 2, $1, $3, Nullarg); }
X	|	sexpr
X	;
X
Xcsexpr	:	',' sexpr
X			{ $$ = $2; }
X	;
X
Xsexpr	:	sexpr '=' sexpr
X			{   $1 = listish($1);
X			    if ($1->arg_type == O_ASSIGN && $1->arg_len == 1)
X				$1->arg_type = O_ITEM;	/* a local() */
X			    if ($1->arg_type == O_LIST)
X				$3 = listish($3);
X			    $$ = l(make_op(O_ASSIGN, 2, $1, $3, Nullarg)); }
X	|	sexpr POW '=' sexpr
X			{ $$ = l(make_op(O_POW, 2, $1, $4, Nullarg)); }
X	|	sexpr MULOP '=' sexpr
X			{ $$ = l(make_op($2, 2, $1, $4, Nullarg)); }
X	|	sexpr ADDOP '=' sexpr
X			{ $$ = rcatmaybe(l(make_op($2, 2, $1, $4, Nullarg)));}
X	|	sexpr LS '=' sexpr
X			{ $$ = l(make_op(O_LEFT_SHIFT, 2, $1, $4, Nullarg)); }
X	|	sexpr RS '=' sexpr
X			{ $$ = l(make_op(O_RIGHT_SHIFT, 2, $1, $4, Nullarg)); }
X	|	sexpr '&' '=' sexpr
X			{ $$ = l(make_op(O_BIT_AND, 2, $1, $4, Nullarg)); }
X	|	sexpr '^' '=' sexpr
X			{ $$ = l(make_op(O_XOR, 2, $1, $4, Nullarg)); }
X	|	sexpr '|' '=' sexpr
X			{ $$ = l(make_op(O_BIT_OR, 2, $1, $4, Nullarg)); }
X
X
X	|	sexpr POW sexpr
X			{ $$ = make_op(O_POW, 2, $1, $3, Nullarg); }
X	|	sexpr MULOP sexpr
X			{ $$ = make_op($2, 2, $1, $3, Nullarg); }
X	|	sexpr ADDOP sexpr
X			{ $$ = make_op($2, 2, $1, $3, Nullarg); }
X	|	sexpr LS sexpr
X			{ $$ = make_op(O_LEFT_SHIFT, 2, $1, $3, Nullarg); }
X	|	sexpr RS sexpr
X			{ $$ = make_op(O_RIGHT_SHIFT, 2, $1, $3, Nullarg); }
X	|	sexpr RELOP sexpr
X			{ $$ = make_op($2, 2, $1, $3, Nullarg); }
X	|	sexpr EQOP sexpr
X			{ $$ = make_op($2, 2, $1, $3, Nullarg); }
X	|	sexpr '&' sexpr
X			{ $$ = make_op(O_BIT_AND, 2, $1, $3, Nullarg); }
X	|	sexpr '^' sexpr
X			{ $$ = make_op(O_XOR, 2, $1, $3, Nullarg); }
X	|	sexpr '|' sexpr
X			{ $$ = make_op(O_BIT_OR, 2, $1, $3, Nullarg); }
X	|	sexpr DOTDOT sexpr
X			{ arg4 = Nullarg;
X			  $$ = make_op(O_F_OR_R, 4, $1, $3, Nullarg); }
X	|	sexpr ANDAND sexpr
X			{ $$ = make_op(O_AND, 2, $1, $3, Nullarg); }
X	|	sexpr OROR sexpr
X			{ $$ = make_op(O_OR, 2, $1, $3, Nullarg); }
X	|	sexpr '?' sexpr ':' sexpr
X			{ $$ = make_op(O_COND_EXPR, 3, $1, $3, $5); }
X	|	sexpr MATCH sexpr
X			{ $$ = mod_match(O_MATCH, $1, $3); }
X	|	sexpr NMATCH sexpr
X			{ $$ = mod_match(O_NMATCH, $1, $3); }
X	|	term INC
X			{ $$ = addflags(1, AF_POST|AF_UP,
X			    l(make_op(O_ITEM,1,$1,Nullarg,Nullarg))); }
X	|	term DEC
X			{ $$ = addflags(1, AF_POST,
X			    l(make_op(O_ITEM,1,$1,Nullarg,Nullarg))); }
X	|	INC term
X			{ $$ = addflags(1, AF_PRE|AF_UP,
X			    l(make_op(O_ITEM,1,$2,Nullarg,Nullarg))); }
X	|	DEC term
X			{ $$ = addflags(1, AF_PRE,
X			    l(make_op(O_ITEM,1,$2,Nullarg,Nullarg))); }
X	|	term
X			{ $$ = $1; }
X	;
X
Xterm	:	'-' term %prec UMINUS
X			{ $$ = make_op(O_NEGATE, 1, $2, Nullarg, Nullarg); }
X	|	'+' term %prec UMINUS
X			{ $$ = $2; }
X	|	'!' term
X			{ $$ = make_op(O_NOT, 1, $2, Nullarg, Nullarg); }
X	|	'~' term
X			{ $$ = make_op(O_COMPLEMENT, 1, $2, Nullarg, Nullarg);}
X	|	FILETEST WORD
X			{ opargs[$1] = 0;	/* force it special */
X			    $$ = make_op($1, 1,
X				stab2arg(A_STAB,stabent($2,TRUE)),
X				Nullarg, Nullarg);
X			}
X	|	FILETEST sexpr
X			{ opargs[$1] = 1;
X			    $$ = make_op($1, 1, $2, Nullarg, Nullarg); }
X	|	FILETEST
X			{ opargs[$1] = ($1 != O_FTTTY);
X			    $$ = make_op($1, 1,
X				stab2arg(A_STAB,
X				  $1 == O_FTTTY?stabent("STDIN",TRUE):defstab),
X				Nullarg, Nullarg); }
X	|	LOCAL '(' expr ')'
X			{ $$ = l(make_op(O_ITEM, 1,
X				localize(listish(make_list($3))),
X				Nullarg,Nullarg)); }
X	|	'(' expr ')'
X			{ $$ = make_list(hide_ary($2)); }
X	|	'(' ')'
X			{ $$ = make_list(Nullarg); }
X	|	DO sexpr	%prec FILETEST
X			{ $$ = fixeval(
X			    make_op(O_DOFILE,2,$2,Nullarg,Nullarg) );
X			  allstabs = TRUE;}
X	|	DO block	%prec '('
X			{ $$ = cmd_to_arg($2); }
X	|	REG	%prec '('
X			{ $$ = stab2arg(A_STAB,$1); }
X	|	STAR	%prec '('
X			{ $$ = stab2arg(A_STAR,$1); }
X	|	REG '[' expr ']'	%prec '('
X			{ $$ = make_op(O_AELEM, 2,
X				stab2arg(A_STAB,aadd($1)), $3, Nullarg); }
X	|	HSH 	%prec '('
X			{ $$ = make_op(O_HASH, 1,
X				stab2arg(A_STAB,$1),
X				Nullarg, Nullarg); }
X	|	ARY 	%prec '('
X			{ $$ = make_op(O_ARRAY, 1,
X				stab2arg(A_STAB,$1),
X				Nullarg, Nullarg); }
X	|	REG '{' expr '}'	%prec '('
X			{ $$ = make_op(O_HELEM, 2,
X				stab2arg(A_STAB,hadd($1)),
X				jmaybe($3),
X				Nullarg); }
X	|	ARY '[' expr ']'	%prec '('
X			{ $$ = make_op(O_ASLICE, 2,
X				stab2arg(A_STAB,aadd($1)),
X				listish(make_list($3)),
X				Nullarg); }
X	|	ARY '{' expr '}'	%prec '('
X			{ $$ = make_op(O_HSLICE, 2,
X				stab2arg(A_STAB,hadd($1)),
X				listish(make_list($3)),
X				Nullarg); }
X	|	DELETE REG '{' expr '}'	%prec '('
X			{ $$ = make_op(O_DELETE, 2,
X				stab2arg(A_STAB,hadd($2)),
X				jmaybe($4),
X				Nullarg); }
X	|	ARYLEN	%prec '('
X			{ $$ = stab2arg(A_ARYLEN,$1); }
X	|	RSTRING	%prec '('
X			{ $$ = $1; }
X	|	PATTERN	%prec '('
X			{ $$ = $1; }
X	|	SUBST	%prec '('
X			{ $$ = $1; }
X	|	TRANS	%prec '('
X			{ $$ = $1; }
X	|	DO WORD '(' expr ')'
X			{ $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
X				stab2arg(A_WORD,stabent($2,TRUE)),
X				make_list($4),
X				Nullarg); Safefree($2); }
X	|	AMPER WORD '(' expr ')'
X			{ $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
X				stab2arg(A_WORD,stabent($2,TRUE)),
X				make_list($4),
X				Nullarg); Safefree($2); }
X	|	DO WORD '(' ')'
X			{ $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
X				stab2arg(A_WORD,stabent($2,TRUE)),
X				make_list(Nullarg),
X				Nullarg); }
X	|	AMPER WORD '(' ')'
X			{ $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
X				stab2arg(A_WORD,stabent($2,TRUE)),
X				make_list(Nullarg),
X				Nullarg); }
X	|	AMPER WORD
X			{ $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
X				stab2arg(A_WORD,stabent($2,TRUE)),
X				Nullarg,
X				Nullarg); }
X	|	DO REG '(' expr ')'
X			{ $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
X				stab2arg(A_STAB,$2),
X				make_list($4),
X				Nullarg); }
X	|	DO REG '(' ')'
X			{ $$ = make_op((perldb ? O_DBSUBR : O_SUBR), 2,
X				stab2arg(A_STAB,$2),
X				make_list(Nullarg),
X				Nullarg); }
X	|	LOOPEX
X			{ $$ = make_op($1,0,Nullarg,Nullarg,Nullarg); }
X	|	LOOPEX WORD
X			{ $$ = make_op($1,1,cval_to_arg($2),
X			    Nullarg,Nullarg); }
X	|	UNIOP
X			{ $$ = make_op($1,1,Nullarg,Nullarg,Nullarg);
X			  if ($1 == O_EVAL || $1 == O_RESET)
X			    $$ = fixeval($$); }
X	|	UNIOP sexpr
X			{ $$ = make_op($1,1,$2,Nullarg,Nullarg);
X			  if ($1 == O_EVAL || $1 == O_RESET)
X			    $$ = fixeval($$); }
X	|	SELECT '(' handle ')'
X			{ $$ = make_op(O_SELECT, 1, $3, Nullarg, Nullarg); }
X	|	SELECT '(' sexpr csexpr csexpr csexpr ')'
X			{ arg4 = $6;
X			  $$ = make_op(O_SSELECT, 4, $3, $4, $5); }
X	|	OPEN WORD	%prec '('
X			{ $$ = make_op(O_OPEN, 2,
X			    stab2arg(A_WORD,stabent($2,TRUE)),
X			    stab2arg(A_STAB,stabent($2,TRUE)),
X			    Nullarg); }
X	|	OPEN '(' WORD ')'
X			{ $$ = make_op(O_OPEN, 2,
X			    stab2arg(A_WORD,stabent($3,TRUE)),
X			    stab2arg(A_STAB,stabent($3,TRUE)),
X			    Nullarg); }
X	|	OPEN '(' handle cexpr ')'
X			{ $$ = make_op(O_OPEN, 2,
X			    $3,
X			    $4, Nullarg); }
X	|	FILOP '(' handle ')'
X			{ $$ = make_op($1, 1,
X			    $3,
X			    Nullarg, Nullarg); }
X	|	FILOP WORD
X			{ $$ = make_op($1, 1,
X			    stab2arg(A_WORD,stabent($2,TRUE)),
X			    Nullarg, Nullarg);
X			  Safefree($2); }
X	|	FILOP REG
X			{ $$ = make_op($1, 1,
X			    stab2arg(A_STAB,$2),
X			    Nullarg, Nullarg); }
X	|	FILOP '(' ')'
X			{ $$ = make_op($1, 1,
X			    stab2arg(A_WORD,Nullstab),
X			    Nullarg, Nullarg); }
X	|	FILOP	%prec '('
X			{ $$ = make_op($1, 0,
X			    Nullarg, Nullarg, Nullarg); }
X	|	FILOP2 '(' handle cexpr ')'
X			{ $$ = make_op($1, 2, $3, $4, Nullarg); }
X	|	FILOP3 '(' handle csexpr cexpr ')'
X			{ $$ = make_op($1, 3, $3, $4, $5); }
X	|	FILOP22 '(' handle ',' handle ')'
X			{ $$ = make_op($1, 2, $3, $5, Nullarg); }
X	|	FILOP4 '(' handle csexpr csexpr cexpr ')'
X			{ arg4 = $6; $$ = make_op($1, 4, $3, $4, $5); }
X	|	FILOP25 '(' handle ',' handle csexpr csexpr cexpr ')'
X			{ arg4 = $7; arg5 = $8;
X			  $$ = make_op($1, 5, $3, $5, $6); }
X	|	PUSH '(' aryword cexpr ')'
X			{ $$ = make_op($1, 2,
X			    $3,
X			    make_list($4),
X			    Nullarg); }
X	|	POP aryword	%prec '('
X			{ $$ = make_op(O_POP, 1, $2, Nullarg, Nullarg); }
X	|	POP '(' aryword ')'
X			{ $$ = make_op(O_POP, 1, $3, Nullarg, Nullarg); }
X	|	SHIFT aryword	%prec '('
X			{ $$ = make_op(O_SHIFT, 1, $2, Nullarg, Nullarg); }
X	|	SHIFT '(' aryword ')'
X			{ $$ = make_op(O_SHIFT, 1, $3, Nullarg, Nullarg); }
X	|	SHIFT	%prec '('
X			{ $$ = make_op(O_SHIFT, 1,
X			    stab2arg(A_STAB,aadd(stabent("ARGV",TRUE))),
X			    Nullarg, Nullarg); }
X	|	SPLIT	%prec '('
X			{ (void)scanpat("/\\s+/");
X			    $$ = make_split(defstab,yylval.arg,Nullarg); }
X	|	SPLIT '(' sexpr csexpr csexpr ')'
X			{ $$ = mod_match(O_MATCH, $4,
X			  make_split(defstab,$3,$5));}
X	|	SPLIT '(' sexpr csexpr ')'
X			{ $$ = mod_match(O_MATCH, $4,
X			  make_split(defstab,$3,Nullarg) ); }
X	|	SPLIT '(' sexpr ')'
X			{ $$ = mod_match(O_MATCH,
X			    stab2arg(A_STAB,defstab),
X			    make_split(defstab,$3,Nullarg) ); }
X	|	FLIST2 '(' sexpr cexpr ')'
X			{ $$ = make_op($1, 2,
X			    $3,
X			    listish(make_list($4)),
X			    Nullarg); }
X	|	FLIST '(' expr ')'
X			{ $$ = make_op($1, 1,
X			    make_list($3),
X			    Nullarg,
X			    Nullarg); }
X	|	LVALFUN sexpr	%prec '('
X			{ $$ = l(make_op($1, 1, fixl($1,$2),
X			    Nullarg, Nullarg)); }
X	|	LVALFUN
X			{ $$ = l(make_op($1, 1,
X			    stab2arg(A_STAB,defstab),
X			    Nullarg, Nullarg)); }
X	|	FUNC0
X			{ $$ = make_op($1, 0, Nullarg, Nullarg, Nullarg); }
X	|	FUNC1 '(' expr ')'
X			{ $$ = make_op($1, 1, $3, Nullarg, Nullarg); }
X	|	FUNC2 '(' sexpr cexpr ')'
X			{ $$ = make_op($1, 2, $3, $4, Nullarg);
X			    if ($1 == O_INDEX && $$[2].arg_type == A_SINGLE)
X				fbmcompile($$[2].arg_ptr.arg_str,0); }
X	|	FUNC3 '(' sexpr csexpr cexpr ')'
X			{ $$ = make_op($1, 3, $3, $4, $5); }
X	|	LFUNC4 '(' sexpr csexpr csexpr cexpr ')'
X			{ arg4 = $6; $$ = make_op($1, 4, l($3), $4, $5); }
X	|	HSHFUN '(' hshword ')'
X			{ $$ = make_op($1, 1,
X				$3,
X				Nullarg,
X				Nullarg); }
X	|	HSHFUN hshword
X			{ $$ = make_op($1, 1,
X				$2,
X				Nullarg,
X				Nullarg); }
X	|	HSHFUN3 '(' hshword csexpr cexpr ')'
X			{ $$ = make_op($1, 3, $3, $4, $5); }
X	|	listop
X	;
X
Xlistop	:	LISTOP
X			{ $$ = make_op($1,2,
X				stab2arg(A_WORD,Nullstab),
X				stab2arg(A_STAB,defstab),
X				Nullarg); }
X	|	LISTOP expr
X			{ $$ = make_op($1,2,
X				stab2arg(A_WORD,Nullstab),
X				maybelistish($1,make_list($2)),
X				Nullarg); }
X	|	LISTOP WORD
X			{ $$ = make_op($1,2,
X				stab2arg(A_WORD,stabent($2,TRUE)),
X				stab2arg(A_STAB,defstab),
X				Nullarg); }
X	|	LISTOP WORD expr
X			{ $$ = make_op($1,2,
X				stab2arg(A_WORD,stabent($2,TRUE)),
X				maybelistish($1,make_list($3)),
X				Nullarg); Safefree($2); }
X	|	LISTOP REG expr
X			{ $$ = make_op($1,2,
X				stab2arg(A_STAB,$2),
X				maybelistish($1,make_list($3)),
X				Nullarg); }
X	;
X
Xhandle	:	WORD
X			{ $$ = stab2arg(A_WORD,stabent($1,TRUE)); Safefree($1);}
X	|	sexpr
X	;
X
Xaryword	:	WORD
X			{ $$ = stab2arg(A_WORD,aadd(stabent($1,TRUE)));
X			    Safefree($1); }
X	|	ARY
X			{ $$ = stab2arg(A_STAB,$1); }
X	;
X
Xhshword	:	WORD
X			{ $$ = stab2arg(A_WORD,hadd(stabent($1,TRUE)));
X			    Safefree($1); }
X	|	HSH
X			{ $$ = stab2arg(A_STAB,$1); }
X	;
X
X%% /* PROGRAM */
!STUFFY!FUNK!
echo ""
echo "End of kit 10 (of 23)"
cat /dev/null >kit10isdone
run=''
config=''
for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23; do
    if test -f kit${iskit}isdone; then
	run="$run $iskit"
    else
	todo="$todo $iskit"
    fi
done
case $todo in
    '')
	echo "You have run all your kits.  Please read README and then type Configure."
	chmod 755 Configure
	;;
    *)  echo "You have run$run."
	echo "You still need to run$todo."
	;;
esac
: Someone might mail this, so...
exit