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