pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (12/15/90)
---cut here---cut here---cut here---
#! /bin/sh
#
# This is a shar file containing zsh, a ksh/tcsh-like shell. To extract,
# cat all 8 parts together and pipe the result through sh. There is
# a "cut here" at the beginning and end of each part--be sure to
# remove everything outside of those. I put the # man page first so
# you can see what zsh is like.
#
# To unbundle, sh this file
# Fri Dec 14 18:10:16 EST 1990
mkdir readline
echo zsh.1 1>&2
sed 's/^-//' >zsh.1 <<'End of zsh.1'
-.TH ZSH 1
-.SH NAME
-zsh \- the Z shell
-.SH SYNTAX
-\fBzsh\fP
-[
-.B \-aefikmnstuvx0123456789ABCDEFGHIJK
-] [
-.B \-c
-string ]
-[ arg .\|.\|. ]
-.SH DESCRIPTION
-\fBzsh\fP
-is a command interpreter and programming language
-that executes commands read from a terminal
-or a file.
-See
-.B Invocation
-for the meanings of arguments to \fBzsh\fP.
-.SS Definitions
-A metacharacter can one of the following characters:
-.RS
-.PP
-\fB; & ( ) { } \(bv < > blank newline\fP
-.RE
-.PP
-A blank is a
-.B tab
-or a
-.BR space .
-An identifier
-is a sequence of letters, digits, or underscores
-starting with a letter or underscore.
-Identifiers are used as names for
-`named parameters'.
-A word is a sequence of
-characters separated by one or more non-quoted
-metacharacters.
-.PP
-A command
-is a sequence of characters in the syntax
-of the shell language.
-\fBzsh\fP reads each command and
-carries out the desired action either directly or by invoking
-separate utilities.
-A builtin is a command that is carried out by the
-parent shell without creating a separate process.
-.SS Commands
-A simple-command is a sequence of blank
-separated words
-which may be preceded by a parameter assignment list.
-See
-.B Environment
-below.
-The first word specifies the name of the command to
-be executed.
-Except as specified below,
-the remaining words are passed as arguments
-to the invoked command.
-The command name is passed as argument 0
-(see
-.BR exec (2)).
-The value of a simple-command is its exit status
-if it terminates normally, or (octal) 200+\fIstatus\^\fP if
-it terminates abnormally (see
-.B signal
-for a list of
-status values).
-.PP
-A pipeline
-is a sequence of one or more
-commands
-separated by
-.B \(bv
-or
-.B \(bv&
-("\fB\(bv&\fP" is actually shorthand for "\fB2>&1\ \|\(bv\fP\|". See
-.B Input/Output
-below).
-The standard output of each command but the last
-is connected by a
-.B pipe
-to the standard input of the next command.
-Each command is run as a separate process;
-\fBzsh\fP waits for all the commands to terminate.
-The exit status of a pipeline is the exit
-status of the last command to terminate. A pipeline may be preceded by
-one of the following keywords:
-.PP
-.PD 0
-.TP
-\fBtime\fP
-The user, system, and real times
-of the commands in the pipeline are printed when the pipeline
-completes.
-.TP
-\fBcoproc\fP
-The processes are
-run asynchronously with the input and output of the pipeline
-connected to a two-way pipe to the parent shell. The parent
-communicates with the coprocess using the \fB>&p\fP
-and \fB<&p\fP redirection operators.
-.TP
-\fB!\fP
-The exit status of the pipeline is the boolean NOT of the
-exit status of the last command.
-.PD
-.PP
-A sublist is a sequence of one or more pipelines
-separated by
-.BR &&
-or
-.BR || .
-The symbol \fB&&\fP (\fB||\fP) causes the list following it to be
-executed only if the preceding pipeline returns
-a zero (non-zero) value.
-.PP
-A list is a sequence of one or more sublists separated
-by, and optionally terminated by, either
-.BR ;
-or
-.BR & .
-A \fB;\fP causes sequential execution of the preceding
-sublist; a \fB&\fP causes asynchronous execution of the preceding
-sublist (that is, it does not wait for that sublist to finish).
-An arbitrary number of newlines may appear in a
-list, instead of a semicolon,
-to delimit a command.
-.PP
-A command
-is either a simple-command
-or one of the following.
-Unless otherwise stated,
-the value returned by a command is that of the
-last simple-command executed in the command.
-.TP
-\fBfor\fP \fIidentifier\^\fP [ \fBin\fP \fIword\^\fP .\|.\|. ] \fB;do\fP \fIlist\^\fP \fB;done\fP
-Each time a
-.B for
-command is executed,
-.I identifier
-is set to the next
-.I word
-taken from the
-.B in
-.I word list.
-If
-.B in
-.I word
-\&.\|.\|.
-is omitted, then the
-.B for
-command executes the \fBdo\fP \fIlist\^\fP once for each positional parameter
-that is set
-(see \fB"Parameter Substitution"\fP).
-Execution ends when there are no more words in the list.
-.TP
-\fBselect\fP \fIidentifier\^\fP [ \fBin\fP \fIword\^\fP .\|.\|. ] \fB;do\fP \fIlist\^\fP \fB;done\fP
-A
-.B select
-command prints on standard error (file descriptor 2), the set of
-.IR word s,
-each preceded by a number.
-If
-.BI in " word"
-\&.\|.\|.
-is omitted, then the positional parameters are used instead
-(see
-.B "Parameter Substitution"
-below).
-The
-.B PROMPT3
-prompt is printed
-and a line is read from the standard input.
-If this line consists of the number
-of one of the listed
-.IR word s,
-then the value of the parameter
-.I identifier
-is set to the
-.I word
-corresponding to this number.
-If this line is empty the selection list is
-printed again.
-Otherwise the value of the parameter
-.I identifier
-is set to null. The contents of the line read from standard input is
-saved in the parameter \fBREPLY\fP. The
-.I list
-is executed for each selection until a
-break or end-of-file is encountered.
-.TP
-\fBcase\fP \fIword\^\fP \fBin\fP [ \fIpattern\^\fP \fB)\fP \fIlist\^\fP \fB;;\fP ] .\|.\|. \fBesac\fP
-A
-.B case
-command executes the
-.I list
-associated with the first
-.I pattern
-that matches
-.IR word .
-The form of the patterns is
-the same as that used for
-filename generation (see
-.B "Filename Generation"
-below).
-.TP
-\fBif\fP \fIlist\^\fP \fB;then\fP \fIlist\^\fP [ \
-\fBelif\fP \fIlist\^\fP \fB;then\fP \fIlist\^\fP ] .\|.\|. \
-[ \fB;else\fP \fIlist\^\fP ] \fB;f\&i\fP
-The
-.I list
-following \fBif\fP is executed and,
-if it
-returns a zero exit status, the
-.I list
-following the first
-.B then
-is executed. Otherwise, the
-.I list
-following \fBelif\fP
-is executed and, if its value is zero, the
-.I list
-following the next
-.B then
-is executed. Failing that, the
-.B else
-.I list
-is executed. If no
-.B else
-.I list
-or
-.B then
-.I list
-is executed, then the
-.B if
-command returns a zero exit status.
-.TP
-.PD 0
-\fBwhile\fP \fIlist\^\fP \fB;do\fP \fIlist\^\fP \fB;done\fP
-.TP
-\fBuntil\fP \fIlist\^\fP \fB;do\fP \fIlist\^\fP \fB;done\fP
-.PD
-A
-.B while
-command repeatedly executes the
-.B while
-.I list
-and, if the exit status of the last command in the list is zero, executes
-the
-.B do
-.IR list ;
-otherwise the loop terminates.
-If no commands in the
-.B do
-.I list
-are executed, then the
-.B while
-command returns a zero exit status;
-.B until
-may be used in place of
-.B while
-to negate
-the loop termination test.
-.TP
-\fBrepeat\fP \fInum\fP\fB ;do\fP \fIlist\^\fP \fB;done\fP
-A
-.B repeat
-command executes the
-.I list
-a certain number of times, as specified by
-.IR num .
-If the exit status of
-.I list
-is nonzero, the loop terminates.
-.TP
-\fB(\fP\fIlist\^\fP\fB)\fP
-Execute
-.I list
-in a separate environment.
-Note, that if two adjacent open parentheses are
-needed for nesting, a space must be inserted to avoid
-arithmetic evaluation as described below.
-.TP
-\fB{\fP\fIlist\^\fP\fB}\fP
-The
-.I list
-is simply executed.
-.TP
-.PD 0
-\fBfunction\fP \fIidentifier\^\fP \fB{\fP\fIlist\fB}\fP
-.TP
-\fIidentifier\^\fP \fB() {\fP\fIlist\fB}\fP
-.PD
-Define a function which is referenced by
-.IR identifier .
-The body of the function is the
-.I list
-of commands between
-.B {
-and
-.BR } .
-(See
-.B Functions
-below).
-.TP
-\fBexec \fP\fIcommand\^\fP
-.br
-The
-.I command
-is executed in place of the parent shell, without forking.
-.TP
-\fBcommand \fP\fIcommand\^\fP
-.br
-The
-.I command
-is run, ignoring shell functions.
-.PP
-The following reserved words
-are only recognized as the first word of a command
-and when not quoted:
-.RS
-.PP
-.B
-if then else elif fi case esac for while until do done repeat function select time coproc ! exec command
-.RE
-.SS History Substitution
-.LP
-History substitution allows you to use words from previous command
-lines in the command line you are typing. This simplifies spelling
-corrections and the repetition of complicated commands or arguments.
-Command lines are saved in the history list, the size of which
-is controlled by the
-.B HISTSIZE
-variable. The most recent command is retained in any case.
-A history substitution begins with a
-.B !
-and may occur anywhere on the command line; history
-substitutions do not nest. The
-.B !
-can be escaped with
-.B \e
-to suppress its special meaning.
-.LP
-Input lines containing history substitutions are echoed on the
-terminal after being expanded, but before any other
-substitutions take place or the command gets executed.
-.SS \fIEvent Designators\fP
-.LP
-An event designator is a reference to a command-line entry in
-the history list.
-.RS
-.PD 0
-.TP
-.B !
-Start a history substitution, except when followed by a blank, newline,
-.BR = ,
-or
-.BR ( .
-.TP
-.B !!
-Refer to the previous command.
-By itself, this substitution
-repeats the previous command.
-.TP
-.BI ! n
-Refer to command-line
-.IR n .
-.TP
-.BI ! \-n
-Refer to the current command-line minus
-.IR n .
-.TP
-.BI ! str
-Refer to the most recent command starting with
-.IR str .
-.TP
-.BI !? str\fR[\fP ? \fR]\fP
-Refer to the most recent command containing
-.IR str .
-.TP
-.B !#
-Refer to the current command line typed in so far.
-.TP
-.BR !{ .\|.\|. }
-Insulate a history reference from adjacent characters (if necessary).
-.PD
-.RE
-.SS \fIWord Designators\fR
-.LP
-A
-.RB ` : '
-separates the event specification from the word designator.
-It can be omitted if the word designator begins with a
-.BR \*^ ,
-.BR $ ,
-.BR * ,
-.B \-
-or
-.BR % .
-If the word is to be selected from the previous command, the second
-.B !
-character can be omitted from the event specification. For instance,
-.B !!:1
-and
-.B !:1
-both refer to the first word of the previous command, while
-.B !!$
-and
-.B !$
-both refer to the last word in the previous command.
-Word designators include:
-.RS
-.PD 0
-.TP
-.B 0
-The first input word (command).
-.TP
-.I n
-The
-.IR n 'th
-argument.
-.TP
-.B ^
-The first argument, that is,
-.BR 1 .
-.TP
-.B $
-The last argument.
-.TP
-.B %
-The word matched by (the most recent)
-.BI ? s
-search.
-.TP
-.IB x \- y
-A range of words;
-.BI \- y
-abbreviates
-.BI 0\- y\fR.
-.TP
-.B *
-All the arguments, or a null value if there is just
-one word in the event.
-.TP
-.IB x *
-Abbreviates
-.IB x \-$ .
-.TP
-.IB x \-
-Like
-.I x*
-but omitting word
-.BR $ .
-.PD
-.RE
-.SS \fIModifiers\fR
-.IX "history substitution modifiers"
-.IX ": modifiers" "" "\fL:\fR modifiers \(em history substitution \(em \fLcsh\fR"
-.LP
-After the optional word designator, you can add
-a sequence of one or more of the following modifiers,
-each preceded by a
-.BR : .
-.RS
-.TP
-.B h
-Remove a trailing pathname component, leaving the head.
-.PD 0
-.TP
-.B r
-Remove a trailing suffix of the form
-.RB ` "\&.\fIxxx" ',
-leaving the basename.
-.TP
-.B e
-Remove all but the suffix.
-.TP
-.BI s/ l / r\fR[\fP / \fR]\fP
-Substitute
-.I r
-for
-.IR l .
-.TP
-.B t
-Remove all leading pathname components, leaving the tail.
-.TP
-.B &
-Repeat the previous substitution.
-.TP
-.B g
-Apply the change to the first occurrence of a match in each word,
-by prefixing the above (for example,
-.BR g& ).
-.TP
-.B p
-Print the new command but do not execute it.
-.TP
-.B q
-Quote the substituted words, escaping further substitutions.
-.TP
-.B x
-Like
-.BR q ,
-but break into words at each blank.
-.PD
-.RE
-.LP
-Unless preceded by a
-.BR g ,
-the modification is applied only to the
-first string that matches
-.IR l ;
-an error results if no string matches.
-.LP
-The left-hand side of substitutions are not regular expressions,
-but character strings.
-Any character can be used as the delimiter in place of
-.BR / .
-A backslash quotes the delimiter character.
-The character
-.BR & ,
-in the right hand side, is replaced by the text
-from the left-hand-side.
-The
-.B &
-can be quoted with a backslash.
-A null
-.I l
-uses the previous string either from a
-.I l
-or from a contextual scan string
-.I s
-from
-.BI !? s\fR.
-You can omit the rightmost delimiter if a newline
-immediately follows
-.IR r ;
-the rightmost
-.B ?
-in a context scan can similarly be omitted.
-.LP
-Without an event specification, a history reference refers either to the
-previous command, or to a previous history reference on the command line
-(if any).
-.PP
-.LP
-.PP
-The character sequence
-.BI ^ foo ^ bar
-repeats the last command, replacing the string "foo" with the
-string "bar".
-.PP
-If \fBzsh\fP encounters the character sequence
-\fB!"\fP
-in the input, the history mechanism is temporarily disabled until
-the current list is fully parsed. The
-\fB!"\fP
-is removed from the input, and any subsequent
-.B !
-characters have no special significance.
-.PP
-A less convenient but more comprehensible
-form of command history support
-is provided by the
-.B fc
-builtin (see below).
-.SS Comments
-In noninteractive shells,
-a word beginning with
-.B #
-causes that word and all the following characters up to a newline
-to be ignored.
-.SS Aliasing
-The first word of each command is replaced by the text of an
-alias if an alias for this word has been defined.
-The replacement string can contain any
-valid input
-including the metacharacters listed above.
-If the last character of the alias value is a blank
-then the word following the alias will also be checked for alias
-substitution.
-Aliases can be nested.
-If an alias is defined with using the \-a flag (see the
-.B alias
-builtin below), it will be replaced no matter where it
-appears in the command line.
-Aliases can be used to redefine
-builtin commands or the
-`reserved words' listed above.
-Aliases can be created and listed with the
-alias
-command and can be removed with the
-unalias
-command.
-.PP
-The following aliases
-are compiled into \fBzsh\fP
-but can be unset or redefined:
-.RS 5
-.PD 0
-.TP
-.B "false=\(fmlet 0\(fm"
-.TP
-.B "history=\(fmfc \-l\(fm"
-.TP
-.B "nohup=\(fmnohup\ \(fm"
-.TP
-.B "r=\(fmfc \-e \-\(fm"
-.TP
-.B "true=\(fm:\(fm"
-.TP
-.B "pwd=\(fmecho $PWD\(fm"
-.PD
-.RE
-.SS Process Substitution
-Each command argument of the form
-\fB<(\fP\fIlist\^\fP\fB)\fP
-or
-\fB>(\fP\fIlist\^\fP\fB)\fP
-or
-\fB=(\fP\fIlist\^\fP\fB)\fP
-is subject to process substitution.
-In the case of the
-.B <
-or
-.B >
-forms, \fBzsh\fP
-will run process
-.I list
-asynchronously connected to a named pipe (FIFO).
-The name of this pipe will become the argument to the command.
-If the form with
-.B >
-is selected then writing on this file will provide input for
-.IR list .
-If
-.B <
-is used,
-then the file passed as an argument will
-be a named pipe connected to the output of the
-.I list
-process.
-For example,
-.RS
-.PP
-\fBpaste <(cut \-f1\fP \fIfile1\fP\fB) <(cut \-f3\fP \fIfile2\fB) | tee >(\fP\fIprocess1\fP\fB) >(\fP\fIprocess2\fP\fB)\fP >/dev/null
-.RE
-.PP
-.BR cut s
-fields 1 and 3 from
-the files
-.I file1
-and
-.I file2
-respectively,
-.BR paste s
-the results together, and sends it to the processes
-.I process1
-and
-.IR process2 .
-Note that the file, which is passed as an argument to the command,
-is a system
-pipe
-so programs that expect to
-.BR lseek (2)
-on the file will not work.
-Also note that the previous example can be more compactly and
-efficiently written as:
-.RS
-.PP
-\fBpaste <(cut \-f1\fP \fIfile1\fP\fB) <(cut \-f3\fP \fIfile2\fB) > >(\fP\fIprocess1\fP\fB) > >(\fP\fIprocess2\fP\fB)\fP
-.RE
-.PP
-\fBzsh\fP uses socketpairs (pipes) instead of a FIFOs to implement the latter
-two process substitutions in the above example.
-.PP
-If
-.B =
-is used,
-then the file passed as an argument will be the name
-of a temporary file containing
-the output of the
-.I list
-process. This may be used instead of the
-.B <
-form for a program that expects to lseek on the input file.
-.SS Parameter Substitution
-A parameter is an identifier,
-one or more digits,
-or any of the characters
-.BR \(** ,
-.BR # ,
-.BR ? ,
-.BR \- ,
-.BR $ ,
-and
-.BR !\\^ .
-The value of a named
-parameter may also be assigned by writing:
-.RS
-.PP
-.IB name = value\^\|
-[
-.IB name = value
-] .\|.\|.
-.RE
-.PP
-If
-.I name
-was declared integer with the
-.B integer
-builtin, the
-.I value
-is subject to arithmetic evaluation as described below.
-.PP
-Positional parameters,
-parameters denoted by a number,
-may be assigned values with the
-\fBset\fP
-builtin. Parameter
-.B $0
-is set from argument zero when \fBzsh\fP
-is invoked.
-.PP
-The character
-.B $
-is used to introduce parameter substitution.
-Note that the results of such
-substitution are quoted from all
-further substitution.
-.PP
-.PD 0
-.RS
-.TP
-\fB${\fP\fIparameter\^\fP\fB}\fP
-The value, if any, of the parameter is substituted.
-The braces are required when
-.I parameter
-is followed by a letter, digit, or underscore
-that is not to be interpreted as part of its name
-or when a named parameter is subscripted.
-If
-.I parameter
-is one or more digits then it is a positional parameter.
-.I parameter
-may be followed by zero or more of any of the modifiers allowed in the
-history mechanism except \fBq\fP and \fBx\fP.
-.TP
-\fB$*\fP
-All the positional
-parameters, starting with
-.BR $1 ,
-are substituted.
-.TP
-\fB${\fP\fIparameter\^\fP\fB:\-\fP\fIword\^\fP\fB}\fP
-If
-.I parameter
-is set and is non-null then substitute its value;
-otherwise substitute
-.IR word .
-.TP
-\fB${\fP\fIparameter\^\fP\fB:=\fP\fIword\^\fP\fB}\fP
-If
-.I parameter
-is not set or is null then set it to
-.IR word ;
-the value of the parameter is then substituted.
-Positional parameters may be assigned to
-in this way.
-.TP
-\fB${\fP\fIparameter\^\fP\fB:?\fP\fIword\^\fP\fB}\fP
-If
-.I parameter
-is set and is non-null then substitute its value;
-otherwise, print
-.I word
-and exit.
-If
-.I word
-is omitted then a standard message is printed.
-.TP
-\fB${\fP\fIparameter\^\fP\fB:+\fP\fIword\^\fP\fB}\fP
-If
-.I parameter
-is set and is non-null then substitute
-.IR word ;
-otherwise substitute nothing.
-.TP
-\fB${\fP\fIparameter\^\fP\fB#\fP\fIpattern\^\fP\fB}\fP
-.TP
-\fB${\fP\fIparameter\^\fP\fB##\fP\fIpattern\^\fP\fB}\fP
-If the shell
-.I pattern
-matches the beginning of the value of
-.IR parameter ,
-then the value of
-this substitution is the value of the
-.I parameter
-with the matched portion deleted;
-otherwise the value of this
-.I parameter
-is substituted.
-In the first form the smallest matching pattern is deleted and in the
-second form the largest matching pattern is deleted.
-.TP
-\fB${\fP\fIparameter\^\fP\fB%\fP\fIpattern\^\fP\fB}\fP
-.TP
-\fB${\fP\fIparameter\^\fP\fB%%\fP\fIpattern\^\fP\fB}\fP
-If
-the shell
-.I pattern
-matches the end of the value of
-.IR parameter ,
-then the value of
-this substitution is the value of the
-.I parameter
-with the matched part deleted;
-otherwise substitute the value of
-.IR parameter .
-In the first form the smallest matching pattern is deleted and in the
-second form the largest matching pattern is deleted.
-.PD
-.RE
-.PP
-In the above,
-.I word
-is not evaluated unless it is
-to be used as the substituted string,
-so that, in the following example,
-pwd
-is executed only if
-.B d
-is not set or is null:
-.RS
-.PP
-.B "echo \|${d:\-\^$(\^pwd\^)\^}"
-.RE
-.PP
-If the
-.B :
-is omitted from the above expressions,
-then \fBzsh\fP only checks whether
-.I parameter
-is set or not.
-.PP
-The following parameters are automatically set by \fBzsh\fP:
-.RS
-.PD 0
-.TP 10
-.B #
-The number of positional parameters in decimal.
-.TP
-.B \-
-Flags supplied to \fBzsh\fP on invocation or by
-the
-.B setopt
-command.
-.TP
-.B ?
-The decimal value returned by the last executed command.
-.TP
-.B $
-The process number of this shell.
-.TP
-.B !
-The process number of the last background command invoked.
-.TP
-.B EUID
-The effective user id of the shell process.
-.TP
-.B HOSTTYPE
-A string corresponding to the architecture \fBzsh\fP is running on.
-.TP
-.B PPID
-The process number of the parent of this shell.
-.TP
-.B PWD
-The present working directory set by the
-cd
-command.
-.TP
-.B RANDOM
-Each time this parameter is referenced, a random integer,
-uniformly distributed between 0 and 32767, is generated.
-The sequence of random numbers can be initialized by assigning
-a numeric value to
-RANDOM.
-.TP
-.B LINENO
-In a script, the current line number.
-.TP
-.B REPLY
-This parameter is set by the
-.B select
-statement and by
-the
-.B read
-builtin when no arguments are supplied.
-.TP
-.B SECONDS
-Each time this parameter is referenced, the number of
-seconds since shell invocation is returned.
-If this parameter is
-assigned a value, then the value returned upon reference will
-be the value that was assigned plus the number of seconds since the assignment.
-.TP
-.B TCxx
-The string or value corresponding to the termcap entry \fBxx\fP.
-.TP
-.B UID
-The user id of the shell process.
-.TP
-.B USERNAME
-The name corresponding to the real user id of this shell process.
-.TP
-.B VERSION
-The version number of this \fBzsh\fP.
-.PD
-.RE
-.PP
-The following parameters are used by \fBzsh\fP:
-.RS
-.PD 0
-.TP
-.B ARGV0
-If placed in the environment for a command, \fBzsh\fP
-will use its value as argv[0] for the \fBexec\fP(2) call
-rather than the specified command name.
-.TP
-.B CDPATH
-The search path for the
-cd
-command.
-.TP
-.B FCEDIT
-The default editor name for the
-.B fc
-command.
-.TP
-.B IFS
-Internal field separators,
-normally
-.BR space ,
-.BR tab ,
-and
-.B newline
-that is used to separate command words which result from
-command or parameter substitution
-and for separating words with the
-.B read
-builtin.
-.TP
-.B HISTSIZE
-If this parameter is set when \fBzsh\fP is invoked, then
-the number of previously entered commands that
-are accessible by this shell
-will be greater than or equal to this number.
-The default is 128.
-.TP
-.B HOME
-The default argument (home directory) for the
-.B cd
-command.
-.TP
-.B MAIL
-If this parameter is set to the name of a mail file
-then \fBzsh\fP informs the user of arrival of mail
-in the specified file.
-.TP
-.B MAILCHECK
-This variable specifies how often (in seconds) \fBzsh\fP
-will check for changes in the modification time
-of any of the files specified by the
-.B MAIL
-parameter.
-The default value is 60 seconds.
-When the time has elapsed
-\fBzsh\fP will check before issuing the next prompt.
-.TP
-.B PROMPT
-The value of this parameter is expanded
-much like printf(3S),
-using "%<char>" to signal an expansion.
-The available sequences are:
-.RS
-.PP
-.TP
-.B %d \fPor\fB %/
-The current working directory.
-.TP
-.B %\(ap
-The current working directory; if it starts with $HOME, that part is
-replaced by a \(ap.
-.TP
-.B %c \fPor\fB %.
-The trailing component of the current working directory.
-.TP
-.B %h \fPor\fB %!
-The current history event number.
-.TP
-.B %M
-The full machine hostname.
-.TP
-.B %m
-The hostname up to the first ".".
-.TP
-.BR %S\ ( %s )
-Start (stop) standout mode.
-.TP
-.BR %B\ ( %b )
-Start (stop) boldfacing mode.
-.TP
-.BR %U\ ( %u )
-Start (stop) underline mode.
-.TP
-.B %t \fPor\fB %@
-Current time of day, in 12-hour, am/pm format.
-.TP
-.B %T
-Current time of day, in 24-hour format.
-.TP
-.B %n
-The user name (contents of \fB$USERNAME\fP).
-.TP
-.B %w
-The date in <Mon> dd format.
-.TP
-.B %W
-The date in mm/dd/yy format.
-.TP
-.B %D
-The date in yy-mm-dd format.
-.TP
-.B %l
-The line (tty) the user is logged on.
-.TP
-.B %#
-A `#' if \fBzsh\fP is run as a root shell, a `%' if not.
-.TP
-.B %%
-A single %.
-.RE
-.PD
-.PP
-.PD 0
-.B PROMPT2
-Secondary prompt string,
-expanded in the
-same manner as
-.BR PROMPT .
-.TP
-.B PROMPT3
-Selection prompt string
-used within a
-.B select
-loop, by default
-.RB `` "#? \|" ''.
-.TP
-.B SHELL
-The pathname of the user's shell.
-.TP
-.B WATCH
-A colon-separated list of users to be checked for login and logout
-activity. If set to `all', the login and logout activity
-of all users will be monitored.
-.TP
-.B WATCHFMT
-The format of the login/logout reports.
-The following
-sequences are available for the format specification:
-.RS
-.PP
-.TP
-.B %n
-The name of the user that logged in/out.
-.TP
-.B %a
-The observed action, i.e. "logged on" or "logged off".
-.TP
-.B %l
-The line (tty) the user is logged on.
-.TP
-.BR %S\ ( %s )
-Start (stop) standout mode.
-.TP
-.BR %B\ ( %b )
-Start (stop) boldfacing mode.
-.TP
-.BR %U\ ( %u )
-Start (stop) underline mode.
-.TP
-.B %M
-The full hostname of the remote host.
-.TP
-.B %m
-The hostname up to the first ".". If only
-the ip address is available or the utmp
-field contains the name of an X-windows
-display, the whole name is printed.
-.TP
-.B %t or %@
-The time, in 12-hour, am/pm format (logout
-time is approximated if unavailable).
-.TP
-.B %T
-The time, in 24-hour format.
-.TP
-.B %w
-The date in <Mon> dd format.
-.TP
-.B %W
-The date in mm/dd/yy format.
-.TP
-.B %D
-The date in yy-mm-dd format.
-.RE
-.PD
-.PP
-If
-.B WATCHFMT
-is not set, the format defaults to
-"%n has %a %l from %m."
-.RE
-.PP
-\fBzsh\fP gives default values to
-\fBPATH\fP, \fBPROMPT\fP, \fBPROMPT2\fP, \fBPROMPT3\fP,
-and \fBIFS\fP,
-while
-.B SHELL
-and
-.B MAIL
-are
-not set at all by \fBzsh\fP (although
-.B HOME
-.I is
-set by
-.IR login (1)).
-On some systems
-.B MAIL
-and
-.B SHELL
-are also
-set by
-.IR login (1)).
-.B \fBzsh\fP
-expands the value of
-.B HOME
-so that it does not contain any symbolic links.
-.SS Arithmetic Substitution
-An arithmetic expression of the form
-.B $[...]
-is replaced by the value of the arithmetic expression
-within the brackets. See
-.B
-Arithmetic Evaluation
-below.
-.SS Command Substitution
-The standard output from a command of the form
-.B $(...)
-or
-.B `...`
-may be used as part or all
-of a word;
-trailing newlines are removed.
-In the second (archaic) form, the string between the quotes is processed
-for special quoting characters before the command is executed. (See
-.BR Quoting ).
-The command substitution
-\^\fB$(\^cat\ file\^)\fP\^
-can be replaced by the equivalent but faster
-\^\fB$(\^<file\^)\fP\^.
-.SS Brace Expansion
-A string of the form
-.B {str,str,...}
-is expanded to each string in the comma-separated list in the
-specified order. This construct may be nested.
-.PP
-A five-character string of the form
-.B {x\-y}
-is expanded to each character in the range from x to y, inclusive.
-.SS Filename Substitution
-After alias substitution is performed, each word
-is checked to see if it begins with an unquoted
-.B \(ap
-or
-.BI = .
-If it begins with a
-.BI \(ap ,
-then the word up to a
-.B /
-is checked to see if it matches a user name on the system.
-If a match is found, the
-.B \(ap
-and the matched login name is replaced by the
-login directory of the matched user.
-A
-.B \(ap
-by itself, or in front of a
-.BR / ,
-is replaced by \fB$HOME\fP.
-A
-.B \(ap
-followed by a
-.B +
-or
-.B \-
-is replaced by \fB$PWD\fP and \fB$OLDPWD\fP respectively.
-.PP
-If the word begins with a
-.B =
-followed by a letter, the word
-is replaced by the full pathname of the command name
-following the
-.BI = .
-Thus
-.BI = foo
-is a shorthand for
-\^\fB$(\^which\ \fIfoo\fB\^)\fR\^.
-If the word is of the form
-.B =number
-or
-.BR =number/... ,
-then the first part of the word is replaced
-by the appopriate element of the directory stack,
-corresponding to the specified number.
-The stack is viewed as zero-based, i.e.,
-.B =0
-is the same as
-.BR $PWD .
-As a special
-case,
-.B =\-
-is recognized as indicating the last directory in the stack.
-.PP
-All of the above forms of filename substitution
-may be followed by any of the modifiers allowed in the
-history mechanism except \fBq\fP and \fBx\fP.
-.SS Filename Generation
-Following substitution, each command
-.I word
-is scanned for
-the characters
-.BR \(** ,
-.BR ? ,
-.BR [ ,
-.BR ^ ,
-.BR # ,
-.BR < ,
-and
-.BR | .
-If one of these characters appears
-then the word is regarded as a
-.IR pattern .
-The word is replaced with alphabetically sorted filenames that match the pattern.
-If no filename is found that matches the pattern, then
-the word is left unchanged.
-When a
-.I pattern
-is used for filename generation,
-the character
-.B .
-at the start of a filename
-or immediately following a
-.BR /
-must be matched explicitly, unless the
-.B globdots
-option is set.
-Also, the
-.B /
-character itself must be matched explicitly.
-In filename generation, no pattern matches "." or "..".
-In other instances of pattern matching the
-.B /
-and
-.B .
-are not treated specially.
-.PP
-.PD 0
-.RS
-.TP
-.B \(**
-Matches any string, including the null string.
-.TP
-.B ?
-Matches any single character.
-.TP
-.BR [ \^.\|.\|.\^ ]
-Matches any one of the enclosed characters.
-A pair of characters separated by
-.B \-
-matches any
-character lexically between the pair, inclusive.
-If the first character following the opening "["
-is a "^" then any character not enclosed is matched.
-A
-.B \-
-can be included in the character set by putting it as the
-first or last character.
-.TP
-.B <...>
-Matches a numeric field. A pattern of the form
-.BR <x\-y> ,
-where x and y are decimal integers, matches any number between
-x and y inclusive. Patterns of the form
-.B <x\->
-and
-.B <\-y>
-match any number greater than or equal to x, and less than or
-equal to y, respectively. The degenerate
-.B <\->
-or simply
-.B <>
-matches any number. Note that a
-.B <...>
-pattern eats up
-any numbers it encounters; thus
-.B foo<1\-5>7
-does not match
-"foo27", even though 2 is between 1 and 5.
-.TP
-.B x#
-Matches zero or more occurrences of the pattern x.
-.TP
-.B x##
-Matches one or more occurrences of the pattern x.
-.TP
-.B ^pattern
-Matches anything but the specified pattern.
-.TP
-.B foo|bar
-Matches either foo or bar.
-.PD
-.RE
-.PP
-Parentheses may be used for grouping. Note that the \fB|\fP character
-must be within parentheses, so that the lexical analyzer does
-not think it is a pipe character. Also note that "/" has a
-higher precedence than "^"; that is:
-.RS
-.PP
-ls
-.BI ^ foo / bar
-.RE
-.PP
-will search directories in "." except "./foo" for a file named bar.
-.PP
-A pathname component of the form
-.BI ( foo /)#
-matches a path consisting of zero or more directories
-matching the pattern foo.
-As a shorthand,
-.B ..../
-is equivalent to
-.BR (*/)# .
-Thus:
-.RS
-.PP
-ls
-.BI (*/)# bar
-.RE
-.PP
-or
-.RS
-.PP
-ls
-.BI ..../ bar
-.RE
-.PP
-does a recursive directory search for files named bar.
-.PP
-If used for filename generation, a pattern may end in a qualifier
-of the form \fB(X)\fP or \fB(^X)\fP, where \fBX\fP is a character that
-specifies which filenames that otherwise match the given pattern
-will be inserted in the argument list. \fBX\fP may be any one of the
-following:
-.PD 0
-.RS
-.TP
-.B /
-directories
-.TP
-.B .
-plain files
-.TP
-.B @
-symbolic links
-.TP
-.B =
-sockets
-.TP
-.B <
-named pipes (FIFOs)
-.TP
-.B *
-executable files (0100)
-.TP
-.B %
-device files (character or block special)
-.TP
-.B r
-readable files (0400)
-.TP
-.B w
-writeable files (0200)
-.TP
-.B x
-executable files (0100, same as *)
-.TP
-.B R
-world-readable files (0004)
-.TP
-.B W
-world-writeable files (0002)
-.TP
-.B X
-world-executable files (0001)
-.PD
-.RE
-.PP
-Thus:
-.RS
-.PP
-ls
-.B
-*(%)
-.RE
-.PP
-lists all device files in the current directory,
-and
-.RS
-.PP
-ls
-.B /tmp/foo*(^@)
-.RE
-.PP
-lists all files beginning with the string
-"foo" in /tmp, ignoring symlinks. A "/" at the end of a pattern
-is equivalent to "(/)".
-.SS Quoting
-Each of the
-.I metacharacters
-listed above (See
-.I Definitions
-above)
-has a special meaning to \fBzsh\fP
-and causes termination of a word unless quoted.
-A character may be
-.I quoted
-(that is, made to stand for itself)
-by preceding
-it with a
-.BR \e .
-The pair
-.B \enewline
-is ignored.
-All characters enclosed between a pair of single quote marks (\^\fB\(fm\^\(fm\fP\^),
-are quoted.
-A single quote cannot appear within single quotes.
-Inside double quote marks
-(\fB"\^"\fP),
-parameter and command substitution occurs and
-.B \e
-quotes the characters
-.BR \e ,
-.BR \f(CW`\fP ,
-\fB"\fP,
-and
-.BR $ .
-Inside grave quote marks
-.Pn ( `` )
-.B \e
-quotes the characters
-.BR \e ,
-` ,
-and
-.PP $ .
-If the grave quotes occur within double quotes then
-.BR \e
-also quotes the character
-\fB"\fP.
-.PP
-The special meaning of reserved words or aliases can be removed by quoting any
-character of the reserved word.
-The recognition of function names or builtin names listed below
-cannot be altered by quoting them.
-.SS Arithmetic Evaluation
-An ability to perform integer arithmetic
-is provided with the builtin
-.BR let .
-Evaluations are performed using
-.I long
-arithmetic.
-Constants are of the form
-[\fIbase\fB#\^\fR]\fIn\^\fP
-where
-.I base
-is a decimal number between two and thirty-six
-representing the arithmetic base
-and
-.I n
-is a number in that base.
-If
-.I base
-is omitted
-then base 10 is used.
-.PP
-An arithmetic expression uses nearly the same syntax, precedence, and
-associativity of
-expressions in C.
-The following operators are supported (listed in decreasing order
-of precedence):
-.PP
-.PD 0
-.RS
-.TP
-.B + \- ! \(ap ++ \-\-
-unary plus/minus, logical NOT, complement, {pre,post}{in,de}crement
-.TP
-.B &
-logical AND
-.TP
-.B ^
-logical XOR
-.TP
-.B |
-logical OR
-.TP
-.B * / %
-multiplication, division, remainder
-.TP
-.B + \-
-addition, subtraction
-.TP
-.B << >>
-logical shift left, shift right
-.TP
-.B < > <= >=
-comparison
-.TP
-.B == !=
-equality and inequality
-.TP
-.B &&
-boolean AND
-.TP
-.B || ^^
-boolean OR, XOR
-.TP
-.B ? :
-ternary operator
-.TP
-.B
-= += \-= *= /= %= &= ^= |= <<= >>= &&= ||= ^^=
-assignment
-.TP
-.B ,
-comma operator
-.PD
-.RE
-.PP
-The operators &&, ||, &&=, and ||= are short-circuiting,
-and only one of the latter two expressions in a ternary operator
-is evaluated. Note the precedence of the logical AND, OR,
-and XOR operators.
-.PP
-Named parameters can be referenced by name within an arithmetic expression
-without using the parameter substitution syntax.
-.PP
-An internal integer representation of a named parameter
-can be specified with the
-.B integer
-builtin.
-Arithmetic evaluation is performed on the value of each
-assignment to a named parameter declared integer
-in this manner.
-.PP
-Since many of the arithmetic operators require
-quoting, an alternative form of the
-.B let
-command is provided.
-For any command which begins with a
-.BR (( ,
-all the characters until a matching
-.B ))
-are treated as a quoted expression.
-More precisely,
-.BR (( .\|.\|. ))
-is equivalent to
-.B let
-\fB"\fP\|.\|.\|.\fB"\fP.
-.SS Prompting
-When used interactively,
-\fBzsh\fP prompts with the value of
-.B PROMPT
-before reading a command.
-If at any time a newline is typed and further input is needed
-to complete a command, then the secondary prompt
-(that is, the value of
-.BR PROMPT2 )
-is issued.
-.SS Input/Output
-Before a command is executed, its input and output
-may be redirected using a special notation interpreted by \fBzsh\fP.
-The following may appear anywhere in a simple-command
-or may precede or follow a
-.I command
-and are
-.I not
-passed on to the invoked command.
-Substitution occurs before
-.I word
-is used except as noted below.
-If the result of substitution on
-.I word
-produces more than one filename,
-redirection occurs for each
-separate filename in turn.
-.TP 14
-.BI < word
-Use file
-.I word
-as standard input (file descriptor 0).
-.TP
-.BI > word
-Use file
-.I word
-as standard output (file descriptor 1).
-If the file does not exist then it is created.
-If the file exists, and the
-.B clobber
-option is not set,
-this causes an error;
-otherwise, it is truncated to zero length.
-.TP
-.BI >! " word"
-Same as
-.BR > ,
-except that the file is truncated to zero length
-if it exists, even if
-.B clobber
-is not set.
-.TP
-.BI >> word
-Use file
-.I word
-as standard output.
-If the file exists then output is appended to it.
-If the file does not exist, and the
-.B clobber
-option is not set,
-this causes an error;
-otherwise, the file is created.
-.TP
-.BI >>! " word"
-Same as
-.BR >> ,
-except that the file is created if it does not
-exist, even if
-.B clobber
-is not set.
-.TP
-.BI << word
-The shell input is read up to a line that is the same as
-.IR word ,
-or to an end-of-file.
-No parameter substitution, command substitution or
-filename generation is performed on
-.IR word .
-The resulting document,
-called a
-.IR here-document ,
-becomes
-the standard input.
-No interpretation
-is placed upon the characters of the document.
-.TP
-.BI <& digit
-The standard input is duplicated from file descriptor
-.I digit
-(see
-.IR dup (2)).
-Similarly for the standard output using
-.BR >&
-.IR digit .
-.TP
-.BI >& word
-Same as
-.BI > word
-.B 2>&1 .
-.TP
-.BI >>& word
-Same as
-.BI >> word
-.B 2>&1 .
-.TP
-.B <&\-
-The standard input is closed.
-Similarly for the standard output using
-.BR >&\- .
-.TP
-.BI <&! " digit"
-Same as
-.B <&\-
-.BI <& digit .
-.TP
-.BI >&! " digit"
-Same as
-.B >&\-
-.BI >& digit .
-.TP
-.B <&p
-The input from the coprocess is moved to standard input.
-.TP
-.B >&p
-The output to the coprocess is moved to standard output.
-.PP
-If one of the above is preceded by a digit,
-then the
-file descriptor number referred to is that specified
-by the digit
-(instead of the default 0 or 1).
-For example:
-.RS
-.PP
-\&.\|.\|. \|2>&1
-.RE
-.PP
-means file descriptor 2 is to be opened
-for writing as a duplicate
-of file descriptor 1.
-.PP
-The order in which redirections are specified is significant.
-\fBzsh\fP evaluates each redirection in terms of the
-.RI ( "file descriptor" ", " file )
-association at the time of evaluation.
-For example:
-.RS
-.PP
-\&.\|.\|. \|1>\fIfname\^\fP 2>&1
-.RE
-.PP
-first associates file descriptor 1 with file
-.IR fname .
-It then associates file descriptor 2 with the file associated with file
-descriptor 1 (that is,
-.IR fname ).
-If the order of redirections were reversed, file descriptor 2 would be associated
-with the terminal (assuming file descriptor 1 had been) and then file descriptor
-1 would be associated with file
-.IR fname .
-.PP
-If the user tries to open a file descriptor for writing more than once,
-\fBzsh\fP opens the file descriptor as a pipe to a process that copies
-its input to all the specified outputs, similar to tee(1). Thus:
-.RS
-.PP
-.B date >foo >bar
-.RE
-.PP
-writes the date to two files, named "foo" and "bar".
-Note that a pipe is an implicit indirection; thus
-.RS
-.PP
-.B date >foo | cat
-.RE
-.PP
-writes the date to the file "foo", and also pipes it to cat.
-.PP
-If the user tries to open a file descritor for reading more than once,
-\fBzsh\fP opens the file descriptor as a pipe to a process that copies
-all the specified inputs to its output in the order
-specified, similar to cat(1). Thus
-.RS
-.PP
-.B sort <foo <fubar
-.RE
-.PP
-or even
-.RS
-.PP
-.B sort <f{oo,ubar}
-.RE
-.PP
-is equivalent to "cat foo bar | sort". Note that
-a pipe is in implicit indirection; thus
-.RS
-.PP
-.B cat bar | sort <foo
-.RE
-.PP
-is equivalent to "cat bar foo | sort" (note the order of the inputs).
-.PP
-If a simple command consists of one or more redirection operators
-and zero or more parameter assignments, but no command name,
-the command \fBcat\fP is assumed. Thus
-.RS
-.PP
-.B < file
-.RE
-.PP
-prints the contents of \fBfile\fP.
-.PP
-If a command is followed by
-.B &
-and job control is not active,
-then the default standard input
-for the command
-is the empty file
-.BR /dev/null .
-Otherwise, the environment for the execution of a command contains the
-file descriptors of the invoking shell as modified by
-input/output specifications.
-.SS Environment
-The
-.I environment
-(see
-.IR environ (7))
-is a list of name-value pairs that is passed to
-an executed program in the same way as a normal argument list.
-The names must be
-.I identifiers
-and the values are character strings.
-\fBzsh\fP interacts with the environment in several ways.
-On invocation, \fBzsh\fP scans the environment
-and creates a
-parameter
-for each name found,
-giving it the corresponding value and marking it exported.
-Executed commands inherit the environment.
-If the user modifies the values of these
-parameters
-or creates new ones,
-using the
-.B export
-command they become part of the
-environment.
-The environment seen by any executed command is thus composed
-of any name-value pairs originally inherited by \fBzsh\fP,
-whose values may be modified by the current shell,
-plus any additions
-which must be noted in
-.B export
-commands.
-.PP
-The environment for any
-.I simple-command
-or function
-may be augmented by prefixing it with one or more parameter assignments.
-A parameter assignment argument is a word of the form
-.IR identifier=value .
-Thus:
-.RS
-.PP
-TERM=450 \|cmd \|args and
-.br
-(export \|TERM; \|TERM=450; \|cmd \|args)
-.RE
-.PP
-are equivalent (as far as the above execution of
-.I cmd
-is concerned).
-.PP
-If the
-.B keyword
-flag is set,
-.I all
-parameter assignment arguments are placed in the environment,
-even if they occur after the command name.
-.SS Function
-.PP
-The
-.B function
-reserved word, described in the
-.I Commands
-section above,
-is used to define shell functions.
-Shell functions are read in and stored internally.
-Alias names are resolved when the function is read.
-Functions are executed like commands with the arguments
-passed as positional parameters.
-(See
-.I Execution
-below).
-.PP
-Functions execute in the same process as the caller and
-share all files
-and present working directory with the
-caller.
-A trap on
-.B EXIT
-set inside a function
-is executed after the function completes in the environment
-of the caller.
-.PP
-The builtin
-.B return
-is used to return
-from function calls.
-Errors within functions return control to the caller.
-.PP
-Function identifiers
-can be listed with the
-.B function
-builtin.
-Functions can be undefined with the
-.B unfunction
-builtin.
-.PP
-The following functions, if defined, have special meaning to \fBzsh\fP:
-.PP
-.PD 0
-.RS
-.TP
-\fBchpwd\fP
-Executed whenever the current working directory is changed.
-.TP
-\fBprecmd\fP
-Executed before each prompt.
-.TP
-\fBperiodic\fP
-If the parameter
-.B PERIOD
-is set, this function is executed every
-.B PERIOD
-minutes, just before a prompt.
-.TP
-\fBTRAPxxx\fP
-If defined and non-null,
-this function will be executed whenever \fBzsh\fP
-catches a signal \fBSIGxxx\fP, where \fBxxx\fP is a signal
-name as specified for the \fBkill\fP builtin (see below).
-In addition, \fBTRAPERR\fP is executed whenever a command has a non-zero
-exit status, \fBTRAPDEBUG\fP is executed after each command, and
-\fBTRAPEXIT\fP
-is executed when \fBzsh\fP exits,
-or when the current function exits if defined
-inside a function.
-If a function of this form is defined and null,
-\fBzsh\fP and processes spawned by it will ignore \fBSIGxxx\fP.
-.PD
-.RE
-.SS Jobs
-.PP
-If the
-.B monitor
-option of the
-.B set
-command is turned on,
-an interactive shell associates a \fIjob\fR with each pipeline.
-It keeps
-a table of current jobs, printed by the
-.B jobs
-command, and assigns them small integer numbers.
-When a job is started asynchronously with
-.BR & ,
-\fBzsh\fP prints a line which looks
-like:
-.PP
-.DT
- [1] 1234
-.PP
-indicating that the job which was started asynchronously was job number
-1 and had one (top-level) process, whose process id was 1234.
-.PP
-If you are running a job and wish to do something else you may hit the key
-\fB^Z\fR (control-Z) which sends a STOP signal to the current job.
-\fBzsh\fP will then normally indicate that the job has been `suspended',
-and print another prompt.
-You can then manipulate the state of this job,
-putting it in the background with the
-.B bg
-command, or run some other
-commands and then eventually bring the job back into the foreground with
-the foreground command
-.BR fg .
-A \fB^Z\fR takes effect immediately and
-is like an interrupt in that pending output and unread input are discarded
-when it is typed.
-.PP
-A job being run in the background will suspend if it tries to read
-from the terminal.
-Background jobs are normally allowed to produce output,
-but this can be disabled by giving the command ``stty tostop''.
-If you set this
-tty option, then background jobs will suspend when they try to produce
-output like they do when they try to read input.
-.PP
-There are several ways to refer to jobs in \fBzsh\fP.
-A job can be referred to by the process id of any process of the job
-or by one of the following:
-.PD 0
-.TP
-.BI % number
-The job with the given number.
-.TP
-.BI % string
-Any job whose command line begins with
-.IR string .
-.TP
-.BI %? string
-Any job whose command line contains
-.IR string .
-.TP
-.BI %%
-Current job.
-.TP
-.BI %+
-Equivalent to
-.BR %% .
-.TP
-.BI %\-
-Previous job.
-.PD
-.PP
-\fBzsh\fP learns immediately whenever a process changes state.
-It normally informs you whenever a job becomes blocked so that
-no further progress is possible. If
-.B notify
-is not set, it waits until
-just before it prints
-a prompt before it informs you.
-.PP
-When the monitor mode is on, each background job that completes
-triggers any trap set for
-.BR CHLD .
-.PP
-When you try to leave \fBzsh\fP while jobs are running or suspended, you will
-be warned that `You have suspended (running) jobs.'
-You may use the
-.B jobs
-command to see what they are.
-If you do this or immediately try to
-exit again, \fBzsh\fP will not warn you a second time; the suspended
-jobs will be terminated, and the running jobs will be sent
-a \fBSIGHUP\fP signal.
-To avoid having \fBzsh\fP terminate the running jobs, either
-use the \fBnohup\fP(1) command or the \fBdisown\fP builtin (see below).
-.SS Signals
-The INT and QUIT signals for an invoked
-command are ignored if the command is followed by
-.B &
-and job
-.B monitor
-option is not active.
-Otherwise, signals have the values
-inherited by \fBzsh\fP from its parent
-(but see the \fBTRAPxxx\fP special function above).
-.SS Execution
-Each time a command is executed, the above substitutions
-are carried out.
-If the command name matches one
-of the
-.I builtins
-listed below,
-it is executed within the
-current shell process.
-Next, the command name is checked to see if
-it matches one of the user defined functions.
-If it does,
-the positional parameters are saved
-and then reset to the arguments of the
-.I function
-call.
-When the
-.I function
-completes or issues a
-.BR return ,
-the positional parameter list is restored
-and any trap set on
-.B EXIT
-within the function is executed.
-The value of a
-.I function
-is the value of the last command executed.
-A function is also executed in the
-current shell process.
-If a command name is not a
-.I builtin
-or a user defined
-.IR function ,
-a process is created and
-an attempt is made to execute the command via
-.IR exec (2).
-.PP
-The shell parameter
-.B PATH
-defines the search path for
-the directory containing the command.
-Alternative directory names are separated by
-a colon.
-The default path is
-.B /bin:/usr/bin:
-(specifying
-.BR /bin ,
-.BR /usr/bin ,
-and the current directory
-in that order).
-The current directory can be specified by
-two or more adjacent colons, or by a colon
-at the beginning or end of the path list.
-If the command name contains a \fB/\fP then the search path
-is not used.
-Otherwise, each directory in the path is
-searched for an executable file.
-.PP
-Whenever \fBzsh\fP executes an external command, it gives
-control of the tty to the command. If the command
-completes with a zero return code, \fBzsh\fP does not reset
-the tty; otherwise, the tty modes are reset to what they were
-before the command was executed. If a process is suspended,
-\fBzsh\fP saves the state of the tty and resets the tty modes;
-if the process is later restarted, the tty modes are restored
-to what they were when the process was suspended.
-.SS Command Re-entry.
-The text of the last
-.B HISTSIZE
-(default 128)
-commands entered from a terminal device
-is saved in memory.
-The builtin
-.B fc
-is used to list or
-edit a portion of this file.
-The portion of the file to be edited or listed can be selected by
-number or by giving the first character or
-characters of the command.
-A single command or range of commands can be specified.
-If you do not specify an editor program as
-an argument to
-.B fc
-then the value of the parameter
-.B FCEDIT
-is used.
-If
-.B FCEDIT
-is not defined then
-.B /usr/ucb/vi
-is used.
-The edited command(s) is printed and re-executed upon
-leaving the editor.
-The editor name
-.B \-
-is used to skip the editing phase and
-to re-execute the command.
-In this case a substitution parameter of the form
-\fIold\fP\fB=\fP\fInew\fP
-can be used to modify the command before execution.
-For example, if
-.B r
-is aliased to
-.B \(fmfc \-e \-\(fm
-then typing
-`\fBr bad=good c\fP'
-will re-execute the most recent command which starts with the letter
-.BR c ,
-replacing the first occurrence of the string
-.B bad
-with the string
-.BR good .
-.SS Readline
-This is the library that handles reading input when using an interactive
-shell.
-By default, the line editing commands
-are similar to those of Emacs.
-A vi-style line editing interface is also available.
-.PP
-In this section, the Emacs\-style notation is used to denote
-keystrokes. Control keys are denoted by C\-\fIkey\fR, e.g. C\-n
-means Control\-N. Similarly,
-.I meta
-keys are denoted by M\-\fIkey\fR, so M\-x means Meta\-X. (On keyboards
-without a
-.I meta
-key, M\-\fIx\fP means ESC \fIx\fP, i.e. press the Escape key
-then the
-.I x
-key.
-The combination M\-C\-\fIx\fP means ESC\-Control\-\fIx\fP,
-or press the Escape key
-then hold the Control key while pressing the
-.I x
-key.)
-.PP
-You may change the default key\-bindings with an
-.B \(ap/.inputrc
-file. Other
-programs that use this library may add their own commands and bindings.
-.PP
-For example, if you wanted to make M\-C\-u execute the command
-.IR universal\-argument ,
-then
-in your
-.B \(ap/.inputrc
-file you would put:
-.RS
-.PP
-M\-Control\-u: universal\-argument
-.RE
-or
-.RS
-C\-Meta\-u: universal\-argument
-.RE
-.PP
-You can use the following names for characters: RUBOUT, DEL, ESC,
-NEWLINE, SPACE, RETURN, LFD, TAB.
-.PP
-You can start with a vi-like editing mode by placing
-.RS
-.PP
-set editing-mode vi
-.RE
-.PP
-in your
-.B \(ap/.inputrc
-file.
-.PP
-You can have readline use a single line for display, scrolling the input
-between the two borders by placing
-.RS
-.PP
-set horizontal\-scroll\-mode On
-.RE
-.PP
-in your
-.B \(ap/.inputrc
-file.
-.PP
-The following is a list of the names of the commands and the default
-key-strokes to get them.
-.SS Commands for Moving
-.PP
-.PD 0
-.TP
-.B beginning\-of\-line (C\-a)
-Move to the start of the current line.
-.TP
-.B end\-of\-line (C\-e)
-Move to the end of the line.
-.TP
-.B forward\-char (C\-f)
-Move forward a character.
-.TP
-.B backward\-char (C\-b)
-Move back a character.
-.TP
-.B forward\-word (M\-f)
-Move forward to the end of the next word.
-.TP
-.B backward\-word (M\-b)
-Move back to the start of this, or the previous, word.
-.TP
-.B clear\-screen (C\-l)
-Clear the screen leaving the current line at the top of the screen.
-.PD
-.SS Commands for Manipulating the History
-.PP
-.PD 0
-.TP
-.B accept\-line (Newline, Return)
-Accept the line regardless of where the cursor is.
-.TP
-.B previous\-history (C\-p)
-Fetch the previous command from the history list, moving back in
-the list.
-.TP
-.B next\-history (C\-n)
-Fetch the next command from the history list, moving forward in the
-list.
-.TP
-.B beginning\-of\-history (M\-<)
-Move to the first line in the history, the first line entered.
-.TP
-.B end\-of\-history (M\->)
-Move to the end of the input history, i.e., the line you are entering.
-.PD
-.SS Commands for Changing Text
-.PP
-.PD 0
-.TP
-.B delete\-char (C\-d)
-Delete the character under the cursor. If the cursor is at the
-beginning of the line, and there are no characters in the line, and
-the last character typed was not C\-d, then return EOF.
-.TP
-.B backward\-delete\-char (Rubout)
-Delete the character behind the cursor. A numeric arg says to kill
-the characters instead of deleting them.
-.TP
-.B quoted\-insert (C\-q, C\-v)
-Add the next character that you type to the line verbatim. This is
-how to insert characters like C\-q, for example.
-.TP
-.B self\-insert (a,\ b,\ A,\ 1,\ !,\ ...)
-Insert the character typed.
-.TP
-.B transpose\-chars (C\-t)
-Drag the character before point forward over the character at point.
-Point moves forward as well. If point is at the end of the line, then
-transpose the two characters before point. Negative arguments don't work.
-.TP
-.B transpose\-words (M\-t)
-Drag the word behind the cursor past the word in front of the cursor
-moving the cursor over that word as well.
-.TP
-.B upcase\-word (M\-u)
-Uppercase the current (or following) word. With a negative argument,
-do the previous word, but do not move point.
-.TP
-.B downcase\-word (M\-l)
-Lowercase the current (or following) word. With a negative argument,
-do the previous word, but do not move point.
-.TP
-.B capitalize\-word (M\-c)
-Capitalize the current (or following) word. With a negative argument,
-do the previous word, but do not move point.
-.PD
-.SS Killing and Yanking
-.PP
-.PD 0
-.TP
-.B kill\-line (C\-k)
-Kill the text from the current cursor position to the end of the line.
-This saves the killed text on the kill\-ring. (see below)
-.TP
-.B backward\-kill\-line
-Kill backward to the beginning of the line. This is normally unbound,
-in favor of \fBunix-line-discard\fP, which emulates the behavior of
-the standard Unix terminal driver.
-.TP
-.B kill\-word (M\-d)
-Kill from the cursor to the end of the current word, or if between
-words, to the end of the next word.
-.TP
-.B backward\-kill\-word (M\-Rubout)
-Kill the word behind the cursor.
-.TP
-.B unix\-line\-discard (C\-u)
-Do what C\-u used to do in Unix line input. We save the killed text on
-the kill\-ring, though.
-.TP
-.B unix\-word\-rubout (C\-w)
-Do what C\-w used to do in Unix line input. The killed text is saved
-on the kill\-ring. This is different than backward\-kill\-word because
-the word boundaries differ.
-.TP
-.B yank (C\-y)
-Yank the top of the kill ring into the buffer at point.
-.TP
-.B yank\-pop (M\-y)
-Rotate the kill\-ring, and yank the new top. Only works following
-`yank' or `yank\-pop'.
-.PD
-.SS Arguments
-.PP
-.PD 0
-.TP
-.B digit\-argument (M\-0, M\-1, ..., M\-\-)
-Add this digit to the argument already accumulating, or start a new
-argument. M\-\- starts a negative argument.
-.TP
-.B universal\-argument
-Do what C\-u does in
-.I Emacs.
-By default, this is not bound to a key.
-.PD
-.SS Completing
-.PP
-.PD 0
-.TP
-.B complete (TAB)
-Perform substitution on the text before point.
-If no substitutions can be performed, attempt
-filename completion.
-If the text before point is a tilde followed by
-a word which is a prefix of one of the usernames
-in
-.BR \(ap/.zfriends ,
-substitute the text with the
-home directory of that user.
-.TP
-.B possible\-completions (M-?)
-List the possible completions of the text before point.
-.PD
-.SS Miscellaneous
-.PP
-.PD 0
-.TP
-.B abort (C\-g)
-Abort the current editing command and
-ring the terminal's bell.
-.TP
-.B do\-uppercase\-version (M\-a, M\-b, ...)
-Run the command that is bound to the uppercased key.
-.TP
-.B prefix\-meta (ESC)
-Metafy the next character typed. This is for
-people without a meta key. ESC f is equivalent to Meta\-f.
-.TP
-.B undo (C\-_)
-Incremental undo, separately remembered for each line.
-.TP
-.B revert\-line (M\-r)
-Undo all changes made to this line. This is like typing the `undo'
-command enough times to get back to the beginning.
-.TP
-.B history\-expand (M\-Space)
-Perform history expansion on this line.
-.TP
-.B check\-spelling (M\-$)
-Check the spelling of the word before the point.
-.PD
-.SS Builtins
-The following simple-commands are executed in the shell process.
-Input/Output redirection is permitted.
-Unless otherwise indicated, the output is written on file descriptor 1
-and the exit status, when there is no syntax error, is zero.
-.PD
-.TP
-\fB:\fP [ \fIarg\^\fP .\|.\|. ]
-The command only expands parameters.
-.br
-.ne 2
-.TP
-\fB\|. \fIfile\fP
-Read commands from
-.IR file .
-The commands are executed in the current shell environment.
-The exit status is the exit status of the last command executed.
-.TP
-\fBalias\fP [ \fB\-a\fP ] [ \fIname\fP [ \fIstr\^\fP .\|.\|. ] ]
-.B alias
-with no arguments prints the list of aliases
-on standard output.
-If
-.I name
-is supplied with no
-.IR str ,
-the alias associated with
-.I name
-is printed.
-Otherwise
-.I name
-is defined as an alias having the specified value.
-A trailing space in the value
-causes the next word to be checked for
-alias substitution.
-Unless the
-.B \-a
-flag is used, the alias will only be substituted with its value
-if it appears as a command word.
-.TP
-.PD 0
-\fBbg\fP [ \fIjob\fP ]
-.TP
-\fIjob\fP \fB&\fP
-.PD
-Puts the specified
-.I job
-into the background.
-The current job is put in the background
-if
-.I job
-is not specified.
-See
-.I Jobs
-for a description of the format of
-.IR job .
-.TP
-\fBbreak\fP [ \fIn\^\fP ]
-Exit from the enclosing
-.BR for
-.BR while
-.BR until
-or
-.B select
-loop, if any.
-If
-.I n
-is specified then break
-.I n
-levels.
-.TP
-\fBcontinue\fP [ \fIn\^\fP ]
-Resume the next iteration of the enclosing
-.BR for
-.BR while
-.BR until
-or
-.B select
-loop.
-If
-.I n
-is specified then resume at the
-.IR n -th
-enclosing loop.
-.TP
-.PD 0
-\fBcd\fP [ \fIarg\^\fP ]
-.TP
-\fBcd\fP \fIold\^\fP \fInew\^\fP
-.PD
-This command can be in either of two forms.
-In the first form it
-changes the current directory to
-.IR arg .
-If
-.I arg
-is
-.B \-
-the directory is changed to the previous
-directory.
-The shell
-parameter
-.B HOME
-is the default
-.IR arg .
-The parameter
-.B PWD
-is set to the current directory.
-The shell parameter
-.B CDPATH
-defines the search path for
-the directory containing
-.IR arg .
-Alternative directory names are separated by
-a colon.
-The default path is
-the current directory.
-If
-.I arg
-begins with a \fB/\fP then the search path
-is not used.
-Otherwise, each directory in the path is
-searched for
-.IR arg .
-.IP
-The second form of
-.B cd
-substitutes the string
-.I new
-for the string
-.I old
-in the current directory name,
-.B PWD
-and tries to change to this new directory.
-.TP
-\fBdirs\fP [ \fIdirs\fP .\|.\|. ]
-If no \fIdirs\fP are specified, prints the directory stack.
-Otherwise loads the directory stack with the arguments,
-which must be directory names, and puts \fB$PWD\fP at the top
-of the stack.
-.TP
-\fBdisown\fP [ \fIjob\fP .\|.\|. ]
-The specified jobs are removed from the job table.
-This means that the status of these jobs will no longer
-be monitored, and the user can exit safely from an interactive
-shell without sending a \fBSIGHUP\fP to these jobs.
-.TP
-\fBecho\fP [ \fB\-n\fP ] [ \fIarg\^\fP .\|.\|. ]
-Echos the arguments to the standard output. Prints
-a final newline if the \fB\-n\fP flag is not specified.
-.TP
-\fBeval\fP [ \fIarg\^\fP .\|.\|. ]
-The arguments are read as input
-to the shell
-and the resulting command(s) executed.
-.TP
-\fBexit\fP [ \fIn\^\fP ]
-Causes the shell to exit
-with the exit status specified by
-.IR n .
-If
-.I n
-is omitted then the exit status is that of the last command executed.
-An end-of-file will also cause the shell to exit
-except for a
-shell which has the
-.I ignoreeof
-option (See
-.B setopt
-below) turned on.
-.TP
-\fBexport\fP [ \fIname\fP[\fB=\fP\fIvalue\^\fP] ] .\|.\|.
-The given
-.IR name s
-are marked for automatic
-export to the
-.I environment
-of subsequently-executed commands.
-.TP
-.PD 0
-\fBfc\fP [ \fB\-e\fP \fIename\^\fP \ ] [ \fB\-nlr\^\fP ] [ \fIold=new\fP .\|.\|. ] [ \fIfirst\^\fP [ \fIlast\^\fP ] ]
-.PD
-A range of commands from
-.I first
-to
-.I last
-is selected from the last
-.B HISTSIZE
-commands that were typed at the terminal.
-The arguments
-.I first
-and
-.I last
-may be specified as a number or as a string.
-A string is used to locate the most recent command starting with
-the given string.
-A negative number is used as an offset to the current command number.
-Any number of substitutions
-.I old=new
-are performed.
-If the flag
-.BR \-l ,
-is selected,
-the commands are listed on standard output.
-Otherwise, the editor program
-.I ename
-is invoked on a file containing these
-keyboard commands.
-If
-.I ename
-is not supplied, then the value of the parameter
-.B FCEDIT
-(default /usr/ucb/vi)
-is used as the editor.
-If
-.I ename
-is `\-', no editor is invoked.
-When editing is complete, the edited command(s)
-are executed.
-If
-.I last
-is not specified
-then it will be set to
-.IR first .
-If
-.I first
-is not specified
-the default is the previous command
-for editing and \-16 for listing.
-The flag
-.B \-r
-reverses the order of the commands and
-the flag
-.B \-n
-suppresses command numbers when listing.
-.TP
-.PD 0
-\fBfg\fP [ \fIjob\fP ]
-.TP
-\fIjob\fP
-.PD
-The
-specified
-.I job
-is brought to the foreground.
-Otherwise, the current job is
-brought into the foreground.
-See
-.I Jobs
-for a description of the format of
-.IR job .
-.TP
-\fBglob\fP \fIname\fP .\|.\|.
-Marks \fIname\fP, which must be a command name,
-for normal filename generation.
-See \fBnoglob\fP below.
-.TP
-\fBhash\fP \fIname\fP \fIfile\fP
-Adds an entry to the command hash table corresponding
-to \fIname\fP. \fIfile\fP is an executable file to be run
-whenever \fIname\fP is specified in a simple command.
-.TP
-\fBinteger\fP \fIname\fP .\|.\|.
-The specified named parameters are marked for an internal
-integer representation.
-.TP
-\fBjobs\fP [ \fB\-lp\^\fP ] [ \fIjob\^\fP .\|.\|. ]
-Lists information about each given job; or all active jobs if
-.I job
-is omitted.
-The
-.B \-l
-flag lists process ids in addition to the normal information.
-The
-.B \-p
-flag causes only the process group to be listed.
-See
-.I Jobs
-for a description of the format of
-.IR job .
-.TP
-.PD 0
-\fBkill\fP [ \fB\-\fP\fIsig\^\fP ] \fIjob\^\fP .\|.\|.
-.TP
-\fBkill\fP \fB\-l\fP
-.PD
-Sends either the TERM (terminate) signal or the
-specified signal to the specified jobs or processes.
-Signals are either given by number or by names (as given in
-.BR /usr/include/signal.h ,
-stripped of the prefix ``SIG'').
-If the job is suspended, it will be send a CONT (continue) signal
-after the specified signal is delivered.
-The argument
-.I job
-can the process id of a process that is not a member of one of the
-active jobs.
-See
-.I Jobs
-for a description of the format of
-.IR job .
-In the second form,
-.BR "kill \-l" ,
-the signal numbers and names are listed.
-.TP
-\fBlet\fP \fIarg\^\fP .\|.\|.
-Each
-.I arg
-is a separate
-.IR "arithmetic expression"
-to be evaluated.
-See
-.I "Arithmetic Evaluation"
-above, for a description of arithmetic expression evaluation.
-The exit status is
-0 if the value of the last expression
-is non-zero, and 1 otherwise.
-.TP
-\fBlimit\fP [ \fB\-h\fP ] [ \fIresource\fP [ \fImax-use\fP ] ]
-.PD 0
-.TP
-.B "limit \-s"
-.PD
-.br
-Limit the consumption by any process the shell spawns,
-each not to exceed
-.I max-use
-on the specified
-.IR resource .
-If
-.I max-use
-is omitted, print the current limit; if
-.I resource
-is omitted, display all limits.
-.RS
-.TP
-.B \-h
-Use hard limits instead of the current limits. Hard limits impose a
-ceiling on the values of the current limits. Only the super-user may
-raise the hard limits.
-.LP
-.I resource
-is one of:
-.RS
-.TP 15
-.B cputime
-Maximum
-.B CPU
-seconds per process.
-.PD 0
-.TP
-.B filesize
-Largest single file allowed.
-.TP
-.B datasize
-Maximum data size (including stack) for the process.
-.TP
-.B stacksize
-Maximum stack size for the process.
-.TP
-.B coredumpsize
-Maximum size of a core dump (file).
-.TP
-.B descriptors
-Maximum value for a file descriptor.
-.PD
-.RE
-.LP
-.I max-use
-is a number, with an optional scaling factor, as follows:
-.RS
-.TP 15
-.IB n h
-Hours (for
-.BR cputime ).
-.PD 0
-.TP
-.IB n k
-.I n
-kilobytes.
-This is the default for all but
-.BR cputime .
-.TP
-.IB n m
-.I n
-megabytes or minutes (for
-.BR cputime ).
-.TP
-.IB mm : ss
-Minutes and seconds (for
-.BR cputime ).
-.PD
-.RE
-.RE
-.IP
-If
-.B limit
-is invoked solely with the
-.B s
-option, the current limits are taken to apply
-to the parent shell as well as to all processes
-spawned by it.
-.TP
-.B log
-Inform the user of all users
-affected by
-.B WATCH
-whether they have been announced before or not.
-.TP
-\fBmostglob\fP \fIname\fP .\|.\|.
-Marks \fIname\fP, which must be a command name,
-for modified filename generation. Whenever \fIname\fP
-is used as a command name in a simple command,
-filename generation is not performed on the first argument
-following the command name.
-If there are one or more initial arguments beginning with a
-dash (corresponding to option arguments), they and the
-first argument following them
-are not subject to filename generation.
-.TP
-\fBnoglob\fP \fIname\fP .\|.\|.
-Marks \fIname\fP, which must be a command name,
-for no filename generation. Whenever \fIname\fP
-is used as a command name in a simple command,
-filename generation is not performed on its arguments.
-.TP
-.B popd [ \fB+\fIn\fP ]
-Pop the directory stack, and
-.BR cd s
-to the new top directory.
-The elements of the directory stack are numbered from 0 starting at the top.
-.RS
-.TP 8
-.BI + n
-Discard the
-.IR n 'th
-entry in the stack.
-.RE
-.HP
-.B pushd
-.RB [ +\c
-.IR n " |"
-.IR dir ]
-.br
-Push a directory onto the directory stack.
-With no arguments, exchange the top two elements,
-unless the option
-.B pushdtohome
-is set, in which case push the current directory
-onto the stack and change to \fB$HOME\fP.
-.RS
-.TP
-.BI + n
-Rotate the
-.IR n 'th
-entry to the top of the stack and
-.B cd
-to it. If the option
-.B dextract
-is set, extract the
-.IR n 'th
-entry from the directory stack
-and
-.B cd
-to it.
-.PD 0
-.TP
-.I dir
-Push the current working directory onto the stack and change to
-.IR dir .
-.PD
-.RE
-.TP
-\fBpwd\fP
-Equivalent to
-\fBecho $PWD\fP.
-.TP
-\fBread\fP [ \fIname\fB?\fIprompt\^\fR ] [ \fIname\^\fP .\|.\|. ]
-The shell input mechanism.
-One line is read and
-is broken up into fields using the characters in
-.B IFS
-as separators.
-If
-.IR name
-is omitted then
-.B REPLY
-is used as the default
-.IR name.
-The exit status is 0 unless an end-of-file is encountered.
-If the first argument contains a
-.BR ? ,
-the remainder of this word is used as a
-.I prompt
-on standard error
-when the shell is interactive.
-The exit status is 0 unless an end-of-file is encountered.
-.TP
-\fBrehash\fP
-Rebuilds the command hash table. This command is executed
-automatically whenever the value of \fB$PATH\fP is changed.
-.TP
-\fBreturn\fP [ \fIn\^\fP ]
-Causes a shell
-.I function
-to return
-to the invoking script
-with the return status specified by
-.IR n .
-If
-.I n
-is omitted then the return status is that of the last command executed.
-If
-.B return
-is invoked while not in a
-.I function
-or a
-\fB\|.\fP
-script,
-then it is the same as an
-.BR exit .
-.TP
-\fBsched\fP [+]hh:mm \fIcommand\fP
-Schedule a command for execution at a later time.
-.TP
-\fBset\fP [ \fIarg\fP .\|.\|. ]
-Assign the arguments to the positional parameters, in order.
-If no arguments are given, then the names and values of
-all named parameters are printed on the standard output.
-.TP
-\fBsetopt\fP [ \fB\(+-aefikmnsuvxABCDEFGHIJK1234567890\fP ] \
-[ \fIopt\fP .\|.\|. ]
-Sets the options by letter or by name. If no options
-are specified, the current option settings are printed.
-Valid options are as follows:
-.RS
-.PD 0
-.TP 8
-.B allexport (\-a)
-All subsequent parameters that are defined are automatically exported.
-.TP 8
-.B errexit (\-e)
-If a command has a non-zero exit status,
-execute the
-.B ERR
-trap, if set,
-and exit.
-.TP 8
-.B norcs (\-f)
-\fBzsh\fP will not read the .zshrc, .zlogin, or .zlogout files.
-.TP 8
-.B keyword (\-k)
-All parameter assigment arguments are placed in the environment
-for a command, not just those that precede the command name.
-.TP 8
-.B interactive (\-i)
-This is an interactive shell.
-.TP 8
-.B monitor (\-m)
-Background jobs will run in a separate process group
-and a line will print upon completion.
-The exit status of background jobs is reported in a completion message.
-This flag is turned on automatically for
-interactive shells.
-.TP 8
-.B noexec (\-n)
-Read commands and check them for syntax errors, but do not execute them.
-.TP 8
-.B \-t
-Exit after reading and executing one command.
-.TP 8
-.B shinstdin (\-s)
-Read commands from the standard input rather than from a file.
-.TP 8
-.B nounset (\-u)
-Treat unset parameters as an error when substituting.
-.TP 8
-.B verbose (\-v)
-Print shell input lines as they are read.
-.TP 8
-.B xtrace (\-x)
-Print commands and their arguments as they are executed.
-.TP 8
-.B clobber (\-1)
-Permits \fB>\fP redirection to truncate existing files.
-Also allows \fB>>\fP redirection to create files.
-.TP 8
-.B nobadpattern (\-2)
-In filename generation, do not report an error
-when given a malformed pattern.
-Instead, pass the pattern unchanged
-as an argument.
-.TP 8
-.B nonomatch (\-3)
-In filename generation,
-do not report an error when pattern matches no filenames.
-Instead, pass the pattern unchanged
-as an argument.
-.TP 8
-.B globdots (\-4)
-In filename generation, do not require that an initial \fB.\fP
-be matched explicitly.
-.TP 8
-.B notify (\-5)
-Notify the user immediately when jobs are completed, rather
-than wait until just before issuing a prompt. This is
-the default mode.
-.TP 8
-.B bgnice (\-6)
-All background jobs are run at a lower priority. This is the
-default mode.
-.TP 8
-.B ignoreeof (\-7)
-The shell will not exit on end-of-file. Either
-\fBexit\fP or \fBlogout\fP must be used.
-.TP 8
-.B markdirs (\-8)
-All directory names resulting from filename generation
-have a trailing / appended.
-.TP 8
-.B autolist (\-9)
-List possilities on an ambiguous completion.
-.TP 8
-.B correct (\-0)
-Automatically try to correct the spelling of commands.
-.TP 8
-.B dextract (\-A)
-See \fBpushd\fP above.
-.TP 8
-.B nobeep (\-B)
-Prevent the shell from beeping.
-.TP 8
-.B printexitvalue (\-C)
-If an interactive program exits non-zero, print the
-exit value.
-.TP 8
-.B pushdtohome (\-D)
-Make pushd with no arguments do the equivalent
-of \fBpushd \(ap\fP, like \fBcd\fP.
-.TP 8
-.B pushdsilent (\-E)
-Prevent \fBpushd\fP and \fBpopd\fP from printing
-the directory stack.
-.TP 8
-.B nullglob (\-G)
-If a pattern for filename generation does not match any
-filenames, delete it from the argument list rather than
-report an error.
-.TP 8
-.B rmstarsilent (\-H)
-Do not prompt the user before execution of `rm *'.
-.TP 8
-.B ignorebraces (\-I)
-Do not perform brace expansion.
-.TP 8
-.B cdablevars (\-J)
-If a named parameter (without the \fB$\fP) is specified
-to the \fBcd\fP, \fBpushd\fP, or \fBpopd\fP commands,
-and the value of the named parameter begins with a `/',
-\fBzsh\fP will act as if the \fB$\fP had been supplied.
-.TP 8
-.B nobanghist (\-K)
-Do not perform `\fB!\fP' history substitution;
-do not treat the `\fB!\fP' character
-specially.
-.RE
-.PD
-.TP
-\fBshift\fP [ \fIn\^\fP ]
-.br
-The positional parameters from
-\fB$\fP\fIn\fP\fB+1\fP
-\&.\|.\|.
-are renamed
-.B $1
-\&.\|.\|.\^
-, default
-.I n
-is 1.
-.PD
-.PP
-.PD 0
-\fBtest\fP \fIexpr\fP
-.TP
-\fB[\fP \fIexpr\fP \fB]\fP
-Return a status of 0 (true) or 1 (false) depending on
-the evaluation of
-the conditional expression
-.IR expr .
-Expressions may be unary or binary. Unary
-expressions are often used to examine the status of a file. There
-are string operators
-and numeric comparison operators as well.
-.RS
-.PD 0
-.TP
-.B \-b \fIfile\fP
-True if \fIfile\fP exists and is block special.
-.TP
-.B \-c \fIfile\fP
-True if \fIfile\fP exists and is character special.
-.TP
-.B \-d \fIfile\fP
-True if \fIfile\fP exists and is a directory.
-.TP
-.B \-f \fIfile\fP
-True if \fIfile\fP exists and is a regular file.
-.TP
-.B \-g \fIfile\fP
-True if \fIfile\fP exists and is set-group-id.
-.TP
-.B \-k \fIfile\fP
-True if \fIfile\fP has its ``sticky'' bit set.
-.TP
-.B \-L \fIfile\fP
-True if \fIfile\fP exists and is a symbolic link.
-.TP
-.B \-p \fIfile\fP
-True if \fIfile\fP exists and is a named pipe.
-.TP
-.B \-r \fIfile\fP
-True if file exists and is readable.
-.TP
-.B \-s \fIfile\fP
-True if \fIfile\fP exists and has a non-zero size.
-.TP
-.B \-S \fIfile\fP
-True if \fIfile\fP exists and is a socket.
-.TP
-.B \-t [\fIfd\fP]
-True if
-.I fd
-is opened on a terminal. If
-.I fd
-is omitted, it defaults to 1 (standard output).
-.TP
-.B \-u \fIfile\fP
-True if the \fIfile\fP exists and its set-user-id bit is set.
-.TP
-.B \-w \fIfile\fP
-True if the \fIfile\fP exists and is writable.
-.TP
-.B \-x \fIfile\fP
-True if the \fIfile\fP exists and is executable.
-.TP
-.B \-O \fIfile\fP
-True if the \fIfile\fP exists and is owned by the effective user id.
-.TP
-.B \-G \fIfile\fP
-True if the \fIfile\fP exists and is owned by the effective group id.
-.TP
-\fIfile1\fP \-\fBnt\fP \fIfile2\fP
-True if \fIfile1\fP is newer (according to
-modification date) than \fIfile2\fP.
-.TP
-\fIfile1\fP \-\fBot\fP \fIfile2\fP
-True if \fIfile1\fP is older than file2.
-.TP
-\fIfile1\fP \fB\-ef\fP \fIfile\fP
-True if \fIfile1\fP and \fIfile2\fP have the same device and
-inode numbers.
-.TP
-.B \-z \fIstring\fP
-True if the length of \fIstring\fP is zero.
-.TP
-.B \-n \fIstring\fP
-.TP
-\fIstring\fP
-True if the length of
-.I string
-is non-zero.
-.TP
-\fIstring1\fP \fB=\fP \fIstring2\fP
-True if the strings are equal.
-.TP
-\fIstring1\fP \fB!=\fP \fIstring2\fP
-True if the strings are not equal.
-.TP
-.B ! \fIexpr\fP
-True if
-.I expr
-is false.
-.TP
-\fIexpr1\fP \-\fBa\fP \fIexpr2\fP
-True if both
-.I expr1
-AND
-.I expr2
-are true.
-.TP
-\fIexpr1\fP \-\fBo\fP \fIexpr2\fP
-True if either
-.I expr1
-OR
-.I expr2
-is true.
-.TP
-.I arg1 \fBOP\fP arg2
-OP is one of
-.BR \-eq ,
-.BR \-ne ,
-.BR \-lt ,
-.BR \-le ,
-.BR \-gt ,
-or
-.BR \-ge .
-These arithmetic binary operators return true if \fIarg1\fP
-is equal, not-equal, less-than, less-than-or-equal,
-greater-than, or greater-than-or-equal than \fIarg2\fP,
-respectively.
-.I Arg1
-and
-.I arg2
-may be positive integers, negative integers, or the special
-expression \fB\-l\fP \fIstring\fP, which evaluates to the
-length of
-.IR string .
-.PD
-.RE
-.TP
-\fBumask\fP [ \fImask\^\fP ]
-The user file-creation mask is set to
-.I mask
-(see
-.IR umask (2)).
-.I mask
-must be an octal number.
-If
-.I mask
-is omitted, the current value of the mask is printed.
-.TP
-\fBunalias\fP \fIname\^\fP .\|.\|.
-The
-.IR
-parameters
-given by the list of
-.IR name s
-are removed from the
-.I alias
-list.
-.TP
-\fBunfunction\fP \fIname\fP .\|.\|.
-The
-.IR
-functions
-given by the list of
-.IR name s
-are removed from the
-.I function
-list.
-.TP
-\fBunhash\fP \fIname\fP .\|.\|.
-Removes \fIname\fP from the command hash table.
-Shell builtins may be undefined in this way.
-.TP
-\fBunlimit [ \fB\-h\fP ] [ \fIresource\fP .\|.\|. ]\fP
-Remove a limitation on
-.IR resource .
-If no
-.I resource
-is specified, then all
-.I resource
-limitations are removed.
-See the description of the
-.B limit
-command for the list of
-.I resource
-names.
-.RS
-.TP 8
-.B \-h
-Remove corresponding hard limits. Only the super-user may do this.
-.RE
-.TP
-\fBunset\fP \fIname\^\fP .\|.\|.
-The parameters given by the list of
-.IR name s
-are unset.
-.TP
-\fBunsetopt\fP [ \fIopt\fP .\|.\|.\| ]
-The named options are unset. See \fBsetopt\fP above.
-.SS Invocation
-The shell first executes the the file
-\fB/etc/zshrc\fP
-and then
-\fB\(ap/.zshrc\fP,
-if it exists.
-If the shell is invoked by
-.IR exec (2),
-and the first character of argument zero
-.RB ( $0 )
-is
-.BR \- ,
-then the shell is assumed to be a
-.I login
-shell and
-commands are read from
-.B /etc/zlogin
-and
-.BR \(ap/.zshrc ,
-if it exists.
-If the
-.B \-s
-flag is not present and
-.I arg
-is, then the first
-.I arg
-is taken as the name of the script to execute.
-The script
-.I arg
-must have read permission and any
-.I setuid
-and
-.I getgid
-settings will be ignored.
-Commands are then read as described below;
-the following flags are interpreted by the shell
-when it is invoked:
-.PP
-.PD 0
-.TP 10
-.BI \-c "\| string"
-If the
-.B \-c
-flag is present then
-commands are read from
-.IR string .
-.TP
-.B \-s
-If the
-.B \-s
-flag is present or if no
-arguments remain
-then commands are read from the standard input.
-Shell output,
-except for the output of the
-.I builtins
-listed above,
-is written to
-file descriptor 2.
-.TP
-.B \-i
-If the
-.B \-i
-flag is present or
-if the shell input and output are attached to a terminal (as told by
-.IR ioctl (2))
-then this shell is
-.IR interactive .
-In this case TERM is ignored (so that \fBkill 0\fP
-does not kill an interactive shell) and INTR is caught and ignored.
-In all cases, QUIT is ignored by the shell.
-.PD
-.PP
-The remaining flags and arguments are described under the
-.B setopt
-command above.
-.SH EXIT STATUS
-Errors detected by the shell, such as syntax errors,
-cause the shell
-to return a non-zero exit status.
-Otherwise, the shell returns the exit status of
-the last command executed (see also the
-.B exit
-command above).
-If the shell is being used non-interactively
-then execution of the shell file is abandoned.
-.SH FILES
-\(ap/.zshrc
-.br
-\(ap/.zlogin
-.br
-\(ap/.zlogout
-.br
-\(ap/.zfriends
-.br
-\(ap/.inputrc
-.br
-/etc/zshrc
-.br
-/etc/zlogin
-.br
-/tmp/zsh\(**
-.SH SEE ALSO
-sh(1),
-csh(1),
-tcsh(1),
-itcsh(1),
---cut here---cut here---cut here---pfalstad@phoenix.Princeton.EDU (Paul John Falstad) (12/15/90)
---cut here---cut here---cut here---
- close(pipes[1]);
- entersubsh(1);
- exiting = 1;
- execpline2(pline->right,ASYNC,pipes[0],output,1);
- _exit(lastval);
- }
- else if (pid == -1)
- {
- zerr("fork failed: %e",errno);
- errflag = 1;
- }
- else
- {
- char *s,*text;
-
- close(pipes[0]);
- text = s = getptext(pline->right);
- for (;*s;s++)
- if (*s == '\n')
- *s = ';';
- untokenize(text);
- addproc(pid,text)->lastfg = 1;
- freepline(pline->right);
- pline->right = NULL;
- }
- }
-
- /* otherwise just do the pipeline normally. */
-
- execcomm(pline->left,input,pipes[1],how==ASYNC,0);
- pline->left = NULL;
- close(pipes[1]);
- if (pline->right)
- {
- execpline2(pline->right,how,pipes[0],output,last1);
- close(pipes[0]);
- }
- }
-}
-
-/* make the argv array */
-
-char **makecline(char *nam,struct xlist *list)
-{
-int ct = 0;
-Node node;
-char **argv,**ptr;
-
- if (isset(XTRACE))
- {
- for (node = list->first; node; node = node->next,ct++);
- ptr = argv = (char **) zalloc((ct+2)*sizeof(char *));
- *ptr++ = nam;
- fprintf(stderr,"+ %s",nam);
- if (list->first)
- fputc(' ',stderr);
- for (node = list->first; node; node = node->next)
- if (*(char *) node->dat)
- {
- *ptr++ = node->dat;
- untokenize(node->dat);
- fputs(node->dat,stderr);
- if (node->next)
- fputc(' ',stderr);
- }
- *ptr = NULL;
- fputc('\n',stderr);
- return(argv);
- }
- else
- {
- for (node = list->first; node; node = node->next,ct++);
- ptr = argv = (char **) zalloc((ct+2)*sizeof(char *));
- *ptr++ = nam;
- for (node = list->first; node; node = node->next)
- if (*(char *) node->dat)
- {
- *ptr++ = node->dat;
- untokenize(node->dat);
- }
- *ptr = NULL;
- return(argv);
- }
-}
-
-/* untokenize the command line and remove null arguments */
-
-void fixcline(table l)
-{
-Node node,next;
-
- for (node = l->first; node; node = next)
- {
- next = node->next;
- if (*(char *) node->dat)
- untokenize(node->dat);
- else
- remnode(l,node);
- }
-}
-
-void untokenize(char *s)
-{
- for (; *s; s++)
- if (istok(*s))
- if (*s == HQUOT || *s == Nularg)
- chuck(s--);
- else
- *s = tokens[*s-Pound];
-}
-
-/* add vars to the environment */
-
-void addenv(table list)
-{
-char *s,*t;
-
- while (s = getnode(list))
- {
- dovarsubs(&s);
- if (errflag)
- break;
- untokenize(s);
- t = getnode(list);
- dovarsubs(&t);
- if (errflag)
- break;
- untokenize(t);
- setparm(s,t,1,0);
- }
-}
-
-/* nonzero if we shouldn't clobber a file */
-
-int dontclob(struct fnode *f)
-{
-struct stat buf;
-
- if (isset(CLOBBER) || f->type & 1)
- return 0;
- if (stat(f->u.name,&buf) == -1)
- return 1;
- return S_ISREG(buf.st_mode);
-}
-
-/* close an mnode (success) */
-
-void closemn(struct mnode *mfds[10],int fd)
-{
- if (mfds[fd])
- {
- if (mfds[fd]->ct > 1)
- if (mfds[fd]->rflag == 0)
- catproc(mfds[fd]);
- else
- teeproc(mfds[fd]);
- free(mfds[fd]);
- mfds[fd] = NULL;
- }
-}
-
-/* close all the mnodes (failure) */
-
-void closemnodes(struct mnode *mfds[10])
-{
-int t0,t1;
-
- for (t0 = 0; t0 != 10; t0++)
- if (mfds[t0])
- {
- for (t1 = 0; t1 != mfds[t0]->ct; t1++)
- close(mfds[t0]->fds[t1]);
- free(mfds[t0]);
- mfds[t0] = NULL;
- }
-}
-
-/* add a fd to an mnode */
-/* an mnode is a list of fds associated with a certain fd.
- thus if you do "foo >bar >ble", the mnode for fd 1 will have
- two fds, the result of open("bar",...), and the result of
- open("ble",....). */
-
-void addfd(int forked,int save[10],struct mnode *mfds[10],int fd1,int fd2,int rflag)
-{
-int pipes[2];
-
- if (!mfds[fd1]) /* starting a new mnode */
- {
- mfds[fd1] = alloc(sizeof(struct mnode));
- if (!forked && fd1 != fd2 && fd1 < 10)
- save[fd1] = movefd(fd1);
- redup(fd2,fd1);
- mfds[fd1]->ct = 1;
- mfds[fd1]->fds[0] = fd1;
- mfds[fd1]->rflag = rflag;
- }
- else
- {
- if (mfds[fd1]->rflag != rflag)
- {
- zerr("file mode mismatch on fd %d",fd1);
- errflag = 1;
- return;
- }
- if (mfds[fd1]->ct == 1) /* split the stream */
- {
- mfds[fd1]->fds[0] = movefd(fd1);
- mfds[fd1]->fds[1] = movefd(fd2);
- mpipe(pipes);
- mfds[fd1]->pipe = pipes[1-rflag];
- redup(pipes[rflag],fd1);
- mfds[fd1]->ct = 2;
- }
- else /* add another fd to an already split stream */
- mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2);
- }
-}
-
-void execcomm(comm comm,int input,int output,int bkg,int last1)
-{
-int type;
-long pid = 0;
-table args = comm->args;
-int save[10] = {0,0,0,0,0,0,0,0,0,0},gstat;
-struct fnode *fn;
-struct mnode *mfds[10] = {0,0,0,0,0,0,0,0,0,0};
-int fil,forked = 0,iscursh = 0,t0;
-struct chnode *chn = NULL;
-char *text;
-list l;
-
- if ((type = comm->type) == SIMPLE && !*comm->cmd)
- {
- if (comm->vars)
- addvars(comm->vars);
- return;
- }
- if (comm->cmd)
- {
- if (*comm->cmd == '%')
- {
- if (full(args))
- {
- zerrnam(comm->cmd,"too many arguments");
- return;
- }
- addnode(args,comm->cmd);
- comm->cmd = strdup((bkg) ? "bg" : "fg");
- bkg = 0;
- }
- docmdsubs(&comm->cmd);
- if (errflag)
- {
- freecmd(comm);
- lastval = 1;
- return;
- }
- untokenize(comm->cmd);
- }
- if (jobbing) /* get the text associated with this command */
- {
- char *s;
- s = text = gettext(comm);
- for (;*s;s++)
- if (*s == '\n')
- *s = ';';
- untokenize(text);
- }
- else
- text = NULL;
- prefork(comm->args); /* do prefork substitutions */
- if (comm->cmd && !(comm->flags & CFLAG_COMMAND))
- {
- if (isset(CORRECT) && jobbing)
- spckcmd(&comm->cmd);
- if ((l = gethnode(comm->cmd,shfunchtab)) &&
- !(comm->flags & CFLAG_COMMAND))
- {
- insnode(comm->args,(Node) comm->args,comm->cmd);
- comm->cmd = NULL;
- comm->left = duplist(l);
- type = comm->type = SHFUNC;
- }
- else
- chn = gethnode(comm->cmd,chtab);
- }
- if (unset(RMSTARSILENT) && jobbing && chn && chn->type != BUILTIN &&
- !strcmp(comm->cmd,"rm") && full(comm->args) &&
- ((char *) comm->args->first->dat)[0] == Star &&
- ((char *) comm->args->first->dat)[1] == '\0')
- checkrmall();
- if (errflag)
- {
- freecmd(comm);
- lastval = 1;
- return;
- }
-
- /* this is nonzero if comm is a current shell procedure */
-
- iscursh = (type >= CURSH) || (type == SIMPLE && chn &&
- chn->type == BUILTIN);
-
- gstat = (chn) ? chn->globstat : GLOB;
-
- /* if this command is backgrounded or (this is an external
- command and we are not exec'ing it) or this is a builtin
- with output piped somewhere, then fork. If this is the
- last stage in a subshell pipeline, don't fork, but make
- the rest of the function think we forked. */
-
- if (bkg || !(iscursh || (comm->flags & CFLAG_EXEC)) ||
- (chn && chn->type == BUILTIN && output))
- {
- pid = (last1 && execok()) ? 0 : phork();
- if (pid == -1)
- return;
- if (pid)
- {
- if (pid == -1)
- zerr("%e",errno);
- else
- (void) addproc(pid,text);
- return;
- }
- entersubsh(bkg);
- forked = 1;
- }
- if (bkg && isset(BGNICE)) /* stupid */
- nice(5);
- if (input) /* add pipeline input/output to mnodes */
- addfd(forked,save,mfds,0,input,0);
- if (output)
- addfd(forked,save,mfds,1,output,1);
- spawnpipes(comm->redir); /* do process substitutions */
- while (full(comm->redir))
- if ((fn = getnode(comm->redir))->type == INPIPE)
- {
- if (fn->u.fd2 == -1)
- execerr();
- addfd(forked,save,mfds,fn->fd1,fn->u.fd2,0);
- free(fn);
- }
- else if (fn->type == OUTPIPE)
- {
- if (fn->u.fd2 == -1)
- execerr();
- addfd(forked,save,mfds,fn->fd1,fn->u.fd2,1);
- free(fn);
- }
- else
- {
- if (!(fn->type == HEREDOC || fn->type == CLOSE || fn->type ==
- MERGE || fn->type == MERGEOUT))
- if (xpandredir(fn,comm->redir))
- continue;
- if (fn->type == READ || fn->type == HEREDOC)
- {
- fil = (fn->type == READ) ? open(fn->u.name,O_RDONLY) : fn->u.fd2;
- if (fil == -1)
- {
- if (errno != EINTR)
- zerr("%e: %s",errno,fn->u.name);
- execerr();
- }
- addfd(forked,save,mfds,fn->fd1,fil,0);
- if (fn->type == READ)
- free(fn->u.name);
- }
- else if (fn->type == CLOSE)
- {
- if (!forked && fn->fd1 < 3)
- {
- zerr("can't close fd %d without forking",fn->fd1);
- execerr();
- }
- closemn(mfds,fn->fd1);
- close(fn->fd1);
- }
- else if (fn->type == MERGE || fn->type == MERGEOUT)
- {
- fil = dup(fn->u.fd2);
- if (mfds[fn->fd1])
- redup(fil,fn->fd1);
- else
- addfd(forked,save,mfds,fn->fd1,fil,fn->type == MERGEOUT);
- }
- else
- {
- if (fn->type >= APP)
- fil = open(fn->u.name,dontclob(fn) ?
- O_WRONLY|O_APPEND : O_WRONLY|O_APPEND|O_CREAT,0666);
- else
- fil = open(fn->u.name,dontclob(fn) ?
- O_WRONLY|O_CREAT|O_EXCL : O_WRONLY|O_CREAT|O_TRUNC,0666);
- if (fil == -1)
- {
- if (errno != EINTR)
- zerr("%e: %s",errno,fn->u.name);
- execerr();
- }
- addfd(forked,save,mfds,fn->fd1,fil,1);
- free(fn->u.name);
- }
- free(fn);
- }
- postfork(comm->args,gstat); /* perform postfork substitutions */
- if (errflag)
- {
- lastval = 1;
- goto err;
- }
-
- /* we are done with redirection. close the mnodes, spawning
- tee/cat processes as necessary. */
- for (t0 = 0; t0 != 10; t0++)
- closemn(mfds,t0);
-
- if (unset(NOEXEC))
- if (type >= CURSH) /* current shell proc */
- {
- void (*func[])(struct cnode *) = {execcursh,execshfunc,
- execfor,execwhile,execrepeat,execif,execcase,execselect};
-
- fixcline(comm->args);
- (func[type-CURSH])(comm);
- fflush(stdout);
- if (ferror(stdout))
- {
- zerr("write error: %e",errno);
- clearerr(stdout);
- }
- }
- else if (iscursh) /* builtin */
- {
- int (*func)() = chn->u.func;
-
- if (comm->vars)
- {
- addvars(comm->vars);
- comm->vars = NULL;
- }
- fixcline(comm->args);
- if (func == test) /* let test know if it is test or [ */
- insnode(comm->args,(Node) comm->args,strdup(comm->cmd));
- lastval = func(comm);
- if (isset(PRINTEXITVALUE) && lastval)
- zerr("exit %d",lastval);
- }
- else
- {
- if (comm->vars)
- addenv(comm->vars);
- if (type == SIMPLE)
- {
- closem();
- execute(comm->cmd,args);
- }
- else /* ( ... ) */
- execlist(comm->left);
- }
-err:
- if (forked)
- _exit(lastval);
- fixfds(save);
- freecmd(comm);
-}
-
-/* restore fds after redirecting a builtin */
-
-void fixfds(int save[10])
-{
-int t0;
-
- for (t0 = 0; t0 != 10; t0++)
- if (save[t0])
- redup(save[t0],t0);
-}
-
-void entersubsh(int bkg)
-{
- if (!jobbing)
- {
- if (bkg && isatty(0))
- {
- close(0);
- if (open("/dev/null",O_RDWR))
- {
- zerr("can't open /dev/null: %e",errno);
- _exit(1);
- }
- }
- }
- else if (!jobtab[curjob].gleader)
- {
- setpgrp(0L,jobtab[curjob].gleader = getpid());
- if (!bkg)
- attachtty(jobtab[curjob].gleader);
- }
- else
- setpgrp(0L,jobtab[curjob].gleader);
- subsh = 1;
- if (SHTTY != -1)
- {
- close(SHTTY);
- SHTTY = -1;
- }
- if (jobbing)
- {
- signal(SIGTTOU,SIG_DFL);
- signal(SIGTTIN,SIG_DFL);
- signal(SIGTSTP,SIG_DFL);
- signal(SIGPIPE,SIG_DFL);
- }
- if (interact)
- {
- signal(SIGTERM,SIG_DFL);
- if (sigtrapped[SIGINT])
- signal(SIGINT,SIG_IGN);
- }
- if (!sigtrapped[SIGQUIT])
- signal(SIGQUIT,SIG_DFL);
- opts[MONITOR] = OPT_UNSET;
- clearjobtab();
-}
-
-/* close all shell files */
-
-void closem(void)
-{
-int t0;
-
- for (t0 = 10; t0 != NOFILE; t0++)
- close(t0);
-}
-
-/* get here document */
-
-int gethere(char *str)
-{
-char pbuf[256],*nam = gettemp();
-int tfil = creat(nam,0666);
-FILE *in = fdopen(SHIN,"r");
-
- FOREVER
- {
- fgetline(pbuf,256,in);
- if (strcmp(str,pbuf))
- {
- pbuf[strlen(pbuf)] = '\n';
- write(tfil,pbuf,strlen(pbuf));
- }
- else
- break;
- }
- close(tfil);
- tfil = open(nam,O_RDONLY);
- unlink(nam);
- free(nam);
- return(tfil);
-}
-
-void catproc(struct mnode *mn)
-{
-int len,t0;
-char *buf;
-
- if (phork())
- {
- for (t0 = 0; t0 != mn->ct; t0++)
- close(mn->fds[t0]);
- close(mn->pipe);
- return;
- }
- closeallelse(mn);
- buf = zalloc(4096);
- for (t0 = 0; t0 != mn->ct; t0++)
- while (len = read(mn->fds[t0],buf,4096))
- write(mn->pipe,buf,len);
- _exit(0);
-}
-
-void teeproc(struct mnode *mn)
-{
-int len,t0;
-char *buf;
-
- if (phork())
- {
- for (t0 = 0; t0 != mn->ct; t0++)
- close(mn->fds[t0]);
- close(mn->pipe);
- return;
- }
- buf = zalloc(4096);
- closeallelse(mn);
- while ((len = read(mn->pipe,buf,4096)) > 0)
- for (t0 = 0; t0 != mn->ct; t0++)
- write(mn->fds[t0],buf,len);
- _exit(0);
-}
-
-void closeallelse(struct mnode *mn)
-{
-int t0,t1;
-
- for (t0 = 0; t0 != NOFILE; t0++)
- if (mn->pipe != t0)
- {
- for (t1 = 0; t1 != mn->ct; t1++)
- if (mn->fds[t1] == t0)
- break;
- if (t1 == mn->ct)
- close(t0);
- }
-}
-
-/* strtol() doesn't work right on my system */
-
-long int zstrtol(const char *s,char **t,int base)
-{
-int ret = 0;
-
- for (; *s >= '0' && *s < ('0'+base); s++)
- ret = ret*base+*s-'0';
- if (t)
- *t = (char *) s;
- return ret;
-}
-
-/* $(...) */
-
-table getoutput(char *cmd,int qt)
-{
-list list;
-int pipes[2];
-
- if (*cmd == '<')
- {
- int stream;
- char *fi;
-
- fi = strdup(cmd+1);
- if (*fi == '~')
- *fi = Tilde;
- else if (*fi == '=')
- *fi = Equals;
- filesub((void **) &fi);
- if (errflag)
- return NULL;
- stream = open(fi,O_RDONLY);
- if (stream == -1)
- {
- magicerr();
- zerr("%e: %s",errno,cmd+1);
- return NULL;
- }
- return readoutput(stream,qt);
- }
- hungets(strdup(cmd));
- strinbeg();
- if (!(list = parlist(1)))
- {
- strinend();
- hflush();
- return NULL;
- }
- if (peek != EOF && peek != EMPTY)
- {
- strinend();
- hflush();
- return NULL;
- }
- strinend();
- mpipe(pipes);
- if (phork())
- {
- close(pipes[1]);
- return readoutput(pipes[0],qt);
- }
- subsh = 1;
- close(pipes[0]);
- redup(pipes[1],1);
- entersubsh(0);
- signal(SIGTSTP,SIG_IGN);
- exiting = 1;
- execlist(list);
- close(1);
- exit(0); return NULL;
-}
-
-/* read output of command substitution */
-
-table readoutput(int in,int qt)
-{
-table ret;
-char *buf,*ptr;
-int bsiz,c,cnt = 0;
-FILE *fin;
-
- fin = fdopen(in,"r");
- ret = newtable();
- ptr = buf = zalloc(bsiz = 256);
- while ((c = fgetc(fin)) != EOF)
- if (!qt && znspace(c))
- {
- if (cnt)
- {
- *ptr = '\0';
- addnode(ret,strdup(buf));
- cnt = 0;
- ptr = buf;
- }
- }
- else
- {
- *ptr++ = c;
- if (++cnt == bsiz)
- {
- char *pp = zalloc(bsiz *= 2);
-
- memcpy(pp,buf,cnt);
- free(buf);
- ptr = (buf = pp)+cnt;
- }
- }
- if (qt && ptr != buf && ptr[-1] == '\n')
- ptr[-1] = '\0';
- if (cnt)
- addnode(ret,strdup(buf));
- free(buf);
- fclose(fin);
- return ret;
-}
-
-/* =(...) */
-
-char *getoutputfile(char *cmd)
-{
-#ifdef WAITPID
-int pid;
-#endif
-char *nam = gettemp(),*str;
-int tfil;
-list list;
-
- for (str = cmd; *str && *str != Outpar; str++);
- if (!*str)
- zerr("oops.");
- *str = '\0';
- hungets(strdup(cmd));
- strinbeg();
- if (!(list = parlist(1)))
- {
- hflush();
- strinend();
- return NULL;
- }
- if (peek != EOF && peek != EMPTY)
- {
- strinend();
- hflush();
- return NULL;
- }
- strinend();
- if (!jobtab[curjob].filelist)
- jobtab[curjob].filelist = newtable();
- addnode(jobtab[curjob].filelist,strdup(nam));
-#ifdef WAITPID
- if (pid = phork())
- {
- waitpid(pid,NULL,WUNTRACED);
- return nam;
- }
-#else
- if (waitfork())
- return nam;
-#endif
- subsh = 1;
- close(1);
- entersubsh(0);
- tfil = creat(nam,0666);
- exiting = 1;
- execlist(list);
- close(1);
- exit(0); return NULL;
-}
-
-/* get a temporary named pipe */
-
-char *namedpipe(void)
-{
-char *tnam = gettemp();
-
- mknod(tnam,0010666,0);
- return tnam;
-}
-
-/* <(...) */
-
-char *getoutproc(char *cmd)
-{
-list list;
-int fd;
-char *pnam,*str;
-
- for (str = cmd; *str && *str != Outpar; str++);
- if (!*str)
- zerr("oops.");
- *str = '\0';
- hungets(strdup(cmd));
- strinbeg();
- if (!(list = parlist(1)))
- {
- strinend();
- hflush();
- return NULL;
- }
- if (peek != EOF && peek != EMPTY)
- {
- strinend();
- hflush();
- return NULL;
- }
- strinend();
- pnam = namedpipe();
- if (!jobtab[curjob].filelist)
- jobtab[curjob].filelist = newtable();
- addnode(jobtab[curjob].filelist,strdup(pnam));
- if (phork())
- return pnam;
- entersubsh(1);
- fd = open(pnam,O_WRONLY);
- if (fd == -1)
- {
- zerr("can't open %s: %e",pnam,errno);
- _exit(0);
- }
- redup(fd,1);
- fd = open("/dev/null",O_RDONLY);
- redup(fd,0);
- exiting = 1;
- execlist(list);
- close(1);
- _exit(0); return NULL;
-}
-
-/* >(...) */
-
-char *getinproc(char *cmd)
-{
-list list;
-int pid,fd;
-char *pnam,*str;
-
- for (str = cmd; *str && *str != Outpar; str++);
- if (!*str)
- zerr("oops.");
- *str = '\0';
- hungets(strdup(cmd));
- strinbeg();
- if (!(list = parlist(1)))
- {
- strinend();
- hflush();
- return NULL;
- }
- if (peek != EOF && peek != EMPTY)
- {
- strinend();
- hflush();
- return NULL;
- }
- strinend();
- pnam = namedpipe();
- if (!jobtab[curjob].filelist)
- jobtab[curjob].filelist = newtable();
- addnode(jobtab[curjob].filelist,strdup(pnam));
- if (pid = phork())
- return pnam;
- entersubsh(1);
- fd = open(pnam,O_RDONLY);
- redup(fd,0);
- exiting = 1;
- execlist(list);
- _exit(0); return NULL;
-}
-
-/* > >(...) (does not use named pipes) */
-
-int getinpipe(char *cmd)
-{
-list list;
-int pipes[2];
-char *str = cmd;
-
- for (str = cmd; *str && *str != Outpar; str++);
- if (!*str)
- zerr("oops.");
- *str = '\0';
- hungets(strdup(cmd+2));
- strinbeg();
- if (!(list = parlist(1)))
- {
- strinend();
- hflush();
- return -1;
- }
- if (peek != EOF && peek != EMPTY)
- {
- strinend();
- hflush();
- return NULL;
- }
- strinend();
- mpipe(pipes);
- if (phork())
- {
- close(pipes[1]);
- return pipes[0];
- }
- close(pipes[0]);
- entersubsh(1);
- redup(pipes[1],1);
- exiting = 1;
- execlist(list);
- _exit(0); return 0;
-}
-
-/* < <(...) */
-
-int getoutpipe(char *cmd)
-{
-list list;
-int pipes[2];
-char *str;
-
- for (str = cmd; *str && *str != Outpar; str++);
- if (!*str)
- zerr("oops.");
- *str = '\0';
- hungets(strdup(cmd+2));
- strinbeg();
- if (!(list = parlist(1)))
- {
- strinend();
- hflush();
- return -1;
- }
- if (peek != EOF && peek != EMPTY)
- {
- strinend();
- hflush();
- return NULL;
- }
- strinend();
- mpipe(pipes);
- if (phork())
- {
- close(pipes[0]);
- return pipes[1];
- }
- close(pipes[1]);
- entersubsh(1);
- redup(pipes[0],0);
- exiting = 1;
- execlist(list);
- _exit(0); return 0;
-}
-
-/* run a list, saving the current job num */
-
-void runlist(list l)
-{
-int cj = curjob;
-
- execlist(l);
- curjob = cj;
-}
-
-char *gettemp(void)
-{
- return mktemp(strdup("/tmp/zshXXXXXX"));
-}
-
-/* my getwd; all the other ones I tried confused the SIGCHLD handler */
-
-char *zgetwd(void)
-{
-static char buf0[MAXPATHLEN];
-char buf3[MAXPATHLEN],*buf2 = buf0+1;
-struct stat sbuf;
-struct direct *de;
-DIR *dir;
-ino_t ino = -1;
-dev_t dev = -1;
-
- holdintr();
- buf2[0] = '\0';
- buf0[0] = '/';
- for(;;)
- {
- if (stat(".",&sbuf) < 0)
- {
- chdir(buf0);
- noholdintr();
- return strdup(".");
- }
- ino = sbuf.st_ino;
- dev = sbuf.st_dev;
- if (stat("..",&sbuf) < 0)
- {
- chdir(buf0);
- noholdintr();
- return strdup(".");
- }
- if (sbuf.st_ino == ino && sbuf.st_dev == dev)
- {
- chdir(buf0);
- noholdintr();
- return strdup(buf0);
- }
- dir = opendir("..");
- if (!dir)
- {
- chdir(buf0);
- noholdintr();
- return strdup(".");
- }
- chdir("..");
- readdir(dir); readdir(dir);
- while (de = readdir(dir))
- if (de->d_fileno == ino)
- {
- lstat(de->d_name,&sbuf);
- if (sbuf.st_dev == dev)
- goto match;
- }
- rewinddir(dir);
- readdir(dir); readdir(dir);
- while (de = readdir(dir))
- {
- lstat(de->d_name,&sbuf);
- if (sbuf.st_dev == dev)
- goto match;
- }
- noholdintr();
- closedir(dir);
- return strdup(".");
-match:
- strcpy(buf3,de->d_name);
- if (*buf2)
- strcat(buf3,"/");
- strcat(buf3,buf2);
- strcpy(buf2,buf3);
- closedir(dir);
- }
-}
-
-/* open pipes with fds >= 10 */
-
-void mpipe(int pp[2])
-{
- pipe(pp);
- pp[0] = movefd(pp[0]);
- pp[1] = movefd(pp[1]);
-}
-
-/* do process substitution with redirection */
-
-void spawnpipes(table l)
-{
-Node n = l->first;
-struct fnode *f;
-
- for (; n; n = n->next)
- {
- f = n->dat;
- if (f->type == OUTPIPE)
- {
- char *str = f->u.name;
- f->u.fd2 = getoutpipe(str);
- free(str);
- }
- if (f->type == INPIPE)
- {
- char *str = f->u.name;
- f->u.fd2 = getinpipe(str);
- free(str);
- }
- }
-}
-
End of exec.c
echo exec.pro 1>&2
sed 's/^-//' >exec.pro <<'End of exec.pro'
-void execstring(char *s);
-void newrunlist(list l);
-int phork(void);
-void execcursh(comm comm);
-void execute(char *arg0,table args);
-char *findcmd(char *arg0);
-void execlist(list list);
-void execlist1(list list);
-void execlist2(list2 list,int type,int last1);
-int execpline(list2 l,int how,int last1);
-void execpline2(pline pline,int how,int input,int output,int last1);
-char **makecline(char *nam,struct xlist *list);
-void fixcline(table l);
-void untokenize(char *s);
-void addenv(table list);
-int dontclob(struct fnode *f);
-void closemn(struct mnode *mfds[10],int fd);
-void closemnodes(struct mnode *mfds[10]);
-void addfd(int forked,int save[10],struct mnode *mfds[10],int fd1,int fd2,int rflag);
-void execcomm(comm comm,int input,int output,int bkg,int last1);
-void fixfds(int save[10]);
-void entersubsh(int bkg);
-void closem(void);
-int gethere(char *str);
-void catproc(struct mnode *mn);
-void teeproc(struct mnode *mn);
-void closeallelse(struct mnode *mn);
-long int zstrtol(const char *s,char **t,int base);
-table getoutput(char *cmd,int qt);
-table readoutput(int in,int qt);
-char *getoutputfile(char *cmd);
-char *namedpipe(void);
-char *getoutproc(char *cmd);
-char *getinproc(char *cmd);
-int getinpipe(char *cmd);
-int getoutpipe(char *cmd);
-void runlist(list l);
-char *gettemp(void);
-char *zgetwd(void);
-void mpipe(int pp[2]);
-void spawnpipes(table l);
End of exec.pro
echo funcs.h 1>&2
sed 's/^-//' >funcs.h <<'End of funcs.h'
-/*
-
- funcs.h - includes for all prototype files
-
- This file is part of zsh, the Z shell.
-
- zsh is free software; no one can prevent you from reading the source
- code, or giving it to someone else.
- This file is copyrighted under the GNU General Public License, which
- can be found in the file called COPYING.
-
- Copyright (C) 1990 Paul Falstad
-
- zsh is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY. No author or distributor accepts
- responsibility to anyone for the consequences of using it or for
- whether it serves any particular purpose or works at all, unless he
- says so in writing. Refer to the GNU General Public License
- for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- zsh, but only under the conditions described in the GNU General Public
- License. A copy of this license is supposed to have been given to you
- along with zsh so you can know your rights and responsibilities.
- It should be in a file named COPYING.
-
- Among other things, the copyright notice and this notice must be
- preserved on all copies.
-
-*/
-
-#include "glob.pro"
-#include "hist.pro"
-#include "table.pro"
-#include "subst.pro"
-#include "builtin.pro"
-#include "loop.pro"
-#include "jobs.pro"
-#include "exec.pro"
-#include "init.pro"
-#include "lex.pro"
-#include "parse.pro"
-#include "utils.pro"
-#include "test.pro"
-char *readline(char *);
-char *mktemp(char *);
End of funcs.h
echo glob.c 1>&2
sed 's/^-//' >glob.c <<'End of glob.c'
-/*
-
- glob.c - filename generation and brace expansion
-
- This file is part of zsh, the Z shell.
-
- zsh is free software; no one can prevent you from reading the source
- code, or giving it to someone else.
- This file is copyrighted under the GNU General Public License, which
- can be found in the file called COPYING.
-
- Copyright (C) 1990 Paul Falstad
-
- zsh is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY. No author or distributor accepts
- responsibility to anyone for the consequences of using it or for
- whether it serves any particular purpose or works at all, unless he
- says so in writing. Refer to the GNU General Public License
- for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- zsh, but only under the conditions described in the GNU General Public
- License. A copy of this license is supposed to have been given to you
- along with zsh so you can know your rights and responsibilities.
- It should be in a file named COPYING.
-
- Among other things, the copyright notice and this notice must be
- preserved on all copies.
-
-*/
-
-#include "zsh.h"
-#include "funcs.h"
-#ifndef INT_MAX
-#include <limits.h>
-#endif
-#include <sys/dir.h>
-#include <sys/errno.h>
-
-#define exists(X) (access(X,0) == 0)
-#define magicerr() { if (magic) putc('\n',stderr); errflag = 1; }
-
-static int gtype; /* file type for (X) */
-static int mode; /* != 0 if we are parsing glob patterns */
-static int sense; /* (X) or (^X) */
-static int pathpos; /* position in pathbuf */
-static int matchsz; /* size of matchbuf */
-static int matchct; /* number of matches found */
-static char pathbuf[MAXPATHLEN]; /* pathname buffer */
-static char **matchbuf; /* array of matches */
-static char **matchptr; /* &matchbuf[matchct] */
-
-/* pathname component in filename patterns */
-
-/* qath is a struct xpath * */
-
-struct xpath {
- qath next;
- comp comp;
- int closure; /* 1 if this is a (foo/)# */
- };
-struct xcomp {
- comp nx1,nx2;
- char *str;
- };
-
-void glob(table list,Node *np)
-{
-Node node = (*np)->last; /* the node before this one */
-Node next = (*np)->next; /* the node after this one */
-int sl; /* length of the pattern */
-char *ostr; /* the pattern before the parser chops it up */
-char *wd; /* the cwd */
-qath q; /* pattern after parsing */
-char *str = (*np)->dat; /* the pattern */
-
- sl = strlen(str);
- ostr = strdup(str);
- remnode(list,*np);
- gtype = 0;
- if (str[sl-1] == Outpar) /* check for (X) or (^X) */
- {
- if (sl > 4 && str[sl-4] == Inpar && str[sl-3] == Hat)
- sense = 1;
- else if (sl > 3 && str[sl-3] == Inpar)
- sense = 0;
- else
- sense = 2;
- if (sense != 2)
- {
- str[sl-3-sense] = '\0';
- switch (str[sl-2])
- {
- case '@': gtype = S_IFLNK; break;
- case '=': gtype = S_IFSOCK; break;
- case Inang: gtype = S_IFIFO; break;
- case '/': gtype = S_IFDIR; break;
- case '.': gtype = S_IFREG; break;
- case Star: gtype = 0100; break;
- case '%': gtype = S_IFCHR; break;
- case 'R': gtype = 0004; break;
- case 'W': gtype = 0002; break;
- case 'X': gtype = 0001; break;
- case 'r': gtype = 0400; break;
- case 'w': gtype = 0200; break;
- case 'x': gtype = 0100; break;
- default:
- magicerr();
- zerr("unknown file attribute");
- return;
- };
- }
- }
- else if (str[sl-1] == '/') /* foo/ == foo(/) */
- {
- gtype = S_IFDIR;
- sense = 0;
- }
- if (*str == '/') /* pattern has absolute path */
- {
- wd = zgetwd();
- str++;
- chdir("/");
- pathbuf[0] = '/';
- pathbuf[pathpos = 1] = '\0';
- }
- else /* pattern is relative to cwd */
- {
- wd = NULL;
- pathbuf[pathpos = 0] = '\0';
- }
- q = parsepat(str);
- if (!q || errflag) /* if parsing failed */
- {
- if (isset(NOBADPATTERN))
- {
- insnode(list,node,ostr);
- return;
- }
- magicerr();
- zerr("bad pattern: %s",ostr);
- free(ostr);
- return;
- }
- matchptr = matchbuf = (char **) zalloc((matchsz = 16)*sizeof(char *));
- matchct = 0;
- scanner(q); /* do the globbing */
- freepath(q);
- if (wd) /* reset cwd */
- {
- chdir(wd);
- free(wd);
- }
- if (!matchct && unset(NULLGLOB))
- if (unset(NONOMATCH))
- {
- if (!errflag)
- {
- magicerr();
- zerr("no matches found: %s",ostr);
- }
- free(matchbuf);
- free(ostr);
- errflag = 1;
- return;
- }
- else
- {
- *matchptr++ = strdup(ostr);
- matchct = 1;
- }
- qsort(&matchbuf[0],matchct,sizeof(char *),notstrcmp);
- matchptr = matchbuf;
- while (matchct--) /* insert matches in the arg list */
- insnode(list,node,*matchptr++);
- free(matchbuf);
- free(ostr);
- if (magic)
- magic = 2; /* tell readline we did something */
- *np = (next) ? next->last : list->last;
-}
-
-int notstrcmp(char **a,char **b)
-{
-char *c = *b,*d = *a;
-
- for (; *c == *d && *c; c++,d++);
- return ((int) (unsigned char) *c-(int) (unsigned char) *d);
-}
-
-/* add a match to the list */
-
-void insert(char *s)
-{
-struct stat buf;
-
- if (isset(MARKDIRS) && !lstat(s,&buf) && S_ISDIR(buf.st_mode)) /* grrr */
- {
- char *t;
- int ll = strlen(s);
-
- t = zalloc(ll+2);
- strcpy(t,s);
- t[ll] = '/';
- t[ll+1] = '\0';
- free(s);
- s = t;
- }
- *matchptr++ = s;
- if (++matchct == matchsz)
- {
- matchbuf = (char **) realloc(matchbuf,sizeof(char **)*(matchsz *= 2));
- matchptr = matchbuf+matchct;
- }
-}
-
-/* check to see if str is eligible for filename generation */
-
-int haswilds(char *str)
-{
- if (!str[1] && (*str == Inbrack || *str == Outbrack))
- return 0;
- if (str[0] == '%')
- return 0;
- for (; *str; str++)
- if (!strncmp(str,"..../",5))
- return 1;
- else if (*str == Pound || *str == Hat || *str == Star ||
- *str == Bar || *str == Inbrack || *str == Inang ||
- *str == Quest)
- return 1;
- return 0;
-}
-
-/* check to see if str is eligible for brace expansion */
-
-int hasbraces(char *str)
-{
-int mb,bc,cmct1,cmct2;
-char *lbr = NULL;
-
- if (str[0] == Inbrace && str[1] == Outbrace)
- return 0;
- for (mb = bc = cmct1 = cmct2 = 0; *str; str++)
- {
- if (*str == Inbrace)
- {
- if (!bc)
- lbr = str;
- bc++;
- if (str[4] == Outbrace && str[2] == '-') /* {a-z} */
- {
- cmct1++;
- if (bc == 1)
- cmct2++;
- }
- }
- else if (*str == Outbrace)
- {
- bc--;
- if (!bc && !cmct2)
- {
- *lbr = '{';
- *str = '}';
- }
- cmct2 = 0;
- }
- else if (*str == Comma && bc)
- {
- cmct1++;
- if (bc == 1)
- cmct2++;
- }
- if (bc > mb)
- mb = bc;
- if (bc < 0)
- return 0;
- }
- return (mb && bc == 0 && cmct1);
-}
-
-/* expand stuff like >>*.c */
-
-int xpandredir(struct fnode *fn,table tab)
-{
-table fake;
-char *nam;
-struct fnode *ff;
-int ret = 0;
-
- fake = newtable();
- addnode(fake,fn->u.name);
- prefork(fake);
- if (!errflag)
- postfork(fake,GLOB);
- if (errflag)
- {
- freetable(fake,freestr);
- return 0;
- }
- if (fake->first && !fake->first->next)
- {
- fn->u.name = fake->first->dat;
- untokenize(fn->u.name);
- }
- else
- while (nam = getnode(fake))
- {
- ff = alloc(sizeof(struct fnode));
- ff->u.name = nam;
- ff->type = fn->type;
- addnode(tab,ff);
- ret = 1;
- }
- free(fake);
- return ret;
-}
-
-/* concatenate s1 and s2 in dynamically allocated buffer */
-
-char *dyncat(char *s1,char *s2)
-{
-char *ptr;
-
- ptr = zalloc(strlen(s1)+strlen(s2)+1);
- strcpy(ptr,s1);
- strcat(ptr,s2);
- return ptr;
-}
-
-/* concatenate s1, s2, and s3 in dynamically allocated buffer */
-
-char *tricat(char *s1,char *s2,char *s3)
-{
-char *ptr;
-
- ptr = zalloc(strlen(s1)+strlen(s2)+strlen(s3)+1);
- strcpy(ptr,s1);
- strcat(ptr,s2);
- strcat(ptr,s3);
- return ptr;
-}
-
-/* brace expansion */
-
-void xpandbraces(table list,Node *np)
-{
-Node node = (*np),last = node->last;
-char *str = node->dat,*str3 = str,*str2;
-int prev;
-
- if (magic)
- magic = 2;
- for (; *str != Inbrace; str++);
- if (str[2] == '-' && str[4] == Outbrace) /* {a-z} */
- {
- char c1,c2;
-
- remnode(list,node);
- chuck(str);
- c1 = *str;
- chuck(str);
- chuck(str);
- c2 = *str;
- chuck(str);
- if (istok(c1))
- c1 = tokens[c1-Pound];
- if (istok(c2))
- c2 = tokens[c2-Pound];
- if (c1 < c2)
- for (; c2 >= c1; c2--) /* {a-z} */
- {
- *str = c2;
- insnode(list,last,strdup(str3));
- }
- else
- for (; c2 <= c1; c2++) /* {z-a} */
- {
- *str = c2;
- insnode(list,last,strdup(str3));
- }
- free(str3);
- *np = last->next;
- return;
- }
- prev = str-str3;
- str2 = getparen(str++);
- if (!str2)
- {
- errflag = 1;
- zerr("how did you get this error?");
- return;
- }
- remnode(list,node);
- node = last;
- FOREVER
- {
- char *zz,*str4;
- int cnt;
-
- for (str4 = str, cnt = 0; cnt || *str != Comma && *str !=
- Outbrace; str++)
- if (*str == Inbrace)
- cnt++;
- else if (*str == Outbrace)
- cnt--;
- else if (!*str)
- exit(10);
- zz = zalloc(prev+(str-str4)+strlen(str2)+1);
- strncpy(zz,str3,prev);
- zz[prev] = '\0';
- strncat(zz,str4,str-str4);
- strcat(zz,str2);
- insnode(list,node,zz);
- node = node->next;
- if (*str != Outbrace)
- str++;
- else
- break;
- }
- free(str3);
- *np = last->next;
-}
-
-/* get closing paren, given pointer to opening paren */
-
-char *getparen(char *str)
-{
-int cnt = 1;
-char typein = *str++,typeout = typein+1;
-
- for (; *str && cnt; str++)
- if (*str == typein)
- cnt++;
- else if (*str == typeout)
- cnt--;
- if (!str && cnt)
- return NULL;
- return str;
-}
-
-/* check to see if a matches b (b is not a filename pattern) */
-
-int matchpat(char *a,char *b)
-{
-comp c;
-int val;
-
- c = parsereg(b);
- if (!c)
- {
- zerr("bad pattern: %s");
- errflag = 1;
- return NULL;
- }
- val = doesmatch(a,c,0);
- freecomp(c);
- return val;
-}
-
-/* do the ${foo%%bar}, ${foo#bar} stuff */
-/* please do not laugh at this code. */
-
-void getmatch(char **sp,char *pat,int dd)
-{
-comp c;
-char *t,*lng = NULL,cc,*s = *sp;
-
- c = parsereg(pat);
- if (!c)
- {
- magicerr();
- zerr("bad pattern: %s",pat);
- return;
- }
- if (!(dd & 2))
- {
- for (t = s; t==s || t[-1]; t++)
- {
- cc = *t;
- *t = '\0';
- if (doesmatch(s,c,0))
- {
- if (!(dd & 1))
- {
- *t = cc;
- t = strdup(t);
- free(s);
- freecomp(c);
- *sp = t;
- return;
- }
- lng = t;
- }
- *t = cc;
- }
- if (lng)
- {
- t = strdup(lng);
- free(s);
- freecomp(c);
- *sp = t;
- return;
- }
- }
- else
- {
- for (t = s+strlen(s); t >= s; t--)
- {
- if (doesmatch(t,c,0))
- {
- if (!(dd & 1))
- {
- *t = '\0';
- freecomp(c);
- return;
- }
- lng = t;
- }
- }
- if (lng)
- {
- *lng = '\0';
- freecomp(c);
- return;
- }
- }
- freecomp(c);
-}
-
-/* add a component to pathbuf */
-
-void addpath(char *s)
-{
- while (pathbuf[pathpos++] = *s++);
- pathbuf[pathpos-1] = '/';
- pathbuf[pathpos] = '\0';
-}
-
-/* do the globbing */
-
-void scanner(qath q)
-{
-comp c;
-
- if (q->closure) /* (foo/)# */
- if (q->closure == 2) /* (foo/)## */
- q->closure = 1;
- else
- scanner(q->next);
- if (c = q->comp)
- {
- if (!(c->nx1 || c->nx2) && !haswilds(c->str))
- if (q->next)
- {
- char *wd = NULL;
-
- if (errflag)
- return;
- if (islink(c->str) || !strcmp(c->str,".."))
- wd = zgetwd();
- if (!chdir(c->str))
- {
- int oppos = pathpos;
-
- addpath(c->str);
- scanner((q->closure) ? q : q->next);
- if (wd)
- chdir(wd);
- else if (strcmp(c->str,"."))
- chdir("..");
- pathbuf[pathpos = oppos] = '\0';
- }
- else
- {
- magicerr();
- zerr("%e: %s",errno,c->str);
- if (wd)
- chdir(wd);
- else if (strcmp(c->str,"."))
- chdir("..");
- return;
- }
- }
- else
- {
- if (exists(c->str))
- insert(dyncat(pathbuf,c->str));
- }
- else
- {
- char *fn;
- int type,type3,dirs = !!q->next;
- struct direct *de;
- DIR *lock = opendir(".");
- static struct stat buf;
-
- if (lock == NULL)
- {
- magicerr();
- if (errno != EINTR)
- zerr("%e: %s",errno,pathbuf);
- return;
- }
- readdir(lock); readdir(lock); /* skip . and .. */
- while (de = readdir(lock))
- {
- if (errflag)
- break;
- fn = &de->d_name[0];
- if (dirs)
- {
- if (lstat(fn,&buf) == -1)
- {
- magicerr();
- zerr("%e: %s",errno,fn);
- }
- type3 = buf.st_mode & S_IFMT;
- if (type3 != S_IFDIR)
- continue;
- }
- else
- if (gtype) /* do the (X) (^X) stuff */
- {
- if (lstat(fn,&buf) == -1)
- {
- if (errno != ENOENT)
- {
- magicerr();
- zerr("%e: %s",errno,fn);
- }
- continue;
- }
- type3 = (type = buf.st_mode) & S_IFMT;
- if (gtype & 0777)
- {
- if ((!(type & gtype) ^ sense) || type3 == S_IFLNK)
- continue;
- }
- else if (gtype == S_IFCHR)
- {
- if ((type3 != S_IFCHR && type3 != S_IFBLK) ^ sense)
- continue;
- }
- else if ((gtype != type3) ^ sense)
- continue;
- }
- if (doesmatch(fn,c,unset(GLOBDOTS)))
- if (dirs)
- {
- if (!chdir(fn))
- {
- int oppos = pathpos;
-
- addpath(fn);
- scanner((q->closure) ? q : q->next); /* scan next level */
- chdir("..");
- pathbuf[pathpos = oppos] = '\0';
- }
- }
- else
- insert(dyncat(pathbuf,fn));
- }
- closedir(lock);
- }
- }
- else
- {
- zerr("no idea how you got this error message.");
- errflag = 1;
- }
-}
-
-/* do the [..(foo)..] business */
-
-int minimatch(char **pat,char **str)
-{
-char *pt = *pat+1,*s = *str;
-
- for (; *pt != Outpar; s++,pt++)
- if ((*pt != Quest || !*s) && *pt != *s)
- {
- *pat = getparen(*pat)-1;
- return 0;
- }
- *str = s-1;
- return 1;
-}
-
-/* see if str matches c; first means worry about matching . explicitly */
-
-int doesmatch(char *str,comp c,int first)
-{
-char *pat = c->str;
-
- FOREVER
- {
- if (!*pat)
- {
- if (errflag)
- return 0;
- if (!(*str || c->nx1 || c->nx2))
- return 1;
- return (c->nx1 && doesmatch(str,c->nx1,first)) ||
- (c->nx2 && doesmatch(str,c->nx2,first));
- }
- if (first && *str == '.' && *pat != '.')
- return 0;
- if (*pat == Star) /* final * is not expanded to ?#; returns success */
- return 1;
- first = 0;
- if (*pat == Quest && *str)
- {
- str++;
- pat++;
- continue;
- }
- if (*pat == Hat)
- return 1-doesmatch(str,c->nx1,first);
- if (*pat == Inbrack)
- if (pat[1] == Hat)
- {
- for (pat += 2; *pat != Outbrack && *pat; pat++)
- if (*pat == '-' && pat[-1] != Hat && pat[1] != Outbrack)
- {
- if (pat[-1] <= *str && pat[1] >= *str)
- break;
- }
- else if (*str == *pat)
- break;
- if (!*pat)
- {
- zerr("something is very wrong.");
- return 0;
- }
- if (*pat != Outbrack)
- break;
- pat++;
- str++;
- continue;
- }
- else
- {
- for (pat++; *pat != Outbrack && *pat; pat++)
- if (*pat == Inpar)
- {
- if (minimatch(&pat,&str))
- break;
- }
- else if (*pat == '-' && pat[-1] != Inbrack && pat[1] != Outbrack)
- {
- if (pat[-1] <= *str && pat[1] >= *str)
- break;
- }
- else if (*str == *pat)
- break;
- if (!pat || !*pat)
- {
- zerr("oh dear. that CAN'T be right.");
- return 0;
- }
- if (*pat == Outbrack)
- break;
- for (str++; *pat != Outbrack; pat++);
- pat++;
- continue;
- }
- if (*pat == Inang)
- {
- int t1,t2,t3;
- char *ptr;
-
- if (*++pat == Outang) /* handle <> case */
- {
- (void) zstrtol(str,&ptr,10);
- if (ptr == str)
- break;
- str = ptr;
- pat++;
- }
- else
- {
- t1 = zstrtol(str,&ptr,10);
- if (ptr == str)
- break;
- str = ptr;
- t2 = zstrtol(pat,&ptr,10);
- if (*ptr != '-')
- exit(31);
- t3 = zstrtol(ptr+1,&pat,10);
- if (!t3)
- t3 = INT_MAX;
- if (*pat++ != Outang)
- exit(21);
- if (t1 < t2 || t1 > t3)
- break;
- }
- continue;
- }
- if (*str == *pat)
- {
- str++;
- pat++;
- continue;
- }
- break;
- }
- return 0;
-}
-
-static char *pptr;
-
-qath parsepat(char *str)
-{
- mode = 0;
- pptr = str;
- return parseqath();
-}
-
-comp parsereg(char *str)
-{
- mode = 1;
- pptr = str;
- return parsecompsw();
-}
-
-qath parseqath(void)
-{
-comp c1;
-qath p1;
-
- if (pptr[0] == '.' && pptr[1] == '.' && pptr[2] == '.' && pptr[3] ==
- '.' && pptr[4] == '/')
- {
- pptr[0] = Inpar;
- pptr[1] = Star;
- pptr[2] = '/';
- pptr[3] = Outpar;
- pptr[4] = Pound; /* "..../" -> "( * /)#" */
- }
- if (*pptr == Inpar)
- {
- char *str;
- int pars = 1;
-
- for (str = pptr+1; *str && pars; str++)
- if (*str == Inpar)
- pars++;
- else if (*str == Outpar)
- pars--;
- if (str[0] != Pound || str[-1] != Outpar || str[-2] != '/')
- goto kludge;
- pptr++;
- if (!(c1 = parsecompsw()))
- return NULL;
- if (pptr[0] == '/' && pptr[1] == Outpar && pptr[2] == Pound)
- {
- int pdflag = 0;
-
- pptr += 3;
- if (*pptr == Pound)
- {
- pdflag = 1;
- pptr++;
- }
- p1 = (qath) alloc(sizeof(struct xpath));
- p1->comp = c1;
- p1->closure = 1+pdflag;
- p1->next = parseqath();
- return (p1->comp) ? p1 : NULL;
- }
- }
- else
- {
-kludge:
- if (!(c1 = parsecompsw()))
- return NULL;
- if (*pptr == '/' || !*pptr)
- {
- int ef = *pptr == '/';
-
- p1 = (qath) alloc(sizeof(struct xpath));
- p1->comp = c1;
- p1->closure = 0;
- p1->next = (*pptr == '/') ? (pptr++,parseqath()) : NULL;
- return (ef && !p1->next) ? NULL : p1;
- }
- }
- magicerr();
- errflag = 1;
- return NULL;
-}
-
-comp parsecomp(void)
-{
-comp c = (comp) alloc(sizeof(struct xcomp)),c1,c2;
-char *s = c->str = alloc(MAXPATHLEN*2),*ls = NULL;
-
- c->nx2 = NULL;
- while (*pptr && (mode || *pptr != '/') && *pptr != Bar &&
- *pptr != Outpar)
- {
- if (*pptr == Hat)
- {
- *s++ = Hat;
- *s++ = '\0';
- pptr++;
- if (!(c->nx1 = parsecomp()))
- {
- free(c->str);
- free(c);
- return NULL;
- }
- return c;
- }
- if (*pptr == Star && pptr[1] && (mode || pptr[1] != '/'))
- {
- *s++ = '\0';
- pptr++;
- c->nx1 = c1 = (comp) alloc(sizeof(struct xcomp));
- *((c1->nx1 = c1)->str = strdup("?")) = Quest;
- c->nx2 = c1->nx2 = parsecomp();
- return (c->nx2) ? c : NULL;
- }
- if (*pptr == Inpar)
- {
- *s++ = '\0';
- pptr++;
- c->nx1 = c1 = parsecompsw();
- if (*pptr != Outpar)
- {
- errflag = 1;
- free(c);
- free(c->str);
- return NULL;
- }
- pptr++;
- if (*pptr == Pound)
- {
- int dpnd = 0;
-
- pptr++;
- if (*pptr == Pound)
- {
- pptr++;
- dpnd = 1;
- }
- c2 = parsecomp();
- if (dpnd)
- c->nx2 = NULL;
- else
- c->nx2 = c2;
- if (!c2)
- {
- free(c);
- free(c->str);
- return NULL;
- }
- adjustcomp(c1,c2,c1);
- return c;
- }
- c2 = parsecomp();
- if (!c2)
- {
- free(c);
- free(c->str);
- return NULL;
- }
- adjustcomp(c1,c2,NULL);
- return c;
- }
- if (*pptr == Pound)
- {
- int dpnd = 0;
-
- *s = '\0';
- pptr++;
- if (*pptr == Pound)
- {
- pptr++;
- dpnd = 1;
- }
- if (!ls)
- return NULL;
- c->nx1 = c1 = (comp) alloc(sizeof(struct xcomp));
- (c1->nx2 = c1)->str = strdup(ls);
- c->nx2 = c1->nx1 = parsecomp();
- if (!c->nx2)
- {
- free(c);
- free(c->str);
- return NULL;
- }
- if (dpnd)
- c->nx2 = NULL;
- *ls++ = '\0';
- return c;
- }
- ls = s;
- if (*pptr == Inang)
- {
- int dshct;
-
- dshct = (pptr[1] == Outang);
- *s++ = *pptr++;
- while (*pptr && (*s++ = *pptr++) != Outang)
- if (s[-1] == '-')
- dshct++;
- else if (!isdigit(s[-1]))
- break;
- if (s[-1] != Outang || dshct != 1)
- {
- free(c);
- free(c->str);
- return NULL;
- }
- }
- else if (*pptr == Inbrack)
- {
- while (*pptr && (*s++ = *pptr++) != Outbrack);
- if (s[-1] != Outbrack)
- {
- free(c);
- free(c->str);
- return NULL;
- }
- }
- else if (istok(*pptr) && *pptr != Star && *pptr != Quest)
- *s++ = tokens[*pptr++-Pound];
- else
- *s++ = *pptr++;
- }
- *s++ = '\0';
- c->nx1 = NULL;
- return c;
-}
-
-comp parsecompsw(void)
-{
-comp c1,c2,c3;
-
- c1 = parsecomp();
- if (!c1)
- return NULL;
- if (*pptr == Bar)
- {
- c2 = (comp) alloc(sizeof(struct xcomp));
- pptr++;
- c3 = parsecompsw();
- if (!c3)
- return NULL;
- c2->str = strdup("");
- c2->nx1 = c1;
- c2->nx2 = c3;
- return c2;
- }
- return c1;
-}
-
-#define MARKER ((void *) 1L)
-
-void adjustcomp(comp c1,comp c2,comp c3)
-{
-comp z;
-
- if (c1->nx1 == c2 && c1->nx2 == c3)
- return;
- if (c1->nx1)
- {
- if ((z = c1->nx1) == MARKER)
- return;
- c1->nx1 = MARKER;
- adjustcomp(z,c2,c3);
- c1->nx1 = z;
- }
- if (c1->nx2)
- adjustcomp(c1->nx2,c2,c3);
- if (!(c1->nx1 || c1->nx2))
- {
- c1->nx1 = c2;
- c1->nx2 = c3;
- }
-}
-
-void freepath(qath p)
-{
- if (p)
- {
- freepath(p->next);
- freecomp(p->comp);
- free(p);
- }
-}
-
-void freecomp(comp c)
-{
- if (c && c->str)
- {
- free(c->str);
- c->str = NULL;
- freecomp(c->nx1);
- freecomp(c->nx2);
- free(c);
- }
-}
-
-/* tokenize and see if ss matches tt */
-
-int patmatch(char *ss,char *tt)
-{
-char *s = ss,*t;
-
- for (; *s; s++)
- if (*s == '\\')
- chuck(s);
- else
- for (t = tokens; *t; t++)
- if (*t == *s)
- {
- *s = (t-tokens)+Pound;
- break;
- }
- return matchpat(ss,tt);
-}
-
-/* remove unnecessary Nulargs */
-
-void remnulargs(char *s)
-{
-int nl = *s;
-char *t = s;
-
- while (*s)
- if (*s == Nularg)
- chuck(s);
- else
- s++;
- if (!*t && nl)
- {
- t[0] = Nularg;
- t[1] = '\0';
- }
-}
-
End of glob.c
echo glob.pro 1>&2
sed 's/^-//' >glob.pro <<'End of glob.pro'
-void glob(table list,Node *np);
-int notstrcmp(char **a,char **b);
-void insert(char *s);
-int haswilds(char *str);
-int hasbraces(char *str);
-int xpandredir(struct fnode *fn,table tab);
-char *dyncat(char *s1,char *s2);
-char *tricat(char *s1,char *s2,char *s3);
-void xpandbraces(table list,Node *np);
-char *getparen(char *str);
-int matchpat(char *a,char *b);
-void getmatch(char **sp,char *pat,int dd);
-void addpath(char *s);
-void scanner(qath q);
-int minimatch(char **pat,char **str);
-int doesmatch(char *str,comp c,int first);
-qath parsepat(char *str);
-comp parsereg(char *str);
-qath parseqath(void);
-comp parsecomp(void);
-comp parsecompsw(void);
-void adjustcomp(comp c1,comp c2,comp c3);
-void freepath(qath p);
-void freecomp(comp c);
-int patmatch(char *ss,char *tt);
-void remnulargs(char *s);
End of glob.pro
echo hist.c 1>&2
sed 's/^-//' >hist.c <<'End of hist.c'
-/*
-
- hist.c - ! history
-
- This file is part of zsh, the Z shell.
-
- zsh is free software; no one can prevent you from reading the source
- code, or giving it to someone else.
- This file is copyrighted under the GNU General Public License, which
- can be found in the file called COPYING.
-
- Copyright (C) 1990 Paul Falstad
-
- zsh is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY. No author or distributor accepts
- responsibility to anyone for the consequences of using it or for
- whether it serves any particular purpose or works at all, unless he
- says so in writing. Refer to the GNU General Public License
- for full details.
-
- Everyone is granted permission to copy, modify and redistribute
- zsh, but only under the conditions described in the GNU General Public
- License. A copy of this license is supposed to have been given to you
- along with zsh so you can know your rights and responsibilities.
- It should be in a file named COPYING.
-
- Among other things, the copyright notice and this notice must be
- preserved on all copies.
-
-*/
-
-#include "zsh.h"
-#include "funcs.h"
-
-int lastc;
-
-/* add a character to the current history word */
-
-void hwaddc(int c)
-{
- if (hlastw)
- {
- if (c == EOF || c == HERR)
- return;
- *hlastp++ = c;
- if (hlastp-hlastw == hlastsz)
- {
- hlastw = realloc(hlastw,hlastsz *= 2);
- hlastp = hlastw+(hlastsz/2);
- }
- }
-}
-
-#define habort() { errflag = 1; return HERR; }
-
-/* get a character after performing history substitution */
-
-int hgetc(void)
-{
-int c,ev,farg,larg,argc,marg = -1,cflag = 0,bflag = 0;
-char buf[256],*ptr;
-table slist,elist;
-
-tailrec:
- c = hgetch();
- if (stophist)
- {
- hwaddc(c);
- return c;
- }
- if (firstch && c == '^' && !(ungots && !magic))
- {
- firstch = 0;
- hungets(strdup(":s^"));
- c = '!';
- goto hatskip;
- }
- if (c != ' ')
- firstch = 0;
- if (c == '\\')
- {
- int g = hgetch();
-
- if (g != '!')
- hungetch(g);
- else
- {
- hwaddc('!');
- return '!';
- }
- }
- if (c != '!' || (ungots && !magic))
- {
- hwaddc(c);
- return c;
- }
-hatskip:
- if ((c = hgetch()) == '{')
- {
- bflag = cflag = 1;
- c = hgetch();
- }
- if (c == '\"')
- {
- stophist = 1;
- goto tailrec;
- }
- if (!cflag && znspace(c) || c == '=' || c == '(')
- {
- hungetch(c);
- hwaddc('!');
- return '!';
- }
- cflag = 0;
- ptr = buf;
-
- /* get event number */
-
- if (c == '?')
- {
- FOREVER
- {
- c = hgetch();
- if (c == '?' || c == '\n')
- break;
- else
- *ptr++ = c;
- }
- if (c != '\n')
- c = hgetch();
- *ptr = NULL;
- ev = hconsearch(last = strdup(buf),&marg);
- if (ev == -1)
- {
- herrflush();
- zerr("no such event: %s",buf);
- habort();
- }
- }
- else
- {
- int t0;
-
- FOREVER
- {
- if (znspace(c) || c == ':' || c == '^' || c == '$' || c == '*'
- || c == '%' || c == '}')
- break;
- if (ptr != buf && c == '-')
- break;
- *ptr++ = c;
- if (c == '#' || c == '!')
- {
- c = hgetch();
- break;
- }
- c = hgetch();
- }
- *ptr = 0;
- if (!*buf)
- ev = dev;
- else if (t0 = atoi(buf))
- ev = (t0 < 0) ? cev+t0 : t0;
- else if (*buf == '!')
- ev = cev-1;
- else if (*buf == '#')
- ev = cev;
- else if ((ev = hcomsearch(buf)) == -1)
- {
- zerr("event not found: %s",buf);
- while (c != '\n')
- c = hgetch();
- habort();
- }
- }
-
- /* get the event */
-
- if (!(elist = getevent(dev = ev)))
- habort();
-
- /* extract the relevant arguments */
-
- argc = getargc(elist)-1;
- if (c == ':')
- {
- cflag = 1;
- c = hgetch();
- }
- if (c == '*')
- {
- farg = 1;
- larg = argc;
- cflag = 0;
- }
- else
- {
- hungetch(c);
- larg = farg = getargspec(argc,marg);
- if (larg == -2)
- habort();
- if (farg != -1)
- cflag = 0;
- c = hgetch();
- if (c == '*')
- {
- cflag = 0;
- larg = argc;
- }
- else if (c == '-')
- {
- cflag = 0;
- larg = getargspec(argc,marg);
- if (larg == -2)
- habort();
- if (larg == -1)
- larg = argc-1;
- }
- else
- hungetch(c);
- }
- if (farg == -1)
- farg = 0;
- if (larg == -1)
- larg = argc;
- if (!(slist = getargs(elist,farg,larg)))
- habort();
-
- /* do the modifiers */
-
- FOREVER
- {
- c = (cflag) ? ':' : hgetch();
- cflag = 0;
- if (c == ':')
- {
- int gbal = 0;
-
- if ((c = hgetch()) == 'g')
- {
- gbal = 1;
- c = hgetch();
- }
- switch(c)
- {
- case 'p':
- hflag = 2;
- break;
- case 'h':
- if (!apply1(gbal,remtpath,slist))
- {
- herrflush();
- zerr("modifier failed: h");
- habort();
- }
- break;
- case 'e':
- if (!apply1(gbal,rembutext,slist))
- {
- herrflush();
- zerr("modifier failed: e");
- habort();
- }
- break;
- case 'r':
- if (!apply1(gbal,remtext,slist))
- {
- herrflush();
- zerr("modifier failed: r");
- habort();
- }
- break;
- case 't':
- if (!apply1(gbal,remlpaths,slist))
- {
- herrflush();
- zerr("modifier failed: t");
- habort();
- }
- break;
- case 's':
- {
- int del;
- char *ptr1,*ptr2;
-
- del = hgetch();
- ptr1 = hdynread(del);
- if (!ptr1)
- habort();
- ptr2 = hdynread2(del);
- if (strlen(ptr1))
- {
- if (last)
- free(last);
- last = ptr1;
- }
- if (rast)
- free(rast);
- rast = ptr2;
- }
- case '&':
- if (last && rast)
- {
- if (subst(gbal,slist,last,rast))
- habort();
- }
- else
- {
- herrflush();
- zerr("no previous substitution with &");
- habort();
- }
- break;
- case 'q':
- apply1(0,quote,slist);
- break;
- case 'x':
- apply1(0,quotebreak,slist);
- break;
- default:
- herrflush();
- zerr("illegal modifier: %c",c);
- habort();
- break;
- }
- }
- else
- {
- if (c != '}' || !bflag)
- hungetch(c);
- if (c != '}' && bflag)
- {
- zerr("'}' expected");
- habort();
- }
- break;
- }
- }
-
- /* stuff the resulting string in the input queue and start over */
-
- hungets(makehlist(slist,1));
- hflag |= 1;
- goto tailrec;
-}
-
-/* begin reading a string */
-
-void strinbeg(void)
-{
- strin = 1;
-}
-
-/* done reading a string */
-
-void strinend(void)
-{
- strin = 0;
- firstch = 1;
- hflag = 0;
- free(ungots);
- ungotptr = ungots = NULL;
- peek = EMPTY;
-}
-
-static char *line = NULL,*oline = NULL;
-
-/* stuff a whole FILE into the input queue */
-
-int stuff(char *fn)
-{
-FILE *in;
-char *buf;
-int len;
-
- if (!(in = fopen(fn,"r")))
- {
- zerr("can't open %s",fn);
- return 1;
- }
- fseek(in,0,2);
- len = ftell(in);
- fseek(in,0,0);
- buf = alloc(len+1);
- if (!(fread(buf,len,1,in)))
- {
- zerr("read error on %s",fn);
- fclose(fn);
- free(buf);
- return 1;
- }
- fclose(in);
- if (!line)
- line = oline = buf;
- else
- {
- line = dyncat(line,buf);
- free(oline);
- oline = line;
- }
- return 0;
-}
-
-/* get a char without history */
-
-int hgetch(void)
-{
-char *pmpt = NULL,*s;
-
- if (ungots)
- {
- if (*ungotptr)
- {
- if (*ungotptr == ALPOP) /* done expanding an alias,
- pop the alias stack */
- {
- if (!alix)
- {
- ungotptr++;
- return lastc = HERR;
- }
- alstack[--alix]->inuse = 0;
- s = alstack[alix]->text;
- if (*s && s[strlen(s)-1] == ' ')
- alstat = ALSTAT_MORE;
- else
- alstat = ALSTAT_JUNK;
- ungotptr++;
- return lastc = hgetch();
- }
- return lastc = *ungotptr++;
- }
- if (strin)
- return lastc = EOF;
- ungotptr = 0;
- free(ungots);
- ungots = NULL;
- }
-kludge:
- if (errflag)
- {
- if (oline)
- free(oline);
- oline = line = NULL;
- return lastc = HERR;
- }
- if (line && *line)
- return lastc = (*line++);
- if (line)
- free(oline);
- if (interact)
- if (!firstln)
- pmpt = putprompt("PROMPT2");
- else
- pmpt = putprompt("PROMPT");
- if (interact && SHTTY == -1)
- write(2,pmpt,strlen(pmpt));
- oline = line = (interact && SHTTY != -1) ? readline(pmpt) :
- fgets(zalloc(256),256,bshin);
- if (isset(VERBOSE) && line)
- fputs(line,stderr);
- if (!line)
- return lastc = EOF;
- if (line[strlen(line)-1] == '\n')
- lineno++;
- firstch = 1;
- firstln = 0;
- goto kludge;
-}
-
-/* unget a character */
-
-void hungetch(int c)
-{
-static char ubuf2[] = {'x',0};
-
- if (c == EOF)
- return;
- ubuf2[0] = c;
- hungets(strdup(ubuf2));
-}
-
-/* unget a character and remove it from the history word */
-
-void hungetc(int c)
-{
- if (hlastw)
- {
- if (hlastw == hlastp)
- zerr("hungetc attempted at buffer start");
- else
- hlastp--;
- }
- hungetch(c);
-}
-
-void hflush(void)
-{
- if (ungots)
- free(ungots);
- ungots = ungotptr = NULL;
-}
-
-/* unget a string into the input queue */
-
-void hungets(char *str)
-{
- if (ungots && !*ungotptr)
- {
- free(ungots);
- ungots = NULL;
- }
- if (ungots)
- {
- char *ptr;
-
- ptr = dyncat(str,ungotptr);
- free(ungots);
- free(str);
- ungotptr = ungots = ptr;
- }
- else
- ungots = ungotptr = str;
-}
-
-/* initialize the history mechanism */
-
-void hbegin(void)
-{
- firstln = firstch = 1;
- histremmed = errflag = hflag = 0;
- stophist = isset(NOBANGHIST);
- if (interact)
- {
- inittty();
- dev = cev++;
- while (cev-tfev >= tevs)
- {
- freetable(getnode(histlist),freestr);
- tfev++;
- }
- addnode(histlist,curtab = newtable());
- }
-}
-
-void inittty(void)
-{
- attachtty(shpgrp);
- settyinfo(&shttyinfo);
-}
-
-/* say we're done using the history mechanism */
-
-int hend(void)
-{
-char *ptr;
-int flag;
-
- if (!interact)
- return 1;
- if (!curtab)
- return 0;
- flag = hflag;
- hflag = 0;
- if (curtab->first && (*(char *) curtab->last->dat == '\n'))
- free(remnode(curtab,curtab->last));
- if (!curtab->first)
- {
- freetable(remnode(histlist,histlist->last),freestr);
- cev--;
- flag = 0;
- }
- if (flag)
- {
- fprintf(stderr,"%s\n",ptr = makehlist(curtab,0));
- free(ptr);
- }
- curtab = NULL;
- return !(flag & 2 || errflag);
-}
-
-/* remove the current line from the history list */
-
-void remhist(void)
-{
- if (!interact)
- return;
- if (!histremmed)
- {
- histremmed = 1;
- freetable(remnode(histlist,histlist->last),freestr);
- cev--;
- }
-}
-
-/* begin a word */
-
-void hwbegin(void)
-{
- if (hlastw)
- free(hlastw);
- hlastw = hlastp = zalloc(hlastsz = 32);
-}
-
-/* add a word to the history list */
-
-char *hwadd(void)
-{
-char *ret = hlastw;
-
- if (hlastw)
- *hlastp = '\0';
- if (hlastw && lastc != EOF && !errflag)
- if (curtab && !alix/* && alstat != ALSTAT_JUNK*/)
- {
- addnode(curtab,hlastw);
- hlastw = NULL;
- }
- if (alstat == ALSTAT_JUNK)
- alstat = 0;
- return ret;
-}
-
-/* get an argument specification */
-
-int getargspec(int argc,int marg)
-{
-int c,ret = -1;
-
- if ((c = hgetch()) == '0')
- return 0;
- if (isdigit(c))
- {
- ret = 0;
- while (isdigit(c))
- {
- ret = ret*10+c-'0';
- c = hgetch();
- }
- hungetch(c);
- }
- else if (c == '^')
- ret = 1;
- else if (c == '$')
- ret = argc;
- else if (c == '%')
- {
- if (marg == -1)
- {
- herrflush();
- zerr("%% with no previous word matched");
- return -2;
- }
- ret = marg;
- }
- else
- hungetch(c);
- return ret;
-}
-
-/* do ?foo? search */
-
-int hconsearch(char *str,int *marg)
-{
-int t0,t1;
-Node node,node2;
-
- if (cev-tfev < 1)
- return -1;
- for (t0 = cev-1,node = histlist->last->last;
- t0 >= tfev; t0--,node = node->last)
- for (t1 = 0,node2 = ((table) node->dat)->first; node2; t1++,node2 =
- node2->next)
- if (strstr(node2->dat,str))
- {
- *marg = t1;
- return t0;
- }
- return -1;
-}
-
-/* do !foo search */
-
-int hcomsearch(char *str)
-{
-int t0;
-Node node,node2;
-
- if (cev-tfev < 1)
- return -1;
- for (t0 = cev-1,node = histlist->last->last; t0 >= tfev;
- t0--,node = node->last)
- if ((node2 = ((table) node->dat)->first)->dat &&
- strstr(node2->dat,str))
- return t0;
- return -1;
-}
-
-/* apply func to a list */
-
-int apply1(int gflag,int (*func)(void **),table list)
-{
-Node node;
-int flag = 0;
-
- for (node = list->first; node; node = node->next)
- if ((flag |= func(&node->dat)) && !gflag)
- return 1;
- return flag;
-}
-
-/* various utilities for : modifiers */
-
-int remtpath(void **junkptr)
-{
-char *str = *junkptr,*cut;
-
- if (cut = strrchr(str,'/'))
- {
- *cut = NULL;
- return 1;
- }
- return 0;
-}
-
-int remtext(void **junkptr)
-{
-char *str = *junkptr,*cut;
-
- if ((cut = strrchr(str,'.')) && cut != str)
- {
- *cut = NULL;
- return 1;
- }
- return 0;
-}
-
-int rembutext(void **junkptr)
-{
-char *str = *junkptr,*cut;
-
- if ((cut = strrchr(str,'.')) && cut != str)
- {
- *junkptr = strdup(cut+1); /* .xx or xx? */
- free(str);
- return 1;
- }
- return 0;
-}
-
-int remlpaths(void **junkptr)
-{
-char *str = *junkptr,*cut;
-
- if (cut = strrchr(str,'/'))
- {
- *cut = NULL;
- *junkptr = strdup(cut+1);
- free(str);
- return 1;
- }
- return 0;
-}
-
-int subst(int gbal,table slist,char *ptr1,char *ptr2)
-{
-Node node;
-int iflag = 0;
-
- for (node = slist->first; node; )
- if (subststr(&node->dat,ptr1,ptr2,gbal))
- {
- iflag = 1;
- if (!gbal)
- return 0;
- }
- else
- node = node->next;
- if (!iflag)
- {
- herrflush();
- zerr("string not found: %s",ptr1);
- return 1;
- }
- return 0;
-}
-
-int subststr(void **strptr,char *in,char *out,int gbal)
-{
-char *str = *strptr,*cut,*sptr,*ss;
-int ret = 0;
-
-maze:
- if (cut = (char *) strstr(str,in))
- {
- char *incop;
-
- incop = strdup(in);
- *cut = '\0';
- cut += strlen(in);
- ss = *strptr;
- *strptr = tricat(*strptr,sptr = convamps(out,incop),cut);
- free(ss);
- free(sptr);
- free(incop);
- if (gbal)
- {
- str = (char *) *strptr+(cut-str)+strlen(in);
- ret = 1;
- goto maze;
- }
- return 1;
- }
- return ret;
-}
-
-char *convamps(char *out,char *in)
-{
-char *ptr,*ret,*pp;
-int slen,inlen = strlen(in);
-
- for (ptr = out, slen = 0; *ptr; ptr++,slen++)
- if (*ptr == '\\')
- ptr++;
- else if (*ptr == '&')
- slen += inlen-1;
- ret = pp = zalloc(slen+1);
- for (ptr = out; *ptr; ptr++)
- if (*ptr == '\\')
- *pp++ = *++ptr;
- else if (*ptr == '&')
- {
- strcpy(pp,in);
- pp += inlen;
- }
- else
- *pp++ = *ptr;
- *pp = '\0';
- return ret;
-}
-
-/* make a string out of a history list */
-
-char *makehlist(table tab,int freeit)
-{
-int ccnt;
-Node node;
-char *ret,*ptr;
-char sep = *ifs;
-
- for (ccnt = 0, node = (freeit == 2) ? tab->first->next : tab->first;
- node; node = node->next)
- ccnt += strlen(node->dat)+1;
- if (!ccnt)
- return strdup("");
- ptr = ret = zalloc(ccnt);
- for (node = (freeit == 2) ? tab->first->next : tab->first;
- node; node = node->next)
- {
- strcpy(ptr,node->dat);
- ptr += strlen(node->dat);
- if (freeit == 1)
- free(node->dat);
- *ptr++ = sep;
- }
- *--ptr = '\0';
- return ret;
-}
-
-table quietgetevent(int ev)
-{
-Node node;
-
- ev -= tfev;
- for (node = histlist->first; ev && node; node = node->next, ev--);
- if (ev)
- return NULL;
- return node->dat;
-}
-
-table getevent(int ev)
-{
-Node node;
-int oev = ev;
-
- ev -= tfev;
- for (node = histlist->first; ev && node; node = node->next, ev--);
- if (ev || !node)
- {
- herrflush();
- zerr("no such event: %d",oev);
- return NULL;
- }
- return node->dat;
-}
-
-int getargc(table tab)
-{
-int argc;
-Node node;
-
- for (argc = 0, node = tab->first; node; node = node->next, argc++);
- return argc;
-}
-
-table getargs(table elist,int arg1,int arg2)
-{
-table ret = newtable();
-Node node;
-int oarg1 = arg1,oarg2 = arg2;
-
- for (node = elist->first; arg1 && node; node = node->next, arg1--,arg2--);
- if (!node)
- {
- herrflush();
- zerr("no such word in event: %d",oarg1);
- return NULL;
- }
- for (arg2++; arg2 && node; node = node->next, arg2--)
- addnode(ret,strdup(node->dat));
- if (arg2 && !node)
- {
- herrflush();
- zerr("no such word in event: %d",oarg2);
- return NULL;
- }
- return ret;
-}
-
-int quote(void **tr)
-{
-char *ptr,*rptr,**str = (char **) tr;
-int len = 1;
-
- for (ptr = *str; *ptr; ptr++,len++)
- if (*ptr == '\'')
- len += 3;
- ptr = *str;
- *str = rptr = alloc(len);
- for (ptr = *str; *ptr; )
- if (*ptr == '\'')
- {
- *rptr++ = '\'';
- *rptr++ = '\\';
- *rptr++ = '\'';
- *rptr++ = '\'';
- ptr++;
- }
- else
- *rptr++ = *ptr++;
- return 0;
-}
-
-int quotebreak(void **tr)
-{
-char *ptr,*rptr,**str = (char **) tr;
-int len = 1;
-
- for (ptr = *str; *ptr; ptr++,len++)
- if (*ptr == '\'')
- len += 3;
- else if (znspace(*ptr))
- len += 2;
- ptr = *str;
- *str = rptr = alloc(len);
- for (ptr = *str; *ptr; )
- if (*ptr == '\'')
- {
- *rptr++ = '\'';
- *rptr++ = '\\';
- *rptr++ = '\'';
- *rptr++ = '\'';
- ptr++;
- }
- else if (znspace(*ptr))
- {
- *rptr++ = '\'';
- *rptr++ = *ptr++;
- *rptr++ = '\'';
- }
- else
- *rptr++ = *ptr++;
- return 0;
-}
-
-void stradd(char **p,char *d)
-{
-char *s = *p;
-
- while (*s++ = *d++);
- *p = s-1;
-}
-
-/* get a prompt string */
-
-char *putprompt(char *fm)
-{
-char *ss,*ttyname(int);
-static char buf[256];
-char *bp = buf;
-int t0;
-struct tm *tm = NULL;
-time_t timet;
-
- clearerr(stdin);
- fm = getparm(fm);
- for(;*fm;fm++)
- {
- if (bp-buf >= 220)
- break;
- if (*fm == '%')
- switch (*++fm)
- {
- case '~':
- if (!strncmp(cwd,home,t0 = strlen(home)))
- {
- *bp++ = '~';
- stradd(&bp,cwd+t0);
- break;
- }
- case 'd':
- case '/':
- stradd(&bp,cwd);
- break;
- case 'c':
- case '.':
- for (ss = cwd+strlen(cwd); ss > cwd; ss--)
- if (*ss == '/')
- {
- ss++;
- break;
- }
- stradd(&bp,ss);
- break;
- case 'h':
- case '!':
- sprintf(bp,"%d",cev);
- bp += strlen(bp);
- break;
---cut here---cut here---cut here---cca04@phsun3 (P.J. Mitchell) (12/19/90)
From article <4742@idunno.Princeton.EDU>, by pfalstad@phoenix.Princeton.EDU (Paul John Falstad): Is it just me or were the contents of the readline directory missing ? Ta. -- Paul Mitchell (CMA#136(18) MAG#65715 DoD#0145) | Computer Centre, JANET: p.j.mitchell@uk.ac.keele.seq1 | Keele University, Keele, USENET: p.j.mitchell@seq1.keele.ac.uk | Staffordshire, ST5 5BG, U.K. BITNET: p.j.mitchell%seq1.keele.ac.uk@ukacrl | (+44 or 0)782 621111 ext 3302