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

lwall@jato.Jpl.Nasa.Gov (Larry Wall) (09/03/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 6 (of 23).  If kit 6 is complete, the line"
echo '"'"End of kit 6 (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.4
sed >perl.man.4 <<'!STUFFY!FUNK!' -e 's/X//'
X''' Beginning of part 4
X''' $Header$
X'''
X''' $Log$
X.Sh "Precedence"
X.I Perl
Xoperators have the following associativity and precedence:
X.nf
X
Xnonassoc\h'|1i'print printf exec system sort reverse
X\h'1.5i'chmod chown kill unlink utime die
Xleft\h'|1i',
Xright\h'|1i'= += \-= *= etc.
Xright\h'|1i'?:
Xnonassoc\h'|1i'.\|.
Xleft\h'|1i'||
Xleft\h'|1i'&&
Xleft\h'|1i'| ^
Xleft\h'|1i'&
Xnonassoc\h'|1i'== != eq ne
Xnonassoc\h'|1i'< > <= >= lt gt le ge
Xnonassoc\h'|1i'chdir exit eval reset sleep rand umask
Xnonassoc\h'|1i'\-r \-w \-x etc.
Xleft\h'|1i'<< >>
Xleft\h'|1i'+ \- .
Xleft\h'|1i'* / % x
Xleft\h'|1i'=~ !~ 
Xright\h'|1i'! ~ and unary minus
Xright\h'|1i'**
Xnonassoc\h'|1i'++ \-\|\-
Xleft\h'|1i'\*(L'(\*(R'
X
X.fi
XAs mentioned earlier, if any list operator (print, etc.) or
Xany unary operator (chdir, etc.)
Xis immediately followed by a left parenthesis, without any intervening
Xspace, the operator and arguments within parentheses are taken to
Xbe of highest precedence, just like a normal function call.
X(This follows the principle of least surprise unless you happen to
Xbe the sort of person who always puts a space between the function name
Xand the left parenthesis.)
XExamples:
X.nf
X
X	chdir $foo || die;	# (chdir $foo) || die
X	chdir($foo) || die;	# (chdir $foo) || die
X	chdir ($foo) || die;	# (chdir $foo) || die
X
Xbut, because + is higher precedence than ||:
X
X	chdir $foo + 20;	# chdir ($foo + 20)
X	chdir($foo) + 20;	# (chdir $foo) + 20
X	chdir ($foo) + 20;	# chdir ($foo + 20)
X
X	rand 10 + 20;		# rand (10 + 20)
X	rand(10) + 20;		# (rand 10) + 20
X	rand (10) + 20;		# rand (10 + 20)
X
X.fi
XIn the absence of parentheses,
Xthe precedence of list operators such as print, sort or chmod is
Xeither very high or very low depending on whether you look at the left
Xside of operator or the right side of it.
XFor example, in
X.nf
X
X	@ary = (1, 3, sort 4, 2);
X	print @ary;		# prints 1324
X
X.fi
Xthe commas on the right of the sort are evaluated before the sort, but
Xthe commas on the left are evaluated after.
XIn other words, list operators tend to gobble up all the arguments that
Xfollow them, and then act like a simple term with regard to the preceding
Xexpression.
XThis means that parentheses don't necessarily do what you expect if you
Xput a space after the list operator:
X.nf
X
X.ne 7
X	# These evaluate exit before doing the print:
X	print ($foo, exit);	# Obviously not what you want.
X	print $foo, exit;	# Nor is this.
X	print ($foo), exit;	# Nor this!
X
X	# These do the print before evaluating exit:
X	(print $foo), exit;	# This is what you want.
X	print($foo), exit;	# Or this.
X
X.fi
X.Sh "Subroutines"
XA subroutine may be declared as follows:
X.nf
X
X    sub NAME BLOCK
X
X.fi
X.PP
XAny arguments passed to the routine come in as array @_,
Xthat is ($_[0], $_[1], .\|.\|.).
XThe return value of the subroutine is the value of the last expression
Xevaluated, and can be either an array value or a scalar value.
XAlternately, a return statement may be used to specify the returned value and
Xexit the subroutine.
XTo create local variables see the
X.I local
Xoperator.
X.PP
XA subroutine is called using the
X.I do
Xoperator or the & operator.
X.nf
X
X.ne 12
XExample:
X
X	sub MAX {
X		local($max) = pop(@_);
X		foreach $foo (@_) {
X			$max = $foo \|if \|$max < $foo;
X		}
X		$max;
X	}
X
X	.\|.\|.
X	$bestday = &MAX($mon,$tue,$wed,$thu,$fri);
X
X.ne 21
XExample:
X
X	# get a line, combining continuation lines
X	#  that start with whitespace
X	sub get_line {
X		$thisline = $lookahead;
X		line: while ($lookahead = <STDIN>) {
X			if ($lookahead \|=~ \|/\|^[ \^\e\|t]\|/\|) {
X				$thisline \|.= \|$lookahead;
X			}
X			else {
X				last line;
X			}
X		}
X		$thisline;
X	}
X
X	$lookahead = <STDIN>;	# get first line
X	while ($_ = do get_line(\|)) {
X		.\|.\|.
X	}
X
X.fi
X.nf
X.ne 6
XUse array assignment to a local list to name your formal arguments:
X
X	sub maybeset {
X		local($key, $value) = @_;
X		$foo{$key} = $value unless $foo{$key};
X	}
X
X.fi
XSubroutines may be called recursively.
XIf a subroutine is called using the & form, the argument list is optional.
XIf omitted, no @_ array is set up for the subroutine; the @_ array at the
Xtime of the call is visible to subroutine instead.
X.nf
X
X	do foo(1,2,3);		# pass three arguments
X	&foo(1,2,3);		# the same
X
X	do foo();		# pass a null list
X	&foo();			# the same
X	&foo;			# pass no arguments--more efficient
X
X.fi
X.Sh "Passing By Reference"
XSometimes you don't want to pass the value of something to a subroutine but
Xrather the name of it, so that the subroutine can modify the global copy
Xof it rather than working with a local copy.
XIn perl you can refer to all the objects of a particular name by prefixing
Xthe name with a star: *foo.
XWhen evaluated, it produces a scalar value that represents all the objects
Xof that name.
XWhen assigned to within a local() operation, it causes the name mentioned
Xto refer to whatever * value was assigned to it.
XExample:
X.nf
X
X	sub doubleary {
X	    local(*someary) = @_;
X	    foreach $elem (@someary) {
X		$elem *= 2;
X	    }
X	}
X	do doubleary(*foo);
X	do doubleary(*bar);
X
X.fi
XAssignment to *name is currently recommended only inside a local().
XYou can actually assign to *name anywhere, but the previous referent of
X*name may be stranded forever.
XThis may or may not bother you.
X.Sh "Regular Expressions"
XThe patterns used in pattern matching are regular expressions such as
Xthose supplied in the Version 8 regexp routines.
X(In fact, the routines are derived from Henry Spencer's freely redistributable
Xreimplementation of the V8 routines.)
XIn addition, \ew matches an alphanumeric character (including \*(L"_\*(R") and \eW a nonalphanumeric.
XWord boundaries may be matched by \eb, and non-boundaries by \eB.
XA whitespace character is matched by \es, non-whitespace by \eS.
XA numeric character is matched by \ed, non-numeric by \eD.
XYou may use \ew, \es and \ed within character classes.
XAlso, \en, \er, \ef, \et and \eNNN have their normal interpretations.
XWithin character classes \eb represents backspace rather than a word boundary.
XAlternatives may be separated by |.
XThe bracketing construct \|(\ .\|.\|.\ \|) may also be used, in which case \e<digit>
Xmatches the digit'th substring, where digit can range from 1 to 9.
X(Outside of the pattern, always use $ instead of \e in front of the digit.
XThe scope of $<digit> (and $\`, $& and $\')
Xextends to the end of the enclosing BLOCK or eval string, or to
Xthe next pattern match with subexpressions.
XThe \e<digit> notation sometimes works outside the current pattern, but should
Xnot be relied upon.)
X$+ returns whatever the last bracket match matched.
X$& returns the entire matched string.
X($0 normally returns the same thing, but don't depend on it.)
X$\` returns everything before the matched string.
X$\' returns everything after the matched string.
XExamples:
X.nf
X    
X	s/\|^\|([^ \|]*\|) \|*([^ \|]*\|)\|/\|$2 $1\|/;	# swap first two words
X
X.ne 5
X	if (/\|Time: \|(.\|.\|):\|(.\|.\|):\|(.\|.\|)\|/\|) {
X		$hours = $1;
X		$minutes = $2;
X		$seconds = $3;
X	}
X
X.fi
XBy default, the ^ character matches only the beginning of the string,
Xthe $ character matches only at the end (or before the newline at the end)
Xand
X.I perl
Xdoes certain optimizations with the assumption that the string contains
Xonly one line.
XYou may, however, wish to treat a string as a multi-line buffer, such that
Xthe ^ will match after any newline within the string, and $ will match
Xbefore any newline.
XAt the cost of a little more overhead, you can do this by setting the variable
X$* to 1.
XSetting it back to 0 makes
X.I perl
Xrevert to its old behavior.
X.PP
XTo facilitate multi-line substitutions, the . character never matches a newline
X(even when $* is 0).
XIn particular, the following leaves a newline on the $_ string:
X.nf
X
X	$_ = <STDIN>;
X	s/.*(some_string).*/$1/;
X
XIf the newline is unwanted, try one of
X
X	s/.*(some_string).*\en/$1/;
X	s/.*(some_string)[^\e000]*/$1/;
X	s/.*(some_string)(.|\en)*/$1/;
X	chop; s/.*(some_string).*/$1/;
X	/(some_string)/ && ($_ = $1);
X
X.fi
XAny item of a regular expression may be followed with digits in curly brackets
Xof the form {n,m}, where n gives the minimum number of times to match the item
Xand m gives the maximum.
XThe form {n} is equivalent to {n,n} and matches exactly n times.
XThe form {n,} matches n or more times.
X(If a curly bracket occurs in any other context, it is treated as a regular
Xcharacter.)
XThe * modifier is equivalent to {0,}, the + modifier to {1,} and the ? modifier
Xto {0,1}.
XThere is no limit to the size of n or m, but large numbers will chew up
Xmore memory.
X.Sp
XYou will note that all backslashed metacharacters in
X.I perl
Xare alphanumeric,
Xsuch as \eb, \ew, \en.
XUnlike some other regular expression languages, there are no backslashed
Xsymbols that aren't alphanumeric.
XSo anything that looks like \e\e, \e(, \e), \e<, \e>, \e{, or \e} is always
Xinterpreted as a literal character, not a metacharacter.
XThis makes it simple to quote a string that you want to use for a pattern
Xbut that you are afraid might contain metacharacters.
XSimply quote all the non-alphanumeric characters:
X.nf
X
X	$pattern =~ s/(\eW)/\e\e$1/g;
X
X.fi
X.Sh "Formats"
XOutput record formats for use with the
X.I write
Xoperator may declared as follows:
X.nf
X
X.ne 3
X    format NAME =
X    FORMLIST
X    .
X
X.fi
XIf name is omitted, format \*(L"STDOUT\*(R" is defined.
XFORMLIST consists of a sequence of lines, each of which may be of one of three
Xtypes:
X.Ip 1. 4
XA comment.
X.Ip 2. 4
XA \*(L"picture\*(R" line giving the format for one output line.
X.Ip 3. 4
XAn argument line supplying values to plug into a picture line.
X.PP
XPicture lines are printed exactly as they look, except for certain fields
Xthat substitute values into the line.
XEach picture field starts with either @ or ^.
XThe @ field (not to be confused with the array marker @) is the normal
Xcase; ^ fields are used
Xto do rudimentary multi-line text block filling.
XThe length of the field is supplied by padding out the field
Xwith multiple <, >, or | characters to specify, respectively, left justification,
Xright justification, or centering.
XIf any of the values supplied for these fields contains a newline, only
Xthe text up to the newline is printed.
XThe special field @* can be used for printing multi-line values.
XIt should appear by itself on a line.
X.PP
XThe values are specified on the following line, in the same order as
Xthe picture fields.
XThe values should be separated by commas.
X.PP
XPicture fields that begin with ^ rather than @ are treated specially.
XThe value supplied must be a scalar variable name which contains a text
Xstring.
X.I Perl
Xputs as much text as it can into the field, and then chops off the front
Xof the string so that the next time the variable is referenced,
Xmore of the text can be printed.
XNormally you would use a sequence of fields in a vertical stack to print
Xout a block of text.
XIf you like, you can end the final field with .\|.\|., which will appear in the
Xoutput if the text was too long to appear in its entirety.
XYou can change which characters are legal to break on by changing the
Xvariable $: to a list of the desired characters.
X.PP
XSince use of ^ fields can produce variable length records if the text to be
Xformatted is short, you can suppress blank lines by putting the tilde (~)
Xcharacter anywhere in the line.
X(Normally you should put it in the front if possible, for visibility.)
XThe tilde will be translated to a space upon output.
X.PP
XExamples:
X.nf
X.lg 0
X.cs R 25
X.ft C
X
X.ne 10
X# a report on the /etc/passwd file
Xformat top =
X\&                        Passwd File
XName                Login    Office   Uid   Gid Home
X------------------------------------------------------------------
X\&.
Xformat STDOUT =
X@<<<<<<<<<<<<<<<<<< @||||||| @<<<<<<@>>>> @>>>> @<<<<<<<<<<<<<<<<<
X$name,              $login,  $office,$uid,$gid, $home
X\&.
X
X.ne 29
X# a report from a bug report form
Xformat top =
X\&                        Bug Reports
X@<<<<<<<<<<<<<<<<<<<<<<<     @|||         @>>>>>>>>>>>>>>>>>>>>>>>
X$system,                      $%,         $date
X------------------------------------------------------------------
X\&.
Xformat STDOUT =
XSubject: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X\&         $subject
XIndex: @<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X\&       $index,                       $description
XPriority: @<<<<<<<<<< Date: @<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X\&          $priority,        $date,   $description
XFrom: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X\&      $from,                         $description
XAssigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X\&             $programmer,            $description
X\&~                                    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X\&                                     $description
X\&~                                    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X\&                                     $description
X\&~                                    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X\&                                     $description
X\&~                                    ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X\&                                     $description
X\&~                                    ^<<<<<<<<<<<<<<<<<<<<<<<...
X\&                                     $description
X\&.
X
X.ft R
X.cs R
X.lg
X.fi
XIt is possible to intermix prints with writes on the same output channel,
Xbut you'll have to handle $\- (lines left on the page) yourself.
X.PP
XIf you are printing lots of fields that are usually blank, you should consider
Xusing the reset operator between records.
XNot only is it more efficient, but it can prevent the bug of adding another
Xfield and forgetting to zero it.
X.Sh "Predefined Names"
XThe following names have special meaning to
X.IR perl .
XI could have used alphabetic symbols for some of these, but I didn't want
Xto take the chance that someone would say reset \*(L"a\-zA\-Z\*(R" and wipe them all
Xout.
XYou'll just have to suffer along with these silly symbols.
XMost of them have reasonable mnemonics, or analogues in one of the shells.
X.Ip $_ 8
XThe default input and pattern-searching space.
XThe following pairs are equivalent:
X.nf
X
X.ne 2
X	while (<>) {\|.\|.\|.	# only equivalent in while!
X	while ($_ = <>) {\|.\|.\|.
X
X.ne 2
X	/\|^Subject:/
X	$_ \|=~ \|/\|^Subject:/
X
X.ne 2
X	y/a\-z/A\-Z/
X	$_ =~ y/a\-z/A\-Z/
X
X.ne 2
X	chop
X	chop($_)
X
X.fi 
X(Mnemonic: underline is understood in certain operations.)
X.Ip $. 8
XThe current input line number of the last filehandle that was read.
XReadonly.
XRemember that only an explicit close on the filehandle resets the line number.
XSince <> never does an explicit close, line numbers increase across ARGV files
X(but see examples under eof).
X(Mnemonic: many programs use . to mean the current line number.)
X.Ip $/ 8
XThe input record separator, newline by default.
XWorks like
X.IR awk 's
XRS variable, including treating blank lines as delimiters
Xif set to the null string.
XIf set to a value longer than one character, only the first character is used.
X(Mnemonic: / is used to delimit line boundaries when quoting poetry.)
X.Ip $, 8
XThe output field separator for the print operator.
XOrdinarily the print operator simply prints out the comma separated fields
Xyou specify.
XIn order to get behavior more like
X.IR awk ,
Xset this variable as you would set
X.IR awk 's
XOFS variable to specify what is printed between fields.
X(Mnemonic: what is printed when there is a , in your print statement.)
X.Ip $"" 8
XThis is like $, except that it applies to array values interpolated into
Xa double-quoted string (or similar interpreted string).
XDefault is a space.
X(Mnemonic: obvious, I think.)
X.Ip $\e 8
XThe output record separator for the print operator.
XOrdinarily the print operator simply prints out the comma separated fields
Xyou specify, with no trailing newline or record separator assumed.
XIn order to get behavior more like
X.IR awk ,
Xset this variable as you would set
X.IR awk 's
XORS variable to specify what is printed at the end of the print.
X(Mnemonic: you set $\e instead of adding \en at the end of the print.
XAlso, it's just like /, but it's what you get \*(L"back\*(R" from
X.IR perl .)
X.Ip $# 8
XThe output format for printed numbers.
XThis variable is a half-hearted attempt to emulate
X.IR awk 's
XOFMT variable.
XThere are times, however, when
X.I awk
Xand
X.I perl
Xhave differing notions of what
Xis in fact numeric.
XAlso, the initial value is %.20g rather than %.6g, so you need to set $#
Xexplicitly to get
X.IR awk 's
Xvalue.
X(Mnemonic: # is the number sign.)
X.Ip $% 8
XThe current page number of the currently selected output channel.
X(Mnemonic: % is page number in nroff.)
X.Ip $= 8
XThe current page length (printable lines) of the currently selected output
Xchannel.
XDefault is 60.
X(Mnemonic: = has horizontal lines.)
X.Ip $\- 8
XThe number of lines left on the page of the currently selected output channel.
X(Mnemonic: lines_on_page \- lines_printed.)
X.Ip $~ 8
XThe name of the current report format for the currently selected output
Xchannel.
X(Mnemonic: brother to $^.)
X.Ip $^ 8
XThe name of the current top-of-page format for the currently selected output
Xchannel.
X(Mnemonic: points to top of page.)
X.Ip $| 8
XIf set to nonzero, forces a flush after every write or print on the currently
Xselected output channel.
XDefault is 0.
XNote that
X.I STDOUT
Xwill typically be line buffered if output is to the
Xterminal and block buffered otherwise.
XSetting this variable is useful primarily when you are outputting to a pipe,
Xsuch as when you are running a
X.I perl
Xscript under rsh and want to see the
Xoutput as it's happening.
X(Mnemonic: when you want your pipes to be piping hot.)
X.Ip $$ 8
XThe process number of the
X.I perl
Xrunning this script.
X(Mnemonic: same as shells.)
X.Ip $? 8
XThe status returned by the last pipe close, backtick (\`\`) command or
X.I system
Xoperator.
XNote that this is the status word returned by the wait() system
Xcall, so the exit value of the subprocess is actually ($? >> 8).
X$? & 255 gives which signal, if any, the process died from, and whether
Xthere was a core dump.
X(Mnemonic: similar to sh and ksh.)
X.Ip $& 8 4
XThe string matched by the last pattern match (not counting any matches hidden
Xwithin a BLOCK or eval enclosed by the current BLOCK).
X(Mnemonic: like & in some editors.)
X.Ip $\` 8 4
XThe string preceding whatever was matched by the last pattern match
X(not counting any matches hidden within a BLOCK or eval enclosed by the current
XBLOCK).
X(Mnemonic: \` often precedes a quoted string.)
X.Ip $\' 8 4
XThe string following whatever was matched by the last pattern match
X(not counting any matches hidden within a BLOCK or eval enclosed by the current
XBLOCK).
X(Mnemonic: \' often follows a quoted string.)
XExample:
X.nf
X
X.ne 3
X	$_ = \'abcdefghi\';
X	/def/;
X	print "$\`:$&:$\'\en";  	# prints abc:def:ghi
X
X.fi
X.Ip $+ 8 4
XThe last bracket matched by the last search pattern.
XThis is useful if you don't know which of a set of alternative patterns
Xmatched.
XFor example:
X.nf
X
X    /Version: \|(.*\|)|Revision: \|(.*\|)\|/ \|&& \|($rev = $+);
X
X.fi
X(Mnemonic: be positive and forward looking.)
X.Ip $* 8 2
XSet to 1 to do multiline matching within a string, 0 to tell
X.I perl
Xthat it can assume that strings contain a single line, for the purpose
Xof optimizing pattern matches.
XPattern matches on strings containing multiple newlines can produce confusing
Xresults when $* is 0.
XDefault is 0.
X(Mnemonic: * matches multiple things.)
X.Ip $0 8
XContains the name of the file containing the
X.I perl
Xscript being executed.
XThe value should be copied elsewhere before any pattern matching happens, which
Xclobbers $0.
X(Mnemonic: same as sh and ksh.)
X.Ip $<digit> 8
XContains the subpattern from the corresponding set of parentheses in the last
Xpattern matched, not counting patterns matched in nested blocks that have
Xbeen exited already.
X(Mnemonic: like \edigit.)
X.Ip $[ 8 2
XThe index of the first element in an array, and of the first character in
Xa substring.
XDefault is 0, but you could set it to 1 to make
X.I perl
Xbehave more like
X.I awk
X(or Fortran)
Xwhen subscripting and when evaluating the index() and substr() functions.
X(Mnemonic: [ begins subscripts.)
X.Ip $] 8 2
XThe string printed out when you say \*(L"perl -v\*(R".
XIt can be used to determine at the beginning of a script whether the perl
Xinterpreter executing the script is in the right range of versions.
XExample:
X.nf
X
X.ne 5
X	# see if getc is available
X        ($version,$patchlevel) =
X		 $] =~ /(\ed+\e.\ed+).*\enPatch level: (\ed+)/;
X        print STDERR "(No filename completion available.)\en"
X		 if $version * 1000 + $patchlevel < 2016;
X
X.fi
X(Mnemonic: Is this version of perl in the right bracket?)
X.Ip $; 8 2
XThe subscript separator for multi-dimensional array emulation.
XIf you refer to an associative array element as
X.nf
X	$foo{$a,$b,$c}
X
Xit really means
X
X	$foo{join($;, $a, $b, $c)}
X
XBut don't put
X
X	@foo{$a,$b,$c}		# a slice--note the @
X
Xwhich means
X
X	($foo{$a},$foo{$b},$foo{$c})
X
X.fi
XDefault is "\e034", the same as SUBSEP in
X.IR awk .
XNote that if your keys contain binary data there might not be any safe
Xvalue for $;.
X(Mnemonic: comma (the syntactic subscript separator) is a semi-semicolon.
XYeah, I know, it's pretty lame, but $, is already taken for something more
Ximportant.)
X.Ip $! 8 2
XIf used in a numeric context, yields the current value of errno, with all the
Xusual caveats.
XIf used in a string context, yields the corresponding system error string.
XYou can assign to $! in order to set errno
Xif, for instance, you want $! to return the string for error n, or you want
Xto set the exit value for the die operator.
X(Mnemonic: What just went bang?)
X.Ip $@ 8 2
XThe error message from the last eval command.
XIf null, the last eval parsed and executed correctly.
X(Mnemonic: Where was the syntax error \*(L"at\*(R"?)
X.Ip $< 8 2
XThe real uid of this process.
X(Mnemonic: it's the uid you came FROM, if you're running setuid.)
X.Ip $> 8 2
XThe effective uid of this process.
XExample:
X.nf
X
X	$< = $>;	# set real uid to the effective uid
X
X.fi
X(Mnemonic: it's the uid you went TO, if you're running setuid.)
X.Ip $( 8 2
XThe real gid of this process.
XIf you are on a machine that supports membership in multiple groups
Xsimultaneously, gives a space separated list of groups you are in.
XThe first number is the one returned by getgid(), and the subsequent ones
Xby getgroups(), one of which may be the same as the first number.
X(Mnemonic: parentheses are used to GROUP things.
XThe real gid is the group you LEFT, if you're running setgid.)
X.Ip $) 8 2
XThe effective gid of this process.
XIf you are on a machine that supports membership in multiple groups
Xsimultaneously, gives a space separated list of groups you are in.
XThe first number is the one returned by getegid(), and the subsequent ones
Xby getgroups(), one of which may be the same as the first number.
X(Mnemonic: parentheses are used to GROUP things.
XThe effective gid is the group that's RIGHT for you, if you're running setgid.)
X.Sp
XNote: $<, $>, $( and $) can only be set on machines that support the
Xcorresponding set[re][ug]id() routine.
X.Ip $: 8 2
XThe current set of characters after which a string may be broken to
Xfill continuation fields (starting with ^) in a format.
XDefault is "\ \en-", to break on whitespace or hyphens.
X(Mnemonic: a \*(L"colon\*(R" in poetry is a part of a line.)
X.Ip @ARGV 8 3
XThe array ARGV contains the command line arguments intended for the script.
XNote that $#ARGV is the generally number of arguments minus one, since
X$ARGV[0] is the first argument, NOT the command name.
XSee $0 for the command name.
X.Ip @INC 8 3
XThe array INC contains the list of places to look for
X.I perl
Xscripts to be
Xevaluated by the \*(L"do EXPR\*(R" command.
XIt initially consists of the arguments to any
X.B \-I
Xcommand line switches, followed
Xby the default
X.I perl
Xlibrary, probably \*(L"/usr/local/lib/perl\*(R".
X.Ip $ENV{expr} 8 2
XThe associative array ENV contains your current environment.
XSetting a value in ENV changes the environment for child processes.
X.Ip $SIG{expr} 8 2
XThe associative array SIG is used to set signal handlers for various signals.
XExample:
X.nf
X
X.ne 12
X	sub handler {	# 1st argument is signal name
X		local($sig) = @_;
X		print "Caught a SIG$sig\-\|\-shutting down\en";
X		close(LOG);
X		exit(0);
X	}
X
X	$SIG{\'INT\'} = \'handler\';
X	$SIG{\'QUIT\'} = \'handler\';
X	.\|.\|.
X	$SIG{\'INT\'} = \'DEFAULT\';	# restore default action
X	$SIG{\'QUIT\'} = \'IGNORE\';	# ignore SIGQUIT
X
X.fi
XThe SIG array only contains values for the signals actually set within
Xthe perl script.
X.Sh "Packages"
XPerl provides a mechanism for alternate namespaces to protect packages from
Xstomping on each others variables.
XBy default, a perl script starts compiling into the package known as \*(L"main\*(R".
XBy use of the
X.I package
Xdeclaration, you can switch namespaces.
XThe scope of the package declaration is from the declaration itself to the end
Xof the enclosing block (the same scope as the local() operator).
XTypically it would be the first declaration in a file to be included by
Xthe \*(L"do FILE\*(R" operator.
XYou can switch into a package in more than one place; it merely influences
Xwhich symbol table is used by the compiler for the rest of that block.
XYou can refer to variables in other packages by prefixing the name with
Xthe package name and a single quote.
XIf the package name is null, the \*(L"main\*(R" package as assumed.
XEval'ed strings are compiled in the package in which the eval was compiled
Xin.
X(Assignments to $SIG{}, however, assume the signal handler specified is in the
Xmain package.
XQualify the signal handler name if you wish to have a signal handler in
Xa package.)
XFor an example, examine perldb.pl in the perl library.
XIt initially switches to the DB package so that the debugger doesn't interfere
Xwith variables in the script you are trying to debug.
XAt various points, however, it temporarily switches back to the main package
Xto evaluate various expressions in the context of the main package.
X.PP
XThe symbol table for a package happens to be stored in the associative array
Xof that name prepended with an underscore.
XThe value in each entry of the associative array is
Xwhat you are referring to when you use the *name notation.
XIn fact, the following have the same effect (in package main, anyway),
Xthough the first is more
Xefficient because it does the symbol table lookups at compile time:
X.nf
X
X.ne 2
X	local(*foo) = *bar;
X	local($_main{'foo'}) = $_main{'bar'};
X
X.fi
XYou can use this to print out all the variables in a package, for instance.
XHere is dumpvar.pl from the perl library:
X.nf
X
X	package dumpvar;
X
X	sub main'dumpvar {
X	\&    ($package) = @_;
X	\&    local(*stab) = eval("*_$package");
X	\&    while (($key,$val) = each(%stab)) {
X	\&        {
X	\&            local(*entry) = $val;
X.ne 3
X	\&            eval <<'.' if defined $entry;
X	print "\$$key = '$entry'\n";
X	.
X.ne 7
X	\&            eval <<'.' if defined @entry;
X	print "\@$key = (\n";
X	foreach $num ($[ .. $#entry) {
X	\&    print "  $num\t'",$entry[$num],"'\n";
X	}
X	print ")\n";
X	.
X.ne 10
X	\&            eval <<'.' if $key ne "_$package" && defined %entry;
X	print "\%$key = (\n";
X	foreach $key (sort keys(%entry)) {
X	\&    print "  $key\t'",$entry{$key},"'\n";
X	}
X	print ")\n";
X	.
X	\&        }
X	\&    }
X	}
X
X.fi
XNote that, even though the subroutine is compiled in package dumpvar, the
Xname of the subroutine is qualified so that it's name is inserted into package
X\*(L"main\*(R".
X.Sh "Style"
XEach programmer will, of course, have his or her own preferences in regards
Xto formatting, but there are some general guidelines that will make your
Xprograms easier to read.
X.Ip 1. 4 4
XJust because you CAN do something a particular way doesn't mean that
Xyou SHOULD do it that way.
X.I Perl
Xis designed to give you several ways to do anything, so consider picking
Xthe most readable one.
XFor instance
X
X	open(FOO,$foo) || die "Can't open $foo: $!";
X
Xis better than
X
X	die "Can't open $foo: $!" unless open(FOO,$foo);
X
Xbecause the second way hides the main point of the statement in a
Xmodifier.
XOn the other hand
X
X	print "Starting analysis\en" if $verbose;
X
Xis better than
X
X	$verbose && print "Starting analysis\en";
X
Xsince the main point isn't whether the user typed -v or not.
X.Ip 2. 4 4
XDon't go through silly contortions to exit a loop at the top or the
Xbottom, when
X.I perl
Xprovides the "last" operator so you can exit in the middle.
XJust outdent it a little to make it more visible:
X.nf
X
X.ne 7
X    line:
X	for (;;) {
X	    statements;
X	last line if $foo;
X	    next line if /^#/;
X	    statements;
X	}
X
X.fi
X.Ip 3. 4 4
XDon't be afraid to use loop labels\*(--they're there to enhance readability as
Xwell as to allow multi-level loop breaks.
XSee last example.
X.Ip 6. 4 4
XFor portability, when using features that may not be implemented on every
Xmachine, test the construct in an eval to see if it fails.
X.Ip 4. 4 4
XChoose mnemonic indentifiers.
X.Ip 5. 4 4
XBe consistent.
X.Sh "Debugging"
XIf you invoke
X.I perl
Xwith a
X.B \-d
Xswitch, your script will be run under a debugging monitor.
XIt will halt before the first executable statement and ask you for a
Xcommand, such as:
X.Ip "?" 12 4
XPrints out a help message.
X.Ip "s" 12 4
XSingle step.
XExecutes until it reaches the beginning of another statement.
X.Ip "c" 12 4
XContinue.
XExecutes until the next breakpoint is reached.
X.Ip "<CR>" 12 4
XRepeat last s or c.
X.Ip "n" 12 4
XSingle step around subroutine call.
X.Ip "l min+incr" 12 4
XList incr+1 lines starting at min.
XIf min is omitted, starts where last listing left off.
XIf incr is omitted, previous value of incr is used.
X.Ip "l min-max" 12 4
XList lines in the indicated range.
X.Ip "l line" 12 4
XList just the indicated line.
X.Ip "l" 12 4
XList incr+1 more lines after last printed line.
X.Ip "l subname" 12 4
XList subroutine.
XIf it's a long subroutine it just lists the beginning.
XUse \*(L"l\*(R" to list more.
X.Ip "L" 12 4
XList lines that have breakpoints or actions.
X.Ip "t" 12 4
XToggle trace mode on or off.
X.Ip "b line" 12 4
XSet a breakpoint.
XIf line is omitted, sets a breakpoint on the current line
Xline that is about to be executed.
XBreakpoints may only be set on lines that begin an executable statement.
X.Ip "b subname" 12 4
XSet breakpoint at first executable line of subroutine.
X.Ip "S" 12 4
XLists the names of all subroutines.
X.Ip "d line" 12 4
XDelete breakpoint.
XIf line is omitted, deletes the breakpoint on the current line
Xline that is about to be executed.
X.Ip "D" 12 4
XDelete all breakpoints.
X.Ip "A" 12 4
XDelete all line actions.
X.Ip "V package" 12 4
XList all variables in package.
XDefault is main package.
X.Ip "a line command" 12 4
XSet an action for line.
XA multi-line command may be entered by backslashing the newlines.
X.Ip "< command" 12 4
XSet an action to happen before every debugger prompt.
XA multi-line command may be entered by backslashing the newlines.
X.Ip "> command" 12 4
XSet an action to happen after the prompt when you've just given a command
Xto return to executing the script.
XA multi-line command may be entered by backslashing the newlines.
X.Ip "! number" 12 4
XRedo a debugging command.
XIf number is omitted, redoes the previous command.
X.Ip "! -number" 12 4
XRedo the command that was that many commands ago.
X.Ip "h -number" 12 4
XDisplay last n commands.
XOnly commands longer than one character are listed.
XIf number is omitted, lists them all.
X.Ip "q or ^D" 12 4
XQuit.
X.Ip "command" 12 4
XExecute command as a perl statement.
XA missing semicolon will be supplied.
X.Ip "p expr" 12 4
XSame as \*(L"print DB'OUT expr\*(R".
XThe DB'OUT filehandle is opened to /dev/tty, regardless of where STDOUT
Xmay be redirected to.
X.PP
XIf you want to modify the debugger, copy perldb.pl from the perl library
Xto your current directory and modify it as necessary.
XYou can do some customization by setting up a .perldb file which contains
Xinitialization code.
XFor instance, you could make aliases like these:
X.nf
X
X    $DBalias{'len'} = 's/^len(.*)/p length(\e$1)/';
X    $DBalias{'stop'} = 's/^stop (at|in)/b/';
X    $DBalias{'.'} =
X      's/^./p "\e$DBsub(\e$DBline):\et\e$DBline[\e$DBline]"/';
X
X.fi
X.Sh "Setuid Scripts"
X.I Perl
Xis designed to make it easy to write secure setuid and setgid scripts.
XUnlike shells, which are based on multiple substitution passes on each line
Xof the script,
X.I perl
Xuses a more conventional evaluation scheme with fewer hidden \*(L"gotchas\*(R".
XAdditionally, since the language has more built-in functionality, it
Xhas to rely less upon external (and possibly untrustworthy) programs to
Xaccomplish its purposes.
X.PP
XIn an unpatched 4.2 or 4.3bsd kernel, setuid scripts are intrinsically
Xinsecure, but this kernel feature can be disabled.
XIf it is,
X.I perl
Xcan emulate the setuid and setgid mechanism when it notices the otherwise
Xuseless setuid/gid bits on perl scripts.
XIf the kernel feature isn't disabled,
X.I perl
Xwill complain loudly that your setuid script is insecure.
XYou'll need to either disable the kernel setuid script feature, or put
Xa C wrapper around the script.
X.PP
XWhen perl is executing a setuid script, it takes special precautions to
Xprevent you from falling into any obvious traps.
X(In some ways, a perl script is more secure than the corresponding
XC program.)
XAny command line argument, environment variable, or input is marked as
X\*(L"tainted\*(R", and may not be used, directly or indirectly, in any
Xcommand that invokes a subshell, or in any command that modifies files,
Xdirectories or processes.
XAny variable that is set within an expression that has previously referenced
Xa tainted value also becomes tainted (even if it is logically impossible
Xfor the tainted value to influence the variable).
XFor example:
X.nf
X
X.ne 5
X	$foo = shift;			# $foo is tainted
X	$bar = $foo,\'bar\';		# $bar is also tainted
X	$xxx = <>;			# Tainted
X	$path = $ENV{\'PATH\'};	# Tainted, but see below
X	$abc = \'abc\';			# Not tainted
X
X.ne 4
X	system "echo $foo";		# Insecure
X	system "echo", $foo;	# Secure (doesn't use sh)
X	system "echo $bar";		# Insecure
X	system "echo $abc";		# Insecure until PATH set
X
X.ne 5
X	$ENV{\'PATH\'} = \'/bin:/usr/bin\';
X	$ENV{\'IFS\'} = \'\' if $ENV{\'IFS\'} ne \'\';
X
X	$path = $ENV{\'PATH\'};	# Not tainted
X	system "echo $abc";		# Is secure now!
X
X.ne 5
X	open(FOO,"$foo");		# OK
X	open(FOO,">$foo"); 		# Not OK
X
X	open(FOO,"echo $foo|");	# Not OK, but...
X	open(FOO,"-|") || exec \'echo\', $foo;	# OK
X
X	$zzz = `echo $foo`;		# Insecure, zzz tainted
X
X	unlink $abc,$foo;		# Insecure
X	umask $foo;			# Insecure
X
X.ne 3
X	exec "echo $foo";		# Insecure
X	exec "echo", $foo;		# Secure (doesn't use sh)
X	exec "sh", \'-c\', $foo;	# Considered secure, alas
X
X.fi
XThe taintedness is associated with each scalar value, so some elements
Xof an array can be tainted, and others not.
X.PP
XIf you try to do something insecure, you will get a fatal error saying 
Xsomething like \*(L"Insecure dependency\*(R" or \*(L"Insecure PATH\*(R".
XNote that you can still write an insecure system call or exec,
Xbut only by explicity doing something like the last example above.
XYou can also bypass the tainting mechanism by referencing
Xsubpatterns\*(--\c
X.I perl
Xpresumes that if you reference a substring using $1, $2, etc, you knew
Xwhat you were doing when you wrote the pattern:
X.nf
X
X	$ARGV[0] =~ /^\-P(\ew+)$/;
X	$printer = $1;		# Not tainted
X
X.fi
XThis is fairly secure since \ew+ doesn't match shell metacharacters.
XUse of .+ would have been insecure, but
X.I perl
Xdoesn't check for that, so you must be careful with your patterns.
XThis is the ONLY mechanism for untainting user supplied filenames if you
Xwant to do file operations on them (unless you make $> equal to $<).
X.PP
XIt's also possible to get into trouble with other operations that don't care
Xwhether they use tainted values.
XMake judicious use of the file tests in dealing with any user-supplied
Xfilenames.
XWhen possible, do opens and such after setting $> = $<.
X.I Perl
Xdoesn't prevent you from opening tainted filenames for reading, so be
Xcareful what you print out.
XThe tainting mechanism is intended to prevent stupid mistakes, not to remove
Xthe need for thought.
X.SH ENVIRONMENT
X.I Perl
Xuses PATH in executing subprocesses, and in finding the script if \-S
Xis used.
XHOME or LOGDIR are used if chdir has no argument.
X.PP
XApart from these,
X.I perl
Xuses no environment variables, except to make them available
Xto the script being executed, and to child processes.
XHowever, scripts running setuid would do well to execute the following lines
Xbefore doing anything else, just to keep people honest:
X.nf
X
X.ne 3
X    $ENV{\'PATH\'} = \'/bin:/usr/bin\';    # or whatever you need
X    $ENV{\'SHELL\'} = \'/bin/sh\' if $ENV{\'SHELL\'} ne \'\';
X    $ENV{\'IFS\'} = \'\' if $ENV{\'IFS\'} ne \'\';
X
X.fi
X.SH AUTHOR
XLarry Wall <lwall@jpl-devvax.Jpl.Nasa.Gov>
X.SH FILES
X/tmp/perl\-eXXXXXX	temporary file for
X.B \-e
Xcommands.
X.SH SEE ALSO
Xa2p	awk to perl translator
X.br
Xs2p	sed to perl translator
X.br
Xperldb	interactive perl debugger
X.SH DIAGNOSTICS
XCompilation errors will tell you the line number of the error, with an
Xindication of the next token or token type that was to be examined.
X(In the case of a script passed to
X.I perl
Xvia
X.B \-e
Xswitches, each
X.B \-e
Xis counted as one line.)
X.PP
XSetuid scripts have additional constraints that can produce error messages
Xsuch as \*(L"Insecure dependency\*(R".
XSee the section on setuid scripts.
X.SH TRAPS
XAccustomed
X.IR awk
Xusers should take special note of the following:
X.Ip * 4 2
XSemicolons are required after all simple statements in
X.IR perl .
XNewline
Xis not a statement delimiter.
X.Ip * 4 2
XCurly brackets are required on ifs and whiles.
X.Ip * 4 2
XVariables begin with $ or @ in
X.IR perl .
X.Ip * 4 2
XArrays index from 0 unless you set $[.
XLikewise string positions in substr() and index().
X.Ip * 4 2
XYou have to decide whether your array has numeric or string indices.
X.Ip * 4 2
XAssociative array values do not spring into existence upon mere reference.
X.Ip * 4 2
XYou have to decide whether you want to use string or numeric comparisons.
X.Ip * 4 2
XReading an input line does not split it for you.  You get to split it yourself
Xto an array.
XAnd the
X.I split
Xoperator has different arguments.
X.Ip * 4 2
XThe current input line is normally in $_, not $0.
XIt generally does not have the newline stripped.
X($0 is initially the name of the program executed, then the last matched
Xstring.)
X.Ip * 4 2
X$<digit> does not refer to fields\*(--it refers to substrings matched by the last
Xmatch pattern.
X.Ip * 4 2
XThe
X.I print
Xstatement does not add field and record separators unless you set
X$, and $\e.
X.Ip * 4 2
XYou must open your files before you print to them.
X.Ip * 4 2
XThe range operator is \*(L".\|.\*(R", not comma.
X(The comma operator works as in C.)
X.Ip * 4 2
XThe match operator is \*(L"=~\*(R", not \*(L"~\*(R".
X(\*(L"~\*(R" is the one's complement operator, as in C.)
X.Ip * 4 2
XThe exponentiation operator is \*(L"**\*(R", not \*(L"^\*(R".
X(\*(L"^\*(R" is the XOR operator, as in C.)
X.Ip * 4 2
XThe concatenation operator is \*(L".\*(R", not the null string.
X(Using the null string would render \*(L"/pat/ /pat/\*(R" unparsable,
Xsince the third slash would be interpreted as a division operator\*(--the
Xtokener is in fact slightly context sensitive for operators like /, ?, and <.
XAnd in fact, . itself can be the beginning of a number.)
X.Ip * 4 2
X.IR Next ,
X.I exit
Xand
X.I continue
Xwork differently.
X.Ip * 4 2
XThe following variables work differently
X.nf
X
X	  Awk	\h'|2.5i'Perl
X	  ARGC	\h'|2.5i'$#ARGV
X	  ARGV[0]	\h'|2.5i'$0
X	  FILENAME\h'|2.5i'$ARGV
X	  FNR	\h'|2.5i'$. \- something
X	  FS	\h'|2.5i'(whatever you like)
X	  NF	\h'|2.5i'$#Fld, or some such
X	  NR	\h'|2.5i'$.
X	  OFMT	\h'|2.5i'$#
X	  OFS	\h'|2.5i'$,
X	  ORS	\h'|2.5i'$\e
X	  RLENGTH	\h'|2.5i'length($&)
X	  RS	\h'|2.5i'$/
X	  RSTART	\h'|2.5i'length($\`)
X	  SUBSEP	\h'|2.5i'$;
X
X.fi
X.Ip * 4 2
XWhen in doubt, run the
X.I awk
Xconstruct through a2p and see what it gives you.
X.PP
XCerebral C programmers should take note of the following:
X.Ip * 4 2
XCurly brackets are required on ifs and whiles.
X.Ip * 4 2
XYou should use \*(L"elsif\*(R" rather than \*(L"else if\*(R"
X.Ip * 4 2
X.I Break
Xand
X.I continue
Xbecome
X.I last
Xand
X.IR next ,
Xrespectively.
X.Ip * 4 2
XThere's no switch statement.
X.Ip * 4 2
XVariables begin with $ or @ in
X.IR perl .
X.Ip * 4 2
XPrintf does not implement *.
X.Ip * 4 2
XComments begin with #, not /*.
X.Ip * 4 2
XYou can't take the address of anything.
X.Ip * 4 2
XARGV must be capitalized.
X.Ip * 4 2
XThe \*(L"system\*(R" calls link, unlink, rename, etc. return nonzero for success, not 0.
X.Ip * 4 2
XSignal handlers deal with signal names, not numbers.
X.Ip * 4 2
XYou can't subscript array values, only arrays (no $x = (1,2,3)[2];).
X.PP
XSeasoned
X.I sed
Xprogrammers should take note of the following:
X.Ip * 4 2
XBackreferences in substitutions use $ rather than \e.
X.Ip * 4 2
XThe pattern matching metacharacters (, ), and | do not have backslashes in front.
X.Ip * 4 2
XThe range operator is .\|. rather than comma.
X.PP
XSharp shell programmers should take note of the following:
X.Ip * 4 2
XThe backtick operator does variable interpretation without regard to the
Xpresence of single quotes in the command.
X.Ip * 4 2
XThe backtick operator does no translation of the return value, unlike csh.
X.Ip * 4 2
XShells (especially csh) do several levels of substitution on each command line.
X.I Perl
Xdoes substitution only in certain constructs such as double quotes,
Xbackticks, angle brackets and search patterns.
X.Ip * 4 2
XShells interpret scripts a little bit at a time.
X.I Perl
Xcompiles the whole program before executing it.
X.Ip * 4 2
XThe arguments are available via @ARGV, not $1, $2, etc.
X.Ip * 4 2
XThe environment is not automatically made available as variables.
X.SH BUGS
X.PP
X.I Perl
Xis at the mercy of your machine's definitions of various operations
Xsuch as type casting, atof() and sprintf().
X.PP
XIf your stdio requires an seek or eof between reads and writes on a particular
Xstream, so does
X.IR perl .
X.PP
XWhile none of the built-in data types have any arbitrary size limits (apart
Xfrom memory size), there are still a few arbitrary limits:
Xa given identifier may not be longer than 255 characters;
Xsprintf is limited on many machines to 128 characters per field (unless the format
Xspecifier is exactly %s);
Xblock nesting depth is limited when tracing is turned on; and
Xno component of your PATH may be longer than 255 if you use \-S.
X.PP
X.I Perl
Xactually stands for Pathologically Eclectic Rubbish Lister, but don't tell
Xanyone I said that.
X.rn }` ''
!STUFFY!FUNK!
echo Extracting array.c
sed >array.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Header: array.c,v 2.0.1.1 88/08/03 22:07:51 root Exp $
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:	array.c,v $
X */
X
X#include "EXTERN.h"
X#include "perl.h"
X
XSTR *
Xafetch(ar,key,lval)
Xregister ARRAY *ar;
Xint key;
Xint lval;
X{
X    STR *str;
X
X    if (key < 0 || key > ar->ary_fill) {
X	if (lval && key >= 0) {
X	    str = str_new(0);
X	    (void)astore(ar,key,str);
X	    return str;
X	}
X	else
X	    return Nullstr;
X    }
X    if (lval && !ar->ary_array[key]) {
X	str = str_new(0);
X	(void)astore(ar,key,str);
X	return str;
X    }
X    return ar->ary_array[key];
X}
X
Xbool
Xastore(ar,key,val)
Xregister ARRAY *ar;
Xint key;
XSTR *val;
X{
X    int retval;
X
X    if (key < 0)
X	return FALSE;
X    if (key > ar->ary_max) {
X	int newmax;
X
X	if (ar->ary_alloc != ar->ary_array) {
X	    retval = ar->ary_array - ar->ary_alloc;
X	    Copy(ar->ary_array, ar->ary_alloc, ar->ary_max+1, STR*);
X	    Zero(ar->ary_alloc+ar->ary_max+1, retval, STR*);
X	    ar->ary_max += retval;
X	    ar->ary_array -= retval;
X	    if (key > ar->ary_max - 10) {
X		newmax = key + ar->ary_max;
X		goto resize;
X	    }
X	}
X	else {
X	    newmax = key + ar->ary_max / 5;
X	  resize:
X	    Renew(ar->ary_alloc,newmax+1, STR*);
X	    Zero(&ar->ary_alloc[ar->ary_max+1], newmax - ar->ary_max, STR*);
X	    ar->ary_array = ar->ary_alloc;
X	    ar->ary_max = newmax;
X	}
X    }
X    if ((ar->ary_flags & ARF_REAL) && ar->ary_fill < key) {
X	while (++ar->ary_fill < key) {
X	    if (ar->ary_array[ar->ary_fill] != Nullstr) {
X		str_free(ar->ary_array[ar->ary_fill]);
X		ar->ary_array[ar->ary_fill] = Nullstr;
X	    }
X	}
X    }
X    retval = (ar->ary_array[key] != Nullstr);
X    if (retval && (ar->ary_flags & ARF_REAL))
X	str_free(ar->ary_array[key]);
X    ar->ary_array[key] = val;
X    return retval;
X}
X
XARRAY *
Xanew(stab)
XSTAB *stab;
X{
X    register ARRAY *ar;
X
X    New(1,ar,1,ARRAY);
X    Newz(2,ar->ary_alloc,5,STR*);
X    ar->ary_array = ar->ary_alloc;
X    ar->ary_magic = str_new(0);
X    str_magic(ar->ary_magic, stab, '#', Nullch, 0);
X    ar->ary_fill = -1;
X    ar->ary_index = -1;
X    ar->ary_max = 4;
X    ar->ary_flags = ARF_REAL;
X    return ar;
X}
X
XARRAY *
Xafake(stab,size,strp)
XSTAB *stab;
Xint size;
XSTR **strp;
X{
X    register ARRAY *ar;
X
X    New(3,ar,1,ARRAY);
X    New(4,ar->ary_alloc,5,STR*);
X    Copy(strp,ar->ary_alloc,size,STR*);
X    ar->ary_array = ar->ary_alloc;
X    ar->ary_magic = str_new(0);
X    str_magic(ar->ary_magic, stab, '#', Nullch, 0);
X    ar->ary_fill = size - 1;
X    ar->ary_index = -1;
X    ar->ary_max = size - 1;
X    ar->ary_flags = 0;
X    return ar;
X}
X
Xvoid
Xaclear(ar)
Xregister ARRAY *ar;
X{
X    register int key;
X
X    if (!ar || !(ar->ary_flags & ARF_REAL))
X	return;
X    if (key = ar->ary_array - ar->ary_alloc) {
X	ar->ary_max += key;
X	ar->ary_array -= key;
X    }
X    for (key = 0; key <= ar->ary_max; key++)
X	str_free(ar->ary_array[key]);
X    ar->ary_fill = -1;
X    Zero(ar->ary_array, ar->ary_max+1, STR*);
X}
X
Xvoid
Xafree(ar)
Xregister ARRAY *ar;
X{
X    register int key;
X
X    if (!ar || !(ar->ary_flags & ARF_REAL))
X	return;
X    if (key = ar->ary_array - ar->ary_alloc) {
X	ar->ary_max += key;
X	ar->ary_array -= key;
X    }
X    for (key = 0; key <= ar->ary_max; key++)
X	str_free(ar->ary_array[key]);
X    str_free(ar->ary_magic);
X    Safefree(ar->ary_alloc);
X    Safefree(ar);
X}
X
Xbool
Xapush(ar,val)
Xregister ARRAY *ar;
XSTR *val;
X{
X    return astore(ar,++(ar->ary_fill),val);
X}
X
XSTR *
Xapop(ar)
Xregister ARRAY *ar;
X{
X    STR *retval;
X
X    if (ar->ary_fill < 0)
X	return Nullstr;
X    retval = ar->ary_array[ar->ary_fill];
X    ar->ary_array[ar->ary_fill--] = Nullstr;
X    return retval;
X}
X
Xaunshift(ar,num)
Xregister ARRAY *ar;
Xregister int num;
X{
X    register int i;
X    register STR **sstr,**dstr;
X
X    if (num <= 0)
X	return;
X    if (ar->ary_array - ar->ary_alloc >= num) {
X	ar->ary_max += num;
X	ar->ary_fill += num;
X	while (num--)
X	    *--ar->ary_array = Nullstr;
X    }
X    else {
X	(void)astore(ar,ar->ary_fill+num,(STR*)0);	/* maybe extend array */
X	dstr = ar->ary_array + ar->ary_fill;
X	sstr = dstr - num;
X	for (i = ar->ary_fill; i >= 0; i--) {
X	    *dstr-- = *sstr--;
X	}
X	Zero(ar->ary_array, num, STR*);
X    }
X}
X
XSTR *
Xashift(ar)
Xregister ARRAY *ar;
X{
X    STR *retval;
X
X    if (ar->ary_fill < 0)
X	return Nullstr;
X    retval = *ar->ary_array;
X    *(ar->ary_array++) = Nullstr;
X    ar->ary_max--;
X    ar->ary_fill--;
X    return retval;
X}
X
Xint
Xalen(ar)
Xregister ARRAY *ar;
X{
X    return ar->ary_fill;
X}
X
Xafill(ar, fill)
Xregister ARRAY *ar;
Xint fill;
X{
X    if (fill < 0)
X	fill = -1;
X    if (fill <= ar->ary_max)
X	ar->ary_fill = fill;
X    else
X	(void)astore(ar,fill,Nullstr);
X}
!STUFFY!FUNK!
echo Extracting patchlevel.h
sed >patchlevel.h <<'!STUFFY!FUNK!' -e 's/X//'
X#define PATCHLEVEL 0
!STUFFY!FUNK!
echo ""
echo "End of kit 6 (of 23)"
cat /dev/null >kit6isdone
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