v29i097: zsh2.2 - The Z shell, Part01/17

26 views
Skip to first unread message

Paul Falstad

unread,
May 13, 1992, 11:52:04 AM5/13/92
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 29, Issue 97
Archive-name: zsh2.2/part01
Environment: BSD
Supersedes: zsh2.1: Volume 24, Issue 1-19

#!/bin/sh
# This is zsh2.2, a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 05/12/1992 04:14 UTC by pfalstad@phoenix
# Source directory /n/homeserver/g/pfalstad
#
# existing files will NOT be overwritten unless -c is specified
#
# This is part 1 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 2684 -rw-r--r-- zsh2.2/FEATURES
# 505 -rw-r--r-- zsh2.2/NOTES
# 17490 -rw-r--r-- zsh2.2/README
# 58603 -rw-r--r-- zsh2.2/doc/intro.txt
# 247 -rw-r--r-- zsh2.2/dots/zlogin
# 2291 -rw-r--r-- zsh2.2/dots/zshrc
# 123 -rw-r--r-- zsh2.2/dots/zshenv
# 104 -rwxr-xr-x zsh2.2/func/acx
# 109 -rwxr-xr-x zsh2.2/func/cx
# 97 -rwxr-xr-x zsh2.2/func/harden
# 84 -rwxr-xr-x zsh2.2/func/mere
# 412 -rwxr-xr-x zsh2.2/func/namedir
# 194 -rwxr-xr-x zsh2.2/func/proto
# 80 -rwxr-xr-x zsh2.2/func/randline
# 29 -rwxr-xr-x zsh2.2/func/yp
# 35 -rwxr-xr-x zsh2.2/func/yu
# 112852 -rw-r--r-- zsh2.2/man/man1/zsh.1
# 755 -rwxr-xr-x zsh2.2/scripts/aproto
# 173 -rwxr-xr-x zsh2.2/scripts/fproto
# 1137 -rw-r--r-- zsh2.2/scripts/ctoz
# 2958 -rw-r--r-- zsh2.2/scripts/fooz
# 3299 -rwxr-xr-x zsh2.2/scripts/c2z
# 2736 -rwxr-xr-x zsh2.2/scripts/c2z.orig
# 11626 -rwxr-xr-x zsh2.2/src/buildzsh
# 61945 -rw-r--r-- zsh2.2/src/builtin.c
# 4064 -rw-r--r-- zsh2.2/src/cond.c
# 35818 -rw-r--r-- zsh2.2/src/exec.c
# 1185 -rw-r--r-- zsh2.2/src/funcs.h
# 24554 -rw-r--r-- zsh2.2/src/glob.c
# 23511 -rw-r--r-- zsh2.2/src/hist.c
# 11807 -rw-r--r-- zsh2.2/src/init.c
# 16421 -rw-r--r-- zsh2.2/src/jobs.c
# 15554 -rw-r--r-- zsh2.2/src/lex.c
# 4752 -rw-r--r-- zsh2.2/src/loop.c
# 10185 -rw-r--r-- zsh2.2/src/math.c
# 4948 -rw-r--r-- zsh2.2/src/mem.c
# 24577 -rw-r--r-- zsh2.2/src/params.c
# 14912 -rw-r--r-- zsh2.2/src/subst.c
# 6810 -rw-r--r-- zsh2.2/src/table.c
# 8584 -rw-r--r-- zsh2.2/src/text.c
# 32116 -rw-r--r-- zsh2.2/src/utils.c
# 7149 -rw-r--r-- zsh2.2/src/watch.c
# 8371 -rw-r--r-- zsh2.2/src/zle.h
# 17212 -rw-r--r-- zsh2.2/src/zle_bindings.c
# 14597 -rw-r--r-- zsh2.2/src/zle_main.c
# 12058 -rw-r--r-- zsh2.2/src/zle_refresh.c
# 4690 -rw-r--r-- zsh2.2/src/zle_utils.c
# 31883 -rw-r--r-- zsh2.2/src/zsh.h
# 4793 -rw-r--r-- zsh2.2/src/zle_vi.c
# 1486 -rw-r--r-- zsh2.2/src/ztype.h
# 26002 -rw-r--r-- zsh2.2/src/zle_tricky.c
# 4239 -rw-r--r-- zsh2.2/src/builtin.pro
# 235 -rw-r--r-- zsh2.2/src/cond.pro
# 2306 -rw-r--r-- zsh2.2/src/exec.pro
# 1511 -rw-r--r-- zsh2.2/src/glob.pro
# 1989 -rw-r--r-- zsh2.2/src/hist.pro
# 395 -rw-r--r-- zsh2.2/src/init.pro
# 892 -rw-r--r-- zsh2.2/src/jobs.pro
# 309 -rw-r--r-- zsh2.2/src/lex.pro
# 206 -rw-r--r-- zsh2.2/src/loop.pro
# 291 -rw-r--r-- zsh2.2/src/math.pro
# 510 -rw-r--r-- zsh2.2/src/mem.pro
# 3478 -rw-r--r-- zsh2.2/src/params.pro
# 619 -rw-r--r-- zsh2.2/src/subst.pro
# 941 -rw-r--r-- zsh2.2/src/table.pro
# 371 -rw-r--r-- zsh2.2/src/text.pro
# 3277 -rw-r--r-- zsh2.2/src/utils.pro
# 371 -rw-r--r-- zsh2.2/src/watch.pro
# 0 -rw-r--r-- zsh2.2/src/zle_bindings.pro
# 686 -rw-r--r-- zsh2.2/src/zle_main.pro
# 596 -rw-r--r-- zsh2.2/src/zle_refresh.pro
# 761 -rw-r--r-- zsh2.2/src/zle_vi.pro
# 1036 -rw-r--r-- zsh2.2/src/parse.pro
# 1817 -rw-r--r-- zsh2.2/src/zle_tricky.pro
# 18760 -rw-r--r-- zsh2.2/src/parse.c
# 684 -rw-r--r-- zsh2.2/src/zle_utils.pro
# 1429 -rw-r--r-- zsh2.2/src/signals.h.sample
# 5181 -rw-r--r-- zsh2.2/src/zle_move.c
# 14519 -rw-r--r-- zsh2.2/src/zle_misc.c
# 6019 -rw-r--r-- zsh2.2/src/zle_word.c
# 10080 -rw-r--r-- zsh2.2/src/zle_hist.c
# 1119 -rw-r--r-- zsh2.2/src/zle_hist.pro
# 1478 -rw-r--r-- zsh2.2/src/zle_misc.pro
# 909 -rw-r--r-- zsh2.2/src/zle_move.pro
# 733 -rw-r--r-- zsh2.2/src/zle_word.pro
# 2607 -rw-r--r-- zsh2.2/src/config.h
# 1322 -rw-r--r-- zsh2.2/src/signals.h
# 921 -rw-r--r-- zsh2.2/src/Makefile
#
if test -r _shar_seq_.tmp; then
echo 'Must unpack archives in sequence!'
echo Please unpack part `cat _shar_seq_.tmp` next
exit 1
fi
# ============= zsh2.2/FEATURES ==============
if test ! -d 'zsh2.2'; then
echo 'x - creating directory zsh2.2'
mkdir 'zsh2.2'
fi
if test -f 'zsh2.2/FEATURES' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/FEATURES (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.2/FEATURES (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/FEATURES' &&
Xvery close to ksh/sh grammar, with csh additions
Xmost features of ksh, bash, and tcsh
X75 builtins, 73 options, 144 key bindings
Xshort for loops, ex: for i (*.c) echo $i
Xselect
Xshell functions
Xconditional expressions (test builtin, [ ... ], and ksh-style [[ ... ]])
Xglobal aliases (may be expanded anywhere on the line)
Xdirectory stack access with =num
Xprocess substitution (vi =(cmd) edits the output of cmd)
Xgeneralized pipes (ls foo >>(cmd1) 2>>(cmd2) pipes stdout to cmd1
X and stderr to cmd2)
Xarithmetic expressions
Xadvanced globbing:
X ls **/file searches recursively for "file" in subdirectories
X ls file<20-> matches file20, file30, file100, etc.
X ls *.(c|pro) matches *.c and *.pro
X ls *(R) matches only world-readable files
X ls *.c~lex.c matches all .c files except lex.c
Xnull command shorthands:
X "< file" is same as "more <file"
X "> file" is same as "cat >file"
X ">> file" is same as "cat >>file"
Xksh-style coprocesses
Xautomatic file stream teeing (ls >foo >bar puts output in two places)
Xchpwd() function run every time you change directory (useful for
X updating the status line)
Xjob control
Xcsh-style history
Xfull vi line editing, including "c2w" and "y$" and such things
Xfull emacs line editing
Xincremental history search
Xmagic-space history
Xspelling correction
Xarray parameters
X$HOSTTYPE, $LINENO, $RANDOM, $SECONDS, $cdpath, $COLUMNS, $fignore,
X $HISTCHARS, $mailpath
Xwith autocd option, typing a directory name by itself is the same as
X typing "cd dirname"
Xmenu completion: pressing TAB repeatedly cycles through the possible matches
Xincremental path hashing
Xautomatic process time reporting for commands that run over a certain limit
Xfull tcsh-style prompt substitution
Xutmp login/logout reporting
Xwith histverify option, performing csh-style history expansions causes the
X input line to be brought up for editing instead of being executed
Xwith sunkeyboardhack option, accidently typed trailing ` characters
X are removed from the input line (for those of you with Sun keyboards :-) )
Xautoloaded functions (loaded from a file when they are first referenced)
X"cd old new" replaces "old" with "new" in directory string
Xgeneralized argument completion, including:
X - command name completion
X - filename and path completion
X - hostname completion
X - key binding completion
X - option completion
X - variable name completion
X - user-specified keyword completion
Xprompt on right side of screen
Xdirectory stacks
Xhistory datestamps and execution time records
Xcommand scheduling (like at(1), but in the shell's context)
Xtty mode freezing
Xup to 9 startup files (but you only need 1 or 2)
X8-bit clean
Xwhich -a cmd lists all occurences of "cmd" in the path
SHAR_EOF
chmod 0644 zsh2.2/FEATURES ||
echo 'restore of zsh2.2/FEATURES failed'
Wc_c="`wc -c < 'zsh2.2/FEATURES'`"
test 2684 -eq "$Wc_c" ||
echo 'zsh2.2/FEATURES: original size 2684, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/NOTES ==============
if test -f 'zsh2.2/NOTES' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/NOTES (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.2/NOTES (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/NOTES' &&
XImportant notes:
X
X1. Stuff like "ls *.sdofij 2>/dev/null" to suppress error messages
X produced by the shell don't work anymore. Filename generation is
X done BEFORE redirection. To avoid the error message, use the
X nonomatch option, or do "( ls *.sdofij ) 2>/dev/null".
X
X2. History substitution is no longer done inside startup files. If you
X have sequences like \! or !" in your startup files, they will break.
X (Especially !"). So check for those; remove the !", and change the
X \! to !.
SHAR_EOF
chmod 0644 zsh2.2/NOTES ||
echo 'restore of zsh2.2/NOTES failed'
Wc_c="`wc -c < 'zsh2.2/NOTES'`"
test 505 -eq "$Wc_c" ||
echo 'zsh2.2/NOTES: original size 505, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/README ==============
if test -f 'zsh2.2/README' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/README (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.2/README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/README' &&
XYou have permission to copy the zsh distribution in whole or in part
Xas long as you don't try to make money off of it, or pretend that you
Xwrote it.
X
XThis is zsh 2.2.0.
X
XTo get this shell running, cd into the src directory and type
X"buildzsh". I tested it on the following machines, where it compiled
Xjust by running this script:
X
XSun SPARCServer 4/690 running SunOS 4.1.2
XNeXTstation running Mach 2.0
XDECStation-5000 running ULTRIX 4.2
XIris 4D/20 running IRIX 4.0.1
XHP 9000/834 running HP-UX 7.00
XIBM RS6000 running AIX 3.2
X(rumored to work on a Pyramid)
X
XIn general, the more BSD-like your system, the more likely it will work.
X
XTabstops are 3 spaces. If you're going to look at my code, run it
Xthough "expand -3" first, or set your tab stops to the same as mine.
X
XThere is a zsh mailing list, "zsh-...@cs.uow.edu.au". To have yourself
Xadded to the list, send a request to "zsh-r...@cs.uow.edu.au".
X
XThe author can be reached via email to one of the following addresses:
X"pfal...@phoenix.princeton.edu", "pfal...@cs.ucsd.edu", "p...@ttisms.com",
X"p...@gnu.ai.mit.edu".
X
XThanks to the following people for help, ideas, accounts, comments,
Xpatches, etc.:
X
XCharles Hannum
XDavid Dobkin
XJim Mattson
XCarlos Carvalho
XBart Schaefer
XPeter Gray
XPure Software, Inc.
XChris P. Ross
XGary Oberbrunner
XJonathan Hardwick
XJohn Navarra
XMichael Lamoureux
XRick Lyons
XDuncan Sinclair
XMark R. Rubin
XJohn Guthrie
XJames Bonfield
XChris Moore
XThomas Winder
XDavid J. MacKenzie
XCharles Rendleman
XRichard Ohnemus
XNik Gervae
XGottfried Necker
XGoran Larsson
XPaul E. Maisano
XNorbert Kiesel
XJosh Diamond
XBill Miskovetz
XPeter Moore
XGeoff Wing
XKent Dickey
XJean-Jacques Moreau
XMichael Brown
XBruce Anderson
XStephen Dum
XLars E. Thon
XMichael Brennan
XXev Gittler
XJarkko Hietaniemi
XZbigniew J Tyrlik
XPierre Racz
XRick Ohnemus
XRichard Dean
XGary D. Kline
XRobert A. Fabian
XByron Rakitzis
XDan Bernstein
XJonathan Kamens
XVincent Granet
XDavid Wilson
XGreg Noel
XPaul Lew
XDan Esbensen
XKartik Subbarao
XRoss Bunker
XMichael Marucheck
XChristopher Pirazzi
XSteve Giovanetti
XKennedy Lemke
XEmin Gun Sirer
XKazuo Itoh
Xlots of other people, I'm sure
X
XModification history:
X
X2.2.0-2.1.0:
Xo should be faster in general
Xo fewer compilation warnings
Xo SPROMPT now uses %R instead of %s for the incorrect string
Xo no longer tries to create FIFOs on NeXTs (thereby causing a panic)
Xo now gets usernames from NIS on irises without crashing (SGI's getpwnam()
X called my strdup(), the pricks. Took me forever to find that. :-) )
Xo fewer 7-bit assumptions
Xo which/whence/type have new options:
X -a = all (find all occurences of command in path)
X -c = csh-style which (default for "which" command)
Xo error message for cd str1 str2 is fixed
Xo relative paths (including .) in cdpath now work
Xo exclusion patterns in glob: ls *.c~lex.c prints all .c files but lex.c
Xo bug with command substitution in chpwd fixed (buffers flushed twice)
Xo relative paths in $path now work
Xo "kill -9 -FOO" no longer kills shell
Xo new options to history/fc:
X -d = prints date commands were entered
X -D = prints running time of commands
Xo "history <num>" prints all commands SINCE <num> as well
Xo history stored differently - should be more efficient
Xo bg'ing a suspended zsh no longer causes problems
Xo "set" no longer prints ONLY exported params (duh)
Xo functions +t now allowed
Xo redirection is done AFTER filename generation
Xo print changes:
X o print -u# prints to fd #
X o print -p prints to coproc
X o -D and -P perform \ substitution first
X o print -0 changed to print -N
Xo read changes:
X o read -u# reads from fd #
X o read -p reads from coproc
X o read -z waits for input if nothing on buffer stack
X o no longer reads from fd 0 if shell is getting input from there
X o echo -n foo | read x now works
Xo getopts is now POSIX conformant
Xo compctl builtin added, replacing hostcmds, foocmds, etc. Controls
X completion of various commands in zle.
X format: compctl -options cmdnams ...
X options tell where to get possible matches from, and include:
X -c = command names
X -f = filenames
X -h = hostnames ($hosts)
X -o = options
X -v = vars
X -b = bindings
X -k name = elements of $name array
X Any number of these options may be used together.
X In addition, compctl -C -options will set the default completion
X names when in command position (by default -c), and compctl -D -options
X will set the default completion names used after unrecognized commands
X or after redirections (by default -f).
Xo foo && bar || fuu now works
Xo ttyctl builtin added
X ttyctl -f freezes the tty. no changes made to the tty settings by
X external programs will be honored when this command is in effect.
X ttyctl -u unfreezes the tty.
X typically, "ttyctl -f" would be used in a zlogin or zshrc script after
X "stty" has been called to set up the terminal.
Xo [[ -e file ]] is now equivalent to [[ -a file ]]
Xo [[ -h file ]] is now equivalent to [[ -L file ]]
Xo the path is now hashed incrementally.
X o if the HASHCMDS option is unset, path hashing is not done at all.
X o if the HASHCMDS option is set but HASHDIRS is unset, commands are placed
X in the hash table when first executed.
X o if the HASHCMDS and HASHDIRS options are both set, commands are placed
X in the hash table when first executed, along with all commands in
X the directory that command was found in (and all directories earlier
X in the path). This is the default situation.
Xo "for i (*.c) do /bin/echo $i ; done | more" no longer hangs
Xo coprocesses now work properly
Xo READNULLCMD is now used instead of NULLCMD for "< file"
Xo POSTEDIT is printed whenever the editor exits
Xo rm path/path/* is now reported by checkrmall()
Xo cmd >&- works
Xo cmd >>! file works
Xo time cmd no longer forks an extra process
Xo setopt printexitvalue ; echo `false` no longer prints anything
Xo here documents work inside eval, etc.
Xo $(...) works inside here documents
Xo "time" by itself prints the shell timings
Xo locals in precmd() or chpwd() work
Xo new glob qualifiers
X o pat(M) sets markdirs, pat(^M) unsets it
X o pat(N) sets nullglob, ...
X o pat(D) sets globdots, ...
Xo ls * only sorts numeric filenames specially if NUMERICGLOBSORT is set
Xo setopt braceccl lets "echo {a-zA-Z}" work
Xo new options: pushdignoredups nohistbeep overstrike
Xo ls **/file is now equivalent to ls ****/file
Xo !'s in history are now escaped when you return to them
Xo history substitution is not done in script files
Xo echo $(!-2) works
Xo histverify and correct 'e' no longer put the edit line in the history
Xo the :x, :q, and :gs modifiers work properly now
Xo zsh -c 'ls =(ls)' no longer hangs
Xo VSWTCH is now set to ^Z on the irises
Xo zsh & no longer causes havoc
Xo USERNAME and LOGNAME are kept separate
Xo $manpath has been added for easy access to the $MANPATH components
Xo zsh now realizes if it is running under emacs, and resigns itself to
X the fact rather than panicking
Xo SIGQUIT is ignored in the PRODUCTION version of zsh, and kills the shell
X in the DEBUG version, rather than vice versa.
Xo GLOBALZSHENV has been added, and GLOBALZPROFILE is sourced in the
X proper place
Xo "kill %" no longer causes the prompt to be printed 3 times if notify
X is set on a NeXT
Xo REPORTTIME has been added; if a job runs longer than this many seconds,
X timing statistics are reported
Xo timing statistics now include a job name (%J)
Xo no longer talks about SIGHUPed jobs if the kill failed
Xo no longer talks about running jobs which don't exist if you do eval exit
X or if you have notify unset
Xo foo=bar comman[tab], for/select/foreach i (*.c[tab] both work
Xo [base]num inside $[...] works
Xo foo=pat(n|ern) works
Xo cd - prints the new directory
Xo l[tab] works if l is an alias
Xo select foo ; ... works (in $argv is assumed)
Xo select reads from the right input
Xo math identifiers can now contain numbers and _'s.
Xo lots of serious memory heap trashing and leaks fixed
Xo echo $HOME[*] no longer crashes the shell
Xo SIGWINCH now changes LINES and COLUMNS in the environment
Xo typeset +r TTY; TTY=foo no longer causes problems
Xo ~ substitution is no longer done in FIGNORE
Xo assignment to SECONDS works
Xo "else if" is no longer a synonym for "elif" <thud>
Xo lots of problems with null lists in flow constructs fixed
Xo no correction done for >file
Xo echo ${foo%bar is no longer weird
Xo modifying array substitutions works
Xo ^O can be bound to something
Xo command substitution in signal handlers no longer causes problems
Xo spelling correction is better ($PAHT is corrected), and SPROMPT
X allows all the regular PROMPT escapes
Xo new prompt escape sequence: %D{...} formats ... part using strftime
Xo shell input no longer butchered using IFS
Xo vi cmd mode has 's' bound to visubstitute, as it should be
Xo you can use ^XS and ^XR in i-search mode
Xo bindings to ^Z and ^@ work now on the irises
Xo ^V{^S,^Q,^Z,etc} now works on sgttyb victims
Xo nopromptclobber changed to nopromptcr
Xo vi 'u' undo works a little better (?)
Xo ESC-key bindings aren't screwed up if VISUAL is set to vi
Xo newline in prompt now works reliably
Xo vi change and delete work with forward-word/search, etc.
Xo somewhat suboptimal screen refresh on irises fixed (several seconds
X per character inserted when TERM=xterm??)
Xo select list printing slightly different
Xo magic-space's handling of hatchars "fixed"
X
X0.03-1.0:
X - "..../" is now "****/". I know this isn't backward compatible,
X but I had no choice; the string "..../" was unquotable.
X - parser was rewritten and improved
X - completion was improved, several bugs fixed (including
X the "$([tab]" bug)
X - vi mode editing is improved
X - the value of PWD and OLDPWD in the environment now change
X - the PROMPT formatting strings %W and %D now print the month
X correctly
X - >&2 echo "error message" no longer prints "bad file number"
X - ${foo%pat} no longer alters the value of foo
X - $_ works
X - ALL_EXPORT no longer causes let statements to crash the shell
X - continue works
X - echo $MAIL no longer dumps core if MAIL is null
X - the new tty driver is selected by default
X - the s modifier no longer complains if it can't find the string
X to substitute
X - list-choices no longer fignores files
X - cd is now smarter about symlinks
X - negative subscripts other than -1 now work
X - $(<filename) works better if filename contains $, ~, or =
X - rehash no longer wastes memory
X - with name=value assignments, name is checked to see if it is
X a valid identifier
X - !1; !2 no longer eats the semicolon
X - $foo:h never returns the empty string if foo starts with /
X - select crashed with some compilers
X - problems with aliases in <(...) constructs have been fixed
X - links pointing to nowhere are denoted with an '&' in listtypes
X - negative arguments are supported
X - the shell does not screw around with the tty so much
X - lots of other stuff
X
X0.02-0.03:
X - two stupid bugs that were introduced in the last patch were fixed:
X - multiple command substitution on a line failed
X - a file descriptor leak caused the shell to crash after a while
X - added 'An Introduction to the Z Shell'
X - behaves properly when the tty session dies suddenly
X - had a serious memory leak on some systems
X - the test and [ builtins have been added, although [[...]]
X is more efficient
X - in your prompt, %m2 now prints foo.bar, %m3 prints foo.bar.com, etc.
X - the -D and -P options to print have been added
X - the NULLCMD and ZDOTDIR parameters have been added
X - ${*:-foo} works
X - "$@" and "$arr[@]" work like ksh
X - .zprofile is sourced before .zshrc in login shells
X - the CSHJUNKIEQUOTES and PUSHDMINUS options have been added
X - REAL_TTY compilation switch added
X - aliases beginning with a space cause the history line to be junked
X if HISTIGNORESPACE is set
X - echo prints bad options instead of complaining about them
X - "set -o" no longer dumps core
X - "alias a=alias; date >a" no longer creates a file called "alias"
X - "function foo() \n { date }" is now legal (the () and the newline
X are allowed)
X - nested brace expressions work properly
X - disabled commands stay disabled after a rehash (or after the shell
X finishes sourcing your .zshrc)
X - corrected aliases work
X - executables in the currect directory are now completed
X - in "case foo", "foo" is not interpreted as a directory name with autocd
X - aliases were not always interpreted properly after a completion
X - bindkey '^?' didn't work
X - echo ${HOST:-{bar}} didn't work
X - editor update is more efficient in some cases
X - menucomplete works even better
X - assign to an array element "foo[1]=bar" didn't always work
X - doesn't print directories like "~tmp" if HOME=/
X - quotes in case statement patterns caused problems
X - pressing ^C right after typing "fc" caused the editor to share
X the tty with the shell
X - echo $(echo 2) produced no output, but echo $(echo x) worked fine (weird)
X
X0.01-0.02:
X - added script to convert most csh aliases to zsh aliases or functions
X - fc -l (history) now appears in the history itself; HISTNOSTORE
X option added to get old behavior
X - the POSIX process group race has been fixed; so 'w | more' should
X no longer hang
X - FCEDIT added, to match the documentation
X - %{...%} in the prompt added
X - execute-named-cmd and execute-last-named-cmd bindings added
X - sources ~/.zshenv in all shells, even if not interactive, unless
X -f is given
X - ^ and # are no longer `magic' by default; use EXTENDEDGLOB option
X to use them
X - now checks for tty sanity before each command
X - if the right side of a variable assignment expands to more than
X one word, array assignment is assumed; so foo=*.c now works
X - ~foo is no longer expanded in completion
X - select now works even if the argument list is not sorted
X - menucompletebeep option added
X - emacs mode is now 8-bit clean by default; use bindkey -em
X to get your meta key back
X - fc -R, fc -W added
X - nocorrect added
X - lines from history file are now split into words at spaces
X - glob-complete, accept-and-menu-complete,
X beginning-of-line-hist, end-of-line-hist bindings added
X - insert-last-word bound to M-. in emacs mode by default; now moves
X back through the history if run repeatedly
X - J and K now bound to history search in vi mode
X - delete-char no longer core dumps on an empty line
X - menu-complete works better
X - the editor checks the settings of VISUAL and EDITOR to set
X default bindings
X - using [[ ... ]] expressions on a symbolic link works as expected
X - various problems with globbing were fixed
X - xx is now the same as !! if HISTCHARS=x
X - added config.h entry for compilers that don't know about void *
X - lexical analysis made more efficient
X - "if echo $? ; then : ; fi" no longer always prints 0
X - removed all enums, '\x7f's from code
X - in "case foo in bar) xxx ;; esac", foo and bar are no longer subject
X to command alias expansion
X - works on platforms where toupper('A') != 'A'
X - \e sequence added to echo
X - + options now work with set
X - AUTORESUME and AUTOCD work better
X - getopts works better (?)
X - spell checking works better
X - "let 2+3=" no longer crashes the shell
X - "foo=bar; echo ${=foo}" no longer crashes the shell
X - "zsh -c" or "zsh -o" no longer causes a core dump
X - "unset MAIL; echo $MAIL" no longer causes a core dump
X - "(xterm&xterm&)&" no longer causes a core dump
X - "echo $HOM[tab]" beeps instead of deleting "$HOM"
X - incremental history search works better
X - the pwd of a fg'd job is now printed _before_ resuming it
X - rv=`echo -n foo` no longer puts garbage in $rv
X - "=1/*" now works as expected
X - ^Z can now be bound to something
X - the STTY parameter and the builtin builtin are now documented
X - IFS=x; foo=`echo foo` no longer puts a newline in $foo
X - $status added for csh compatibility
X - arrays are automatically expanded if you say 'foo[1234]=x'
X - shell now ignores SIGQUIT (it was commented out before :-)
X - the times builtin works on systems where times() returns > 0
X - no longer hangs the terminal if you ^S before flow control
X is turned off
X - "date ; read foo" now works in interactive shells
X - <<-foo is now parsed as <<- foo, not << -foo
X - fixed various errors in the documentation
X
X0.00-0.01:
X - %M and %m now work as documented.
X - bad things no longer happen if COLUMNS is set to 0
X - SH_WORD_SPLIT and ${=foo} now work
X - the default value of WORDCHARS includes more characters
X - if the cursor is at the end of the line, vi-cmd-mode
X moves it back one position.
X - delete-char now acts more like x in vi.
X - a "prompt" parameter has been added, which is equivalent to
X PROMPT and PS1.
X - zsh no longer expands symbolic links. The CHASELINKS option
X has been provided to get the old behavior.
X - history searches ignore lines that are the same as the line
X in the buffer.
X - you can get a literal ! in your prompt now with \!.
X - -z, -n, and != in [[ ... ]] expressions work.
X - the shell no longer hangs when inputting "[[ ]\n"
X - the "menu-complete" and "menu-expand-or-complete" bindings have
X been added.
X - menu-complete no longer beeps.
X - reverse-menu-complete no longer dumps core if it gets called before
X a normal completion.
X - typeahead lines are no longer thrown away on machines with sgttyb.
X - !foo no longer matches lines with 'foo' in them (not at the beginning)
X - kill -9 % no longer kills the shell
X - no longer sources .zshrc from shell scripts or with -c
X - no longer needs limits.h, strtol
X - exporting HOSTTYPE, etc. works
X - fixed serious bugs related to . in path
X - numbers in weird bases now work
X
XKnown Bugs
X - terminal acts weird under OpenWindows cmdtool
X - xterm run in background inherits bad terminal modes
X
SHAR_EOF
chmod 0644 zsh2.2/README ||
echo 'restore of zsh2.2/README failed'
Wc_c="`wc -c < 'zsh2.2/README'`"
test 17490 -eq "$Wc_c" ||
echo 'zsh2.2/README: original size 17490, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/doc/intro.txt ==============
if test ! -d 'zsh2.2/doc'; then
echo 'x - creating directory zsh2.2/doc'
mkdir 'zsh2.2/doc'
fi
if test -f 'zsh2.2/doc/intro.txt' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/doc/intro.txt (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.2/doc/intro.txt (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/doc/intro.txt' &&
X
X
X
X
X
X
X An Introduction to the Z Shell
X
X
X Paul Falstad
X pfal...@phoenix.princeton.edu
X
X
X
X
X
X
Xzsh is a shell designed for interactive use, although it is
Xalso a powerful scripting language. Many of the useful
Xfeatures of bash, ksh, and tcsh were incorporated into zsh;
Xmany original features were added. This document details
Xsome of the unique features of zsh. It assumes basic
Xknowledge of the standard UNIX shells; the intent is to show
Xa reader already familiar with one of the other major shells
Xwhat makes zsh more useful or more powerful. This document
Xis not at all comprehensive; read the manual entry for a
Xdescription of the shell that is complete and concise,
Xalthough somewhat overwhelming and devoid of examples.
X
XFilename Generation
X
XOtherwise known as globbing, filename generation is quite
Xextensive in zsh. Of course, it has all the basics:
X
X% ls
XMakefile file.pro foo.o main.o q.c run234 stuff
Xbar.o foo link morestuff run123 run240 sub
Xfile.h foo.c main.h pipe run2 run303
X% ls *.c
Xfoo.c q.c
X% ls *.[co]
Xbar.o foo.c foo.o main.o q.c
X% ls foo.?
Xfoo.c foo.o
X% ls *.[^c]
Xbar.o file.h foo.o main.h main.o
X% ls *.[^oh]
Xfoo.c q.c
X
X
XAlso, if the EXTENDEDGLOB option is set, some new features
Xare activated. For example, the ^ character negates the
Xpattern following it:
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X - 2 -
X
X% setopt extendedglob
X% ls -d ^*.c
XMakefile file.pro link morestuff run2 run303
Xbar.o foo main.h pipe run234 stuff
Xfile.h foo.o main.o run123 run240 sub
X% ls -d ^*.*
XMakefile link pipe run2 run240 stuff
Xfoo morestuff run123 run234 run303 sub
X% ls -d ^Makefile
Xbar.o foo link morestuff run123 run240 sub
Xfile.h foo.c main.h pipe run2 run303
Xfile.pro foo.o main.o q.c run234 stuff
X% ls -d *.^c
X.rhosts bar.o file.h file.pro foo.o main.h main.o
X
X
XAn expression of the form <x-y> matches a range of integers:
X
X% ls run<200-300>
Xrun234 run240
X% ls run<300-400>
Xrun303
X% ls run<-200>
Xrun123 run2
X% ls run<300->
Xrun303
X% ls run<>
Xrun123 run2 run234 run240 run303
X
X
XGrouping is possible:
X
X% ls (foo|bar).*
Xbar.o foo.c foo.o
X% ls *.(c|o|pro)
Xbar.o file.pro foo.c foo.o main.o q.c
X
X
XAlso, the string ****/ forces a recursive search of sub-
Xdirectories:
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X - 3 -
X
X% ls -R
XMakefile file.pro foo.o main.o q.c run234 stuff
Xbar.o foo link morestuff run123 run240 sub
Xfile.h foo.c main.h pipe run2 run303
X
Xmorestuff:
X
Xstuff:
Xfile xxx yyy
X
Xstuff/xxx:
Xfoobar
X
Xstuff/yyy:
Xfrobar
X% ls ****/*bar
Xstuff/xxx/foobar stuff/yyy/frobar
X% ls ****/f*
Xfile.h foo foo.o stuff/xxx/foobar
Xfile.pro foo.c stuff/file stuff/yyy/frobar
X% ls *bar*
Xbar.o
X% ls ****/*bar*
Xbar.o stuff/xxx/foobar stuff/yyy/frobar
X% ls stuff/****/*bar*
Xstuff/xxx/foobar stuff/yyy/frobar
X
X
X
XIt is possible to exclude certain files from the patterns
Xusing the ~ character. A pattern of the form *.c~bar.c
Xlists all files matching *.c, except for the file bar.c.
X
X% ls *.c
Xfoo.c foob.c bar.c
X% ls *.c~bar.c
Xfoo.c foob.c
X% ls *.c~f*
Xbar.c
X
X
X
XOne can add a number of qualifiers to the end of any of
Xthese patterns, to restrict matches to certain file types.
XA qualified pattern is of the form
X
X pattern(...)
X
X
Xwith single-letter qualifiers inside the parentheses.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X - 4 -
X
X% alias l='ls -dF'
X% l *
XMakefile foo* main.h q.c run240
Xbar.o foo.c main.o run123 run303
Xfile.h foo.o morestuff/ run2 stuff/
Xfile.pro link@ pipe run234 sub
X% l *(/)
Xmorestuff/ stuff/
X% l *(@)
Xlink@
X% l *(*)
Xfoo* link@ morestuff/ stuff/
X% l *(x)
Xfoo* link@ morestuff/ stuff/
X% l *(X)
Xfoo* link@ morestuff/ stuff/
X% l *(R)
Xbar.o foo* link@ morestuff/ run123 run240
Xfile.h foo.c main.h pipe run2 run303
Xfile.pro foo.o main.o q.c run234 stuff/
X
X
XNote that *(x) and *(*) both match executables. *(X)
Xmatches files executable by others, as opposed to *(x),
Xwhich matches files executable by the owner. *(R) and *(r)
Xmatch readable files; *(W) and *(w), which checks for writ-
Xable files. *(W) is especially important, since it checks
Xfor world-writable files:
X
X% l *(w)
Xbar.o foo* link@ morestuff/ run123 run240
Xfile.h foo.c main.h pipe run2 run303
Xfile.pro foo.o main.o q.c run234 stuff/
X% l *(W)
Xlink@ run240
X% l -l link run240
Xlrwxrwxrwx 1 pfalstad 10 May 23 18:12 link -> /bin/false*
X-rw-rw-rw- 1 pfalstad 0 May 23 18:12 run240
X
X
XYou can filter out the symbolic links with the ^ character:
X
X% l *(W^@)
Xrun240
X% l *(x)
Xfoo* link@ morestuff/ stuff/
X% l *(x^@/)
Xfoo*
X
X
XTo find all plain files, you can use .:
X
X
X
X
X
X
X
X
X
X
X
X
X
X - 5 -
X
X% l *(.)
XMakefile file.h foo* foo.o main.o run123 run234 run303
Xbar.o file.pro foo.c main.h q.c run2 run240 sub
X% l *(^.)
Xlink@ morestuff/ pipe stuff/
X% l s*(.)
Xstuff/ sub
X% l *(p)
Xpipe
X% l -l *(p)
Xprw-r--r-- 1 pfalstad 0 May 23 18:12 pipe
X
X
X*(U) matches all files owned by you. To search for all
Xfiles not owned by you, use *(^U):
X
X% l -l *(^U)
X-rw------- 1 subbarao 29 May 23 18:13 sub
X
X
XThis searches for setuid files:
X
X% l -l *(s)
X-rwsr-xr-x 1 pfalstad 16 May 23 18:12 foo*
X
X
XThis checks for a certain user's files:
X
X% ypmatch subbarao passwd
Xsubbarao:*:3338:35:Kartik Subbarao:/u/subbarao:/usr/princeton/bin/zsh
X% l -l *(u3338)
X-rw------- 1 subbarao 29 May 23 18:13 sub
X
X
X
XStartup Files
X
XThere are five startup files that zsh will read commands
Xfrom:
X
X$ZDOTDIR/.zshenv
X$ZDOTDIR/.zprofile
X$ZDOTDIR/.zshrc
X$ZDOTDIR/.zlogin
X$ZDOTDIR/.zlogout
X
X
XIf ZDOTDIR is not set, then the value of HOME is used; this
Xis the usual case.
X
X.zshenv is sourced on all invocations of the shell, unless
Xthe -f option is set. It should contain commands to set the
Xcommand search path, plus other important environment vari-
Xables. .zshenv should not contain commands that produce
Xoutput or assume the shell is attached to a tty.
X
X.zshrc is sourced in interactive shells. It should contain
Xcommands to set up aliases, functions, options, key bind-
Xings, etc.
X
X
X
X
X
X - 6 -
X.zlogin is sourced in login shells. It should contain com-
Xmands that should be executed only in login shells. .zlo-
Xgout is sourced when login shells exit. .zprofile is simi-
Xlar to .zlogin, except that it is sourced before .zshrc.
X.zprofile is meant as an alternative to .zlogin for ksh
Xfans; the two are not intended to be used together, although
Xthis could certainly be done if desired. .zlogin is not the
Xplace for alias definitions, options, environment variable
Xsettings, etc.; as a general rule, it should not change the
Xshell environment at all. Rather, it should be used to set
Xthe terminal type and run a series of external commands
X(fortune, msgs, etc).
X
XShell Functions
X
Xzsh also allows you to create your own commands by defining
Xshell functions. For example:
X
X% yp () {
X> ypmatch $1 passwd.byname
X> }
X% yp pfalstad
Xpfalstad:*:3564:35:Paul John Falstad:/u/pfalstad:/usr/princeton/bin/zsh
X
X
XThis function looks up a user in the NIS password map. The
X$1 expands to the first argument to yp. The function could
Xhave been equivalently defined in one of the following ways:
X
X% function yp {
X> ypmatch $1 passwd.byname
X> }
X% function yp () {
X> ypmatch $1 passwd.byname
X> }
X% function yp () ypmatch $1 passwd.byname
X
X
XNote that aliases are expanded when the function definition
Xis parsed, not when the function is executed. For example:
X
X% alias ypmatch=echo
X% yp pfalstad
Xpfalstad:*:3564:35:Paul John Falstad:/u/pfalstad:/usr/princeton/bin/zsh
X
X
XSince the alias was defined after the function was parsed,
Xit has no effect on the function's execution. However, if
Xwe define the function again with the alias in place:
X
X% function yp () { ypmatch $1 passwd.byname }
X% yp pfalstad
Xpfalstad passwd.byname
X
X
Xit is parsed with the new alias definition in place. There-
Xfore, in general you must define aliases before functions.
X
XWe can make the function take multiple arguments:
X
X
X
X
X
X
X - 7 -
X
X% unalias ypmatch
X% yp () {
X> for i
X> do ypmatch $i passwd.byname
X> done
X> }
X% yp pfalstad subbarao sukthnkr
Xpfalstad:*:3564:35:Paul John Falstad:/u/pfalstad:/usr/princeton/bin/zsh
Xsubbarao:*:3338:35:Kartik Subbarao:/u/subbarao:/usr/princeton/bin/zsh
Xsukthnkr:*:1267:35:Rahul Sukthankar:/u/sukthnkr:/usr/princeton/bin/tcsh
X
X
XThe for i loops through each of the function's arguments,
Xsetting i equal to each of them in turn. We can also make
Xthe function do something sensible if no arguments are
Xgiven:
X
X% yp () {
X> if (( $# == 0 ))
X> then echo usage: yp name ...; fi
X> for i; do ypmatch $i passwd.byname; done
X> }
X% yp
Xusage: yp name ...
X% yp pfalstad sukthnkr
Xpfalstad:*:3564:35:Paul John Falstad:/u/pfalstad:/usr/princeton/bin/zsh
Xsukthnkr:*:1267:35:Rahul Sukthankar:/u/sukthnkr:/usr/princeton/bin/tcsh
X
X
X$# is the number of arguments supplied to the function. If
Xit is equal to zero, we print a usage message; otherwise, we
Xloop through the arguments, and ypmatch all of them.
X
XHere's a function that selects a random line from a file:
X
X% randline () {
X> integer z=$(wc -l <$1)
X> sed -n $[RANDOM % z + 1]p $1
X> }
X% randline /etc/motd
XPHOENIX WILL BE DOWN briefly Friday morning, 5/24/91 from 8 AM to
X% randline /etc/motd
XSunOS Release 4.1.1 (PHOENIX) #19: Tue May 14 19:03:15 EDT 1991
X% randline /etc/motd
X| Please use the "msgs" command to read announcements. Refer to the |
X% echo $z
X
X%
X
X
Xrandline has a local variable, z, that holds the number of
Xlines in the file. $[RANDOM % z + 1] expands to a random
Xnumber between 1 and z. An expression of the form $[...]
Xexpands to the value of the arithmetic expression within the
Xbrackets, and the RANDOM variable returns a random number
Xeach time it is referenced. % is the modulus operator, as
Xin C. Therefore, sed -n $[RANDOM%z+1]p picks a random line
Xfrom its input, from 1 to z.
X
X
X
X
X
X
X - 8 -
XFunction definitions can be viewed with the functions buil-
Xtin:
X
X% functions randline
Xrandline () {
X integer z=$(wc -l <$1)
X sed -n $[RANDOM % z + 1]p $1
X
X}
X% functions
Xyp () {
X if let $# == 0
X
X then
X echo usage: yp name ...
X
X fi
X for i
X do
X ypmatch $i passwd.byname
X
X done
X
X}
Xrandline () {
X integer z=$(wc -l <$1)
X sed -n $[RANDOM % z + 1]p $1
X
X}
X
X
XHere's another one:
X
X% cx () { chmod +x $* }
X% ls -l foo bar
X-rw-r--r-- 1 pfalstad 29 May 24 04:38 bar
X-rw-r--r-- 1 pfalstad 29 May 24 04:38 foo
X% cx foo bar
X% ls -l foo bar
X-rwxr-xr-x 1 pfalstad 29 May 24 04:38 bar
X-rwxr-xr-x 1 pfalstad 29 May 24 04:38 foo
X
X
XNote that this could also have been implemented as an alias:
X
X% chmod 644 foo bar
X% alias cx='chmod +x'
X% cx foo bar
X% ls -l foo bar
X-rwxr-xr-x 1 pfalstad 29 May 24 04:38 bar
X-rwxr-xr-x 1 pfalstad 29 May 24 04:38 foo
X
X
X
XInstead of defining a lot of functions in your .zshrc, all
Xof which you may not use, it is often better to use the
Xautoload builtin. The idea is, you create a directory where
Xfunction definitions are stored, declare the names in your
X.zshrc, and tell the shell where to look for them. Whenever
Xyou reference a function, the shell will automatically load
X
X
X
X
X
X - 9 -
Xit into memory.
X
X% mkdir /tmp/funs
X% cat >/tmp/funs/yp
Xypmatch $1 passwd.byname
X^D
X% cat >/tmp/funs/cx
Xchmod +x $*
X^D
X% FPATH=/tmp/funs
X% autoload cx yp
X% functions cx yp
Xundefined cx ()
Xundefined yp ()
X% chmod 755 /tmp/funs/{cx,yp}
X% yp egsirer
Xegsirer:*:3214:35:Emin Gun Sirer:/u/egsirer:/bin/sh
X% functions yp
Xyp () {
X ypmatch $1 passwd.byname
X}
X
X
XThis idea has other benefits. By adding a #! header to the
Xfiles, you can make them double as shell scripts. (Although
Xit is faster to use them as functions, since a separate pro-
Xcess is not created.)
X
X% ed /tmp/funs/yp
X25
Xi
X#! /usr/local/bin/zsh
Xw
X42
Xq
X% </tmp/funs/yp
X#! /usr/local/bin/zsh
Xypmatch $1 passwd.byname
X% /tmp/funs/yp sukthnkr
Xsukthnkr:*:1267:35:Rahul Sukthankar:/u/sukthnkr:/usr/princeton/bin/tcsh
X
X
XNow other people, who may not use zsh, or who don't want to
Xcopy all of your .zshrc, may use these functions as shell
Xscripts.
X
XDirectories
X
XOne nice feature of zsh is the way it prints directories.
XFor example, if we set the prompt like this:
X
Xphoenix% PROMPT='%~> '
X~> cd src
X~/src>
X
X
Xthe shell will print the current directory in the prompt,
Xusing the ~ character. However, zsh is smarter than most
Xother shells in this respect:
X
X
X
X
X
X
X - 10 -
X
X~/src> cd ~subbarao
X~subbarao> cd ~maruchck
X~maruchck> cd lib
X~maruchck/lib> cd fun
X~maruchck/lib/fun> foo=/usr/princeton/common/src
X~maruchck/lib/fun> cd ~foo
X~foo> cd ..
X/usr/princeton/common> cd src
X~foo> cd news/nntp
X~foo/news/nntp> cd inews
X~foo/news/nntp/inews>
X
X
XNote that zsh prints other users' directories in the form
X~user. Also note that you can set a parameter and use it as
Xa directory name; zsh will act as if foo is a user with the
Xlogin directory /usr/princeton/common/src. This is con-
Xvenient, especially if you're sick of seeing prompts like
Xthis:
X
Xphoenix:/usr/princeton/common/src/X.V11R4/contrib/clients/xv/docs>
X
X
XIf you get stuck in this position, you can give the current
Xdirectory a short name, like this:
X
X/usr/princeton/common/src/news/nntp/inews> inews=$PWD
X/usr/princeton/common/src/news/nntp/inews> echo ~inews
X/usr/princeton/common/src/news/nntp/inews
X~inews>
X
X
XWhen you reference a directory in the form ~inews, the shell
Xassumes that you want the directory displayed in this form;
Xthus simply typing echo ~inews or cd ~inews causes the
Xprompt to be shortened. You can define a shell function for
Xthis purpose:
X
X~inews> namedir () { $1=$PWD ; : ~$1 }
X~inews> cd /usr/princeton/bin
X/usr/princeton/bin> namedir pbin
X~pbin> cd /var/spool/mail
X/var/spool/mail> namedir spool
X~spool> cd .msgs
X~spool/.msgs>
X
X
XYou may want to add this one-line function to your .zshrc.
X
Xzsh can also put the current directory in your title bar, if
Xyou are using a windowing system. One way to do this is
Xwith the chpwd function, which is automatically executed by
Xthe shell whenever you change directory. If you are using
Xxterm, this will work:
X
Xchpwd () { print -Pn '^[]2;%~^G' }
X
X
XThe -P option tells print to treat its arguments like a
X
X
X
X
X
X - 11 -
Xprompt string; otherwise the %~ would not be expanded. The
X-n option suppresses the terminating newline, as with echo.
X
XIf you are using an IRIS wsh, do this:
X
Xchpwd () { print -Pn '^[P1.y%~^[' }
X
X
XThe print -D command has other uses. For example, to print
Xthe current directory to standard output in short form, you
Xcan do this:
X
X% print -D $PWD
X~subbarao/src
X
X
Xand to print each component of the path in short form:
X
X% print -D $path
X/bin /usr/bin ~locbin ~locbin/X11 ~/bin
X
X
X
XDirectory Stacks
X
XIf you use csh, you may know about directory stacks. The
Xpushd command puts the current directory on the stack, and
Xchanges to a new directory; the popd command pops a direc-
Xtory off the stack and changes to it.
X
Xphoenix% cd
Xphoenix% PROMPT='Z %~> '
XZ ~> pushd /tmp
X/tmp ~
XZ /tmp> pushd /usr/etc
X/usr/etc /tmp ~
XZ /usr/etc> pushd /usr/bin
X/usr/bin /usr/etc /tmp ~
XZ /usr/bin> popd
X/usr/etc /tmp ~
XZ /usr/etc> popd
X/tmp ~
XZ /tmp> pushd /etc
X/etc /tmp ~
XZ /etc> popd
X/tmp ~
X
X
Xzsh's directory stack commands work similarly. One differ-
Xence is the way pushd is handled if no arguments are given.
XAs in csh, this exchanges the top two elements of the direc-
Xtory stack:
X
XZ /tmp> dirs
X/tmp ~
XZ /tmp> pushd
X~ /tmp
X
X
Xunless the stack only has one entry:
X
X
X
X
X
X - 12 -
X
XZ ~> popd
X/tmp
XZ /tmp> dirs
X/tmp
XZ /tmp> pushd
X~ /tmp
X
X
Xor unless the PUSHDTOHOME option is set:
X
XZ ~> setopt pushdtohome
XZ ~> pushd
X~ ~ /tmp
X
X
X
XAs an alternative to using directory stacks in this manner,
Xwe can get something like a directory history by setting a
Xfew more options and parameters:
X
X~> DIRSTACKSIZE=8
X~> setopt autopushd pushdminus pushdsilent pushdtohome
X~> alias dh='dirs -v'
X~> cd /tmp
X/tmp> cd /usr
X/usr> cd bin
X/usr/bin> cd ../pub
X/usr/pub> dh
X0 /usr/pub
X1 /usr/bin
X2 /usr
X3 /tmp
X4 ~
X/usr/pub> cd -3
X/tmp> dh
X0 /tmp
X1 /usr/pub
X2 /usr/bin
X3 /usr
X4 ~
X/tmp> ls =2/df
X/usr/bin/df
X/tmp> cd -4
X~>
X
X
XNote that =2 expanded to the second directory in the history
Xlist, and that cd -3 recalled the third directory in the
Xlist.
X
XYou may be wondering what all those options do. AUTOPUSHD
Xmade cd act like pushd. (alias cd=pushd is not sufficient,
Xfor various reasons.) PUSHDMINUS swapped the meaning of cd
X+1 and cd -1; we want them to mean the opposite of what they
Xmean in csh, because it makes more sense in this scheme, and
Xit's easier to type:
X
X
X
X
X
X
X
X
X - 13 -
X
X~> dh
X0 ~
X1 /tmp
X2 /usr/pub
X3 /usr/bin
X4 /usr
X~> unsetopt pushdminus
X~> cd +1
X/tmp> dh
X0 /tmp
X1 ~
X2 /usr/pub
X3 /usr/bin
X4 /usr
X/tmp> cd +2
X/usr/pub>
X
X
XPUSHDSILENT keeps the shell from printing the directory
Xstack each time we do a cd, and PUSHDTOHOME we mentioned
Xearlier:
X
X/usr/pub> unsetopt pushdsilent
X/usr/pub> cd /etc
X/etc /usr/pub /tmp ~ /usr/bin /usr
X/etc> cd
X~ /etc /usr/pub /tmp ~ /usr/bin /usr
X~> unsetopt pushdtohome
X~> cd
X/etc ~ /usr/pub /tmp ~ /usr/bin /usr
X/etc>
X
X
XDIRSTACKSIZE keeps the directory stack from getting too
Xlarge, much like HISTSIZE:
X
X/etc> setopt pushdsilent
X/etc> cd /
X/> cd /
X/> cd /
X/> cd /
X/> cd /
X/> cd /
X/> cd /
X/> cd /
X/> dh
X0 /
X1 /
X2 /
X3 /
X4 /
X5 /
X6 /
X7 /
X
X
X
X
X
X
X
X
X
X
X - 14 -
XCommand/Process Substitution
X
XCommand substitution in zsh can take two forms. In the
Xtraditional form, a command enclosed in backquotes (`...`)
Xis replaced on the command line with its output. This is
Xthe form used by the older shells. Newer shells (like zsh)
Xalso provide another form, $(...). This form is much easier
Xto nest.
X
X% ls -l `echo /vmunix`
X-rwxr-xr-x 1 root 1209702 May 14 19:04 /vmunix
X% ls -l $(echo /vmunix)
X-rwxr-xr-x 1 root 1209702 May 14 19:04 /vmunix
X% who | grep mad
Xsubbarao ttyt7 May 23 15:02 (mad55sx15.Prince)
Xpfalstad ttyu1 May 23 16:25 (mad55sx14.Prince)
Xsubbarao ttyu6 May 23 15:04 (mad55sx15.Prince)
Xpfalstad ttyv3 May 23 16:25 (mad55sx14.Prince)
X% who | grep mad | awk '{print $2}'
Xttyt7
Xttyu1
Xttyu6
Xttyv3
X% cd /dev; ls -l $(who |
X> grep $(echo mad) |
X> awk '{ print $2 }')
Xcrwx-w---- 1 subbarao 20, 71 May 23 18:35 ttyt7
Xcrw--w---- 1 pfalstad 20, 81 May 23 18:42 ttyu1
Xcrwx-w---- 1 subbarao 20, 86 May 23 18:38 ttyu6
Xcrw--w---- 1 pfalstad 20, 99 May 23 18:41 ttyv3
X
X
XMany common uses of command substitution, however, are
Xsuperseded by other mechanisms of zsh:
X
X% ls -l `tty`
Xcrw-rw-rw- 1 root 20, 28 May 23 18:35 /dev/ttyqc
X% ls -l $TTY
Xcrw-rw-rw- 1 root 20, 28 May 23 18:35 /dev/ttyqc
X% ls -l `which rn`
X-rwxr-xr-x 1 root 172032 Mar 6 18:40 /usr/princeton/bin/rn
X% ls -l =rn
X-rwxr-xr-x 1 root 172032 Mar 6 18:40 /usr/princeton/bin/rn
X
X
XA command name with a = prepended is replaced with its full
Xpathname. This can be very convenient. If it's not con-
Xvenient for you, you can turn it off:
X
X% ls
X=foo =bar
X% ls =foo =bar
Xzsh: foo not found
X% setopt noequals
X% ls =foo =bar
X=foo =bar
X
X
X
XAnother nice feature is process substitution:
X
X
X
X
X
X - 15 -
X
X% who | fgrep -f =(print -l root lemke shgchan subbarao)
Xroot console May 19 10:41
Xlemke ttyq0 May 22 10:05 (narnia:0.0)
Xlemke ttyr7 May 22 10:05 (narnia:0.0)
Xlemke ttyrd May 22 10:05 (narnia:0.0)
Xshgchan ttys1 May 23 16:52 (gaudi.Princeton.)
Xsubbarao ttyt7 May 23 15:02 (mad55sx15.Prince)
Xsubbarao ttyu6 May 23 15:04 (mad55sx15.Prince)
Xshgchan ttyvb May 23 16:51 (gaudi.Princeton.)
X
X
XA command of the form =(...) is replaced with the name of a
Xfile containing its output. (A command substitution, on the
SHAR_EOF
true || echo 'restore of zsh2.2/doc/intro.txt failed'
fi
echo 'End of zsh2.2 part 1'
echo 'File zsh2.2/doc/intro.txt is continued in part 2'
echo 2 > _shar_seq_.tmp
exit 0

exit 0 # Just in case...

Paul Falstad

unread,
May 13, 1992, 11:53:28 AM5/13/92
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 29, Issue 98
Archive-name: zsh2.2/part02

Environment: BSD
Supersedes: zsh2.1: Volume 24, Issue 1-19

#!/bin/sh
# this is aa.02 (part 2 of zsh2.2)


# do not concatenate these parts, unpack them in order with /bin/sh

# file zsh2.2/doc/intro.txt continued
#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck
if test "$Scheck" != 2; then
echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping zsh2.2/doc/intro.txt'
else
echo 'x - continuing file zsh2.2/doc/intro.txt'


sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.2/doc/intro.txt' &&

Xother hand, is replaced with the output itself.) print -l is
Xlike echo, excepts that it prints its arguments one per
Xline, the way fgrep expects them:
X
X% print -l foo bar
Xfoo
Xbar
X
X
XWe could also have written:
X
X% who | fgrep -f =(echo 'root
X> lemke
X> shgchan
X> subbarao')
X
X
XUsing process substitution, you can edit the output of a
Xcommand:
X
X% ed =(who | fgrep -f ~/.friends)
X355
Xg/lemke/d
Xw /tmp/filbar
X226
Xq
X% cat /tmp/filbar


Xroot console May 19 10:41

Xshgchan ttys1 May 23 16:52 (gaudi.Princeton.)
Xsubbarao ttyt7 May 23 15:02 (mad55sx15.Prince)
Xsubbarao ttyu6 May 23 15:04 (mad55sx15.Prince)
Xshgchan ttyvb May 23 16:51 (gaudi.Princeton.)
X
X

Xor easily read archived mail:


X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X

X - 16 -
X
X% mail -f =(zcat ~/mail/oldzshmail.Z)
X"/tmp/zsha06024": 84 messages, 0 new, 43 unread
X> 1 U TO: pfalstad, zsh (10)
X 2 U nytim!t...@uunet.uu.net, Re: Zsh on Sparc1 /SunOS 4.0.3
X 3 U JAM%T...@utrcgw.utc.com, zsh fix (15)
X 4 U d...@eng.umd.edu, way to find out if running zsh? (25)
X 5 U d...@eng.umd.edu, Re: way to find out if running zsh? (17)
X 6 r d...@eng.umd.edu, Meta . (18)
X 7 U ja...@cs.glasgow.ac.uk, Re: problem building zsh (147)
X 8 U nytim!t...@uunet.uu.net, Re: Zsh on Sparc1 /SunOS 4.0.3
X 9 ursa!jmd, Another fix... (61)
X 10 U ppla...@bbn.com, Re: v18i084: Zsh 2.00 - A small complaint (36)
X 11 U lub...@cs.rochester.edu, POSIX job control (34)
X 12 U yale!bronson!t...@uunet.UU.NET
X 13 U br...@rpi.edu, zsh (36)
X 14 S subbarao, zsh sucks!!!! (286)
X 15 U snibru!d241s008!d241s013!a...@relay.EU.net, zsh (165)
X 16 U nytim!t...@uunet.UU.NET, Re: Zsh on Sparc1 /SunOS 4.0.3
X 17 U subbarao, zsh is a junk shell (43)
X 18 U amar...@vela.acs.oakland.edu, zsh (33)
X43u/84 1: x
X% ls -l /tmp/zsha06024
X/tmp/zsha06024 not found
X
X
XNote that the shell creates a temporary file, and deletes it
Xwhen the command is finished.
X
X% diff =(ls) =(ls -F)
X3c3
X< fortune
X---
X> fortune*
X10c10
X< strfile
X---
X> strfile*
X
X
XIf you read zsh's man page, you may notice that <(...) is
Xanother form of process substitution which is similar to
X=(...). There is an important difference between the two.
XIn the <(...) case, the shell creates a named pipe (FIFO)
Xinstead of a file. This is better, since it does not fill
Xup the file system; but it does not work in all cases. In
Xfact, if we had replaced =(...) with <(...) in the examples
Xabove, all of them would have stopped working except for
Xfgrep -f <(...). You can not edit a pipe, or open it as a
Xmail folder; fgrep, however, has no problem with reading a
Xlist of words from a pipe. You may wonder why diff <(foo)
Xbar doesn't work, since foo | diff - bar works; this is
Xbecause diff creates a temporary file if it notices that one
Xof its arguments is -, and then copies its standard input to
Xthe temporary file.
X
XAliasing
X
XOften-used commands can be abbreviated with an alias:


X
X
X
X
X
X

X - 17 -
X
X% alias uc=uncompress
X% ls
Xhanoi.Z
X% uc hanoi
X% ls
Xhanoi
X
X
Xor commands with certain desired options:
X
X% alias fm='finger -m'
X% fm root
XLogin name: root In real life: Operator
XDirectory: / Shell: /bin/csh
XOn since May 19 10:41:15 on console 3 days 5 hours Idle Time
XNo unread mail
XNo Plan.
X
X% alias lock='lock -p -60000'
X% lock
Xlock: /dev/ttyr4 on phoenix. timeout in 60000 minutes
Xtime now is Fri May 24 04:23:18 EDT 1991
XKey:
X
X% alias l='ls -AF'
X% l /
X.bash_history kadb*
X.bashrc lib@
X.cshrc licensed/
X.exrc lost+found/
X.login macsyma
X
X
XAliases can also be used to replace old commands:
X
X% alias grep=egrep ps=sps make=gmake
X% alias whoami='echo root'
X% whoami
Xroot
X
X
Xor to define new ones:


X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X

X - 18 -
X
X% cd /
X% alias sz='ls -l | sort -n +3 | tail -10'
X% sz
Xdrwxr-sr-x 7 bin 3072 May 23 11:59 etc
Xdrwxrwxrwx 26 root 5120 May 24 04:20 tmp
Xdrwxr-xr-x 2 root 8192 Dec 26 19:34 lost+found
Xdrwxr-sr-x 2 bin 14848 May 23 18:48 dev
X-r--r--r-- 1 root 140520 Dec 26 20:08 boot
X-rwxr-xr-x 1 root 311172 Dec 26 20:08 kadb
X-rwxr-xr-x 1 root 1209695 Apr 16 15:33 vmunix.old
X-rwxr-xr-x 1 root 1209702 May 14 19:04 vmunix
X-rwxr-xr-x 1 root 1209758 May 21 12:23 vmunix.new.kernelmap.old
X-rwxr-xr-x 1 root 1711848 Dec 26 20:08 vmunix.org
X% cd
X% alias rable='ls -AFtrd *(R)' nrable='ls -AFtrd *(^R)'
X% rable
XREADME func/ bin/ pub/ News/ src/
Xnicecolors etc/ scr/ tmp/ iris/ zsh*
X% nrable
XMailboxes/ mail/ notes
X
X
X(The pattern *(R) matches all readable files in the current
Xdirectory, and *(^R) matches all unreadable files.)
X
XMost other shells have aliases of this kind (command
Xaliases). However, zsh also has global aliases, which are
Xsubstituted anywhere on a line. Global aliases can be used
Xto abbreviate frequently-typed usernames, hostnames, etc.
X
X% alias -g me=pfalstad gun=egsirer mjm=maruchck
X% who | grep me
Xpfalstad ttyp0 May 24 03:39 (mickey.Princeton)
Xpfalstad ttyp5 May 24 03:42 (mickey.Princeton)
X% fm gun
XLogin name: egsirer In real life: Emin Gun Sirer
XDirectory: /u/egsirer Shell: /bin/sh
XLast login Thu May 23 19:05 on ttyq3 from bow.Princeton.ED
XNew mail received Fri May 24 02:30:28 1991;
X unread since Fri May 24 02:30:27 1991
X% alias -g phx=phoenix.princeton.edu warc=wuarchive.wustl.edu
X% ftp warc
XConnected to wuarchive.wustl.edu.
X
X
XHere are some more interesting uses.
X
X% alias -g M='| more' GF='| fgrep -f ~/.friends'
X% who M # pipes the output of who through more
X% who GF # see if your friends are on
X% w GF # see what your friends are doing
X
X
XAnother example makes use of zsh's process substitution. If
Xyou run NIS, and you miss being able to do this:
X
X% grep pfalstad /etc/passwd


X
X
X
X
X
X
X

X - 19 -
Xyou can define an alias that will seem more natural than
Xypmatch pfalstad passwd:
X
X% alias -g PASS='<(ypcat passwd)'
X% grep pfalstad PASS


Xpfalstad:*:3564:35:Paul John Falstad:/u/pfalstad:/usr/princeton/bin/zsh
X
X

XIf you're really crazy, you can even call it /etc/passwd:
X
X% alias -g /etc/passwd='<(ypcat passwd)'
X% grep pfalstad /etc/passwd


Xpfalstad:*:3564:35:Paul John Falstad:/u/pfalstad:/usr/princeton/bin/zsh
X
X

XThe last example shows one of the perils of global aliases;
Xthey have a lot of potential to cause confusion. For exam-
Xple, if you defined a global alias called | (which is possi-
Xble), zsh would begin to act very strangely; every pipe sym-
Xbol would be replaced with the text of your alias. To some
Xextent, global aliases are like macros in C; discretion is
Xadvised in using them and in choosing names for them. Using
Xnames in all caps is not a bad idea, especially for aliases
Xwhich introduce shell metasyntax (like M and GF above).
X
XNote that zsh aliases are not like csh aliases. The syntax
Xfor defining them is different, and they do not have argu-
Xments. All your favorite csh aliases will probably not work
Xunder zsh. For example, if you try:
X
Xalias rm mv '\!* /tmp/wastebasket'
X
X
Xno aliases will be defined, but zsh will not report an
Xerror. In csh, this line defines an alias that makes rm
Xsafe---files that are rm'd will be moved to a temporary
Xdirectory instead of instantly destroyed. In zsh's syntax,
Xhowever, this line asks the shell to print any existing
Xalias definitions for rm, mv, or !* /tmp/wastebasket. Since
Xthere are none, most likely, the shell will not print any-
Xthing, although alias will return a nonzero exit code. The
Xproper syntax is this:
X
Xalias rm='mv \!* /tmp/wastebasket'
X
X
XHowever, this won't work either:
X
X% rm foo.dvi
Xzsh: no matches found: !*
X
X
XWhile this makes rm safe, it is certainly not what the user
Xintended. In zsh, you must use a shell function for this:
X
X% unalias rm
X% rm () { mv $* /tmp/wastebasket }
X% rm foo.dvi
X% ls /tmp/wastebasket
Xfoo.dvi


X
X
X
X
X

X - 20 -
XWhile this is much cleaner and easier to read (I hope you
Xwill agree), it is not csh-compatible. Therefore, a script
Xto convert csh aliases and variables has been provided. You
Xshould only need to use it once, to convert all your csh
Xaliases and parameters to zsh format:
X
X% csh
Xcsh> alias
Xl ls -AF
Xmore less
Xon last -2 !:1 ; who | grep !:1
Xcsh> exit
X% c2z >neat_zsh_aliases
X% cat neat_zsh_aliases
Xalias l='ls -AF'
Xalias more='less'
Xon () { last -2 $1 ; who | grep $1 }
X...
X
X
XThe first two aliases were converted to regular zsh aliases,
Xwhile the third, since it needed to handle arguments, was
Xconverted to a function. c2z can convert most aliases to
Xzsh format without any problems. However, if you're using
Xsome really arcane csh tricks, or if you have an alias with
Xa name like do (which is reserved in zsh), you may have to
Xfix some of the aliases by hand.
X
XThe c2z script checks your csh setup, and produces a list of
Xzsh commands which replicate your aliases and parameter set-
Xtings as closely as possible. You could include its output
Xin your startup file, .zshrc.
X
XHistory
X
XThere are several ways to manipulate history in zsh. One
Xway is to use csh-style ! history:
X
X% /usr/local/bin/!:0 !-2*:s/foo/bar/ >>!$
X
X
XIf you don't want to use this, you can turn it off by typing
Xsetopt nobanghist.
X
XAnother way is to use the fc command. For example, if you
Xtype an erroneous command:
X
X% for i in `cat /etc/clients`
X do
X rpu $i
X done
Xzsh: command not found: rpu
Xzsh: command not found: rpu
Xzsh: command not found: rpu
X
X
Xtyping fc will execute an editor on this command, allowing
Xyou to fix it. (The default editor is vi, by the way, not
Xed).


X
X
X
X
X
X

X - 21 -
X
X% fc
X49
X/rpu/s//rup/p
X rup $i
Xw
X49
Xq
Xfor i in `cat /etc/clients`
X do
X rup $i
X done
X beam up 2 days, 10:17, load average: 0.86, 0.80, 0.50
X bow up 4 days, 8:41, load average: 0.91, 0.80, 0.50
X burn up 17:18, load average: 0.91, 0.80, 0.50
X burst up 9 days, 1:49, load average: 0.95, 0.80, 0.50
X tan up 11:14, load average: 0.91, 0.80, 0.50
X bathe up 3 days, 17:49, load average: 1.84, 1.79, 1.50
X bird up 1 day, 9:13, load average: 1.95, 1.82, 1.51
X bonnet up 2 days, 21:18, load average: 0.93, 0.80, 0.50
X
X
XA variant of the fc command is r, which redoes the last com-
Xmand, with optional changes:
X
X% echo foo
Xfoo
X% r
Xecho foo
Xfoo
X
X% echo foo
Xfoo
X% r foo=bar
Xecho bar
Xbar
X
X
X
XCommand Line Editing
X
Xzsh's command line editor, ZLE, is quite powerful. It is
Xdesigned to emulate either emacs or vi; the default is
Xemacs. To set the bindings for vi mode, type bindkey -v.
X
XIn addition to basic editing, the shell allows you to recall
Xprevious lines in the history. In emacs mode, this is done
Xwith ^P (control-P):
X
X% ls ~
X- README file mail pub tmp
XMailboxes bin func nicecolors scr zsh
XNews etc iris notes src
X% echo foobar
Xfoobar
X% ^P
X% echo foobar^P
X% ls ~_


X
X
X
X
X
X
X

X - 22 -
XPressing ^P once brings up the previous line (echo foobar);
Xpressing it again brings up the line before that (ls ~).
XThe cursor is left at the end of the line, allowing you to
Xedit the line if desired before executing it. In many
Xcases, ZLE eliminates the need for the fc command, since it
Xis powerful enough to handle even multiline commands:
X
X% for i in a b c d e
X> do
X> echo $i
X> done
Xa
Xb
Xc
Xd
Xe
X% ^P
X% for i in a b c d e
X do
X echo $i
X done_
X
X
XNow you can just move up to the part you want to change...
X
X% for i in _ b c d e
X do
X echo $i
X done
X
X
Xchange it, and execute the new command.
X
X% for i in f g h i j
X do
X echo $i
X done
Xf
Xg
Xh
Xi
Xj
X
X
XAlso, you can search the history for a certain command using
XESC-P:
X
X% set ESC-P
X% setopt autolist ESC-P
X% setopt nocorrect_
X
X
XAnother way is to do an incremental search, emacs-style:


X
X
X
X
X
X
X
X
X
X
X
X

X - 23 -
X
X% ^R
X% _
Xi-search:
X
X% l_ /usr/bin
Xi-search: l
X
X% date > foofile_c
Xi-search: le
X
X
XAnother useful feature of the editor is command and filename
Xcompletion.
X
X% compTAB
X% compress _
X
X% ls /nicTAB
X% ls /nicecolors _
X
X% ls /usr/prTAB
X% ls /usr/princeton/_
X
X% ls -l =comTAB
X% ls -l =compress _
X
X
XIf the completion is ambiguous, the editor will beep. You
Xcan list possible completions by pressing ^D:
X
X% ls /vmuTAB -beep-
X% ls /vmunix_
X% ls /vmunix^D
Xvmunix vmunix.old
Xvmunix.new.kernelmap.old vmunix.org
X
X
XOr, you could just set the AUTOLIST option:
X
X% setopt autolist
X% ls /vmuTAB -beep-
Xvmunix vmunix.old
Xvmunix.new.kernelmap.old vmunix.org
X% ls /vmunix_
X
X
XAnother option you could set is RECEXACT, which causes exact
Xmatches to be accepted, even if there are other possible
Xcompletions:
X
X% setopt recexact
X% ls /vmuTAB -beep-
Xvmunix vmunix.old
Xvmunix.new.kernelmap.old vmunix.org
X% ls /vmunix_TAB
X% ls /vmunix _
X
X
XThe fignore variable lists suffixes of files to ignore


X
X
X
X
X

X - 24 -
Xduring completion.
X
X% ls fooTAB -beep-
Xfoofile.c foofile.o
X% fignore=( .o \~ .bak .junk )
X% ls fooTAB
X% ls foofile.c _
X
X
XSince foofile.o has a suffix that is in the fignore list, it
Xwas not considered a possible completion of foo.
X
XUsername completion is also supported:
X
X% ls ~pfalTAB
X% ls ~pfalstad/_
X
X
Xand parameter name completion:
X
X% echo $ORGTAB
X% echo $ORGANIZATION _
X
X
Xand hostname completion, if you give the shell a list of
Xhosts to complete:
X
X% hosts=( phoenix.princeton.edu uunet.uu.net nic.ddn.mil
X> diskfarm.princeton.edu gnu.ai.mit.edu
X> eniac.seas.upenn.edu )
X% telnet diskTAB
X% telnet diskfarm.princeton.edu _
X
X% ftp uuTAB
X% ftp uunet.uu.net _
X
X% mail subbarao@phTAB
X% mail subb...@phoenix.princeton.edu _
X
X
Xand option completion:
X
X% setopt noclTAB
X% setopt noclobber _
X
X
Xand binding completion:
X
X% bindkey '^X^X' puTAB
X% bindkey '^X^X' push-line _
X
X
X
XThe compctl command is used to control how completion works.
XFor example, to specify that certain commands show take com-
Xmands as arguments, you use compctl -c:
X
X% compctl -c man nohup
X% man uptTAB
X% man uptime _


X
X
X
X
X

X - 25 -
XTo specify that a command should complete filenames, you
Xshould use compctl -f. This is the default. It can be com-
Xbined with -c, as well.
X
X% compctl -cf echo
X% echo uptTAB
X% echo uptime _
X
X% echo foTAB
X% echo foo.c
X
X
XSimilarly, use -h to specify hostnames, -o to specify
Xoptions, -v to specify variables, and -b to specify bind-
Xings.
X
X% compctl -h rlogin
X% compctl -hfc rsh
X% compctl -b bindkey
X
X
XYou can also use -k to specify a custom list of keywords to
Xuse in completion.
X
X% ftphosts=(ftp.uu.net wuarchive.wustl.edu)
X% compctl -k ftphosts ftp
X% ftp wuTAB
X% ftp wuarchive.wustl.edu _
X
X% friends=(cpirazzi subbarao sukthnkr)
X% compctl -k friends mail finger su
X% finger cpTAB
X% finger cpirazzi _
X
X
X
XIn addition to completion, TAB performs expansion if possi-
Xble.
X
X% ls *.cTAB
X% ls foofile.c fortune.c rnd.c strfile.c unstr.c_
X
X
XFor example, suppose you have a bunch of weird files in an
Ximportant directory:
X
X% ls
X * * * ; & % $??foo dspfok foo.c
X !"foo"! ` \ ` foo rrr
X
X
XYou want to remove them, but you don't want to damage foo.c.
XHere is one way to do this:
X
X% rm *TAB
X% rm \ \ \*\ \*\ \*\ \ \ \!\"foo\"\! \;\ \&\ %\ \$'
X'foo \`\ \\\ \` dspfok foo foo.c rrr_
X
X
XWhen you expand *, zsh inserts the names of all the files


X
X
X
X
X

X - 26 -
Xinto the editing buffer, with proper shell quoting. Now,
Xjust move back and remove foo.c from the buffer:
X
X% rm \ \ \*\ \*\ \*\ \ \ \!\"foo\"\! \;\ \&\ %\ \$'
X'foo \`\ \\\ \` dspfok foo _rr
X
X
Xand press return. Everything except foo.c will be deleted
Xfrom the directory.
X
XHere's another trick; let's say you have typed this command
Xin:
X
X% gcc -o x.out foob.c -g -Wpointer-arith -Wtrigraphs_
X
X
Xand you forget which library you want. You need to escape
Xout for a minute and check by typing ls /usr/lib, or some
Xother such command; but you don't want to retype the whole
Xcommand again, and you can't press return now because the
Xcurrent command is incomplete. In zsh, you can put the line
Xon the buffer stack, using ESC-Q, and type some other com-
Xmands. The next time a prompt is printed, the gcc line will
Xbe popped off the stack and put in the editing buffer
Xautomatically; you can then enter the proper library name
Xand press return (or, ESC-Q again and look for some other
Xlibraries whose names you forgot).
X
XA similar situation: what if you forget the option to gcc
Xthat finds bugs using AI techniques? You could either use
XESC-Q again, and type man gcc, or you could press ESC-H,
Xwhich essentially does the same thing; it puts the current
Xline on the buffer stack, and executes the command run-help
Xgcc, where run-help is an alias for man.
X
XAnother interesting command is ESC-A. This executes the
Xcurrent line, but retains it in the buffer, so that it
Xappears again when the next prompt is printed. Also, the
Xcursor stays in the same place. This is useful for execut-
Xing a series of similar commands:
X
X% cc grok.c -g -lc -lgl -lsun -lmalloc -Bstatic -o b.out
X% cc fubar.c -g -lc -lgl -lsun -lmalloc -Bstatic -o b.out
X% cc fooble.c -g -lc -lgl -lsun -lmalloc -Bstatic -o b.out
X
X
X
XThe ESC-' command is useful for managing the shell's quoting
Xconventions. Let's say you want to print this string:
X
Xdon't do that; type 'rm -rf \*', with a \ before the *.
X
X
XAll that is necessary is to type it into the editing buffer:
X
X% don't do that; type 'rm -rf \*', with a \ before the *.
X
X
Xpress ESC-' (escape-quote):


X
X
X
X
X
X

X - 27 -
X
X% 'don'\''t do that; type '\''rm -rf \*'\'', with a \ before the *.'
X
X
Xthen move to the beginning and add the echo command.
X
X% echo 'don'\''t do that; type '\''rm -rf \*'\'', with a \ before the *.'
Xdon't do that; type 'rm -rf \*', with a \ before the *.
X
X
XLet's say you want to create an alias to do this echo com-
Xmand. This can be done by recalling the line with ^P and
Xpressing ESC-' again:
X
X% 'echo '\''don'\''\'\'''\''t do that; type '\''\'\'''\''rm -rf
X\*'\''\'\'''\'', with a \ before the *.'\'''
X
X
Xand then move to the beginning and add the command to create
Xan alias.
X
X% alias zoof='echo '\''don'\''\'\'''\''t do that; type '\''\'\'''\''rm
X-rf \*'\''\'\'''\'', with a \ before the *.'\'''
X% zoof
Xdon't do that; type 'rm -rf \*', with a \ before the *.
X
X
X
XAnother interesting option is MENUCOMPLETE. This affects
Xthe way TAB works. Let's look at the /vmunix example again:
X
X% setopt menucomplete
X% ls /vmuTAB
X% ls /vmunixTAB
X% ls /vmunix.new.kernelmap.oldTAB
X% ls /vmunix.old_
X
X
XEach time you press TAB, it displays the next possible com-
Xpletion. In this way, you can cycle through the possible
Xcompletions until you find the one you want.
X
XThe AUTOMENU option makes a nice compromise between this
Xmethod of completion and the regular method. If you set
Xthis option, pressing the TAB key repeatedly after an ambi-
Xguous completion will cycle through the possible comple-
Xtions.
X
XBindings
X
XEach of the above editor commands was actually a function
Xbound by default to a certain key. The real names of the
Xcommands are:
X
Xexpand-or-complete TAB
Xpush-line ESC-Q
Xrun-help ESC-H
Xaccept-and-hold ESC-A
Xquote-line ESC-'


X
X
X
X
X
X

X - 28 -
XThese bindings are arbitrary; you could change them if you
Xwant. For example, to bind accept-line to ^Z:
X
X% bindkey '^Z' accept-line
X
X
XAnother idea would be to bind the delete key to delete-char;
Xthis might be convenient if you use ^H for backspace.
X
X% bindkey '^?' delete-char
X
X
XOr, you could bind ^X^H to run-help:
X
X% bindkey '^X^H' run-help
X
X
XOther examples:
X
X% bindkey '^X^Z' universal-argument
X% bindkey ' ' magic-space
X% bindkey -s '^T' 'uptime
X> '
X
X
Xuniversal-argument multiplies the next command by 4. Thus
X^X^Z^W might delete the last four words on the line. If you
Xbind space to magic-space, then csh-style history expansion
Xis done on the line whenever you press the space bar.
X
XThe -s flag to bindkey specifies that you are binding the
Xkey to a string, not a command. Thus bindkey -s '^T'
X'uptime\n' lets you VMS lovers get the load average whenever
Xyou press ^T.
X
XIf you have a NeXT keyboard, the one with the | and \ keys
Xvery inconveniently placed, the following bindings may come
Xin handy:
X
X% bindkey -s '\e/' '\\'
X% bindkey -s '\e=' '|'
X
X
XNow you can type ALT-/ to get a backslash, and ALT-= to get
Xa vertical bar. This only works inside zsh, of course;
Xbindkey has no effect on the key mappings inside talk or
Xmail, etc.
X
XAnother use of the editor is to edit the value of variables.
XFor example, an easy way to change your path is to use the
Xvared command:
X
X% vared PATH
X> /u/pfalstad/scr:/u/pfalstad/bin/sun4:/u/maruchck/scr:/u/subbarao/bin:/u/maruc
Xhck/bin:/u/subbarao/scripts:/usr/princeton/bin:/usr/ucb:/usr/bin:/bin:/usr/host
Xs:/usr/princeton/bin/X11:/./usr/lang:/./usr/etc:/./etc
X
X
XYou can now edit the path. When you press return, the con-
Xtents of the edit buffer will be assigned to PATH.


X
X
X
X
X

X - 29 -
XParameter Substitution
X
XIn zsh, parameters are set like this:
X
X% foo=bar
X% echo $foo
Xbar
X
X
XSpaces before or after the = are frowned upon:
X
X% foo = bar
Xzsh: command not found: foo
X
X
XAlso, set doesn't work for setting parameters:
X
X% set foo=bar
X% set foo = bar
X% echo $foo
X
X%
X
X
XNote that no error message was printed. This is because
Xboth of these commands were perfectly valid; the set builtin
Xassigns its arguments to the positional parameters ($1, $2,
Xetc.).
X
X% set foo=bar
X% echo $1
Xfoo=bar
X% set foo = bar
X% echo $3 $2
Xbar =
X
X
XIf you're really intent on using the csh syntax, define a
Xfunction like this:
X
X% set () {
X> eval "$1$2$3"
X> }
X% set foo = bar
X% set fuu=brrr
X% echo $foo $fuu
Xbar brrr
X
X
XBut then, of course you can't use the form of set with
Xoptions, like set -F (which turns off filename generation).
XAlso, the set command by itself won't list all the parame-
Xters like it should. To get around that you need a case
Xstatement:


X
X
X
X
X
X
X
X
X
X
X

X - 30 -
X
X% set () {
X> case $1 in
X> -*|+*|'') builtin set $* ;;
X> *) eval "$1$2$3" ;;
X> esac
X> }
X
X
XFor the most part, this should make csh users happy.
X
XThe following sh-style operators are supported in zsh:
X
X% unset null
X% echo ${foo-xxx}
Xbar
X% echo ${null-xxx}
Xxxx
X% unset null
X% echo ${null=xxx}
Xxxx
X% echo $null
Xxxx
X% echo ${foo=xxx}
Xbar
X% echo $foo
Xbar
X% unset null
X% echo ${null+set}
X
X% echo ${foo+set}
Xset
X
X
XAlso, csh-style : modifiers may be appended to a parameter
Xsubstitution.
X
X% echo $PWD
X/home/learning/pf/zsh/zsh2.00/src
X% echo $PWD:h
X/home/learning/pf/zsh/zsh2.00
X% echo $PWD:h:h
X/home/learning/pf/zsh
X% echo $PWD:t
Xsrc
X% name=foo.c
X% echo $name
Xfoo.c
X% echo $name:r
Xfoo
X% echo $name:e
Xc
X
X
XThe equivalent constructs in ksh (which are also supported
Xin zsh) are a bit more general and easier to remember. When
Xthe shell expands ${foo#pat}, it checks to see if pat
Xmatches a substring at the beginning of the value of foo.
XIf so, it removes that portion of foo, using the shortest
Xpossible match. With ${foo##pat}, the longest possible


X
X
X
X
X

X - 31 -
Xmatch is removed. ${foo%pat} and ${foo%%pat} remove the
Xmatch from the end. Here are the ksh equivalents of the :
Xmodifiers:
X
X% echo ${PWD%/*}
X/home/learning/pf/zsh/zsh2.00
X% echo ${PWD%/*/*}
X/home/learning/pf/zsh
X% echo ${PWD##*/}
Xsrc
X% echo ${name%.*}
Xfoo
X% echo ${name#*.}
Xc
X
X
Xzsh also has upper/lowercase modifiers:
X
X% xx=Test
X% echo $xx:u
XTEST
X% echo $xx:l
Xtest
X
X
Xand a substitution modifier:
X
X% echo $name:s/foo/bar/
Xbar.c
X% ls
Xfoo.c foo.h foo.o foo.pro
X% for i in foo.*; mv $i $i:s/foo/bar/
X% ls
Xbar.c bar.h bar.o bar.pro
X
X
XOne possible source of confusion is the fact that in zsh,
Xthe result of parameter substitution is not split into
Xwords. Thus, this will not work:
X
X% srcs='glob.c exec.c init.c'
X% ls $srcs
Xglob.c exec.c init.c not found
X
X
XThis is considered a feature, not a bug. If splitting were
Xdone by default, as it is in most other shells, functions
Xlike this would not work properly:
X
X$ ll () { ls -F $* }
X$ ll 'fuu bar'
Xfuu not found
Xbar not found
X
X% ll 'fuu bar'
Xfuu bar not found
X
X
XOf course, a hackish workaround is available in sh (and
Xzsh):


X
X
X
X
X

X - 32 -
X
X% setopt shwordsplit
X% ll () { ls -F "$@" }
X% ll 'fuu bar'
Xfuu bar not found
X
X
XIf you like the sh behaviour, zsh can accomodate you:
X
X% ls ${=srcs}
Xexec.c glob.c init.c
X% setopt shwordsplit
X% ls $srcs
Xexec.c glob.c init.c
X
X
XAnother way to get the $srcs trick to work is to use an
Xarray:
X
X% unset srcs
X% srcs=( glob.c exec.c init.c )
X% ls $srcs
Xexec.c glob.c init.c
X
X
Xor an alias:
X
X% alias -g SRCS='exec.c glob.c init.c'
X% ls SRCS
Xexec.c glob.c init.c
X
X
XAnother option that modifies parameter expansion is RCEX-
XPANDPARAM:
X
X% echo foo/$srcs
Xfoo/glob.c exec.c init.c
X% setopt rcexpandparam
X% echo foo/$srcs
Xfoo/glob.c foo/exec.c foo/init.c
X% echo foo/${^srcs}
Xfoo/glob.c foo/exec.c foo/init.c
X% echo foo/$^srcs
Xfoo/glob.c foo/exec.c foo/init.c
X
X
X
XShell Parameters
X
XThe shell has many predefined parameters that may be
Xaccessed. Here are some examples:


X
X
X
X
X
X
X
X
X
X
X
X
X
X

X - 33 -
X
X% sleep 10 &
X[1] 3820
X% echo $!
X3820
X% set a b c
X% echo $#
X3
X% echo $ARGC
X3
X% ( exit 20 ) ; echo $?
X20
X% false; echo $status
X1
X
X
X($? and $status are equivalent.)
X
X% echo $HOST $HOSTTYPE
Xdendrite sun4
X% echo $UID $GID
X701 60
X% cd /tmp
X% cd /home
X% echo $PWD $OLDPWD
X/home /tmp
X% ls $OLDPWD/.getwd
X/tmp/.getwd
X
X
X~+ and ~- are short for $PWD and $OLDPWD, respectively.
X
X% ls ~-/.getwd
X/tmp/.getwd
X% ls -d ~+/learning
X/home/learning
X% echo $RANDOM
X4880
X% echo $RANDOM
X11785
X% echo $RANDOM
X2062
X% echo $TTY
X/dev/ttyp4
X% echo $VERSION
Xzsh v2.00.03
X% echo $USERNAME
Xpf
X
X
X
XThe cdpath variable sets the search path for the cd command.
XIf you do not specify . somewhere in the path, it is assumed
Xto be the first component.


X
X
X
X
X
X
X
X
X
X
X

X - 34 -
X
X% cdpath=( /usr ~ ~/zsh )
X% ls /usr
X5bin dict lang net sccs sys
X5include etc lector nserve services tmp
X5lib export lib oed share ucb
Xadm games local old skel ucbinclude
Xbin geac lost+found openwin spool ucblib
Xboot hosts macsyma_417 pat src xpg2bin
Xdemo include man princeton stand xpg2include
Xdiag kvm mdec pub swap xpg2lib
X% cd spool
X/usr/spool
X% cd bin
X/usr/bin
X% cd func
X~/func
X% cd
X% cd pub
X% pwd
X/u/pfalstad/pub
X% ls -d /usr/pub
X/usr/pub
X
X
XPATH and path both set the search path for commands. These
Xtwo variables are equivalent, except that one is a string
Xand one is an array. If the user modifies PATH, the shell
Xchanges path as well, and vice versa.
X
X% PATH=/bin:/usr/bin:/tmp:.
X% echo $path
X/bin /usr/bin /tmp .
X% path=( /usr/bin . /usr/local/bin /usr/ucb )
X% echo $PATH
X/usr/bin:.:/usr/local/bin:/usr/ucb
X
X
XThe same is true of CDPATH and cdpath:
X
X% echo $CDPATH
X/usr:/u/pfalstad:/u/pfalstad/zsh
X% CDPATH=/u/subbarao:/usr/src:/tmp
X% echo $cdpath
X/u/subbarao /usr/src /tmp
X
X
XIn general, parameters with names in all lowercase are
Xarrays; assignments to them take the form:
X
Xname=( elem ... )
X
X
XParameters with names in all uppercase are strings. If
Xthere is both an array and a string version of the same
Xparameter, the string version is a colon-separated list,
Xlike PATH.
X
XHISTFILE is the name of the history file, where the history
Xis saved when a shell exits.


X
X
X
X
X

X - 35 -
X
X% zsh
Xphoenix% HISTFILE=/tmp/history
Xphoenix% SAVEHIST=20
Xphoenix% echo foo
Xfoo
Xphoenix% date
XFri May 24 05:39:35 EDT 1991
Xphoenix% uptime
X 5:39am up 4 days, 20:02, 40 users, load average: 2.30, 2.20, 2.00
Xphoenix% exit
X% cat /tmp/history
XHISTFILE=/tmp/history
XSAVEHIST=20
Xecho foo
Xdate
Xuptime
Xexit
X% HISTSIZE=3
X% history
X 28 rm /tmp/history
X 29 HISTSIZE=3
X 30 history
X
X
X
XIn zsh, if you say
X
X% >file
X
X
Xthe command cat is normally assumed:
X
X% >file
Xfoo!
X^D
X% cat file
Xfoo!
X
X
XThus, you can view a file simply by typing:
X
X% <file
Xfoo!
X
X
XHowever, this is not csh or sh compatible. To correct this,
Xchange the value of the parameter NULLCMD, which is cat by
Xdefault.
X
X% NULLCMD=:
X% >file
X% ls -l file
X-rw-r--r-- 1 pfalstad 0 May 24 05:41 file
X
X
XIf NULLCMD is unset, the shell reports an error if no com-
Xmand is specified (like csh).


X
X
X
X
X
X
X

X - 36 -
X
X% unset NULLCMD
X% >file
Xzsh: redirection with no command
X
X
XActually, READNULLCMD is used whenever you have a null com-
Xmand reading input from a single file. Thus, you can set
XREADNULLCMD to more or less rather than cat. Also, if you
Xset NULLCMD to : for sh compatibility, you can still read
Xfiles with < file if you leave READNULLCMD set to more.
X
XPrompting
X
XThe default prompt for zsh is:
X
Xphoenix% echo $PROMPT
X%m%#
X
X
XThe %m stands for the short form of the current hostname,
Xand the %# stands for a % or a #, depending on whether the
Xshell is running as root or not. zsh supports many other
Xcontrol sequences in the PROMPT variable.
X
X% PROMPT='%/> '
X/u/pfalstad/etc/TeX/zsh>
X
X% PROMPT='%~> '
X~/etc/TeX/zsh>
X
X% PROMPT='%h %~> '
X6 ~/etc/TeX/zsh>
X
X
X%h represents the number of current history event.
X
X% PROMPT='%h %~ %M> '
X10 ~/etc/TeX/zsh apple-gunkies.gnu.ai.mit.edu>
X
X% PROMPT='%h %~ %m> '
X11 ~/etc/TeX/zsh apple-gunkies>
X
X% PROMPT='%h %t> '
X12 6:11am>
X
X% PROMPT='%n %w tty%l>'
Xpfalstad Fri 24 ttyp0>
X
X
XAlso available is the RPROMPT parameter. If this is set,
Xthe shell puts a prompt on the right side of the screen.


X
X
X
X
X
X
X
X
X
X
X
X
X

X - 37 -
X
X% RPROMPT='%t'
X% 6:14am
X
X% RPROMPT='%~'
X% ~/etc/TeX/zsh
X
X% PROMPT='%l %T %m[%h] ' RPROMPT=' %~'
Xp0 6:15 phoenix[5] ~/etc/TeX/zsh
X
X
XThese special escape sequences can also be used with the -P
Xoption to print:
X
X% print -P %h tty%l
X15 ttyp1
X
X
X
XThe POSTEDIT parameter is printed whenever the editor exits.
XThis can be useful for termcap tricks. To highlight the
Xprompt and command line while leaving command output
Xunhighlighted, try this:
X
X% POSTEDIT=`echotc se`
X% PROMPT='%S%% '
X
X
X
XLogin/logout watching
X
XYou can specify login or logout events to monitor by setting
Xthe watch variable. Normally, this is done by specifying a
Xlist of usernames.
X
X% watch=( pfalstad subbarao sukthnkr egsirer )
X
X
XThe log command reports all people logged in that you are
Xwatching for.
X
X% log
Xpfalstad has logged on p0 from mickey.
Xpfalstad has logged on p5 from mickey.
X% ...
Xsubbarao has logged on p8 from phoenix.
X% ...
Xsubbarao has logged off p8 from phoenix.
X% ...
Xsukthnkr has logged on p8 from dew.
X% ...
Xsukthnkr has logged off p8 from dew.
X
X
XIf you specify hostnames with an @ prepended, the shell will
Xwatch for all users logging in from the specified host.


X
X
X
X
X
X
X
X
X

X - 38 -
X
X% watch=( @mickey @phoenix )
X% log
Xdjthongs has logged on q2 from phoenix.
Xpfalstad has logged on p0 from mickey.
Xpfalstad has logged on p5 from mickey.
X
X
XIf you give a tty name with a % prepended, the shell will
Xwatch for all users logging in on that tty.
X
X% watch=( %ttyp0 %console )
X% log
Xroot has logged on console from .
Xpfalstad has logged on p0 from mickey.
X
X
XThe format of the reports may also be changed.

X - 39 -
X
X% watch=( pfalstad gettes eps djthongs jcorr bdavis )
X% log
Xjcorr has logged on tf from 128.112.176.3:0.
Xjcorr has logged on r0 from 128.112.176.3:0.
Xgettes has logged on p4 from yo:0.0.
Xdjthongs has logged on pe from grumpy:0.0.
Xdjthongs has logged on q2 from phoenix.
Xbdavis has logged on qd from BRUNO.
Xeps has logged on p3 from csx30:0.0.
Xpfalstad has logged on p0 from mickey.
Xpfalstad has logged on p5 from mickey.
X% WATCHFMT='%n on tty%l from %M'
X% log
Xjcorr on ttytf from 128.112.176.3:0.
Xjcorr on ttyr0 from 128.112.176.3:0.
Xgettes on ttyp4 from yo:0.0
Xdjthongs on ttype from grumpy:0.0
Xdjthongs on ttyq2 from phoenix.Princeto
Xbdavis on ttyqd from BRUNO.pppl.gov
Xeps on ttyp3 from csx30:0.0
Xpfalstad on ttyp0 from mickey.Princeton
Xpfalstad on ttyp5 from mickey.Princeton
X% WATCHFMT='%n fm %m'
X% log
Xjcorr fm 128.112.176.3:0
Xjcorr fm 128.112.176.3:0
Xgettes fm yo:0.0
Xdjthongs fm grumpy:0.0
Xdjthongs fm phoenix
Xbdavis fm BRUNO
Xeps fm csx30:0.0
Xpfalstad fm mickey
Xpfalstad fm mickey
X% WATCHFMT='%n %a at %t %w.'
X% log
Xjcorr logged on at 3:15pm Mon 20.
Xjcorr logged on at 3:16pm Wed 22.
Xgettes logged on at 6:54pm Wed 22.
Xdjthongs logged on at 7:19am Thu 23.
Xdjthongs logged on at 7:20am Thu 23.
Xbdavis logged on at 12:40pm Thu 23.
Xeps logged on at 4:19pm Thu 23.
Xpfalstad logged on at 3:39am Fri 24.
Xpfalstad logged on at 3:42am Fri 24.
X
X
XIf you have a .friends file in your home directory, a con-
Xvenient way to make zsh watch for all your friends is to do
Xthis:
X
X% watch=( $(< ~/.friends) )
X% echo $watch
Xsubbarao maruchck root sukthnkr ...
X
X
XIf watch is set to all, then all users logging in or out
Xwill be reported.


X
X
X
X
X
X
X

X - 40 -
XOptions
X
XSome options have already been mentioned; here are a few
Xmore:
X
X% cd /
X% setopt autocd
X% bin
X% pwd
X/bin
X% ../etc
X% pwd
X/etc
X
X
XUsing the AUTOCD option, you can simply type the name of a
Xdirectory, and it will become the current directory.
X
X% setopt cdablevars
X% foo=/tmp
X% cd foo
X/tmp
X
X
XWith CDABLEVARS, if the argument to cd is the name of a
Xparameter whose value is a valid directory, it will become
Xthe current directory.
X
XCORRECT turns on spelling correction for commands, and the
XCORRECTALL option turns on spelling correction for all argu-
Xments.
X
X% setopt correct
X% sl
Xzsh: correct `sl' to `ls' [nyae]? y
X% setopt correctall
X% ls x.v11r4
Xzsh: correct `x.v11r4' to `X.V11R4' [nyae]? n
X/usr/princton/src/x.v11r4 not found
X% ls /etc/paswd
Xzsh: correct to `/etc/paswd' to `/etc/passwd' [nyae]? y
X/etc/passwd
X
X
XIf you press y when the shell asks you if you want to
Xcorrect a word, it will be corrected. If you press n, it
Xwill be left alone. Pressing a aborts the command, and
Xpressing e brings the line up for editing again, in case you
Xagree the word is spelled wrong but you don't like the
Xcorrection.
X
XNormally, a quoted expression may contain a newline:
X
X% echo '
X> foo
X> '
X
Xfoo
X
X%


X
X
X
X
X

X - 41 -
XWith CSHJUNKIEQUOTES set, this is illegal, as it is in csh.
X
X% setopt cshjunkiequotes
X% ls 'foo
Xzsh: unmatched '
X
X
XGLOBDOTS lets files beginning with a . be matched without
Xexplicitly specifying the dot.
X
X% ls -d *x*
XMailboxes
X% setopt globdots
X% ls -d *x*
X.exrc .pnewsexpert .xserverrc
X.mushexpert .xinitrc Mailboxes
X
X
XHISTIGNOREDUPS prevents the current line from being saved in
Xthe history if it is the same as the previous one; HISTIG-
XNORESPACE prevents the current line from being saved if it
Xbegins with a space.
X
X% PROMPT='%h> '
X39> setopt histignoredups
X40> echo foo
Xfoo
X41> echo foo
Xfoo
X41> echo foo
Xfoo
X41> echo bar
Xbar
X42> setopt histignorespace
X43> echo foo
Xfoo
X43> echo fubar
Xfubar
X43> echo fubar
Xfubar
X
X
XIGNOREBRACES turns off csh-style brace expansion.
X
X% echo x{y{z,a},{b,c}d}e
Xxyze xyae xbde xcde
X% setopt ignorebraces
X% echo x{y{z,a},{b,c}d}e
Xx{y{z,a},{b,c}d}e
X
X
XIGNOREEOF forces the user to type exit or logout, instead of
Xjust pressing ^D.
X
X% setopt ignoreeof
X% ^D
Xzsh: use 'exit' to exit.
X
X
XINTERACTIVECOMMENTS turns on interactive comments; comments


X
X
X
X
X

X - 42 -
Xbegin with a #.
X
X% setopt interactivecomments
X% date # this is a comment
XFri May 24 06:54:14 EDT 1991
X
X
XNOCLOBBER prevents you from accidentally overwriting an
Xexisting file.
X
X% setopt noclobber
X% cat /dev/null >~/.zshrc
Xzsh: file exists: /u/pfalstad/.zshrc
X
X
XIf you really do want to clobber a file, you can use the >!
Xoperator. To make things easier in this case, the > is
Xstored in the history list as a >!:
X
X% cat /dev/null >! ~/.zshrc
X% cat /etc/motd > ~/.zshrc
Xzsh: file exists: /u/pfalstad/.zshrc
X% !!
Xcat /etc/motd >! ~/.zshrc
X% ...
X
X
XRCQUOTES lets you use a more elegant method for including
Xsingle quotes in a singly quoted string:
X
X% echo '"don'\''t do that."'
X"don't do that."
X% echo '"don''t do that."'
X"dont do that."
X% setopt rcquotes
X% echo '"don''t do that."'
X"don't do that."
X
X
XFinally, SUNKEYBOARDHACK wins the award for the strangest
Xoption. If a line ends with `, and there are an odd number
Xof them on the line, the shell will ignore the trailing `.
XThis is provided for keyboards whose RETURN key is too
Xsmall, and too close to the ` key.
X
X% setopt sunkeyboardhack
X% date`
XFri May 24 06:55:38 EDT 1991
X
X
X
XClosing Comments
X
XI would be happy to receive mail if anyone has any tricks or
Xideas to add to this document, or if there are some points
Xthat could be made clearer or covered more thoroughly.
XPlease notify me of any errors in this document.


X
X
X
X
X
X

SHAR_EOF
echo 'File zsh2.2/doc/intro.txt is complete' &&
chmod 0644 zsh2.2/doc/intro.txt ||


echo 'restore of zsh2.2/doc/intro.txt failed'

Wc_c="`wc -c < 'zsh2.2/doc/intro.txt'`"
test 58603 -eq "$Wc_c" ||
echo 'zsh2.2/doc/intro.txt: original size 58603, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/dots/zlogin ==============
if test ! -d 'zsh2.2/dots'; then
echo 'x - creating directory zsh2.2/dots'
mkdir 'zsh2.2/dots'
fi
if test -f 'zsh2.2/dots/zlogin' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/dots/zlogin (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/dots/zlogin (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/dots/zlogin' &&
Xclear
Xcd
Xstty dec new cr0 -tabs
Xttyctl -f # freeze the terminal modes... can't change without a ttyctl -u
Xumask 022
Xexport MAIL=/usr/spool/mail/$USER
XMAILCHECK=60
Xmesg y
Xuptime
Xfortune
Xlog
Xfrom 2>/dev/null
Xcat notes
Xunlimit
Xlimit core 0
Xmsgs -fp
SHAR_EOF
chmod 0644 zsh2.2/dots/zlogin ||
echo 'restore of zsh2.2/dots/zlogin failed'
Wc_c="`wc -c < 'zsh2.2/dots/zlogin'`"
test 247 -eq "$Wc_c" ||
echo 'zsh2.2/dots/zlogin: original size 247, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/dots/zshrc ==============
if test -f 'zsh2.2/dots/zshrc' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/dots/zshrc (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/dots/zshrc (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/dots/zshrc' &&
X#
X# my rc file for zsh 2.2
X# all this runs in interactive shells only
X#
X
X# search path for the cd command
Xcdpath=(. ~ ~/src/cs320 ~/src)
X
X# where to look for function definitions
X# fpath=(~/func)
X
X# useful directory
Xcsrc=/usr/princeton/common/src
X
X# use hard limits, except for a smaller stack and no core dumps
Xunlimit
Xlimit stack 8192
Xlimit core 0
Xlimit -s
X
Xumask 022
X
X# define some aliases
Xalias a=alias
Xa a.out=./a.out sendmail=/usr/lib/sendmail c=cp 0=vi 09='vi -t' 00=r
Xa d=dirs en='enscript -2rGh' fm='finger -m' grep=egrep h=history
Xa hinfo='host -t hinfo' j=jobs l='ls -AF' lock='lock -p -60000'
Xa lsd='ls -d */' m=make mm=less
Xa nrable='ls -AFltrd *(^R)' sz='ls -l | sort -n +3 | tail -20'
Xa sn='sed -n' nw='l -ltr | tail' pd=pushd pop=popd mroe=more
Xa rable='ls -AFltrd *(R)' strings='strings -' t=cat
Xa v=mv where='hostname; echo >/dev/null' k9='kill -9' whoami='echo root'
Xa find='noglob find' bindkey='noglob bindkey' dh='dirs -v'
Xa mv='nocorrect mv' z=suspend
X
X# global aliases
Xa -g 'GF'='| fgrep -f ~/.friends' G='| grep' M='| less' cex='/u/pup/centrex'
X
X# setenv for csh junkies (including tset)
Xsetenv() { export $1=$2 }
X
Xmanpath=(/usr/man /usr/princeton/man /u/cad/man /usr/lang/man)
Xexport MANPATH
X
X# filename completion suffixes to ignore
Xfignore=(.o .pro .old)
X
X# hosts to use for completion
Xhosts=(uunet.uu.net `hostname` wuarchive.wustl.edu quiche.cs.mcgill.ca)
X
XPROMPT='%l %T %m[%h] '
X
X# prompt on the right side of the screen
XRPROMPT=' %~'
X
X# some environment variables
Xexport MAILCALL='NEW MAIL! '
Xexport YOUSAID='In %C you wrote:'
Xexport ATTRIBUTION='%f wrote:'
X
X# functions to autoload
X# autoload cx acx mere yu yp randline proto namedir ilogin
X
XMAILCHECK=30
XHISTSIZE=600
XDIRSTACKSIZE=50
X
X# lots of options
Xsetopt notify globdots correct pushdtohome cdablevars autolist \
X sunkeyboardhack correctall autocd recexact longlistjobs mailwarning \
X autoresume histignoredups pushdsilent noclobber \
X autopushd pushdminus extendedglob rcquotes
Xunsetopt bgnice
X
X# watch for my friends
Xwatch=($(cat ~/.friends))
XWATCHFMT='%n %a %l from %m at %t.'
XLOGCHECK=0
X
Xexport LESS=-ainx3
Xunhash p
X
X# some nice bindings
Xbindkey '^X^Z' universal-argument ' ' magic-space
Xbindkey '^X^A' vi-find-prev-char-skip
Xbindkey '^Z' accept-and-hold
Xbindkey -s '\M-/' \\\\
Xbindkey -s '\M-=' \|
SHAR_EOF
chmod 0644 zsh2.2/dots/zshrc ||
echo 'restore of zsh2.2/dots/zshrc failed'
Wc_c="`wc -c < 'zsh2.2/dots/zshrc'`"
test 2291 -eq "$Wc_c" ||
echo 'zsh2.2/dots/zshrc: original size 2291, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/dots/zshenv ==============
if test -f 'zsh2.2/dots/zshenv' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/dots/zshenv (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/dots/zshenv (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/dots/zshenv' &&
Xpath=(~/scr ~/bin/$HOSTTYPE
X /usr/princeton/bin /usr/ucb /usr/bin /bin
X /usr/hosts /usr/princeton/bin/X11 /usr/etc /etc .)
SHAR_EOF
chmod 0644 zsh2.2/dots/zshenv ||
echo 'restore of zsh2.2/dots/zshenv failed'
Wc_c="`wc -c < 'zsh2.2/dots/zshenv'`"
test 123 -eq "$Wc_c" ||
echo 'zsh2.2/dots/zshenv: original size 123, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/func/acx ==============
if test ! -d 'zsh2.2/func'; then
echo 'x - creating directory zsh2.2/func'
mkdir 'zsh2.2/func'
fi
if test -f 'zsh2.2/func/acx' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/func/acx (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/func/acx (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/func/acx' &&
X#! /bin/sh
X#
X# zsh shell function to make its arguments 755
X# also works as an sh script
X#
Xchmod 755 $*
SHAR_EOF
chmod 0755 zsh2.2/func/acx ||
echo 'restore of zsh2.2/func/acx failed'
Wc_c="`wc -c < 'zsh2.2/func/acx'`"
test 104 -eq "$Wc_c" ||
echo 'zsh2.2/func/acx: original size 104, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/func/cx ==============
if test -f 'zsh2.2/func/cx' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/func/cx (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/func/cx (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/func/cx' &&
X#! /bin/sh
X#
X# zsh shell function to make its arguments executable
X# also works as a sh script
X#
Xchmod +x $*
SHAR_EOF
chmod 0755 zsh2.2/func/cx ||
echo 'restore of zsh2.2/func/cx failed'
Wc_c="`wc -c < 'zsh2.2/func/cx'`"
test 109 -eq "$Wc_c" ||
echo 'zsh2.2/func/cx: original size 109, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/func/harden ==============
if test -f 'zsh2.2/func/harden' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/func/harden (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/func/harden (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/func/harden' &&
X#! /bin/sh
X# harden a link (convert it to a singly linked file)
Xcp $1 $1.foo
Xrm $1
Xmv $1.foo $1
X
SHAR_EOF
chmod 0755 zsh2.2/func/harden ||
echo 'restore of zsh2.2/func/harden failed'
Wc_c="`wc -c < 'zsh2.2/func/harden'`"
test 97 -eq "$Wc_c" ||
echo 'zsh2.2/func/harden: original size 97, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/func/mere ==============
if test -f 'zsh2.2/func/mere' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/func/mere (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/func/mere (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/func/mere' &&
X#! /bin/sh
X# read a man page in the current directory
Xnroff -man -Tman $1 | less -s
SHAR_EOF
chmod 0755 zsh2.2/func/mere ||
echo 'restore of zsh2.2/func/mere failed'
Wc_c="`wc -c < 'zsh2.2/func/mere'`"
test 84 -eq "$Wc_c" ||
echo 'zsh2.2/func/mere: original size 84, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/func/namedir ==============
if test -f 'zsh2.2/func/namedir' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/func/namedir (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/func/namedir (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/func/namedir' &&
X# give a name to a directory
X
X$1=~+
X: ~$1
X
X# for example, if we say: namedir foo
X# where the current directory is /usr/princeton/common/src/news/nntp/inews
X# this will do:
X#
X# foo=/usr/princeton/common/src/news/nntp/inews
X# : ~foo
X#
X# The : ~foo just evaluates ~foo, which declares foo as a named directory.
X# The first time a parameter is used with tilde expansion, it is declared
X# as the name of a named dir.
SHAR_EOF
chmod 0755 zsh2.2/func/namedir ||
echo 'restore of zsh2.2/func/namedir failed'
Wc_c="`wc -c < 'zsh2.2/func/namedir'`"
test 412 -eq "$Wc_c" ||
echo 'zsh2.2/func/namedir: original size 412, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/func/proto ==============
if test -f 'zsh2.2/func/proto' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/func/proto (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/func/proto (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/func/proto' &&
X#! /bin/sh
X# generate prototypes, if your style is the same as mine
Xfor i
Xdo
X rm $i:r.pro 2>/dev/null
X grep -v '[{};:#]' $i | grep '^[A-Za-z]' |
X grep -v static | sed 's/$/;/' >! $i:r.pro
Xdone
SHAR_EOF
chmod 0755 zsh2.2/func/proto ||
echo 'restore of zsh2.2/func/proto failed'
Wc_c="`wc -c < 'zsh2.2/func/proto'`"
test 194 -eq "$Wc_c" ||
echo 'zsh2.2/func/proto: original size 194, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/func/randline ==============
if test -f 'zsh2.2/func/randline' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/func/randline (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/func/randline (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/func/randline' &&
X# get a random line from a file
SHAR_EOF
true || echo 'restore of zsh2.2/func/randline failed'
fi
echo 'End of zsh2.2 part 2'
echo 'File zsh2.2/func/randline is continued in part 3'
echo 3 > _shar_seq_.tmp

Paul Falstad

unread,
May 13, 1992, 11:55:07 AM5/13/92
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 29, Issue 99
Archive-name: zsh2.2/part03

Environment: BSD
Supersedes: zsh2.1: Volume 24, Issue 1-19

#!/bin/sh
# this is aa.03 (part 3 of zsh2.2)


# do not concatenate these parts, unpack them in order with /bin/sh

# file zsh2.2/func/randline continued


#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 3; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then

echo 'x - still skipping zsh2.2/func/randline'
else
echo 'x - continuing file zsh2.2/func/randline'


sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.2/func/randline' &&

Xinteger z=$(wc -l <$1)
Xsed -n $[RANDOM%z+1]p $1
SHAR_EOF
echo 'File zsh2.2/func/randline is complete' &&
chmod 0755 zsh2.2/func/randline ||


echo 'restore of zsh2.2/func/randline failed'

Wc_c="`wc -c < 'zsh2.2/func/randline'`"
test 80 -eq "$Wc_c" ||
echo 'zsh2.2/func/randline: original size 80, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/func/yp ==============
if test -f 'zsh2.2/func/yp' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/func/yp (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/func/yp (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/func/yp' &&
X#! /bin/sh
Xypmatch $1 passwd
SHAR_EOF
chmod 0755 zsh2.2/func/yp ||
echo 'restore of zsh2.2/func/yp failed'
Wc_c="`wc -c < 'zsh2.2/func/yp'`"
test 29 -eq "$Wc_c" ||
echo 'zsh2.2/func/yp: original size 29, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/func/yu ==============
if test -f 'zsh2.2/func/yu' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/func/yu (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/func/yu (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/func/yu' &&
X#! /bin/sh
Xypmatch $1 passwd.byuid
SHAR_EOF
chmod 0755 zsh2.2/func/yu ||
echo 'restore of zsh2.2/func/yu failed'
Wc_c="`wc -c < 'zsh2.2/func/yu'`"
test 35 -eq "$Wc_c" ||
echo 'zsh2.2/func/yu: original size 35, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/man/man1/zsh.1 ==============
if test ! -d 'zsh2.2/man'; then
echo 'x - creating directory zsh2.2/man'
mkdir 'zsh2.2/man'
fi
if test ! -d 'zsh2.2/man/man1'; then
echo 'x - creating directory zsh2.2/man/man1'
mkdir 'zsh2.2/man/man1'
fi
if test -f 'zsh2.2/man/man1/zsh.1' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/man/man1/zsh.1 (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/man/man1/zsh.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/man/man1/zsh.1' &&
X.\"
X.TH ZSH 1 "1992 May 2"
X.SH NAME
Xzsh \- the Z shell
X.SH SYNOPSIS
X\fBzsh\fP [ \(+-\fIoptions\fP ] [ \(+-\fBo\fP \fIoption\fP ] ... [ \-\fBc\fP \fIstring\fP ] [ \fIarg\fP ... ]
X.SH "SHELL GRAMMAR"
XA \fIsimple command\fP is a sequence of optional parameter
Xassignments followed by blank-separated words,
Xwith optional redirections interspersed.
XThe first word is the command to be executed, and the remaining
Xwords, if any, are arguments to the command.
XIf a command name is given, the parameter assignments modify
Xthe environment of the command when it is executed.
XThe value of a simple command is its exit status,
Xor 128 plus the signal number if terminated by a signal.
X.PP
XIf a simple command is preceded by the word \fBexec\fP,
Xit is executed in the parent shell without forking.
XIf preceded by \fBcommand\fP, the command word is taken
Xto be the name of an external command, rather than a
Xshell function or builtin.
XIf preceded by \fBnoglob\fP, filename generation is not performed
Xon any of the words. If preceded by a \-, the command
Xis executed with a \- prepended to its \fBargv[0]\fP string.
XIf preceded by \fBnocorrect\fP, spelling correction is not
Xdone on any of the words.
X.PP
XA \fIpipeline\fP is a sequence of one or more commands
Xseparated by \fB|\fP or \fB|&\fP. \fB|&\fP is shorthand
Xfor \fB2>&1 |\fP. The standard output of each command is
Xconnected to the standard input of the next command in the
Xpipeline.
X.PP
XThe value of a pipeline is the value of the last command.
XIf a pipeline is preceded by a \fB!\fP, the value
Xof that pipeline is the logical NOT of the value of the last
Xcommand.
X.PP
XIf a pipeline is preceded by \fBcoproc\fP, it is
Xexecuted as a coprocess; a two-way pipe is established
Xbetween it and the parent shell. The shell can read from or write to
Xthe coprocess by means of the \fB>&p\fP and \fB<&p\fP
Xredirection operators.
X.PP
XA \fIsublist\fP is a sequence of one or more pipelines
Xseparated by \fB&&\fP or \fB|\||\fP. If two pipelines
Xare separated by \fB&&\fP, the second pipeline is executed
Xonly if the first is successful (returns a zero value).
XIf two pipelines are separated by \fB|\||\fP, the second is executed
Xonly if the first is unsuccessful (returns a nonzero value).
X.PP
XA \fIlist\fP is a sequence of one or more sublists
Xseparated by, and optionally terminated by, \fB;\fP, \fB&\fP,
Xor a newline.
XNormally the shell waits for each list to finish before executing
Xthe next one.
XIf a list is terminated by a \fB&\fP, the shell executes
Xit in the background, and does not wait for it to finish.
X.PP
XA \fIcomplex command\fP is one of the following:
X.PP
X.RS
X.PD 0
X.TP
X\fBfor\fP \fIname\fP [ \fBin\fP \fIword\fP ... ]
X.TP
X\fBdo\fP \fIlist\fP
X.TP
X\fBdone\fP
X.PD
XExpand the list of \fIword\fPs, and set the parameter
X\fIname\fP to each of them in turn, executing
X\fIlist\fP each time. If the \fBin\fP \fIword\fP is omitted,
Xuse the positional parameters instead of the \fIword\fPs.
X.TP
X\fBfor\fP \fIname\fP [ \fBin\fP \fIword\fP ... ] ; \fIsublist\fP
XThis is a shorthand for \fBfor\fP.
XThough it may cause confusion, it is included for convenience;
Xits use in scripts is discouraged,
Xunless \fIsublist\fP is a command of the form { \fIlist\fP }.
X.PP
X.PD 0
X.TP
X\fBforeach\fP \fIname\fP \fB(\fP \fIword\fP ... \fB)\fP
X.TP
X\fIlist\fP
X.TP
X\fBend\fP
X.PD
XAnother form of \fBfor\fP.
X.PP
X.PD 0
X.TP
X\fBfor\fP \fIname\fP \fBin\fP \fIword\fP ...
X.TP
X\fB{\fP
X.TP
X\fIlist\fP
X.TP
X\fB}\fP
X.PD
XAnother form of \fBfor\fP.
X.PP
X.PD 0
X.TP
X\fBfor\fP \fIname\fP \fB(\fP \fIword\fP ... \fB) {\fP
X.TP
X\fIlist\fP
X.TP
X\fB}\fP
X.PD
XAnother form of \fBfor\fP.
X.PP
X.PD 0
X.TP
X\fBfor\fP \fIname\fP \fB(\fP \fIword\fP ... \fB) \fIsublist\fP
X.PD
XAnother form of \fBfor\fP.
X.PP
X.PD 0
X.TP
X\fBselect\fP \fIname\fP [ \fBin\fP \fIword\fP ... ]
X.TP
X\fBdo\fP \fIlist\fP
X.TP
X\fBdone\fP
X.PD
XPrint the set of \fIword\fPs, each preceded by a number.
XIf the \fBin\fP \fIword\fP is omitted, use the positional parameters.
XThe \fBPROMPT3\fP prompt is printed and a line is read from standard
Xinput. If this line consists of the number of one of the listed
X\fIword\fPs, then the parameter \fIname\fP
Xis set to the \fIword\fP corresponding to this number.
XIf this line is empty, the selection list is printed again.
XOtherwise, the value of the parameter \fIname\fP is set to null.
XThe contents of the line read from standard input is saved
Xin the parameter \fBREPLY\fP. \fIlist\fP is executed
Xfor each selection until a break or end-of-file is encountered.
X.TP
X\fBselect\fP \fIname\fP [ \fBin\fP \fIword\fP ] ; \fIsublist\fP
XA short form of \fBselect\fP.
X.TP
X\fBcase\fP \fIword\fP \fBin\fP [ \fIpattern\fP ) \fIlist\fP ;; ] ... \fBesac\fP
XExecute the \fIlist\fP associated with the first \fIpattern\fP
Xthat matches \fIword\fP, if any. The form of the patterns
Xis the same as that used for filename generation. See
X\fIFilename Generation\fP below.
X.TP
X\fBcase\fP \fIword\fP \fB{\fP [ \fIpattern\fP ) \fIlist\fP ;; ] ... \fB}\fP
XAnother form of \fBcase\fP.
X.TP
X.PD 0
X\fBif\fP \fIlist\fP
X.TP
X\fBthen\fP \fIlist\fP
X.TP
X[ \fBelif\fP \fIlist\fP ; \fBthen\fP \fIlist\fP ] ...
X.TP
X[ \fBelse\fP \fIlist\fP ]
X.TP
X\fBfi\fP
X.PD
XThe \fBif\fP \fIlist\fP is executed, and,
Xif it returns a zero exit status,
Xthe \fBthen\fP \fIlist\fP is executed.
XOtherwise, the \fBelif\fP \fIlist\fP is
Xexecuted and, if its value is zero,
Xthe \fBthen\fP \fIlist\fP is executed.
XIf each \fBelif\fP \fIlist\fP returns
Xnonzero, the \fBelse\fP \fIlist\fP is executed.
X.TP
X\fBif (\fP \fIlist\fP \fB)\fP \fIsublist\fP
XA short form of \fBif\fP.
X.PP
X.PD 0
X.TP
X\fBif\fP \fB(\fP \fIlist\fP \fB) {\fP
X.TP
X\fIlist\fP
X.TP
X\fB} elif (\fP \fIlist\fP \fB) {\fP
X.TP
X\fIlist\fP
X.TP
X\fB} ... else {\fP
X.TP
X\fIlist\fP
X.TP
X\fB}\fP
X.PD
XAn alternate form of \fBif\fP.
X.TP
X.PD 0
X\fBwhile\fP \fIlist\fP
X.TP
X\fBdo\fP \fIlist\fP
X.TP
X\fBdone\fP
X.PD
XExecute the \fBdo\fP \fIlist\fP as long as the \fBwhile\fP \fIlist\fP
Xreturns a zero exit status.
X.PP
X.PD 0
X.TP
X\fBwhile (\fP \fIlist\fP \fB) {\fP
X.TP
X\fIlist\fP
X.TP
X\fB}\fP
X.PD
XAn alternate form of \fBwhile\fP.
X.TP
X.PD 0
X\fBuntil\fP \fIlist\fP
X.TP
X\fBdo\fP \fIlist\fP
X.TP
X\fBdone\fP
X.PD
XExecute the \fBdo\fP \fIlist\fP as long as \fBuntil\fP \fIlist\fP
Xreturns a nonzero exit status.
X.TP
X.PD 0
X\fBrepeat\fP \fIword\fP
X.TP
X\fBdo\fP \fIlist\fP
X.TP
X\fBdone\fP
X.PD
X\fIword\fP is expanded and treated as an arithmetic expression,
Xwhich must evaluate to a number \fIn\fP.
X\fIlist\fP is then executed \fBn\fP times.
X.TP
X\fBrepeat\fP \fIword\fP \fIsublist\fP
XThis is a short form of \fBrepeat\fP.
X.TP
X( \fIlist\fP )
XExecute \fIlist\fP in a subshell.
X.TP
X{ \fIlist\fP }
XExecute \fIlist\fP.
X.TP
X.PD 0
X\fBfunction\fP \fIword\fP [ (\|) ] ... { \fIlist\fP }
X.TP
X\fIword\fP ... (\|) { \fIlist\fP }
X.TP
X\fIword\fP ... (\|) \fIsublist\fP
X.PD
XDefine a function which is referenced by any one of \fIword\fP.
XNormally, only one \fIword\fP is provided; multiple \fIword\fPs
Xare usually only useful for setting traps.
XThe body of the function is the \fIlist\fP between
Xthe { and }.
XSee \fBFUNCTIONS\fP below.
X.TP
X\fBtime\fP [ \fIpipeline\fP ]
XThe \fIpipeline\fP is executed, and timing statistics are
Xreported on the standard error in the form specified
Xby the \fBTIMEFMT\fP parameter.
XIf \fIpipeline\fP is omitted, print statistics about the
Xshell process and its children.
X.TP
X[[ \fIexp\fP ]]
XEvaluates the conditional expression \fIexp\fP
Xand return a zero exit status if it is true.
XSee \fBConditional Expressions\fP below for a description
Xof \fIexp\fP.
X.SH "RESERVED WORDS"
XThe following words are recognized as reserved words when used
Xas the first word of a command
Xunless quoted or removed using the \fBunalias\fP builtin:
X.RS
X.PP
X\fBdo done esac then elif else fi for case
Xif while function repeat time until exec command
Xselect coproc noglob \- nocorrect foreach end\fP
X.RE
X.SH COMMENTS
XIn noninteractive shells, or in interactive shells with the
X\fBINTERACTIVE_COMMENTS\fP option set, a word beginning
Xwith the third character of the \fBHISTCHARS\fP parameter
X(`#' by default) causes that word and all the following
Xcharacters up to a newline to be ignored.
X.SH ALIASING
XEvery token in the shell input is checked to see if there
Xis an alias defined for it.
XIf so, it is replaced by the text of the alias if it is in command
Xposition (if it could be the first word of a simple command),
Xor if the alias is global.
XIf the text ends with a space, the next word in the shell input
Xis treated as though it were in command position for purposes of alias
Xexpansion.
XAn alias is defined using the \fBalias\fP builtin; global aliases
Xmay be defined using the \-\fBg\fP option to that bulitin.
X.PP
XAlias substitution is done on the shell input before any
Xother substitution except history substitution. Therefore,
Xif an alias is defined for the word \fBfoo\fP, alias substitution
Xmay be avoided by quoting part of the word, e.g. \fB\efoo\fP.
XBut there is nothing to prevent an alias being defined
Xfor \fB\efoo\fP as well.
X.SH QUOTING
XA character may be \fIquoted\fP (that is, made
Xto stand for itself) by preceding it with a \e\|.
X\e followed by a newline is ignored.
XAll characters enclosed between a pair of single quotes ('')
Xare quoted.
XA single quote cannot appear within single quotes.
XInside double quotes (""), parameter and command substitution
Xoccurs, and \e quotes the characters \e\|, `, ", and $.
X.SH EXPANSION
XExpansion is performed on the command line after it has been
Xparsed. The types of expansions performed are
X\fIfilename expansion\fP,
X\fIprocess substitution\fP,
X\fIparameter expansion\fP,
X\fIcommand substitution\fP,
X\fIarithmetic expansion\fP,
X\fIbrace expansion\fP,
Xand \fIfilename generation\fP.
X.SS Filename Expansion
XEach word is checked to see if it begins with an unquoted ~.
XIf it does, then the word up to a / is checked to see if it matches
Xthe name of a named directory. If so, then the ~ and the matched portion
Xare replaced with the value of the named directory.
XA ~ by itself or followed by a / is replaced by the value of the
X\fBHOME\fP parameter.
XA ~ followed by a + or a \- is replaced by the value of
X\fBPWD\fP or \fBOLDPWD\fP, respectively.
X.PP
XNamed directories are typically login directories for users on the system.
XThey may also be defined if the text after the ~ is the name
Xof a shell parameter whose value begins with a /.
XIn certain circumstances (in prompts, for instance), when the shell
Xprints a path, the path is checked to see if it has a named
Xdirectory as its prefix. If so, then the prefix portion
Xis replaced with a ~ followed by the name of the directory.
XThe longest match is preferred.
X.PP
XIf a word begins with an unquoted \fB=\fP and the
X\fBNO_EQUALS\fP option is not set,
Xthe remainder of the word is taken as the
Xname of a command or alias. If a command
Xexists by that name, the word is replaced
Xby the full pathname of the command.
XIf an alias exists by that name, the word
Xis replaced with the text of the alias.
XOtherwise the word is checked up to a /
Xto see if it is a number or a \-. If so,
Xthe matched portion is replaced with
Xthe \fIn\fPth directory in the directory stack,
Xwhere \fIn\fP is the number matched, or
Xthe last directory in the directory stack
Xif a \- is matched.
X.SS Process Substitution
XEach command argument of the form
X\fB<(\fIlist\^\fB)\fR
Xor
X\fB>(\fIlist\^\fB)\fR
Xor
X\fB=(\fIlist\^\fB)\fR
Xis subject to process substitution.
XIn the case of the
X.B <
Xor
X.B >
Xforms, the shell will run process
X.I list
Xasynchronously connected to a named pipe (FIFO).
XThe name of this pipe will become the argument to the command.
XIf the form with
X.B >
Xis selected then writing on this file will provide input for
X.IR list .
XIf
X.B <
Xis used,
Xthen the file passed as an argument will
Xbe a named pipe connected to the output of the
X.I list
Xprocess.
XFor example,
X.RS
X.PP
X\fBpaste <(cut \-f1\fP \fIfile1\fB) <(cut \-f3\fP \fIfile2\fB) | tee >(\fIprocess1\fB) >(\fIprocess2\fB)\fR >/dev/null
X.RE
X.PP
X.BR cut s
Xfields 1 and 3 from
Xthe files
X.I file1
Xand
X.I file2
Xrespectively,
X.BR paste s
Xthe results together, and sends it to the processes
X.I process1
Xand
X.IR process2 .
XNote that the file, which is passed as an argument to the command,
Xis a system
Xpipe
Xso programs that expect to
X.BR lseek (2)
Xon the file will not work.
XAlso note that the previous example can be more compactly and
Xefficiently written as:
X.RS
X.PP
X\fBpaste <(cut \-f1\fP \fIfile1\fB) <(cut \-f3\fP \fIfile2\fB) > >(\fIprocess1\fB) > >(\fIprocess2\fB)\fR
X.RE
X.PP
Xthe shell uses pipes instead of a FIFOs to implement the latter
Xtwo process substitutions in the above example.
X.PP
XIf
X.B =
Xis used,
Xthen the file passed as an argument will be the name
Xof a temporary file containing
Xthe output of the
X.I list
Xprocess. This may be used instead of the
X.B <
Xform for a program that expects to \fBlseek\fP(2) on the input file.
X.SS Parameter Expansion
XThe character \fB$\fP is used to introduce parameter expansions.
XSee \fBPARAMETERS\fP below for a description of parameters.
X.PD
X.RS
X.TP
X\fB${\fIname\fB}\fR
XThe value, if any, of the parameter \fIname\fP is substituted.
XThe braces are required with \fIname\fP is followed by
Xa letter, digit, or underscore that is not to be interpreted
Xas part of its name.
XIf \fIname\fP is an array parameter, then the values of each
Xelement of \fIname\fP is substituted, one element per word.
XOtherwise, the expansion results in one word only; no
Xword splitting is done on the result.
X.TP
X\fB${\fIname\fB:\-\fIword\fB}\fR
XIf \fIname\fP is set and is non-null then substitute its
Xvalue; otherwise substitute \fIword\fP.
X.TP
X\fB${\fIname\fB:=\fIword\fB}\fR
XIf \fIname\fP is unset and is null then
Xset it to \fIword\fP; the value of the parameter is then
Xsubstituted.
X.TP
X\fB${\fIname\fB:?\fIword\fB}\fR
XIf \fIname\fP is set and is non-null, then substitute
Xits value; otherwise, print \fIword\fP and exit from the shell.
XIf \fIword\fP is omitted, then a standard message is printed.
X.TP
X\fB${\fIname\fB:+\fIword\fB}\fR
XIf \fIname\fP is set and is non-null then substitute
X\fIword\fP; otherwise substitute nothing.
X.PD 0
X.TP
X\fB${\fIname\fB#\fIpattern\fB}\fR
X.TP
X\fB${\fIname\fB##\fIpattern\fB}\fR
X.PD
XIf the \fIpattern\fP matches the beginning of the value of
X\fIname\fP, then substitute the value of \fIname\fP with
Xthe matched portion deleted; otherwise, just
Xsubstitute the value of \fIname\fP. In the first
Xform, the smallest matching pattern is preferred;
Xin the second form, the largest matching pattern is preferred.
X.PD 0
X.TP
X${\fIname\fB%\fIpattern\fR}
X.TP
X${\fIname\fB%%\fIpattern\fR}
X.PD
XIf the \fIpattern\fP matches the end of the value of
X\fIname\fP, then substitute the value of \fIname\fP with
Xthe matched portion deleted; otherwise, just
Xsubstitute the value of \fIname\fP. In the first
Xform, the smallest matching pattern is preferred;
Xin the second form, the largest matching pattern is preferred.
X.TP
X${\fB#\fIspec\fR}
XIf \fIspec\fP is one of the above substitutions, substitute
Xthe length in characters of the result instead of
Xthe result itself. If \fIspec\fP is an array expression,
Xsubstitute the number of elements of the result.
X.TP
X${\fB^\fIspec\fR}
XToggle the value of the \fBRC_EXPAND_PARAM\fP option for the
Xevaluation of \fIspec\fP.
XWhen this option is set, array expansions of the form
X\fIfoo\fB${\fIxx\fB}\fIbar\fR, where the parameter
X\fIxx\fP is set to (\fIa b c\fP), are substituted with
X\fIfooabar foobbar foocbar\fP instead of the default
X\fIfooa b cbar\fP.
X.TP
X${\fB=\fIspec\fR}
XToggle the value of the \fBSH_WORD_SPLIT\fP option for the
Xevaluation of \fIspec\fP.
XWhen this option is set, parameter values are split into
Xseparate words using \fBIFS\fP as a delimiter
Xbefore substitution.
XThis is done by default in most other shells.
X.PD
X.RE
X.PP
XIf the colon is omitted from one of the above expressions
Xcontaining a colon, then the shell only checks whether
X\fIname\fP is set or not, not whether it is null.
X.SS Command Substitution
XA command enclosed in parentheses
Xpreceded by a dollar sign, like so: $(...) or quoted with grave
Xaccents: `...` is replaced with its standard output.
XIf the substitution is not enclosed in double quotes, the
Xoutput is broken into words using the \fBIFS\fP parameter.
XThe substitution \fB$(cat foo)\fP may be replaced
Xby the equivalent but faster \fB$(<foo)\fP.
X.SS Arithmetic Expansion
XA string of the form \fB$[\fIexp\fB]\fR is substituted
Xwith the value of the arithmetic expression \fIexp\fP.
X\fIexp\fP is treated as if it were within single quotes.
XSee \fBARITHMETIC EVALUATION\fP below.
X.SS Brace Expansion
XA string of the form
X\fIfoo\fB{\fIxx\fB,\fIyy\fB,\fIzz\fB}\fIbar\fR
Xis expanded to the individual words
X\fIfooxxbar\fP, \fIfooyybar\fP, and \fIfoozzbar\fP.
XLeft-to-right order is preserved. This construct
Xmay be nested. Malformed brace expansion expressions,
Xincluding expressions without a comma, are left unchanged
Xby the shell.
X.PP


XAn expression of the form

X\fB{\fIx\fB\-\fIy\fB}\fR,
Xwhere \fIx\fP and \fIy\fP are single characters,
Xis expanded to every character between
X\fIx\fP and \fIy\fP, inclusive.
X.SS Filename Generation
XIf a word contains an unquoted instance of one of the characters
X*, |, <, [, or ?, it is regarded
Xas a pattern for filename generation, unless the \fBNOGLOB\fP option is set.
XIf the \fBEXTENDED_GLOB\fP option is set, the
X^ and # characters also denote a pattern; otherwise
Xthey are not treated specially by the shell.
XThe word is replaced with a list of sorted filenames that match
Xthe pattern. If no matching pattern is found, the shell gives
Xan error message, unless the \fBNULLGLOB\fP option is set,
Xin which case the word is deleted; or unless the \fBNO_NOMATCH\fP
Xoption is set, in which case the word is left unchanged.
XIn filename generation,
Xthe character / must be matched explicitly; also, a . must be matched
Xexplicitly at the beginning of a pattern or after a /, unless the
X\fBGLOBDOTS\fP option is set. No filename generation pattern
Xmatches the files "." or "..". In other instances of pattern
Xmatching, the / and . are not treated specially.
X.PP
X.RS
X.PD 0
X.TP
X.B *
Xmatches any string, including the null string.
X.TP
X.B ?
Xmatches any character.
X.TP
X\fB[ ... ]\fP
Xmatches any of the enclosed characters.
X.TP
X\fB[^ ... ]\fP
Xmatches any character except the enclosed characters.
X.TP
X\fB<x\-y>\fP
Xmatches any number in the range x to y, inclusive.
XIf x is omitted, the number must be less than or equal to y.
XIf y is omitted, the number must be greater than or equal to x.
XA pattern of the form \fB<\->\fP or
Xsimply \fB<>\fP matches any number.
X.TP
X\fB^x\fP
Xmatches anything except the pattern x.
X.TP
X\fBx|y\fP
Xmatches either x or y.
X.TP
X\fBx#\fP
Xmatches zero or more occurrences of the pattern x.
X.TP
X\fBx##\fP
Xmatches one or more occurrences of the pattern x.
X.RE
X.PD
X.PP
XParentheses may be used for grouping. Note that the \fB|\fP character
Xmust be within parentheses, so that the lexical analyzer does
Xnot think it is a pipe character. Also note that "/" has a
Xhigher precedence than "^"; that is:
X.RS
X.PP
Xls
X.BI ^ foo / bar
X.RE
X.PP
Xwill search directories in "." except "./foo" for a file named bar.
X.PP
XA pathname component of the form
X.BI ( foo /)#
Xmatches a path consisting of zero or more directories
Xmatching the pattern foo.
XAs a shorthand,
X.B **/
Xis equivalent to
X.BR (*/)# .
XThus:
X.RS
X.PP
Xls
X.BI (*/)# bar
X.RE
X.PP
Xor
X.RS
X.PP
Xls
X.BI **/ bar
X.RE
X.PP
Xdoes a recursive directory search for files named bar.
X.PP
XIf used for filename generation, a pattern may contain an exclusion
Xspecifier. Such patterns are of the form \fIpat1\fB~\fIpat2\fR.
XThis pattern will generate all files matching \fIpat1\fP, but which
Xdo not match \fIpat2\fP. For example, \fB*.c~lex.c\fP will match
Xall files ending in .c, except the file \fBlex.c\fP.
X.PP
XPatterns used for filename generation may also end in a
Xlist of qualifiers enclosed in parentheses.
XThe qualifiers
Xspecify which filenames that otherwise match the given pattern
Xwill be inserted in the argument list.
XA qualifier may be any one of the following:
X.PD 0
X.RS
X.TP
X.B /
Xdirectories
X.TP
X.B .
Xplain files
X.TP
X.B @
Xsymbolic links
X.TP
X.B =
Xsockets
X.TP
X.B p
Xnamed pipes (FIFOs)
X.TP
X.B *
Xexecutable plain files (0100)
X.TP
X.B %
Xdevice files (character or block special)
X.TP
X.B r
Xreadable files (0400)
X.TP
X.B w
Xwritable files (0200)
X.TP
X.B x
Xexecutable files (0100)
X.TP
X.B R
Xworld-readable files (0004)
X.TP
X.B W
Xworld-writable files (0002)
X.TP
X.B X
Xworld-executable files (0001)
X.TP
X.B s
Xsetuid files (04000)
X.TP
X.B S
Xsetgid files (02000)
X.TP
X\fBd\fIdev\fR
Xfiles on the device \fIdev\fP
X.TP
X\fBl\fIct\fR
Xfiles having a link count of \fIct\fP
X.TP
X\fBU\fP
Xfiles owned by the effective user id
X.TP
X\fBG\fP
Xfiles owned by the effective group id
X.TP
X\fBu\fInum\fR
Xfiles owned by user id \fInum\fP
X.TP
X\fBg\fInum\fR
Xfiles owned by group id \fInum\fP
X.TP
X\fB^\fP
Xnegates all qualifiers following it
X.TP
X\fBM\fP
Xsets the \fBMARKDIRS\fP option for the current pattern
X.TP
X\fBN\fP
Xsets the \fBNULLGLOB\fP option for the current pattern
X.TP
X\fBD\fP
Xsets the \fBGLOBDOTS\fP option for the current pattern
X.PD
X.RE
X.PP
XThus:
X.RS
X.PP
Xls
X.B
X*(%W)
X.RE
X.PP
Xlists all world-writable device files in the current directory,
Xand
X.RS
X.PP
Xls
X.B /tmp/foo*(u0^@)
X.RE
X.PP
Xlists all root-owned files beginning with the string
X"foo" in /tmp, ignoring symlinks, and
X.RS
X.PP
Xls
X.B *.*~(lex|parse).[ch](^D^l1)
X.RE
X.PP
Xlists all files having a link count of one whose names contain a dot
X(but not those starting with a dot, since \fBGLOBDOTS\fP is explicitly
Xswitched off) except for lex.c, lex.h, parse.c, and parse.h.
XA "/" at the end of a pattern
Xis equivalent to "(\|/\|)".
X.SH REDIRECTION
XBefore a command is executed, its input and output
Xmay be redirected.
XThe following may appear anywhere in a simple-command
Xor may precede or follow a complex command.
XSubstitution occurs before
X.I word
Xis used except as noted below.
XIf the result of substitution on
X.I word
Xproduces more than one filename,
Xredirection occurs for each
Xseparate filename in turn.
X.TP
X.BI < word
XOpen file
X.I word
Xas standard input.
X.TP
X.BI > word
XOpen file
X.I word
Xas standard output.
XIf the file does not exist then it is created.
XIf the file exists, and the
X.B NOCLOBBER
Xoption is set,
Xthis causes an error;
Xotherwise, it is truncated to zero length.
X.TP
X.BI >! " word"
XSame as
X.BR > ,
Xexcept that the file is truncated to zero length
Xif it exists, even if
X.B NOCLOBBER
Xis set.
X.TP
X.BI >> word
XOpen file
X.I word
Xas standard output.
XIf the file exists then output is appended to it.
XIf the file does not exist, and the
X.B NOCLOBBER
Xoption is set,
Xthis causes an error;
Xotherwise, the file is created.
X.TP
X.BI >>! " word"
XSame as
X.BR >> ,
Xexcept that the file is created if it does not
Xexist, even if
X.B NOCLOBBER
Xis set.
X.TP
X\fB<<\fP[\-] \fIword\fP
XThe shell input is read up to a line that is the same as
X.IR word ,
Xor to an end-of-file.
XNo parameter substitution, command substitution or
Xfilename generation is performed on
X.IR word .
XThe resulting document,
Xcalled a
X.IR here-document ,
Xbecomes
Xthe standard input.
XIf any character of \fIword\fP is quoted with
Xsingle or double quotes (a \e alone is \fInot\fP sufficient),
Xno interpretation
Xis placed upon the characters of the document.
XOtherwise, parameter and command substitution
Xoccurs, \e followed by a newline is removed,
Xand \e must be used to quote the characters
X\e, $, `, and the first character of \fIword\fP.
XIf <<\- is used, then all leading
Xtabs are stripped from \fIword\fP and from the document.
X.TP
X.BI <<< word
XOpen a file containing \fIword\fP, after expansion,
Xas standard input.
X.TP
X.BI <& digit
XThe standard input
Xis duplicated from file descriptor
X.I digit
X(see
X.IR dup (2)).
XSimilarly for standard output using
X\fB>&\fIdigit\fP.
X.TP
X.BI >& word
XSame as
X.BI > word
X\fB2>&\fP1.
X.TP
X.BI >>& word
XSame as
X.BI >> word
X\fB2>&\fP1.
X.TP
X.BI <&\-
XClose the standard input.
X.TP
X.BI >&\-
XClose the standard output.
X.TP
X.BI <&p
XThe input from the coprocess is moved to the standard input.
X.TP
X.BI >&p
XThe output to the coprocess is moved to the standard output.
X.PP
XIf one of the above is preceded by a digit, then the file
Xdescriptor referred to is that specified by the digit
X(instead of the default 0 or 1).
XThe order in which redirections are specified is significant.
Xthe shell evaluates each redirection in terms of the
X.RI ( "file descriptor" ", " file )
Xassociation at the time of evaluation.
XFor example:
X.RS
X.PP
X\&.\|.\|. \|1>\fIfname\^\fP 2>&1
X.RE
X.PP
Xfirst associates file descriptor 1 with file
X.IR fname .
XIt then associates file descriptor 2 with the file associated with file
Xdescriptor 1 (that is,
X.IR fname ).
XIf the order of redirections were reversed, file descriptor 2 would be associated
Xwith the terminal (assuming file descriptor 1 had been) and then file descriptor
X1 would be associated with file
X.IR fname .
X.PP
XIf the user tries to open a file descriptor for writing more than once,
Xthe shell opens the file descriptor as a pipe to a process that copies
Xits input to all the specified outputs, similar to tee(1). Thus:
X.RS
X.PP
X.B date >foo >bar
X.RE
X.PP
Xwrites the date to two files, named "foo" and "bar".
XNote that a pipe is an implicit indirection; thus
X.RS
X.PP
X.B date >foo | cat
X.RE
X.PP
Xwrites the date to the file "foo", and also pipes it to cat.
X.PP
XIf the user tries to open a file descriptor for reading more than once,
Xthe shell opens the file descriptor as a pipe to a process that copies
Xall the specified inputs to its output in the order
Xspecified, similar to cat(1). Thus
X.RS
X.PP
X.B sort <foo <fubar
X.RE
X.PP
Xor even
X.RS
X.PP
X.B sort <f{oo,ubar}
X.RE
X.PP
Xis equivalent to "cat foo bar | sort". Note that
Xa pipe is in implicit indirection; thus
X.RS
X.PP
X.B cat bar | sort <foo
X.RE
X.PP
Xis equivalent to "cat bar foo | sort" (note the order of the inputs).
X.PP
XIf a simple command consists of one or more redirection operators
Xand zero or more parameter assignments, but no command name,
Xthe command \fBcat\fP is assumed. Thus
X.RS
X.PP
X.B < file
X.RE
X.PP
Xprints the contents of \fBfile\fP.
X.PP
XIf a command is followed by
X.B &
Xand job control is not active,
Xthen the default standard input
Xfor the command
Xis the empty file
X.BR /dev/null .
XOtherwise, the environment for the execution of a command contains the
Xfile descriptors of the invoking shell as modified by
Xinput/output specifications.
X.SH "COMMAND EXECUTION"
XIf a command name contains no slashes, the shell attempts to locate
Xit. If there exists a shell function by that name, the function
Xis invoked as described below in \fBFUNCTIONS\fP. If there exists
Xa shell builtin by that name, the builtin is invoked.
X.PP
XOtherwise, the shell searches each element of \fBpath\fP for a
Xdirectory containing an executable file by that name. If the
Xsearch is unsuccessful, the shell prints an error message and returns
Xa nonzero exit status.
X.PP
XIf execution fails because the file is not in executable format,
Xand the file is not a directory, it is assumed to be a shell
Xscript. /bin/sh is spawned to execute it. If the program
Xis a file beginning with \fB#!\fP, the remainder of the first line
Xspecifies an interpreter for the program. The shell will
Xexecute the specified interpreter on operating systems that do
Xnot handle this executable format in the kernel.
X.SH FUNCTIONS
X.PP
XThe
X.B function
Xreserved word is used to define shell functions.
XShell functions are read in and stored internally.
XAlias names are resolved when the function is read.
XFunctions are executed like commands with the arguments
Xpassed as positional parameters.
X(See
X.I Execution
Xbelow).
X.PP
XFunctions execute in the same process as the caller and
Xshare all files
Xand present working directory with the
Xcaller.
XA trap on
X.B EXIT
Xset inside a function
Xis executed after the function completes in the environment
Xof the caller.
X.PP
XThe
X.B return
Xbuiltin is used to return
Xfrom function calls.
X.PP
XFunction identifiers
Xcan be listed with the
X.B functions
Xbuiltin.
XFunctions can be undefined with the
X.B unfunction
Xbuiltin.
X.PP
XThe following functions, if defined, have special meaning to
Xthe shell:
X.PP
X.PD 0
X.TP
X\fBchpwd\fP
XExecuted whenever the current working directory is changed.
X.TP
X\fBprecmd\fP
XExecuted before each prompt.
X.TP
X\fBperiodic\fP
XIf the parameter
X.B PERIOD
Xis set, this function is executed every
X.B PERIOD
Xseconds, just before a prompt.
X.TP
X\fBTRAPxxx\fP
XIf defined and non-null,
Xthis function will be executed whenever the shell
Xcatches a signal \fBSIGxxx\fP, where \fBxxx\fP is a signal
Xname as specified for the \fBkill\fP builtin (see below).
XIn addition, \fBTRAPERR\fP is executed whenever a command has a non-zero
Xexit status, \fBTRAPDEBUG\fP is executed after each command, and
X\fBTRAPEXIT\fP
Xis executed when the shell exits,
Xor when the current function exits if defined
Xinside a function.
XIf a function of this form is defined and null,
Xthe shell and processes spawned by it will ignore \fBSIGxxx\fP.
X.PD
X.SH JOBS
X.PP
XIf the
X.B MONITOR
Xoption is set,
Xan interactive shell associates a \fIjob\fR with each pipeline.
XIt keeps
Xa table of current jobs, printed by the
X.B jobs
Xcommand, and assigns them small integer numbers.
XWhen a job is started asynchronously with
X.BR & ,
Xthe shell prints a line which looks
Xlike:
X.PP
X.DT
X [1] 1234
X.PP
Xindicating that the job which was started asynchronously was job number
X1 and had one (top-level) process, whose process id was 1234.
X.PP
XIf you are running a job and wish to do something else you may hit the key
X\fB^Z\fR (control-Z) which sends a STOP signal to the current job.
Xthe shell will then normally indicate that the job has been `suspended',
Xand print another prompt.
XYou can then manipulate the state of this job,
Xputting it in the background with the
X.B bg
Xcommand, or run some other
Xcommands and then eventually bring the job back into the foreground with
Xthe foreground command
X.BR fg .
XA \fB^Z\fR takes effect immediately and
Xis like an interrupt in that pending output and unread input are discarded
Xwhen it is typed.
X.PP
XA job being run in the background will suspend if it tries to read
Xfrom the terminal.
XBackground jobs are normally allowed to produce output,
Xbut this can be disabled by giving the command ``stty tostop''.
XIf you set this
Xtty option, then background jobs will suspend when they try to produce
Xoutput like they do when they try to read input.
X.PP
XThere are several ways to refer to jobs in the shell.
XA job can be referred to by the process id of any process of the job
Xor by one of the following:
X.PD 0
X.TP
X.BI % number
XThe job with the given number.
X.TP
X.BI % string
XAny job whose command line begins with
X.IR string .
X.TP
X.BI %? string
XAny job whose command line contains
X.IR string .
X.TP
X.BI %%
XCurrent job.
X.TP
X.BI %+
XEquivalent to
X.BR %% .
X.TP
X.BI %\-
XPrevious job.
X.PD
X.PP
XThe shell learns immediately whenever a process changes state.
XIt normally informs you whenever a job becomes blocked so that
Xno further progress is possible. If
X.B notify
Xis not set, it waits until
Xjust before it prints
Xa prompt before it informs you.
X.PP
XWhen the monitor mode is on, each background job that completes
Xtriggers any trap set for
X.BR CHLD .
X.PP
XWhen you try to leave the shell while jobs are running or suspended, you will
Xbe warned that `You have suspended (running) jobs.'
XYou may use the
X.B jobs
Xcommand to see what they are.
XIf you do this or immediately try to
Xexit again, the shell will not warn you a second time; the suspended
Xjobs will be terminated, and the running jobs will be sent
Xa \fBSIGHUP\fP signal.
XTo avoid having the shell terminate the running jobs, either
Xuse the \fBnohup\fP(1) command or the \fBdisown\fP builtin (see below).
X.SH SIGNALS
XThe INT and QUIT signals for an invoked
Xcommand are ignored if the command is followed by
X.B &
Xand job
X.B monitor
Xoption is not active.
XOtherwise, signals have the values
Xinherited by the shell from its parent
X(but see the \fBTRAPxxx\fP special function above).
X.SH HISTORY
XHistory substitution allows you to use words from previous command
Xlines in the command line you are typing. This simplifies spelling
Xcorrections and the repetition of complicated commands or arguments.
XCommand lines are saved in the history list, the size of which
Xis controlled by the
X.B HISTSIZE
Xvariable. The most recent command is retained in any case.
XA history substitution begins with a
X.B !
Xand may occur anywhere on the command line; history
Xsubstitutions do not nest. The
X.B !
Xcan be escaped with
X.B \e
Xto suppress its special meaning.
XSingle or double quotes will \fInot\fP work for this.
X.PP
XInput lines containing history substitutions are echoed on the
Xterminal after being expanded, but before any other
Xsubstitutions take place or the command gets executed.
X.SS Event Designators
X.PP
XAn event designator is a reference to a command-line entry in
Xthe history list.
X.RS
X.PD 0
X.TP
X.B !
XStart a history substitution, except when followed by a blank, newline,
X.BR = ,
Xor
X.BR ( .
X.TP
X.B !!
XRefer to the previous command.
XBy itself, this substitution
Xrepeats the previous command.
X.TP
X.BI ! n
XRefer to command-line
X.IR n .
X.TP
X.BI ! \-n
XRefer to the current command-line minus
X.IR n .
X.TP
X.BI ! str
XRefer to the most recent command starting with
X.IR str .
X.TP
X.BI !? str\fR[\fP ? \fR]\fP
XRefer to the most recent command containing
X.IR str .
X.TP
X.B !#
XRefer to the current command line typed in so far.
X.TP
X.BR !{ .\|.\|. }
XInsulate a history reference from adjacent characters (if necessary).
X.PD
X.RE
X.SS Word Designators
X.PP
XA
X.RB ` : '
Xseparates the event specification from the word designator.
XIt can be omitted if the word designator begins with a
X.BR \*^ ,
X.BR $ ,
X.BR * ,
X.B \-
Xor
X.BR % .
XIf the word is to be selected from the previous command, the second
X.B !
Xcharacter can be omitted from the event specification. For instance,
X.B !!:1
Xand
X.B !:1
Xboth refer to the first word of the previous command, while
X.B !!$
Xand
X.B !$
Xboth refer to the last word in the previous command.
XWord designators include:
X.RS
X.PD 0
X.TP
X.B 0
XThe first input word (command).
X.TP
X.I n
XThe
X.IR n 'th
Xargument.
X.TP
X.B ^
XThe first argument, that is,
X.BR 1 .
X.TP
X.B $
XThe last argument.
X.TP
X.B %
XThe word matched by (the most recent)
X.BI ? s
Xsearch.
X.TP
X.IB x \- y
XA range of words;
X.BI \- y
Xabbreviates
X.BI 0\- y\fR.
X.TP
X.B *
XAll the arguments, or a null value if there is just
Xone word in the event.
X.TP
X.IB x *
XAbbreviates
X.IB x \-$ .
X.TP
X.IB x \-
XLike
X.I x*
Xbut omitting word
X.BR $ .
X.PD
X.RE
X.SS Modifiers
X.PP
XAfter the optional word designator, you can add
Xa sequence of one or more of the following modifiers,
Xeach preceded by a
X.BR : .
XThese modifiers also work on the result
Xof filename and parameter expansion.
X.RS
X.TP
X.B h
XRemove a trailing pathname component, leaving the head.
X.PD 0
X.TP
X.B r
XRemove a trailing suffix of the form
X.RB ` "\&.\fIxxx" ',
Xleaving the basename.
X.TP
X.B e
XRemove all but the suffix.
X.TP
X.B t
XRemove all leading pathname components, leaving the tail.
X.TP
X.B &
XRepeat the previous substitution.
X.TP
X.B g
XApply the change to the first occurrence of a match in each word,
Xby prefixing the above (for example,
X.BR g& ).
X.TP
X.B p
XPrint the new command but do not execute it.
X.TP
X.B q
XQuote the substituted words, escaping further substitutions.
X.TP
X.B x
XLike
X.BR q ,
Xbut break into words at each blank.
X.TP
X.B l
XConvert the words to all lowercase.
X.TP
X.B u
XConvert the words to all uppercase.
X.TP
X.BI s/ l / r\fR[\fP / \fR]\fP
XSubstitute
X.I r
Xfor
X.IR l .
X.PD
X.RE
X.PP
XUnless preceded by a
X.BR g ,
Xthe substitution is done only for the
Xfirst string that matches
X.IR l .
X.PP
XThe left-hand side of substitutions are not regular expressions,
Xbut character strings.
XAny character can be used as the delimiter in place of
X.BR / .
XA backslash quotes the delimiter character.
XThe character
X.BR & ,
Xin the right hand side, is replaced by the text
Xfrom the left-hand-side.
XThe
X.B &
Xcan be quoted with a backslash.
XA null
X.I l
Xuses the previous string either from a
X.I l
Xor from a contextual scan string
X.I s
Xfrom
X.BI !? s\fR.
XYou can omit the rightmost delimiter if a newline
Ximmediately follows
X.IR r ;
Xthe rightmost
X.B ?
Xin a context scan can similarly be omitted.
X.PP
XWithout an event specification, a history reference refers either to the
Xprevious command, or to a previous history reference on the command line
X(if any).
X.PP
XThe character sequence
X.BI ^ foo ^ bar
Xrepeats the last command, replacing the string "foo" with the
Xstring "bar".
X.PP
XIf the shell encounters the character sequence
X\fB!"\fP
Xin the input, the history mechanism is temporarily disabled until
Xthe current list is fully parsed. The
X\fB!"\fP
Xis removed from the input, and any subsequent
X.B !
Xcharacters have no special significance.
X.PP
XA less convenient but more comprehensible
Xform of command history support
Xis provided by the
X.B fc
Xbuiltin (see below).
X.SH "ARITHMETIC EVALUATION"
XAn ability to perform integer arithmetic
Xis provided with the builtin
X.BR let .
XEvaluations are performed using
X.I long
Xarithmetic.
XConstants are of the form
X[\fIbase\fB#\^\fR]\fIn\^\fP
Xwhere
X.I base
Xis a decimal number between two and thirty-six
Xrepresenting the arithmetic base
Xand
X.I n
Xis a number in that base.
XIf
X.I base
Xis omitted
Xthen base 10 is used.
X.PP
XAn arithmetic expression uses nearly the same syntax, precedence, and
Xassociativity of
Xexpressions in C.
XThe following operators are supported (listed in decreasing order
Xof precedence):
X.PP
X.PD 0
X.RS
X.TP
X.B + \- ! \(ap ++ \-\|\-
Xunary plus/minus, logical NOT, complement, {pre,post}{in,de}crement
X.TP
X.B &
Xlogical AND
X.TP
X.B ^
Xlogical XOR
X.TP
X.B |
Xlogical OR
X.TP
X.B * / %
Xmultiplication, division, remainder
X.TP
X.B + \-
Xaddition, subtraction
X.TP
X.B << >>
Xlogical shift left, shift right
X.TP
X.B < > <= >=
Xcomparison
X.TP
X.B == !=
Xequality and inequality
X.TP
X.B &&
Xboolean AND
X.TP
X.B |\|| ^^
Xboolean OR, XOR
X.TP
X.B ? :
Xternary operator
X.TP
X.B
X= += \-= *= /= %= &= ^= |= <<= >>= &&= |\||= ^^=
Xassignment
X.TP
X.B ,
Xcomma operator
X.PD
X.RE
X.PP
XThe operators &&, |\||, &&=, and |\||= are short-circuiting,
Xand only one of the latter two expressions in a ternary operator
Xis evaluated. Note the precedence of the logical AND, OR,
Xand XOR operators.
X.PP
XNamed parameters can be referenced by name within an arithmetic expression
Xwithout using the parameter substitution syntax.
X.PP
XAn internal integer representation of a named parameter
Xcan be specified with the
X.B integer
Xbuiltin.
XArithmetic evaluation is performed on the value of each
Xassignment to a named parameter declared integer
Xin this manner.
X.PP
XSince many of the arithmetic operators require
Xquoting, an alternative form of the
X.B let
Xcommand is provided.
XFor any command which begins with a
X.BR (( ,
Xall the characters until a matching
X.B ))
Xare treated as a quoted expression.
XMore precisely,
X.BR (( ... ))
Xis equivalent to
X.B let
X\fB"\fP...\fB"\fP.
X.SH "CONDITIONAL EXPRESSIONS"
XA \fIconditional expression\fP is used with the
X.B [[
Xcompound command to test attributes of files and to compare strings.
XEach expression can be constructed from one or more
Xof the following unary or binary expressions:
X.PD 0
X.TP
X\fB\-a\fP \fIfile\fP
Xtrue if
X.I file
Xexists.
X.TP
X\fB\-b\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a block special file.
X.TP
X\fB\-c\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a character special file.
X.TP
X\fB\-d\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a directory.
X.TP
X\fB\-e\fP \fIfile\fP
Xtrue if
X.I file
Xexists.
X.TP
X\fB\-f\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is an ordinary file.
X.TP
X\fB\-g\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is has its setgid bit set.
X.TP
X\fB\-h\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a symbolic link.
X.TP
X\fB\-k\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is has its sticky bit set.
X.TP
X\fB\-n\fP \fIstring\fP
Xtrue if length of
X.I string
Xis non-zero.
X.TP
X\fB\-o\fP \fIoption\fP
Xtrue if option named
X.I option
Xis on.
X.TP
X\fB\-p\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a fifo special file or a pipe.
X.TP
X\fB\-r\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is readable by current process.
X.TP
X\fB\-s\fP \fIfile\fP
Xtrue if
X.I file
Xexists and has size greater than zero.
X.TP
X\fB\-t\fP \fIfd\fP
Xtrue if file descriptor number
X.I fd
Xis open and associated with a terminal device.
X(note: \fIfd\fP is not optional)
X.TP
X\fB\-u\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is has its setuid bit set.
X.TP
X\fB\-w\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is writable by current process.
X.TP
X\fB\-x\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is executable by current process.
XIf
X.I file
Xexists and is a directory, then the current process
Xhas permission to search in the directory.
X.TP
X\fB\-z\fP \fIstring\fP
Xtrue if length of
X.I string
Xis zero.
X.TP
X\fB\-L\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a symbolic link.
X.TP
X\fB\-O\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is owned by the effective user id of this process.
X.TP
X\fB\-G\fP \fIfile\fP
Xtrue if
X.I file
Xexists and its group matches the effective group id of this process.
X.TP
X\fB\-S\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a socket.
X.TP
X\fIfile1\fP \fB\-nt\fP \fIfile2\fP
Xtrue if
X.I file1
Xexists and is newer than
X.IR file2 .
X.TP
X\fIfile1\fP \fB\-ot\fP \fIfile2\fP
Xtrue if
X.I file1
Xexists and is older than
X.IR file2 .
X.TP
X\fIfile1\fP \fB\-ef\fP \fIfile2\fP
Xtrue if
X.I file1
Xand
X.I file2
Xexist and refer to the same file.
X.TP
X\fIstring\fP \fB=\fP \fIpattern\fP
Xtrue if
X.I string
Xmatches
X.IR pattern .
X.TP
X\fIstring\fP \fB!=\fP \fIpattern\fP
Xtrue if
X.I string
Xdoes not match
X.IR pattern .
X.TP
X\fIstring1\fP \fB<\fP \fIstring2\fP
Xtrue if
X.I string1
Xcomes before
X.I string2
Xbased on ASCII value of their characters.
X.TP
X\fIstring1\fP \fB>\fP \fIstring2\fP
Xtrue if
X.I string1
Xcomes after
X.I string2
Xbased on ASCII value of their characters.
X.TP
X\fIexp1\fP \fB\-eq\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis equal to
X.IR exp2.
X.TP
X\fIexp1\fP \fB\-ne\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis not equal to
X.IR exp2.
X.TP
X\fIexp1\fP \fB\-lt\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis less than
X.IR exp2.
X.TP
X\fIexp1\fP \fB\-gt\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis greater than
X.IR exp2.
X.TP
X\fIexp1\fP \fB\-le\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis less than or equal to
X.IR exp2.
X.TP
X\fIexp1\fP \fB\-ge\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis greater than or equal to
X.IR exp2.
X.TP
X\fB(\fP \fIexp\fP \fB)\fP
Xtrue if \fIexp\fP is true.
X.TP
X\fB!\fP \fIexp\fP
Xtrue if \fIexp\fP is false.
X.TP
X\fIexp1\fP \fB&&\fP \fIexp2\fP
Xtrue if \fIexp1\fP and \fIexp2\fP are both true.
X.TP
X\fIexp1\fP \fB|\||\fP \fIexp2\fP
Xtrue if either \fIexp1\fP or \fIexp2\fP is true.
X.PD
X.PP
XIn each of the above expressions, if
X.I file
Xis of the form
X\fB/dev/fd/\fP\fIn\fR,
Xwhere
X.I n
Xis an integer,
Xthen the test applied to the open file whose
Xdescriptor number is
X.IR n ,
Xeven if the underlying system does not support
Xthe \fB/dev/fd\fP directory.
X.PD
X.SH "ZSH LINE EDITOR"
XIf the \fBZLE\fP option is set (it is by default)
Xand the shell input is attached to the terminal, the user
Xis allowed to edit command lines.
X.PP
XThere are two display modes. The first, multiline mode, is the default.
XIt only works if the \fBTERM\fP parameter is set to a valid
Xterminal type that can move the cursor up. The second,
Xsingle line mode, is used if \fBTERM\fP is invalid or incapable
Xof moving the cursor up, or if the \fBSINGLE_LINE_ZLE\fP
Xoption is set. This mode is similar to ksh, and uses no
Xtermcap sequences.
X.SS Bindings
XCommand bindings may be set using the \fBbindkey\fP builtin.
XThere are two keymaps\-the main keymap and the alternate keymap.
XThe alternate keymap is bound to vi command mode.
XThe main keymap is bound to emacs mode by default.
XTo bind the main keymap to vi insert mode, use
X\fBbindkey \-v\fP, or set one of the \fBVISUAL\fP or \fBEDITOR\fP
Xenvironment variables to a string containing \fBvi\fP.
X.PP
XThe following is a list of all the key commands
Xand their default bindings in emacs and vi command mode.
X.SS Movement
X.TP
X\fBvi-backward-blank-word\fP (unbound) (B)
XMove backward one word, where a word is defined as a series of
Xnon-blank characters.
X.TP
X\fBbackward-char\fP (^B ESC-[D) (\|)
XMove backward one character.
X.TP
X\fBvi-backward-char\fP (\|) (h)
XMove backward one character, without changing lines.
X.TP
X\fBbackward-word\fP (ESC-B ESC-b) (unbound)
XMove to the beginning of the previous word.
X.TP
X\fBemacs-backward-word\fP
XMove to the beginning of the previous word.
X.TP
X\fBvi-backward-word\fP (unbound) (b)
XMove to the beginning of the previous word, vi-style.
X.TP
X\fBbeginning-of-line\fP (^A) (0)
XMove to the beginning of the line. If already at the beginning
Xof the line, move to the beginning of the previous line, if any.
X.TP
X\fBvi-beginning-of-line\fP
XMove to the beginning of the line, without changing lines.
X.TP
X\fBend-of-line\fP (^E)
XMove to the end of the line. If already at the end
Xof the line, move to the end of the next line, if any.
X.TP
X\fBvi-end-of-line\fP (unbound) ($)
XMove to the end of the line.
X.TP
X\fBvi-forward-blank-word\fP (unbound) (W)
XMove forward one word, where a word is defined as a series of
Xnon-blank characters.
X.TP
X\fBvi-forward-blank-word-end\fP (unbound) (E)
XMove to the end of the current word,
Xor, if at the end of the current word,
Xto the end of the next word,
Xwhere a word is defined as a series of
Xnon-blank characters.
X.TP
X\fBforward-char\fP (^F ESC-[C)
XMove forward one character.
X.TP
X\fBvi-forward-char\fP (unbound) (space l)
XMove forward one character.
X.TP
X\fBvi-find-next-char\fP (^X^F) (f)
XRead a character from the keyboard, and move to
Xthe next occurrence of it in the line.
X.TP
X\fBvi-find-next-char-skip\fP (unbound) (t)
SHAR_EOF
true || echo 'restore of zsh2.2/man/man1/zsh.1 failed'
fi
echo 'End of zsh2.2 part 3'
echo 'File zsh2.2/man/man1/zsh.1 is continued in part 4'
echo 4 > _shar_seq_.tmp

Paul Falstad

unread,
May 13, 1992, 11:55:49 AM5/13/92
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 29, Issue 100
Archive-name: zsh2.2/part04

Environment: BSD
Supersedes: zsh2.1: Volume 24, Issue 1-19

#!/bin/sh
# this is aa.04 (part 4 of zsh2.2)


# do not concatenate these parts, unpack them in order with /bin/sh

# file zsh2.2/man/man1/zsh.1 continued


#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 4; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then

echo 'x - still skipping zsh2.2/man/man1/zsh.1'
else
echo 'x - continuing file zsh2.2/man/man1/zsh.1'


sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.2/man/man1/zsh.1' &&

XRead a character from the keyboard, and move to

Xthe position just before the next occurrence of it in the line.
X.TP
X\fBvi-find-prev-char\fP (unbound) (F)


XRead a character from the keyboard, and move to

Xthe previous occurrence of it in the line.
X.TP
X\fBvi-find-prev-char-skip\fP (unbound) (T)


XRead a character from the keyboard, and move to

Xthe position just after the previous occurrence of it in the line.
X.TP
X\fBvi-first-non-blank\fP (unbound) (^)
XMove to the first non-blank character in the line.
X.TP
X\fBvi-forward-word\fP (unbound) (w)
XMove forward one word, vi-style.
X.TP
X\fBforward-word\fP (ESC-F ESC-f) (unbound)
XMove to the beginning of the next word.
XThe editor's idea of a word is specified with the \fBWORDCHARS\fP
Xparameter.
X.TP
X\fBemacs-forward-word\fP
XMove to the end of the next word.
X.TP
X\fBvi-forward-word-end\fP (unbound) (e)
XMove to the end of the next word.
X.TP
X\fBvi-goto-column\fP (ESC-|) (|)
XMove to the column specified by the numeric argument.
X.TP
X\fBvi-goto-mark\fP (unbound) (`)
XMove to the specified mark.
X.TP
X\fBvi-goto-mark-line\fP (unbound) (')
XMove to beginning of the line containing the specified mark.
X.TP
X\fBvi-repeat-find\fP (unbound) (;)
XRepeat the last \fBvi-find\fP command.
X.TP
X\fBvi-rev-repeat-find\fP (unbound) (,)
XRepeat the last \fBvi-find\fP command in the opposite direction.
X.SS History
X.TP
X\fBbeginning-of-buffer-or-history\fP (ESC-<)
XMove to the beginning of the buffer, or if already there,
Xmove to the first event in the history list.
X.TP
X\fBbeginning-of-line-hist\fP


XMove to the beginning of the line. If already at the

Xbeginning of the buffer, move to the previous history line.
X.TP
X\fBbeginning-of-history\fP
XMove to the first event in the history list.
X.TP
X\fBdown-line-or-history\fP (^N ESC-[B) (+ j)
XMove down a line in the buffer, or if already at the bottom line,
Xmove to the next event in the history list.
X.TP
X\fBdown-history\fP (unbound) (^N)
XMove to the next event in the history list.
X.TP
X\fBend-of-buffer-or-history\fP (ESC->)
XMove to the end of the buffer, or if already there,
Xmove to the last event in the history list.
X.TP
X\fBend-of-line-hist\fP
XMove to the end of the line. If already at the end of
Xthe buffer, move to the next history line.
X.TP
X\fBend-of-history\fP
XMove to the last event in the history list.
X.TP
X\fBvi-fetch-history\fP (unbound) (G)
XFetch the history line specified by the numeric argument.
X.TP
X\fBhistory-incremental-search-backward\fP (^R ^Xr)
XSearch backward incrementally for a specified string.
XThe string may begin with `^' to anchor the search to the
Xbeginning of the line.
X.TP
X\fBhistory-incremental-search-forward\fP (^Xs)
XSearch forward incrementally for a specified string.
XThe string may begin with `^' to anchor the search to the
Xbeginning of the line.
X.TP
X\fBhistory-search-backward\fP (ESC-P ESC-p) (K)
XSearch backward in the history for a line beginning with the first
Xword in the buffer.
X.TP
X\fBvi-history-search-backward\fP (unbound) (/)
XSearch backward in the history for a specified string.
XThe string may begin with `^' to anchor the search to the
Xbeginning of the line.
X.TP
X\fBhistory-search-forward\fP (ESC-N ESC-n) (J)
XSearch forward in the history for a line beginning with the first
Xword in the buffer.
X.TP
X\fBvi-history-search-forward\fP (unbound) (?)
XSearch forward in the history for a specified string.
XThe string may begin with `^' to anchor the search to the
Xbeginning of the line.
X.TP
X\fBinfer-next-history\fP (^X^N)
XSearch in the history list for a line matching the current one and
Xfetch the event following it.
X.TP
X\fBinsert-last-word\fP (ESC-_ ESC-.)
XInsert the last word from the previous history event at the
Xcursor position.
X.TP
X\fBvi-repeat-search\fP (unbound) (n)
XRepeat the last vi history search.
X.TP
X\fBvi-rev-repeat-search\fP (unbound) (N)
XRepeat the last vi history search, but in reverse.
X.TP
X\fBtoggle-literal-history\fP (ESC-R ESC-r)
XToggle between literal and lexical history. The default is
Xlexical history unless the \fBHISTLIT\fP option is set.
X.TP
X\fBup-line-or-history\fP (^P ESC-[A) (- k)
XMove up a line in the buffer, or if already at the top line,
Xmove to the previous event in the history list.
X.TP
X\fBup-history\fP (unbound) (^P)
XMove to the previous event in the history list.
X.SS Modifying Text
X.TP
X\fBvi-add-eol\fP (unbound) (A)
XMove to the end of the line and enter insert mode.
X.TP
X\fBvi-add-next\fP (unbound) (a)
XMove forward one character and enter insert mode.
X.TP
X\fBbackward-delete-char\fP (^H ^?) (^?)
XDelete the character behind the cursor.
X.TP
X\fBvi-backward-delete-char\fP (unbound) (X)
XDelete the character behind the cursor, without changing lines.
X.TP
X\fBbackward-delete-word\fP
XDelete the word behind the cursor.
X.TP
X\fBbackward-kill-line\fP
XKill from the beginning of the line to the cursor position.
X.TP
X\fBbackward-kill-word\fP (^W ESC-^H ESC-^?)
XKill the word behind the cursor.
X.TP
X\fBvi-backward-kill-word\fP (unbound) (^W)
XKill the word behind the cursor.
X.TP
X\fBcapitalize-word\fP (ESC-C ESC-c)
XCapitalize the current word and move past it.
X.TP
X\fBvi-change\fP (unbound) (c)
XRead a movement command from the keyboard, and kill
Xfrom the cursor position to the endpoint of the movement.
XThen enter insert mode.
XIf the command is \fBvi-change\fP, kill the current line.
X.TP
X\fBvi-change-eol\fP (unbound) (C)
XKill to the end of the line and enter insert mode.
X.TP
X\fBvi-change-whole-line\fP (unbound) (S s)
XKill the current line and enter insert mode.
X.TP
X\fBcopy-region-as-kill\fP (ESC-W ESC-w)
XCopy the area from the cursor to the mark to the kill buffer.
X.TP
X\fBcopy-prev-word\fP (ESC-^_)
XDuplicate the word behind the cursor.
X.TP
X\fBvi-delete\fP (unbound) (d)
XRead a movement command from the keyboard, and kill
Xfrom the cursor position to the endpoint of the movement.
XIf the command is \fBvi-delete\fP, kill the current line.
X.TP
X\fBdelete-char\fP (unbound) (x)
XDelete the character under the cursor.
X.TP
X\fBvi-delete-char\fP (unbound) (x)
XDelete the character under the cursor.
X.TP
X\fBdelete-word\fP (ESC-D ESC-d)
XDelete the current word.
X.TP
X\fBdown-case-word\fP (ESC-L ESC-l)
XConvert the current word to all lowercase and move past it.
X.TP
X\fBkill-word\fP
XKill the current word.
X.TP
X\fBgosmacs-transpose-chars\fP
XExchange the two characters behind the cursor.
X.TP
X\fBvi-indent\fP (unbound) (>)
XIndent a number of lines.
X.TP
X\fBvi-insert\fP (unbound) (i)
XEnter insert mode.
X.TP
X\fBvi-insert-bol\fP (unbound) (I)
XMove to the beginning of the line and enter insert mode.\fP
X.TP
X\fBvi-join\fP (^X^J)
XJoin the current line with the next one.
X.TP
X\fBkill-line\fP (^K) (D)
XKill from the cursor to the end of the line.
X.TP
X\fBkill-region\fP
XKill from the cursor to the mark.
X.TP
X\fBkill-buffer\fP (^X^U) (^U)
XKill the entire buffer.
X.TP
X\fBkill-whole-line\fP (^U) (unbound)
XKill the current line.
X.TP
X\fBvi-match-bracket\fP (^X^B) (%)
XMove to the bracket character (one of {\|}, (\|), or [\|]) that
Xmatches the one under the cursor.
X.TP
X\fBvi-open-line-above\fP (unbound) (O)
XOpen a line above the cursor and enter insert mode.
X.TP
X\fBvi-open-line-below\fP (unbound) (o)
XOpen a line below the cursor and enter insert mode.
X.TP
X\fBvi-oper-swap-case\fP
XRead a movement command from the keyboard, and swap
Xthe case of all characters
Xfrom the cursor position to the endpoint of the movement.
XIf the movement command is \fBvi-oper-swap-case\fP,
Xswap the case of all characters on the current line.
X.TP
X\fBoverwrite-mode\fP (^X^O)
XToggle between overwrite mode and insert mode.
X.TP
X\fBvi-put-after\fP (unbound) (p)
XInsert the contents of the kill buffer after the cursor.
X.TP
X\fBquoted-insert\fP (^V)
XInsert the next character typed into the buffer literally.
X.TP
X\fBquote-line\fP (ESC-')
XQuote the current line; that is, put a ' character at the
Xbeginning and the end, and convert all ' characters
Xto '\e''.
X.TP
X\fBquote-region\fP (ESC-")
XQuote the region from the cursor to the mark.
X.TP
X\fBvi-replace\fP (unbound) (R)
XEnter overwrite mode.
X.TP
X\fBvi-repeat-change\fP (unbound) (.)
XRepeat the last vi mode text modification.
X.TP
X\fBvi-replace-chars\fP (unbound) (r)
XReplace the character under the cursor with a character
Xread from the keyboard.
X.TP
X\fBself-insert\fP (printable characters)
XPut a character in the buffer at the cursor position.
X.TP
X\fBself-insert-unmeta\fP (ESC-^I ESC-^J ESC-^M)
XPut a character in the buffer after stripping the meta bit
Xand converting \fB^M\fP to \fB^J\fP.
X.TP
X\fBvi-substitute\fP (unbound) (s)
XSubstitute the next character(s).
X.TP
X\fBvi-swap-case\fP (unbound) (~)
XSwap the case of the character under the cursor and move past it.
X.TP
X\fBtranspose-chars\fP (^T)
XExchange the two characters to the left of the
Xcursor if at end of line, else exchange the
Xcharacter under the cursor with the character
Xto the left.
X.TP
X\fBtranspose-words\fP (ESC-T ESC-t)
XExchange the current word with the one before it.
X.TP
X\fBvi-unindent\fP (unbound) (<)
XUnindent a number of lines.
X.TP
X\fBup-case-word\fP (ESC-U ESC-u)
XConvert the current word to all caps and move past it.
X.TP
X\fByank\fP (^Y) (P)
XInsert the contents of the kill buffer at the cursor position.
X.TP
X\fByank-pop\fP (ESC-y) (unbound)
XRemove the text just yanked, rotate the kill\-ring,
Xand yank the new top. Only works following
X\fByank\fP or \fByank-pop\fP.
X.TP
X\fBvi-yank\fP (unbound) (y)
XRead a movement command from the keyboard, and copy the region
Xfrom the cursor position to the endpoint of the movement
Xinto the kill buffer.
XIf the command is \fBvi-yank\fP, copy the current line.
X.TP
X\fBvi-yank-eol\fP (unbound) (Y)
XCopy the region from the cursor position to the end of the line
Xinto the kill buffer.
X.SS Arguments
X.TP
X\fBdigit-argument\fP (ESC-0..ESC-9) (0-9)
XStart a new numeric argument, or add to the current one.
X.TP
X\fBuniversal-argument\fP
XMultiply the argument of the next command by 4.
X.SS Completion
X.TP
X\fBaccept-and-menu-complete\fP
XIn a menu completion, insert the current completion into the buffer,
Xand advance to the next possible completion.
X.TP
X\fBcomplete-word\fP (unbound) (\|\e\|)
XAttempt completion on the current word.
X.TP
X\fBdelete-char-or-list\fP (^D)
XDelete the character under the cursor. If the cursor
Xis at the end of the line, list possible completions for the
Xcurrent word.
X.TP
X\fBexecute-named-cmd\fP (ESC-x)
XRead the name of a editor command and execute it.
X.TP
X\fBexecute-last-named-cmd\fP (ESC-z)
XRedo the last function executed with \fBexecute-named-cmd\fP.
X.TP
X\fBexpand-cmd-path\fP
XExpand the current command to its full pathname.
X.TP
X\fBexpand-or-complete\fP (TAB) (TAB ^X)
XAttempt shell expansion on the current word.
XIf that fails,
Xattempt completion.
X.TP
X\fBexpand-history\fP (ESC-space ESC-!)
XPerform history expansion on the edit buffer.
X.TP
X\fBexpand-word\fP (^X*)
XAttempt shell expansion on the current word.
X.TP
X\fBlist-choices\fP (ESC-^D) (^D =)
XList possible completions for the current word.
X.TP
X\fBlist-expand\fP (^Xg ^XG) (^G)
XList the expansion of the current word.
X.TP
X\fBmagic-space\fP
XPerform history expansion and insert a space into the
Xbuffer. This is intended to be bound to space.
X.TP
X\fBmenu-complete\fP
XLike \fBcomplete-word\fP, except that menu completion is used.
XSee the \fBMENU_COMPLETE\fP option below.
X.TP
X\fBmenu-expand-or-complete\fP
XLike \fBexpand-or-complete\fP, except that menu completion is used.
X.TP
X\fBreverse-menu-complete\fP
XSee the \fBMENU_COMPLETE\fP option below.
X.SS Miscellaneous
X.TP
X\fBaccept-and-hold\fP (ESC-A ESC-a)
XPush the contents of the buffer on the buffer stack
Xand execute it.
X.TP
X\fBaccept-and-infer-next-history\fP
XExecute the contents of the buffer.
XThen search the history list for a line matching the current one
Xand push the event following onto the buffer stack.
X.TP
X\fBaccept-line\fP (^J ^M)
XExecute the contents of the buffer.
X.TP
X\fBaccept-line-and-down-history\fP (^O)
XExecute the current line, and push the next history
Xevent on the the buffer stack.
X.TP
X\fBvi-cmd-mode\fP (^X^V) (^[)
XEnter command mode; that is, use the alternate keymap.
XYes, this is bound by default in emacs mode.
X.TP
X\fBvi-caps-lock-panic\fP (unbound) (H K)
XHang until any lowercase key is pressed.
XThis is for vi users without the mental capacity to keep
Xtrack of their caps lock key (like the author).
X.TP
X\fBclear-screen\fP (^L ESC-^L)
XClear the screen and redraw the prompt.
X.TP
X\fBexchange-point-and-mark\fP (^X^X)
XExchange the cursor position with the position of the mark.
X.TP
X\fBget-line\fP (ESC-G ESC-g)
XPop the top line off the buffer stack and insert it at the
Xcursor position.
X.TP
X\fBpound-insert\fP (unbound) (#)
XIf there is no # character at the beginning of the current line,
Xadd one. If there is one, remove it. In either case, accept the
Xcurrent line. The \fBINTERACTIVE_COMMENTS\fP option must be set
Xfor this to have any usefulness.
X.TP
X\fBpush-line\fP (^Q ESC-Q ESC-q)
XPush the current buffer onto the buffer stack and clear
Xthe buffer.
XNext time the editor starts up, the buffer will be popped
Xoff the top of the buffer stack and loaded into the editing
Xbuffer.
X.TP
X\fBredisplay\fP (unbound) (^R)
XRedisplays the edit buffer.
X.TP
X\fBrun-help\fP (ESC-H ESC-h)
XPush the buffer onto the buffer stack, and execute the
Xcommand "\fBrun-help\fP \fIcmd\fP", where \fIcmd\fP is the current
Xcommand. \fBrun-help\fP is normally aliased to \fBman\fP.
X.TP
X\fBsend-break\fP (^C)
XAbort the parsing of the current line.
X.TP
X\fBvi-set-buffer\fP (unbound) (")
XSpecify a buffer to be used in the following command.
X.TP
X\fBvi-set-mark\fP (unbound) (m)
XSet the specified mark at the cursor position.
X.TP
X\fBset-mark-command\fP (^@)
XSet the mark at the cursor position.
X.TP
X\fBspell-word\fP (ESC-$ ESC-S ESC-s)
XAttempt spelling correction on the current word.
X.TP
X\fBundefined-key\fP
XBeep.
X.TP
X\fBundo\fP (^_ ^X^U) (u)
XIncrementally undo the last text modification.
X.TP
X\fBwhich-command\fP (ESC-?)
XPush the buffer onto the buffer stack, and execute the
Xcommand "\fBwhich-command\fP \fIcmd\fP", where \fIcmd\fP is the current
Xcommand. \fBwhich-command\fP is normally aliased to \fBwhence\fP.
X.SH PARAMETERS
XA parameter has a name, a value, and a number of attributes.
XA name may be any sequence of alphanumeric
Xcharacters and _'s, or the single characters
X*, @, #, ?, \-, $, or !.
XThe value may be either a \fIscalar\fP (a string),
Xan integer, or an array.
XTo assign a scalar or integer value to a parameter,
Xuse the \fBtypeset\fP builtin.
XTo assign an array value, use \fBset \-A\fP \fIname\fP \fIvalue\fP ....
XThe value of a parameter may also be assigned by writing:
X.RS
X.PP
X\fIname\fP=\fIvalue\fP ...
X.RE
X.PP
XIf the integer attribute, \-\fBi\fP, is set for \fIname\fP,
Xthe \fIvalue\fP is subject to arithmetic evaluation.
X.PP
XThe value of an array parameter may be assigned by writing:
X.RS
X.PP
X\fIname\fP=(\fIvalue\fP ...) ...
X.RE
XIndividual elements of an array may be selected using a
Xsubscript. A subscript of the form \fB[\fIexp\fB]\fR
Xselects the single element \fIexp\fP, where \fIexp\fP is
Xan arithmetic expression. The elements are numbered
Xbeginning with 1.
XA subscript of the form \fB[*]\fP or \fB[@]\fP evaluates to all
Xelements of an array; there is no difference between the two
Xexcept when they appear within double quotes.
X"$foo[*]" evaluates to "$foo[1] $foo[2] ...", while
X"$foo[@]" evaluates to "$foo[1]" "$foo[2]", etc.
XA subscript of the form \fB[\fIexp1\fP,\fIexp2\fB]\fR
Xselects all elements in the range \fIexp1\fP to \fIexp2\fP,
Xinclusive.
XIf one of the subscripts evaluates to a negative number,
Xsay \-\fIn\fP, then the \fIn\fPth element from the end
Xof the array is used. Thus "$foo[-3]" is the third element
Xfrom the end of the array \fIfoo\fP, and
X"$foo[1,-1]" is the same as "$foo[*]".
X.PP
XSubscripting may also be performed on non-array values, in which
Xcase the subscripts specify a substring to be extracted.
XFor example, if \fBFOO\fP is set to \fBfoobar\fP, then
X\fBecho $FOO[2,5]\fP prints \fBooba\fP.
X.SS Positional Parameters
XPositional parameters are set by the shell on invocation,
Xby the \fBset\fP builtin, or by direct assignment.
XThe parameter \fIn\fP, where \fIn\fP is a number,
Xis the \fIn\fPth positional parameter.
XThe parameters \fB*\fP, \fB@\fP, and \fBargv\fP are
Xarrays containing all the positional parameters;
Xthus \fBargv\fP[\fIn\fP], etc. is equivalent to simply \fIn\fP.
X.SS Special Parameters
XThe following parameters are automatically set by the shell:


X.PP
X.RS
X.PD 0
X.TP

X.B !
XThe process id of the last background command invoked.
X.TP
X.B #
XThe number of positional parameters in decimal.
X.TP
X.B ARGC
XSame as \fB#\fP.
X.TP
X.B $
XThe process id of this shell.
X.TP
X.B \-
XFlags supplied to the shell on invocation or by the \fBset\fP
Xor \fBsetopt\fP commands.
X.TP
X.B *
XAn array containing the positional parameters.
X.TP
X.B argv
XSame as \fB*\fP.
X.TP
X.B @
XSame as \fBargv[@]\fP.
X.TP
X.B ?
XThe exit value returned by the last command.
X.TP
X.B status
XSame as \fB?\fP.
X.TP
X.B _
XThe last argument of the previous command.
XAlso, this parameter is set in the environment of every command
Xexecuted to the full pathname of the command.
X.TP
X.B ERRNO
XThe value of errno as set by the most recently failed system call.
XThis value is system dependent and is intended for debugging
Xpurposes.
X.TP
X.B GID
XThe group id of the shell process.
X.TP
X.B HOST
XThe current hostname.
X.TP
X.B HOSTTYPE
XA string corresponding to the type of the host the shell
Xis running on.
X.TP
X.B LINENO
XThe line number of the current line within the current script
Xbeing executed.
X.TP
X.B OLDPWD
XThe previous working directory.
X.TP
X.B OPTARG
XThe value of the last option argument processed by the \fBgetopts\fP
Xcommand.
X.TP
X.B OPTIND
XThe index of the last option argument processed by the \fBgetopts\fP
Xcommand.
X.TP
X.B PPID
XThe process id of the parent of the shell.
X.TP
X.B PWD
XThe present working directory.
X.TP
X.B RANDOM
XA random integer from 0 to 32767, newly generated each time
Xthis parameter is referenced. The random number generator
Xcan be seeded by assigning a numeric value to \fBRANDOM\fP.
X.TP
X.B SECONDS
XThe number of seconds since shell invocation. If this parameter
Xis assigned a value, then the value returned upon reference
Xwill be the value that was assigned plus the number of seconds
Xsince the assignment.
X.TP
X.B SHLVL
XIncremented by one each time a new shell is started.
X.TP
X.B signals
XAn array containing the names of the signals.
X.TP
X.B TTY
XThe name of the tty associated with the shell, if any.
X.TP
X.B UID
XThe user id of the shell process.
X.TP
X.B USERNAME
X.TP
X.B LOGNAME
XThe username corresponding to the user id of the shell process.
X.TP
X.B VERSION
XThe version number of this \fBzsh\fP.
X.PD
X.RE
X.PP
XThe following parameters are used by the shell:


X.PP
X.RS
X.PD 0
X.TP

X.B BAUD
XThe baud rate of the current connection. Used by the line editor
Xupdate mechanism to compensate for a slow terminal by delaying
Xupdates until necessary. This may be profitably set to a lower value
Xin some circumstances, e.g.
Xfor slow modems dialing into a communications server which is connected
Xto a host via a fast link; in this case, this variable
Xwould be set by default to the speed of the fast link, and not
Xthe modem.
XThis parameter should be set to the baud
Xrate of the slowest part of the link for best performance.
X.TP
X.B bindcmds
XAn write-only array
Xof command names which take line editor function names
Xas arguments, and which therefore should allow binding
Xcompletion.
X.TP
X.B cdpath (CDPATH)
XAn array (colon-separated list)
Xof directories specifying the search path for the \fBcd\fP command.
X.TP
X.B COLUMNS
XThe number of columns for this terminal session.
XUsed for printing select lists and for the line editor.
X.TP
X.B DIRSTACKSIZE
XThe maximum size of the directory stack. If the
Xstack gets larger than this, it will be truncated automatically.
XThis is useful with the \fBAUTO_PUSHD\fP option.
X.TP
X.B FCEDIT
XThe default editor for the \fBfc\fP builtin.
X.TP
X.B fignore (FIGNORE)
XAn array (colon separated list)
Xcontaining the suffixes of files to be ignored
Xduring filename completion.
X.TP
X.B fpath (FPATH)
XAn array (colon separated list)
Xof directories specifying the search path for
Xfunction definitions. This path is searched when a function
Xwith the \-\fBu\fP attribute is referenced. If an executable
Xfile is found, then it is read and executed in the current environment.
X.TP
X.B HISTCHARS
XThree characters used by the shell's history and lexical analysis
Xmechanism. The first character signals the start of a history
Xsubstitution (default `!'). The second character signals the
Xstart of a quick history substitution (default `^'). The third
Xcharacter is the comment character (default `#').
X.TP
X.B HISTFILE
XThe file to save the history in when an interactive shell exits.
XIf unset, the history is not saved.
X.TP
X.B HISTSIZE
XThe maximum size of the history list.
X.TP
X.B HOME
XThe default argument for the \fBcd\fP command.
X.TP
X.B hostcmds
XAn write-only array of command names which
Xtake hostnames as arguments, and which should therefore
Xallow hostname completion. This sort of completion is also
Xused in words containing a \fB@\fP character.
X.TP
X.B hosts (HOSTS)
XAn array (colon separated list) of hostnames to use
Xfor hostname completion.
X.TP
X.B IFS
XInternal field separators, normally space, tab, and newline, that
Xare used to separate words which result from
Xcommand or parameter substitution and words read by
Xthe \fBread\fP builtin.
X.TP
X.B LINES
XThe number of lines for this terminal session.
XUsed for printing select lists and for the line editor.
X.TP
X.B LISTMAX
XIn the line editor,
Xthe number of filenames to list without asking first.
X.TP
X.B LITHISTSIZE
XThe maximum size of the literal history list (before history expansion).
X.TP
X.B LOGCHECK
XThe interval in seconds between checks for login/logout activity
Xusing the \fBwatch\fP parameter.
X.TP
X.B MAIL
XIf this parameter is set and \fBmailpath\fP is not set,
Xthe shell looks for mail in the specified file.
X.TP
X.B MAILCHECK
XThe interval in seconds between checks for new mail.
X.TP
X.B mailpath (MAILPATH)
XAn array (colon-separated list)
Xof filenames to check for new mail. Each filename can
Xbe followed by a ? and a message that will be printed.
XThe sequence $_ in the message will be replaced by the name
Xof the mail file.
XThe default message is "You have new mail."
X.TP
X.B manpath (MANPATH)
XAn array (colon-separated list)
Xwhose value is not used by the shell. The \fBmanpath\fP
Xarray can be useful, however, since setting it also sets
X\fBMANPATH\fP, and vice versa.
X.TP
X.B NULLCMD
XThe command name to assume if a redirection is specified
Xwith no command. Defaults to \fBcat\fP. For sh/ksh-like
Xbehavior, change this to \fB:\fP. For csh-like
Xbehavior, unset this parameter; the shell will print an
Xerror message if null commands are entered.
X.TP
X.B optcmds
XAn write-only array of
Xcommands which take options as arguments, and which
Xtherefore should allow option completion.
X.TP
X.B path (PATH)
XAn array (colon-separated list)
Xof directories to search for commands.
XWhen this parameter is set, each directory is scanned
Xand all files found are put in a hash table.
X.TP
X.B POSTEDIT
XThis string is output whenever the line editor exits.
XIt usually contains termcap strings to reset the terminal.
X.TP
X.B PROMPT
XThe primary prompt string, printed before a command is read;
Xthe default is "%m%# ".
XThe following escape sequences are recognized:
X.PD


X.PP
X.PD 0
X.RS
X.TP

X.B %d
X.TP
X.B %/
XPresent working directory ($PWD).
X.TP
X.B %~
X$PWD.
XIf it has a named directory as its prefix, that part is replaced
Xby a ~ followed by the name of the directory.
XIf it starts with $HOME, that part is
Xreplaced by a ~.
X.TP
X.B %c
X.TP
X.B %.
X.TP
X.B %C
XTrailing component of $PWD.
XMay be followed by a digit to get more than one component.
XUnless \fB%C\fP is used, tilde expansion is performed first.
X.TP
X.B !
X.TP
X.B %h
X.TP
X.B %!
XCurrent history event number
X.TP
X.B %M
XThe full machine hostname.
X.TP
X.B %m
XThe hostname up to the first '.'.
XMay be followed by a digit to specify
Xhow many components of the hostname are desired.
X.TP
X.B %S (%s)
XStart (stop) standout mode.
X.TP
X.B %U (%u)
XStart (stop) underline mode.
X.TP
X.B %B (%b)
XStart (stop) boldface mode.
X.TP
X.B %t
X.TP
X.B %@
XCurrent time of day, in 12-hour, am/pm format.
X.TP
X.B %T
XCurrent time of day, in 24-hour format.
X.TP
X.B %*
XCurrent time of day in 24-hour format, with seconds.
X.TP
X.B %n
X\fB$USERNAME\fP.
X.TP
X.B %w
XThe date in day\-dd format.
X.TP
X.B %W
XThe date in mm/dd/yy format.
X.TP
X.B %D
XThe date in yy\-mm\-dd format.
X.TP
X.B %D{\fIstring\fP}
X\fIstring\fP is formatted using the \fBstrftime\fP function.
XSee \fBstrftime(3)\fP for more details, if your system has it.
X.TP
X.B %l
XThe line (tty) the user is logged in on.
X.TP
X.B %?
XThe return code of the last command executed just before the prompt.
X.TP
X.B %#
XA '#' if the shell is running as root, a '%' if not.
X.TP
X\fB%{\fP...\fB%}\fP
XInclude a string as a literal escape sequence.
XThe string within the braces should not change the cursor
Xposition.
X.RE
X.PD
X.PP
X.PD 0
X.TP
X.B PROMPT2
XThe secondary prompt, printed when the shell needs more information
Xto complete a command.
XRecognizes the same escape sequences as \fB$PROMPT\fP.
XThe default is "> ".
X.TP
X.B PROMPT3
XSelection prompt used within a \fBselect\fP loop.
XRecognizes the same escape sequences as \fB$PROMPT\fP.
XThe default is "?# ".
X.TP
X.B PROMPT4
XThe execution trace prompt. Default is "+ ".
X.TP
X.B PS1
X.TP
X.B PS2
X.TP
X.B PS3
X.TP
X.B PS4
XSame as \fBPROMPT\fP, \fBPROMPT2\fP, \fBPROMPT3\fP, and \fBPROMPT4\fP,
Xrespectively.
X.TP
X.B prompt
XSame as \fBPROMPT\fP.
X.TP
X.B READNULLCMD
XThe command name to assume if a single input redirection
Xis specified with no command. Defaults to \fBmore\fP.
X.TP
X.B REPORTTIME
XIf nonzero, commands whose combined user and system execution times
X(measured in seconds) are greater than this value have timing
Xstatistics printed for them.
X.TP
X.B RPROMPT
X.TP
X.B RPS1
XThis prompt is displayed on the right-hand side of the screen
Xwhen the primary prompt is being displayed on the left.
XThis does not work if the \fBSINGLELINEZLE\fP option is set.
XRecognizes the same escape sequences as \fBPROMPT\fP,
Xexcept that termcap sequences like \fB%s\fP, etc. will not work.
X.TP
X.B SAVEHIST
XThe maximum number of history events to save in the history file.
X.TP
X.B SPROMPT
XThe prompt used for spelling correction. The sequence
X\fB%R\fP expands to the string which presumably needs spelling
Xcorrection, and \fB%r\fP expands to the proposed correction.
XAll other \fBPROMPT\fP escapes are also allowed.
X.TP
X.B STTY
XIf this parameter is set in a command's environment, the shell
Xruns the \fBstty\fP command with the value of this parameter as arguments
Xin order to set up the terminal before executing the command.
X.TP
X.B TIMEFMT
XThe format of process time reports with the \fBtime\fP keyword.
XThe default is "%E real %U user %S system %P".
XRecognizes the following escape sequences:
X.PD


X.PP
X.PD 0
X.RS
X.TP

X.B %U
XCPU seconds spent in user mode.
X.TP
X.B %S
XCPU seconds spent in kernel mode.
X.TP
X.B %E
XElapsed time in seconds.
X.TP
X.B %P
XThe CPU percentage, computed as (%U+%S)/%E.
X.TP
X.B %W
XNumber of times the process was swapped.
X.TP
X.B %X
XThe average amount in (shared) text space used in Kbytes.
X.TP
X.B %D
XThe average amount in (unshared) data/stack space used in Kbytes.
X.TP
X.B %K
XThe total space used (%X+%D) in Kbytes.
X.TP
X.B %M
XThe maximum memory the process had in use at any time in Kbytes.
X.TP
X.B %F
XThe number of major page faults (page needed to be brought from disk).
X.TP
X.B %R
XThe number of minor page faults.
X.TP
X.B %I
XThe number of input operations.
X.TP
X.B %O
XThe number of output operations.
X.TP
X.B %r
XThe number of socket messages received.
X.TP
X.B %s
XThe number of socket messages sent.
X.TP
X.B %k
XThe number of signals received.
X.TP
X.B %w
XNumber of voluntary context switches (waits).
X.TP
X.B %c
XNumber of involuntary context switches.
X.TP
X.B %J
XThe name of this job.
X.RE
X.PD
X.PP
X.PD 0
X.TP
X.B TMOUT
XIf this parameter is nonzero, the shell will terminate if a command is not
Xentered within the specified number of seconds after issuing
Xa prompt.
X.TP
X.B TMPPREFIX
XA pathname prefix which the shell will use for all temporary files.
X.TP
X.B varcmds
XAn write-only array
Xof command names which take parameter names
Xas arguments, and which therefore should allow parameter
Xcompletion.
X.TP
X.B watch (WATCH)
XAn array (colon-separated list) of login/logout events to report.
XIf it contains the single word "all", then all login/logout events
Xare reported.
XAn entry in this list may consist of a username,
Xan `@' followed by a remote hostname,
Xand a `%' followed by a line (tty).
XAny or all of these components may be present in an entry;
Xif a login/logout event matches all of them,
Xit is reported.
X.TP
X.B WATCHFMT
XThe format of login/logout reports if the \fBwatch\fP parameter is set.
XDefault is "%n has %a %l from %m."
XRecognizes the following escape sequences:
X.PD


X.PP
X.PD 0
X.RS
X.TP

X.B %n
XThe name of the user that logged in/out.
X.TP
X.B %a
XThe observed action, i.e. "logged on" or "logged off".
X.TP
X.B %l
XThe line (tty) the user is logged in on.
X.TP
X.B %M
XThe full hostname of the remote host.
X.TP
X.B %m
XThe hostname up to the first ".". If only the
Xip address is available or the utmp field contains
Xthe name of an X-windows display, the whole name is printed.
X.TP
X.B %S (%s)
XStart (stop) standout mode.
X.TP
X.B %U (%u)
XStart (stop) underline mode.
X.TP
X.B %B (%b)
XStart (stop) boldface mode.
X.TP
X.B %t
X.TP
X.B %@
XThe time, in 12-hour, am/pm format.
X.TP
X.B %T
XThe time, in 24-hour format.
X.TP
X.B %w
XThe date in day\-dd format.
X.TP
X.B %W
XThe date in mm/dd/yy format.
X.TP
X.B %D
XThe date in yy\-mm\-dd format.
X.RE
X.PD
X.PP
X.PD 0
X.TP
X.B WORDCHARS
XA list of nonalphanumeric characters considered part of a word
Xby the line editor.
X.TP
X.B ZDOTDIR
XThe directory to search for shell startup files (.zshrc, etc),
Xif not \fB$HOME\fP.
X.PD
X.RE
X.PP
X.SH OPTIONS
XThe following options may be set upon invocation of the shell,
Xor with the \fBset\fP or \fBsetopt\fP builtins:
X.RS
X.PD 0
X.TP
X\fBALLEXPORT\fP (\-\fBa\fP)
XAll parameters subsequently defined are automatically exported.
X.TP
X\fBAUTO_CD\fP (\-\fBJ\fP)
XIf a command is not in the hash table, and there exists an
Xexecutable directory by that name, perform the \fBcd\fP
Xcommand to that directory.
X.TP
X\fBAUTOLIST\fP (\-\fB9\fP)
XAutomatically list choices on an ambiguous completion.
X.TP
X\fBAUTOMENU\fP
XAutomatically use menu completion if the \fPTAB\fP
Xkey is pressed repeatedly.
X.TP
X\fBAUTO_PUSHD\fP (\-\fBN\fP)
XMake \fBcd\fP act like \fBpushd\fP.
X.TP
X\fBAUTO_RESUME\fP (\-\fBW\fP)
XTreat single word simple commands without redirection
Xas candidates for resumption of an existing job.
X.TP
X\fBBGNICE\fP (\-\fB6\fP)
XRun all background jobs at a lower priority. This option
Xis set by default.
X.TP
X\fBBRACECCL\fP
XAllow brace expansions of the form \fB{a-zA-Z}\fP, etc.
X.TP
X\fBCDABLEVARS\fP (\-\fBT\fP)
XIf the argument to a \fBcd\fP command is not a directory,
Xbut a parameter exists by the same name whose value
Xbegins with a /, try to change to the directory
Xspecified by the parameter's value.
X.TP
X\fBCHASELINKS\fP (\-\fBw\fP)
XResolve symbolic links to their true values.
X.TP
X\fBCORRECT\fP (\-\fB0\fP)
XTry to correct the spelling of commands.
X.TP
X\fBCORRECT_ALL\fP (\-\fBO\fP)
XTry to correct the spelling of all arguments in a line.
X.TP
X\fBCSH_JUNKIE_LOOPS\fP
XAllow loop bodies to take the form
X"\fIlist\fP; \fBend\fP" instead of
X"\fBdo\fP \fIlist\fP; \fBdone\fP".
X.TP
X\fBCSH_JUNKIE_QUOTES\fP
XComplain if a quoted expression runs off the end of a line;
Xprevent quoted expressions from containing unescaped newlines.
X.TP
X\fBCSH_NULL_GLOB\fP
XIf a pattern for filename generation has no matches,
Xdelete the pattern from the argument list;
Xdo not report an error unless all the patterns
Xin a command have no matches.
XOverrides \fBNULLGLOB\fP.
X.TP
X\fBERREXIT\fP (\-\fBe\fP)
XIf a command has a non-zero exit status, execute the \fBERR\fP
Xtrap, if set, and exit.
X.TP
X\fBEXTENDED_GLOB\fP
XTreat the # and ^ characters as part of patterns for filename
Xgeneration, etc.
X.TP
X\fBGLOB_COMPLETE\fP
XLike \fBMENU_COMPLETE\fP, except that the current word
Xis expanded using normal shell expansion instead of completion.
XIf no matches are found, a * is added to the end of the word, and expansion
Xis attempted again.
X.TP
X\fBGLOB_DOTS\fP (\-\fB4\fP)
XDo not require a leading . in a filename to be matched explicitly.
X.TP
X\fBHASH_CMDS\fP
XPlace the location of each command in the hash table the first
Xtime it is executed. If this option is unset, no path hashing
Xwill be done at all.
X.TP
X\fBHASH_DIRS\fP
XWhenever a command is executed, hash the directory containing it,
Xas well as all directories that occur earlier in the path.
XHas no effect if \fBHASH_CMDS\fP is unset.
X.TP
X\fBHASH_LIST_ALL\fP
XWhenever a command completion is attempted, make sure the entire
Xcommand path is hashed first. This makes the first completion slower.
X.TP
X\fBHIST_IGNORE_DUPS\fP (\-\fBh\fP)
XDo not enter command lines into the history list
Xif they are duplicates of the previous event.
X.TP
X\fBHIST_IGNORE_SPACE\fP (\-\fBg\fP)
XDo not enter command lines into the history list
Xif they begin with a blank.
X.TP
X\fBHISTLIT\fP (\-\fBj\fP)
XUse literal (unparsed) versions of the history lines
Xin the editor.
X.TP
X\fBHIST_NO_STORE\fP
XRemove the \fBhistory\fP (\fBfc\fP \-\fBl\fP) command from
Xthe history when invoked.
X.TP
X\fBHIST_VERIFY\fP
XWhenever the user enters a line with history substitution,
Xdon't execute the line directly; instead, perform
Xhistory substitution and reload the line into the editing buffer.
X.TP
X\fBIGNORE_BRACES\fP (\-\fBI\fP)
XDo not perform brace expansion.
X.TP
X\fBIGNOREEOF\fP (\-\fB7\fP)
XDo not exit on end-of-file. Require the use
Xof \fBexit\fP or \fBlogout\fP instead.
X.TP
X\fBINTERACTIVE\fP (\-\fBi\fP)
XThis is an interactive shell.
X.TP
X\fBINTERACTIVE_COMMENTS\fP (\-\fBk\fP)
XAllow comments even in interactive shells.
X.TP
X\fBKSH_OPTION_PRINT\fP
XAlters the way options settings are printed.
X.TP
X\fBLIST_TYPES\fP (\-\fBX\fP)
XWhen listing files that are possible completions, show the
Xtype of each file with a trailing identifying mark.
X.TP
X\fBLOGIN\fP (\-\fBl\fP)
XThis is a login shell.
X.TP
X\fBLONG_LIST_JOBS\fP (\-\fBR\fP)
XList jobs in the long format by default.
X.TP
X\fBMAIL_WARNING\fP (\-\fBU\fP)
XPrint a warning message if a mail file has been
Xaccessed since the shell last checked.
X.TP
X\fBMARKDIRS\fP (\-\fB8\fP)
XAppend a trailing / to all directory
Xnames resulting from filename generation (globbing).
X.TP
X\fBMENU_COMPLETE\fP (\-\fBY\fP)
XOn an ambiguous completion, instead of listing possibilities,
Xinsert the first match. Then when completion is requested
Xagain, remove the first match and insert the second match, etc.
XWhen there are no more matches, go back to the first one again.
X\fBreverse-menu-complete\fP may be used to loop through the list
Xin the other direction.
X.TP
X\fBMENU_COMPLETE_BEEP\fP
XBeep on an ambiguous menu completion.
X.TP
X\fBMONITOR\fP (\-\fBm\fP)
XAllow job control. Set by default in interactive shells.
X.TP
X\fBNO_BAD_PATTERN\fP (\-\fB2\fP)
XIf a pattern for filename generation is badly formed,
Xleave it unchanged in the argument list instead of
Xprinting an error.
X.TP
X\fBNO_BANG_HIST\fP (\-\fBK\fP)
XDo not perform textual history substitution. Do not
Xtreat the ! character specially.
X.TP
X\fBNOBEEP\fP (\-\fBB\fP)
XDo not beep.
X.TP
X\fBNO_CLOBBER\fP (\-\fB1\fP)
XPrevents \fB>\fP redirection from truncating existing files.
X\fB>!\fP may be used to truncate a file instead.
XAlso prevents \fB>>\fP from creating files.
X\fB>>!\fP may be used instead.
X.TP
X\fBNO_EQUALS\fP
XDon't perform \fB=\fP filename substitution.
X.TP
X\fBNOEXEC\fP (\-\fBn\fP)
XRead commands and check them for syntax errors, but do not execute them.
X.TP
X\fBNOGLOB\fP (\-\fBF\fP)
XDisable filename generation.
X.TP
X\fBNO_HIST_BEEP\fP
XDon't beep when an attempt is made to access a history entry which
Xisn't there.
X.TP
X\fBNOHUP\fP
XDon't send the \fBHUP\fP signal to running jobs when the
Xshell exits.
X.TP
X\fBNO_LIST_BEEP\fP
XDon't beep on an ambiguous completion.
X.TP
X\fBNO_NOMATCH\fP (\-\fB3\fP)
XIf a pattern for filename generation has no matches,
Xleave it unchanged in the argument list instead of
Xprinting an error.
X.TP
X\fBNO_PROMPT_CR\fP (\-\fBV\fP)
XDon't print a carriage return just before printing
Xa prompt in the line editor.
X.TP
X\fBNO_RCS\fP (\-\fBf\fP)
XDo not source the .zshenv, .zshrc, .zlogin, .zlogout, or .zprofile files.
X.TP
X\fBNO_SHORT_LOOPS\fP
XDisallow the short forms of \fBfor\fP, \fBselect\fP,
X\fBif\fP, and \fBfunction\fP constructs.
X.TP
X\fBNOTIFY\fP (\-\fB5\fP)
XReport the status of background jobs immediately, rather than
Xwaiting until just before printing a prompt.
X.TP
X\fBNOUNSET\fP (\-\fBu\fP)
XTreat unset parameters as an error when substituting.
X.TP
X\fBNULLGLOB\fP (\-\fBG\fP)
XIf a pattern for filename generation has no matches,
Xdelete the pattern from the argument list instead
Xof reporting an error. Overrides \fBNO_NOMATCH\fP.
X.TP
X\fBNUMERICGLOBSORT\fP
XIf numeric filenames are matched by a filename generation pattern,
Xsort the filenames numerically rather than lexicographically.
X.TP
X\fBOVERSTRIKE\fP
XStart up the line editor in overstrike mode.
X.TP
X\fBPATH_DIRS\fP (\-\fBQ\fP)
XPerform a path search even on command names with slashes in them.
XThus if "/usr/local/bin" is in the user's path, and he types
X"X11/xinit", the command "/usr/local/bin/X11/xinit" will be executed
X(assuming it exists).
X.TP
X\fBPRINT_EXIT_VALUE\fP (\-\fBC\fP)
XPrint the exit value of programs with non-zero exit status.
X.TP
X\fBPUSHD_IGNORE_DUPS\fP
XDon't push multiple copies of the same directory onto the directory stack.
X.TP
X\fBPUSHD_MINUS\fP
XSee \fBpopd\fP below.
X.TP
X\fBPUSHD_SILENT\fP (\-\fBE\fP)
XDo not print the directory stack after \fBpushd\fP
Xor \fBpopd\fP.
X.TP
X\fBPUSHD_TO_HOME\fP (\-\fBD\fP)
XHave \fBpushd\fP with no arguments act like
X\fBpushd\fP $HOME.
X.TP
X\fBRC_EXPAND_PARAM\fP (\-\fBP\fP)
XSee \fIParameter Expansion\fP.
X.TP
X\fBRC_QUOTES\fP
XAllow the character sequence \fB''\fP to signify a single quote
Xwithin singly quoted strings.
X.TP
X\fBRECEXACT\fP (\-\fBS\fP)
XIn completion, recognize exact matches even
Xif they are ambiguous.
X.TP
X\fBRMSTARSILENT\fP (\-\fBH\fP)
XDo not query the user before executing "rm *" or "rm path/*".
X.TP
X\fBSHINSTDIN\fP (\-\fBs\fP)
XRead commands from the standard input.
X.TP
X\fBSH_WORD_SPLIT\fP (\-\fBy\fP)
XSee \fIParameter Expansion\fP.
X.TP
X\fBSINGLE_LINE_ZLE\fP (\-\fBM\fP)
XUse single-line command line editing instead of multi-line.
X.TP
X\fBSUN_KEYBOARD_HACK\fP (\-\fBL\fP)
XIf a line ends with a backquote, and there are an odd number
Xof backquotes on the line, ignore the trailing backquote.
XThis is useful on some keyboards where the return key is
Xtoo small, and the backquote key lies annoyingly close to it.
X.TP
X\fBVERBOSE\fP (\-\fBv\fP)
XPrint shell input lines as they are read.
X.TP
X\fBXTRACE\fP (\-\fBx\fP)
XPrint commands and their arguments as they are executed.
X.TP
X\fBZLE\fP (\-\fBZ\fP)
XUse the zsh line editor.
X.RE
X.PD
X.SH "SHELL BUILTIN COMMANDS"
X.TP
X\fB\&.\fP \fIfile\fP [ \fIarg\fP ... ]
XRead and execute commands from \fIfile\fP in the current shell
Xenvironment.
XIf \fIfile\fP does not contain a slash, the shell
Xlooks in the components of \fBpath\fP to find the directory
Xcontaining \fIfile\fP.
XIf any arguments \fIarg\fP are given,
Xthey become the positional parameters; the old positional
Xparameters are restored when the \fIfile\fP is done executing.
XThe exit status is the exit status of the last command executed.
X.TP
X\fB:\fP [ \fIarg\fP ... ]
XThis command only expands parameters. A zero exit code is returned.
X.TP
X\fBalias\fP [ \-\fBg\fP ] [ \fIname\fP[=\fIvalue\fP] ] ...
XWith no arguments, print the list of aliases in the form
X\fIname\fP=\fBvalue\fP on the standard output.
XFor each \fIname\fP with a corresponding \fIvalue\fP, define an alias
Xwith that value.
XA trailing space in \fIvalue\fP causes the next
Xword to be checked for alias substitution.
XIf the \-\fBg\fP flag is present, define a global alias; global aliases
Xare expanded even if they do not occur in command position.
XFor each \fIname\fP with no \fIvalue\fP, print the value of \fIname\fP,
Xif any.
XThe exit status is nonzero if a \fIname\fP (with no \fIvalue\fP)
Xgiven for which no alias has been defined.
X.TP
X\fBautoload\fP [ \fIname\fP ... ]
XFor each of the \fIname\fPs (which are names of functions),
Xcreate a function marked undefined.
XThe \fBfpath\fP variable will be searched to find the
Xactual function definition when the function is first referenced.
X.TP
X.PD 0
X\fBbg\fP [ \fIjob\fP ... ]
X.TP
X\fIjob\fP ... \fB&\fP
X.PD
XPut each specified \fIjob\fP in the background,
Xor the current job if none is specified.
X.TP
X.PD 0
X\fBbindkey\fP \-\fBmevd
X.TP
X\fBbindkey\fP \-\fBr\fP \fIin-string\fP ...
X.TP
X\fBbindkey\fP [ \-\fBa\fP ] \fIin-string\fP [ \fIcommand\fP ] ...
X.TP
X\fBbindkey\fP \-\fBs\fP [ \-\fBa\fP ] \fIin-string\fP \fIout-string\fP ...
X.PD
XIf one of the \-\fBe\fP, \-\fBv\fP, or \-\fBd\fP options is given,
Xreset the keymaps for emacs mode, vi mode, or the default mode,
Xrespectively; if the \-\fBm\fP option is also given,
Xallow the use of a meta key.
XIf the \-\fBr\fP option is given, remove any binding for each \fIin-string\fP.
XIf the \-\fBs\fP option is not specified, bind each \fIin-string\fP
Xto a specified \fIcommand\fP. If no \fIcommand\fP is specified,
Xprint the binding of \fIin-string\fP if it is bound, or return
Xa nonzero exit code if it is not bound.
XIf the \-\fBs\fP option is specified, bind each \fIin-string\fP
Xto each specified \fIout-string\fP. When \fIin-string\fP is typed,
X\fIout-string\fP will be pushed back and treated as input to the
Xline editor.
XIf the \-\fBa\fP option is specified, bind the \fIin-string\fPs in the
Xalternative keymap instead of the standard one. The alternative
Xkeymap is used in vi command mode.
X.RS
X.PP
XFor either \fIin-string\fP or \fIout-string\fP, control characters
Xmay be specified in the form \fB^X\fP, and the backslash may
Xbe used to introduce one of the following escape sequences:
X.RS
X.PD 0
X.TP
X.B \ea
Xbell character
X.TP
X.B \en
Xlinefeed (newline)
X.TP
X.B \eb
Xbackspace
X.TP
X.B \et
Xhorizontal tab
X.TP
X.B \ev
Xvertical tab
X.TP
X.B \ef
Xform feed
X.TP
X.B \er
Xcarriage return
X.TP
X.B \ee
Xescape
X.TP
X.B \ennn
Xcharacter code in octal
X.TP
X.B \eM\-xxx
Xcharacter or escape sequence with meta bit set
X.PD
X.PP
X.RE
XIn all other cases, \e escapes the following character. Delete is
Xwritten as `\fB^?\fP'.
X.RE
X.TP
X\fBbreak\fP [ \fIn\fP ]
XExit from an enclosing \fBfor\fP, \fBwhile\fP,
X\fBuntil\fP, \fBselect\fP, or \fBrepeat\fP loop. If \fIn\fP
Xis specified, then break \fIn\fP levels instead of just one.
X.TP
X\fBbuiltin\fP \fIname\fP [ \fIargs\fP ] ...
XExecutes the builtin \fIname\fP, with the given \fIargs\fP.
X.TP
X\fBbye\fP
XSame as \fBexit\fP.
X.TP
X.PD 0
X\fBcd\fP [ \fIarg\fP ]
X.TP
X\fBcd\fP \fIold\fP \fInew\fP
X.TP
X\fBcd\fP \(+-\fBn\fP
X.PD
XChange the current directory. In the first form, change the
Xcurrent directory to \fIarg\fP, or to the value of \fBHOME\fP if
X\fIarg\fP is not specified. If \fIarg\fP is \-, change to the
Xvalue of \fBOLDPWD\fP, the previous directory.
XIf a directory named \fIarg\fP is not found in the current directory
Xand \fIarg\fP does not begin with a slash,
Xsearch each component of the shell parameter \fBcdpath\fP.
XIf the option \fBCDABLEVARS\fP is set, and a parameter named \fIarg\fP
Xexists whose value begins with a slash, treat its value as
Xthe directory.
X.RS
X.PP
XThe second form of \fBcd\fP substitutes the string \fInew\fP
Xfor the string \fIold\fP in the name of the current directory,
Xand tries to change to this new directory.
X.PP
XThe third form of \fBcd\fP is equivalent to \fBpopd\fP.
X.RE
X.TP
X\fBchdir\fP
XSame as \fBcd\fP.
X.TP
X\fBcompctl\fP [ \-\fBcfhovbCD\fP ] [ \-\fBk\fP \fIname\fP ] [ \fIarg\fP ... ]
XControl the editor's completion behavior when one of \fIarg\fP is the current
Xcommand. With the \-\fBD\fP flag, control default completion behavior
Xfor commands not assigned any special behavior; with \-\fBC\fP, control
Xcompletion when there is no current command. The remaining options
Xspecify the type of command arguments to look for during completion.
XFor example, \fBcompctl\fP \-\fBhf\fP \fBrlogin\fP is equivalent
Xto \fBhostcmds=(rlogin)\fP.
X.RS
X.PD 0
X.TP
X\-\fBc\fP
XExpect command names.
X.TP
X\-\fBf\fP
XExpect filenames and filesystem paths.
X.TP
X\-\fBh\fP
XExpect hostnames taken from the \fB$hosts\fP variable.
X.TP
X\-\fBo\fP
XExpect option names.
X.TP
X\-\fBv\fP
XExpect variable names.
X.TP
X\-\fBb\fP
XExpect key binding names.
X.TP
X\-\fBk\fP \fIname\fP
XExpect names taken from the elements of \fB$name\fP.
X.PD
X.RE
X.TP
X\fBcontinue\fP [ \fInum\fP ]
XResume the next iteration of the enclosing
X\fBfor\fP, \fBwhile\fP, \fBuntil\fP, \fBselect\fP, or
X\fBrepeat\fP loop. If \fIn\fP is specified, break out of
X\fIn\fP \- 1 loops and resume at the \fIn\fPth enclosing loop.
X.TP
X\fBdeclare\fP [ \fIarg\fP ... ]
XSame as \fBtypeset\fP.
X.TP
X\fBdirs\fP [ \-\fBv\fP ] [ \fIarg\fP ... ]
XWith no arguments, print the contents of the directory stack.
XIf the \-\fBv\fP option is given, number the directories
Xin the stack when printing.
XDirectories are added to this stack with the \fBpushd\fP command,
Xand removed with the \fBcd\fP or \fBpopd\fP commands.
XIf arguments are specified, load them onto the directory stack,
Xreplacing anything that was there, and push the current directory
Xonto the stack.
X.TP
X\fBdisable\fP \fIarg\fP ...
XDisable the builtin \fIarg\fP temporarily. This allows you to use
Xan external command with the same name as a shell builtin.
XActually the same as \fBunhash\fP.
XBuiltins can be enabled with the \fBenable\fP command.
X.TP
X\fBdisown\fP \fIjob\fP ...
XRemove the specified jobs from the job table; the shell will
Xno longer report their status, and will not complain if you
Xtry to exit an interactive shell with them running or stopped.
X.TP
X\fBecho\fP [ \-\fBn\fP ] [ \fIarg\fP ... ]
XWrite each \fIarg\fP on the standard output, with a space separating
Xeach one.
XIf the \-\fBn\fP flag is not present, print a newline at the end.
X\fBecho\fP recognizes the following escape sequences:
X.RS
X.PD 0
X.TP
X.B \eb
Xbackspace
X.TP
X.B \ec
Xdon't print an ending newline
X.TP
X.B \ee
Xescape
X.TP
X.B \ef
Xform feed
X.TP
X.B \en
Xnewline
X.TP
X.B \er
Xcarriage return
X.TP
X.B \et
Xhorizontal tab
X.TP
X.B \ev
Xvertical tab
X.TP
X.B \e\e
Xbackslash
X.TP
X.B \exxx
Xcharacter code in octal
X.PD
X.RE
X.TP
X\fBechotc\fP \fIcap\fP [ \fIarg\fP ... ]
XOutput the termcap string corresponding to the capability
X\fIcap\fP, with optional arguments.
X.TP
X\fBenable\fP \fIarg\fP ...
XEnable the specified builtin commands, presumably disabled earlier
Xwith \fBdisable\fP.
X.TP
X\fBeval\fP [ \fIarg\fP ... ]
XRead the arguments as input to the shell and execute the resulting
Xcommand(s) in the current shell process.
X.TP
X\fBexit\fP [ \fIn\fP ]
XExit the shell with the exit code specified by \fIn\fP; if none
Xis specified, use the exit code from the last command executed.
XAn EOF condition will also cause the shell to exit, unless
Xthe \fBIGNOREEOF\fP option is set.
X.TP
X\fBexport\fP [ \fIname\fP[=\fIvalue\fP] ... ]
XThe specified \fIname\fPs are marked for automatic export
Xto the environment of subsequently executed commands.
X.TP
X\fBfalse\fP
XDo nothing and return an exit code of 1.
X.TP
X.PD 0
X\fBfc\fP [ \-\fBe\fP \fIename\fP ] [ \-\fBnlrdD\fP ] [ \fIold\fP=\fInew\fP ... ] [ \fIfirst\fP [ \fIlast\fP ] ]
X.TP
X\fBfc\fP \-\fBARW\fP [ \fIfilename\fP ]
X.PD
XSelect a range of commands from \fIfirst\fP to \fIlast\fP from the
Xhistory list.
XThe arguments \fIfirst\fP and \fIlast\fP may be specified as a
Xnumber or as a string. A negative number is used as an offset
Xto the current history event number.
XA string specifies the most recent event
Xbeginning with the given string.
XAll substitutions \fIold\fP=\fInew\fP, if any, are then performed
SHAR_EOF
true || echo 'restore of zsh2.2/man/man1/zsh.1 failed'
fi
echo 'End of zsh2.2 part 4'
echo 'File zsh2.2/man/man1/zsh.1 is continued in part 5'
echo 5 > _shar_seq_.tmp

Paul Falstad

unread,
May 13, 1992, 11:58:55 AM5/13/92
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 29, Issue 101
Archive-name: zsh2.2/part05

Environment: BSD
Supersedes: zsh2.1: Volume 24, Issue 1-19

#!/bin/sh
# this is aa.05 (part 5 of zsh2.2)


# do not concatenate these parts, unpack them in order with /bin/sh

# file zsh2.2/man/man1/zsh.1 continued
#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 5; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping zsh2.2/man/man1/zsh.1'
else
echo 'x - continuing file zsh2.2/man/man1/zsh.1'
sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.2/man/man1/zsh.1' &&

Xon the commands.
XIf the \-\fBl\fP flag is given, the resulting commands are listed on
Xstandard output.
XOtherwise the editor program \fIename\fP is invoked on a file containing
Xthese history events. If \fIename\fP is not given, the value
Xof the parameter \fBFCEDIT\fP is used. If \fIename\fP is "\-",
Xno editor is invoked. When editing is complete, the edited
Xcommand(s) is executed.
XIf \fIfirst\fP is not specified, it will be set to \-1 (the most recent
Xevent), or to -16 if the \-\fBl\fP flag is given.
XIf \fIlast\fP is not specified, it will be set to \fIfirst\fP,
Xor to \-1 if the \-\fBl\fP flag is given.
XThe flag \-\fBr\fP reverses the order of the commands and the
Xflag \-\fBn\fP suppresses command numbers when listing.
XAlso when listing, \-\fBd\fP prints datestamps for each command,
Xand \-\fBD\fP prints real execution times.
X.RS
X.PP
X\fBfc\fP \-\fBR\fP reads the history from the given file,
X\fBfc\fP \-\fBW\fP writes the history out to the given file,
Xand \fBfc\fP \-\fBA\fP appends the history out to the given file.
X.RE
X.TP
X.PD 0
X\fBfg\fP [ \fIjob\fP ... ]


X.TP
X\fIjob\fP ...

X.PD
XBring the specified \fIjob\fPs to the foreground.
XIf no \fIjob\fP is specified, use the current job.
X.TP
X\fBfunctions\fP [ \(+-\fBtu\fP ] [ \fIname\fP ... ]
XEquivalent to \fBtypeset\fP \-\fBf\fP.
X.TP
X\fBgetln\fP \fIname\fP ...
XRead the top value from the buffer stack and put it in
Xthe shell parameter \fIname\fP. Equivalent to
X\fBread\fP \-\fBzr\fP.
X.TP
X\fBgetopts\fP \fIoptstring\fP \fIname\fP [ \fIarg\fP ... ]
XChecks \fBarg\fP for legal options. If \fIarg\fP is omitted,
Xuse the positional parameters. A valid option argument
Xbegins with a + or a \-. An argument not beginning with
Xa + or a \-, or the argument \-\-, ends the options.
X\fIoptstring\fP contains the letters that \fBgetopts\fP
Xrecognizes. If a letter is followed by a `:', that option
Xis expected to have an argument. The options can be
Xseparated from the argument by blanks.
X.RS
X.PP
XEach time it is invoked, \fBgetopts\fP places the option letter it finds
Xin the shell parameter \fIname\fP, prepended with a + when
X\fIarg\fP begins with a +. The index of the next \fIarg\fP
Xis stored in \fBOPTIND\fP. The option argument, if any,
Xis stored in \fBOPTARG\fP.
X.PP
XA leading : in \fIoptstring\fP causes \fBgetopts\fP to store the
Xletter of the invalid option in \fBOPTARG\fP, and to set \fIname\fP
Xto `?' for an unknown option and to `:' when a required option
Xis missing. Otherwise, \fBgetopts\fP prints an error
Xmessage. The exit status is nonzero when there are no more options.
X.RE
X.TP
X\fBhash\fP \fIname\fP \fIpath\fP
XPuts \fIname\fP in the command hash table, associating it with
Xthe pathname \fIpath\fP. Whenever \fIname\fP is used as a command
Xargument, the shell will try to execute the file given by \fIpath\fP.
X.TP
X\fBhistory\fP [ \-\fBnr\fP ] [ \fIfirst\fP [ \fIlast\fP ] ]
XSame as \fBfc\fP \-\fBl\fP.
X.TP
X\fBinteger\fP
XSame as \fBtypeset\fP \-\fBi\fP.
X.TP
X\fBjobs\fP [ \-\fBlp\fP ] [ \fIjob\fP ... ]
XLists information about each given job, or all jobs
Xif \fIjob\fP is omitted. The \-\fBl\fP flag lists process
Xids, and the \-\fBp\fP flag lists process groups.
X.TP
X.PD 0
X\fBkill\fP [ \-\fIsig\fP ] \fIjob\fP ...
X.TP
X\fBkill\fP \-\fBl\fP
X.PD
XSends either SIGTERM or the specified signal to the given
Xjobs or processes.
XSignals are given by number or by names
X(with the prefix "SIG" removed).
XIf the signal being sent is not KILL or CONT, then the job
Xwill be sent a CONT signal if it is stopped.
XThe argument \fIjob\fP can be the process id of a job
Xnot in the job list.
XIn the second form, \fBkill\fP \-\fBl\fP, the signal names
Xare listed.
X.TP
X\fBlet\fP \fIarg\fP ...
XEvaluate each \fIarg\fP as an arithmetic expression.
XSee \fBARITHMETIC EVALUATION\fP above for a description
Xof arithmetic expressions. The exit status is 0 if the
Xvalue of the last expression is nonzero, and 1 otherwise.
X.TP
X.PD 0
X\fBlimit\fP [ \-\fBh\fP ] [ \fIresource\fP [ \fIlimit\fP ] ] ...
X.TP
X\fBlimit\fP \-\fBs\fP
X.PD
XLimit the resource consumption of children of the current shell.
XIf \fIlimit\fP is not specified, print the current limit placed
Xon \fIresource\fP; otherwise
Xset the limit to the specified value. If the \-\fBh\fP flag
Xis given, use hard limits instead of soft limits.
XIf no \fIresource\fP is given, print all limits.
X.RS
X.PP
X\fIresource\fP is one of:
X.PP
X.PD 0
X.TP
X.B cputime
XMaximum CPU seconds per process.
X.TP
X.B filesize
XLargest single file allowed.
X.TP
X.B datasize
XMaximum data size (including stack) for each process.
X.TP
X.B stacksize
XMaximum stack size for each process.
X.TP
X.B coredumpsize
XMaximum size of a core dump.
X.TP
X.B resident
XMaximum resident set size.
X.TP
X.B descriptors
XMaximum value for a file descriptor.
X.PD
X.PP
X\fIlimit\fP is a number, with an optional scaling factor, as follows:
X.PP
X.PD 0
X.TP
X\fIn\fPh
Xhours.
X.TP
X\fIn\fPk
Xkilobytes.
XThis is the default for all but cputime.
X.TP
X\fIn\fPm
Xmegabytes or minutes.
X.TP
X\fImm\fP:\fBss\fP
Xminutes and seconds.
X.PD
X.RE
X.TP
X\fBlocal\fP


XSame as \fBtypeset\fP.
X.TP

X\fBlog\fP
XList all users currently logged in who are affected by
Xthe current setting of the \fBwatch\fP parameter.
X.TP
X\fBlogout\fP
XExit the shell, if this is a login shell.
X.TP
X\fBpopd\fP [ \(+-\fIn\fP ]
XRemoves entries from the directory stack. With no arguments,
Xremoves the top directory from the stack, and performs a \fBcd\fP
Xto the new top directory. With an argument of the form +\fIn\fP,
Xremove the \fIn\fPth entry counting from the left of the list
Xshown by the \fBdirs\fP command, starting with zero, and change
Xto that directory. With an argument of the form \-\fIn\fP,
Xremove the \fIn\fPth entry counting from the right.
XIf the \fBPUSHD_MINUS\fP option is set, the meanings of +
Xand \- in this context are swapped.
X.TP
X\fBprint\fP [ \-\fBRnrslzpNDP\fP ] [ \-\fBu\fP\fIn\fP ] [ \fIarg\fP ... ]
XWith no flags or with flag \-, the arguments are printed on
Xthe standard output as described by \fBecho\fP.
X.RS
X.PD 0
X.TP
X\-\fBR\fP, \-\fBr\fP
Xignore the escape conventions of \fBecho\fP.
XThe \-\fBR\fP option will print all subsequent
Xarguments and options.
X.TP
X\-\fBs\fP
Xplace the results in the history list instead of on the standard output.
X.TP
X\-\fBn\fP
Xdo not add a newline to the output.
X.TP
X\-\fBl\fP
Xprint the arguments separated by newlines instead of spaces.
X.TP
X\-\fBN\fP
Xprint the arguments separated and terminated by nulls.
X.TP
X\-\fBu\fP\fIn\fP
Xprint the arguments to file descriptor \fIn\fP.
X.TP
X\-\fBp\fP
Xprint the arguments to the input of the coprocess.
X.TP
X\-\fBz\fP
Xpush the arguments onto the editing buffer stack, separated by spaces;
Xno escape sequences are recognized.
X.TP
X\-\fBD\fP
Xtreat the arguments as directory names, replacing prefixes with ~
Xexpressions, as appropriate.
X.TP
X\-\fBP\fP
Xrecognize the same escape sequences as in the \fBPROMPT\fP parameter.
X.PD
X.RE
X.TP
X.PD 0
X\fBpushd\fP [ \fIarg\fP ]
X.TP
X\fBpushd\fP \fIold\fP \fInew\fP
X.TP
X\fBpushd\fP \(+-\fBn\fP
X.PD
XChange the current directory, and push the old current directory
Xonto the directory stack. In the first form, change the
Xcurrent directory to \fIarg\fP.
XIf \fIarg\fP is not specified, change to the second directory
Xon the stack (that is, exchange the top two entries), or
Xchange to the value of \fBHOME\fP if the \fBPUSHD_TO_HOME\fP
Xoption is set or if there is only one entry on the stack.
XIf \fIarg\fP is \-, change to the


Xvalue of \fBOLDPWD\fP, the previous directory.
XIf a directory named \fIarg\fP is not found in the current directory

Xand \fIarg\fP does not contain a slash,


Xsearch each component of the shell parameter \fBcdpath\fP.
XIf the option \fBCDABLEVARS\fP is set, and a parameter named \fIarg\fP
Xexists whose value begins with a slash, treat its value as
Xthe directory.

XIf the option \fBPUSHD_SILENT\fP is not set, the directory
Xstack will be printed after a \fBpushd\fP is performed.
X.RS
X.PP
XThe second form of \fBpushd\fP substitutes the string \fInew\fP


Xfor the string \fIold\fP in the name of the current directory,
Xand tries to change to this new directory.
X.PP

XThe third form of \fBpushd\fP is equivalent to \fBpopd\fP.
X.RE
X.TP
X\fBpwd\fP
XEquivalent to \fBprint \-R $PWD\fP.
X.TP
X\fBr\fP
XEquivalent to \fBfc \-e \-\fP.
X.TP
X\fBread\fP [ \-\fBrzp\fP ] [ \-\fBu\fIn\fR ] [ \fIname\fP?\fIprompt\fP ] [ \fIname\fP ... ]
XRead one line and break it into fields using the characters
Xin \fBIFS\fP as separators. In raw mode, \-\fBr\fP, a \e
Xat the end of a line does not signify line continuation.
XIf the \-\fBz\fP flag is set, read from the editor buffer stack.
XThe first field is assigned to the first \fIname\fP, the second field
Xto the second \fIname\fP, etc., with leftover
Xfields assigned to the last \fIname\fP.
XIf \fIname\fP is omitted then \fBREPLY\fP is used.
XIf \-\fBu\fIn\fR is specified, then input is read from file
Xdescriptor \fIn\fP; if \-\fBp\fP is specified, then input is
Xread from the coprocess.
XThe exit status is 0 unless end-of-file is encountered.
XIf the first argument contains a \fB?\fP, the remainder of this
Xword is used as a \fIprompt\fP on standard error when the shell
Xis interactive. The exit status is 0 unless an end-of-file
Xis encountered.
X.TP
X\fBreadonly\fP [ \fIname\fP[=\fIvalue\fP] ] ...
XThe given \fInames\fP are marked readonly; these names
Xcannot be changed by subsequent assignment.
X.TP
X\fBrehash\fP [ \-\fBf\fP ]
XThrow out the command hash table and start over.
XIf the \-\fBf\fP option is set, rescan the command path
Ximmediately, instead of rebuilding the hash table incrementally.
X.TP
X\fBreturn\fP [ \fIn\fP ]
XCauses a shell function or \fB\&.\fP script to return to
Xthe invoking script
Xwith the return status specified by \fIn\fP. If \fIn\fP
Xis omitted then the return status is that of the last command
Xexecuted.
X.TP
X.PD 0
X\fBsched\fP [+]\fIhh\fP:\fImm\fP \fIcommand\fP ...
X.TP
X\fBsched\fP [ \-\fIitem\fP ]
X.PD
XMake an entry in the scheduled list of commands to execute.
XThe time may be specified in either absolute or relative time.
XWith no arguments, prints the list of scheduled commands.
XWith the argument \-\fIitem\fP, removes the given item
Xfrom the list.
X.TP
X\fBset\fP [ \(+-\fIoptions\fP ] [ \(+-\fBo\fP \fIoption name\fP ] ... [ \-\fBA\fP \fIname\fP ] [ \fIarg\fP ] ...
XSet the options for the shell and/or set the positional parameters, or
Xdeclare an array. For the meaning of the flags, see
X\fBOPTIONS\fP above.
XFlags may be specified by name using the \-\fBo\fP option.
XIf the \-\fBA\fP flag is specified, \fIname\fP is set to an
Xarray containing the given \fIarg\fPs.
XOtherwise the positional parameters are set.
XIf no arguments are given, then the names and values
Xof all parameters are printed on the standard output.
XIf the only argument is +, the names of all parameters are printed.
X.TP
X\fBsetopt\fP [ \(+-\fIoptions\fP ] [ \fIname\fP ... ]
XSet the options for the shell. All options specified either
Xwith flags or by name are set. If no arguments are supplied,
Xthe names of all options currently set are printed.
XIn option names, case is insignificant, and all underscore
Xcharacters are ignored.
X.TP
X\fBshift\fP [ \fIn\fP ]
XThe positional parameters from $\fIn\fP+\fB1\fP ... are renamed
X$\fB1\fP, where \fIn\fP is an arithmetic expression that
Xdefaults to 1.
X.TP
X\fBsource\fP
XSame as \fB.\fP.
X.TP
X\fBsuspend\fP [ \-\fBf\fP ]
XSuspend the execution of the shell (send it a \fBSIGTSTP\fP)
Xuntil it receives a \fBSIGCONT\fP.
XIf the \-\fBf\fP option is not given, complain if this is a login shell.
X.TP
X.PD 0
X\fBtest\fP \fIarg\fP ...
X.TP
X\fB[\fP \fIarg\fP ... \fB]\fP
X.PD
XLike the system version of \fBtest\fP. Added for compatibility;
Xuse conditional expressions instead.
X.TP
X\fBtimes\fP
XPrint the accumulated user and system times for the shell
Xand for processes run from the shell.
X.TP
X\fBtrap\fP [ \fIarg\fP ] [ \fIsig\fP ] ...
X\fIarg\fP is a command to be read and executed when the shell
Xreceives \fIsig\fP. Each \fIsig\fP can be given as a number
Xor as the name of a signal.
XIf \fIarg\fP is \-, then all traps \fIsig\fP are reset to their
Xdefault values. If \fIarg\fP is the null string, then this signal
Xis ignored by the shell and by the commands it invokes.
XIf \fIsig\fP is \fBERR\fP then \fIarg\fP will be executed
Xafter each command.
XIf \fIsig\fP is \fB0\fP or \fBEXIT\fP
Xand the \fBtrap\fP statement is executed inside the body of a function,
Xthen the command \fIarg\fP is executed after the function completes.
XIf \fIsig\fP is \fB0\fP or \fBEXIT\fP
Xand the \fBtrap\fP statement is not executed inside the body of a function,
Xthen the command \fIarg\fP is executed when the shell terminates.
XThe \fBtrap\fP command with no arguments prints a list of commands
Xassociated with each signal.
X.TP
X\fBtrue\fP
XDo nothing and return an exit code of 0.
X.TP
X\fBttyctl\fP \-\fBfu\fP
XThe \-\fBf\fP option freezes the tty, and \-\fBu\fP unfreezes it.
XWhen the tty is frozen, no changes made to the tty settings by
Xexternal programs will be honored by the shell; the shell will
Xsimply reset the settings to their previous values as soon as each
Xcommand exits. Thus, \fBstty\fP and similar programs have no
Xeffect when the tty is frozen.
X.TP
X\fBtype\fP
XSame as \fBwhence\fP \-\fBv\fP.
X.TP
X\fBtypeset\fP [ \(+-\fBLRZfilrtux [\fIn\fP]] [ \fIname\fP[=\fIvalue\fP] ] ...
XSet attributes and values for shell parameters.
XWhen invoked inside a function, if \fIname\fP is not already
Xdefined, a new parameter is created which will be unset when the
Xfunction completes.
XThe following attributes are valid:
X.RS
X.PD 0
X.TP
X\-\fBL\fP
XLeft justify and remove leading blanks from \fIvalue\fP.
XIf \fIn\fP is nonzero, it defines the width of the field;
Xotherwise it is determined by the width of the value of the first
Xassignment.
XWhen the parameter is printed, it is filled on the right with
Xblanks or truncated if necessary to fit the field.
XLeading zeros are removed if the \-\fBZ\fP flag is also set.
X.TP
X\-\fBR\fP
XRight justify and fill with leading blanks. If \fIn\fP is nonzero
Xif defines the width of the field;
Xotherwise it is determined by the width of the value of the first
Xassignment.
XWhen the parameter is printed, the field is left filled with
Xblanks or truncated from the end.
X.TP
X\-\fBZ\fP
XRight justify and fill with leading zeros if the first non-blank
Xcharacter is a digit and the \-\fBL\fP flag has not been set.
XIf \fIn\fP is nonzero it defines the width of the field;
Xotherwise it is determined by the width of the value of the
Xfirst assignment.


X.TP
X\-\fBf\fP

XThe names refer to functions rather than parameters. No assignments
Xcan be made, and the only other valid flags are \-\fBt\fP
Xand \-\fBu\fP. The flag \-\fBt\fP turns on execution tracing for this
Xfunction. The flag \-\fBu\fP causes this function to be marked
Xfor autoloading. The \fBfpath\fP parameter will be searched to find the
Xfunction definition when the function is first referenced.
X.TP
X\-\fBi\fP
XUse an internal integer representation. If \fBi\fP is nonzero
Xit defines the output arithmetic base, otherwise it is determined by the first
Xassignment.
X.TP
X\-\fBl\fP
XConvert to lower case.
X.TP
X\-\fBr\fP
XThe given \fIname\fPs are marked readonly.
X.TP
X\-\fBt\fP
XTags the named parameters. Tags have no special meaning to the shell.
X.TP
X\-\fBu\fP
XConvert to upper case.
X.TP
X\-\fBx\fP
XMark for automatic export to the environment of subsequently
Xexecuted commands.
X.RE
X.PD
X.PP
XUsing + rather than \- causes these flags to be turned off.
XIf no arguments are given but flags are specified,
Xa list of named parameters which have these flags set is printed.
XUsing + instead of \- keeps their values from being printed.
XIf no arguments or options are given, the names and attributes
Xof all parameters are printed.
X.TP
X\fBulimit\fP [ \-\fBHSacdfmnt\fP ] [ \fIlimit\fP ]
XSet or display a resource limit. The value of limit can be a number
Xin the unit specified below or the value \fBunlimited\fP.
XThe \fBH\fP and \fBS\fP flags specify whether the hard limit
Xor the soft limit for the given resource is set.
X.RS
X.PD 0
X.TP
X\-\fBa\fP
XLists all of the current resource limits.


X.TP
X\-\fBc\fP

XThe number of 512-byte blocks on the size of core dumps.
X.TP
X\-\fBd\fP
XThe number of K-bytes on the size of the data segment.


X.TP
X\-\fBf\fP

XThe number of 512-byte blocks on the size of files written.
X.TP
X\-\fBm\fP
XThe number of K-bytes on the size of physical memory.
X.TP
X\-\fBn\fP
XThe number of file descriptors.
X.TP
X\-\fBs\fP
XThe number of K-bytes on the size of the stack.
X.TP
X\-\fBt\fP
XThe number of CPU seconds to be used.
X.RE
X.PD
X.TP
X\fBumask\fP [ \fImask\fP ]
XThe umask is set to \fImask\fP. \fImask\fP can be either
Xan octal number or a symbolic value as described in \fBchmod\fP(1).
XIf \fImask\fP is omitted, the current value is printed.
X.TP
X\fBunalias\fP \fIname\fP ...
XThe alias definition, if any, for each \fIname\fP is removed.
X.TP
X\fBunfunction\fP \fIname\fP ...
XThe function definition, if any, for each \fIname\fP is removed.
X.TP
X\fBunhash\fP \fIname\fP ...
XThe entry in the command hash table, if any, for each \fIname\fP
Xis removed.
X.TP
X\fBunlimit\fP [ \-\fBh\fP ] \fIresource\fP ...
XThe resource limit for each \fIresource\fP is set to the hard limit.
XIf the \-\fBh\fP flag is given and the shell is running as root,
Xthe hard resource limit for each \fIresource\fP is removed.
X.TP
X\fBunset\fP \fIname\fP ...
XEach named parameter is unset.
X.TP
X\fBunsetopt\fP [ \(+-\fIoptions\fP ] [ \fIname\fP ... ]
XUnset the options for the shell. All options specified either
Xwith flags or by name are unset.
X.TP
X\fBvared\fP \fIname\fP
XThe value of the parameter \fIname\fP is loaded into the edit
Xbuffer, and the line editor is invoked. When the editor exits,
X\fIname\fP is set to the string value returned by the editor.
X.TP
X\fBwait\fP [ \fIjob\fP ... ]
XWait for the specified jobs or processes. If \fIjob\fP is not given
Xthen all currently active child processes are waited for.
XEach \fIjob\fP can be either a job specification or the process-id
Xof a job in the job table.
XThe exit status from this command is that of the job waited for.
X.TP
X\fBwhence\fP [ \-\fBacpv\fP ] \fIname\fP ...
XFor each name, indicate how it would be interpreted if used
Xas a command name. The \-\fBv\fP flag produces a more verbose
Xreport. The \-\fBp\fP flag does a path search for \fIname\fP
Xeven if it is a shell function, alias, or reserved word.
XThe \-\fBc\fP flag prints the results in a csh-like format.
XThe \-\fBa\fP flag does a search for all occurences of \fIname\fP
Xthroughout the command path.
X.TP
X\fBwhich\fP
XSame as \fBwhence \-c\fP.
X.RE
X.SH INVOCATION
XCommands are first read from /etc/zshenv.
XThen, if the \fBNO_RCS\fP option is unset, commands are read
Xfrom $ZDOTDIR/.zshenv.
X(If \fBZDOTDIR\fP is unset, \fBHOME\fP is used instead).
XThen, if the shell is interactive and
Xthe \fBNO_RCS\fP option is unset, commands are read
Xfrom /etc/zshrc and $ZDOTDIR/.zshrc, in that order, if either file
Xexists.
XIf the first character of argument zero passed to the shell
Xis \-, then the shell is assumed to be a login shell, and commands
Xare read from /etc/zprofile and $ZDOTDIR/.zprofile before .zshrc is read,
Xthen /etc/zlogin and $ZDOTDIR/.zlogin after .zshrc is read.
XIf the \fBNO_RCS\fP option is set, only /etc/zshrc
X/etc/zlogin, and /etc/zprofile may be read.
XIf the \-\fBs\fP flag is not present and an argument is given,
Xthe first argument is taken to be the pathname of a script to
Xexecute. The remaining arguments are assigned to the positional
Xparameters. The following flags are interpreted by the shell
Xwhen invoked:
X.TP
X.PD 0
X\-\fBc\fP \fIstring\fP
XRead commands from \fIstring\fP.
X.TP
X\-\fBs\fP
XRead command from the standard input.
X.TP
X\-\fBi\fP
XIf this flag is present or the shell input and output
Xare attached to a terminal, this shell is interactive.
X.PD
X.SH "SEE ALSO"
Xsh(1),
Xcsh(1),
Xtcsh(1),
Xitcsh(1),
Xrc(1),
Xbash(1),
Xash(1),
Xksh(1),
Xclam(1),
Xstrftime(3).
X.SH FILES
X$ZDOTDIR/.zshenv
X.br
X$ZDOTDIR/.zshrc
X.br
X$ZDOTDIR/.zlogin
X.br
X$ZDOTDIR/.zlogout
X.br
X$ZDOTDIR/.zprofile
X.br
X/tmp/zsh*
X.br
X/etc/zshenv
X.br
X/etc/zprofile
X.br
X/etc/zshrc
X.br
X/etc/zlogin
X.SH AUTHOR
XPaul Falstad (pfal...@phoenix.princeton.edu)
X.SH "UNDOCUMENTED FEATURES"
XNone known, but many suspected.
XPlease mail the author if you find any.
SHAR_EOF
echo 'File zsh2.2/man/man1/zsh.1 is complete' &&
chmod 0644 zsh2.2/man/man1/zsh.1 ||


echo 'restore of zsh2.2/man/man1/zsh.1 failed'

Wc_c="`wc -c < 'zsh2.2/man/man1/zsh.1'`"
test 112852 -eq "$Wc_c" ||
echo 'zsh2.2/man/man1/zsh.1: original size 112852, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/scripts/aproto ==============
if test ! -d 'zsh2.2/scripts'; then
echo 'x - creating directory zsh2.2/scripts'
mkdir 'zsh2.2/scripts'
fi
if test -f 'zsh2.2/scripts/aproto' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/scripts/aproto (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/scripts/aproto (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/scripts/aproto' &&
X#! /bin/sh
Xfproto builtin.c >builtin.pro
Xfproto cond.c >cond.pro
Xfproto exec.c >exec.pro
Xfproto glob.c >glob.pro
Xfproto hist.c >hist.pro
Xfproto init.c >init.pro
Xfproto jobs.c >jobs.pro
Xfproto lex.c >lex.pro
Xfproto loop.c >loop.pro
Xfproto math.c >math.pro
Xfproto mem.c >mem.pro
Xfproto params.c >params.pro
Xfproto subst.c >subst.pro
Xfproto table.c >table.pro
Xfproto text.c >text.pro
Xfproto utils.c >utils.pro
Xfproto watch.c >watch.pro
Xfproto parse.c >parse.pro
Xfproto zle_hist.c >zle_hist.pro
Xfproto zle_main.c >zle_main.pro
Xfproto zle_misc.c >zle_misc.pro
Xfproto zle_move.c >zle_move.pro
Xfproto zle_refresh.c >zle_refresh.pro
Xfproto zle_tricky.c >zle_tricky.pro
Xfproto zle_utils.c >zle_utils.pro
Xfproto zle_vi.c >zle_vi.pro
Xfproto zle_word.c >zle_word.pro
SHAR_EOF
chmod 0755 zsh2.2/scripts/aproto ||
echo 'restore of zsh2.2/scripts/aproto failed'
Wc_c="`wc -c < 'zsh2.2/scripts/aproto'`"
test 755 -eq "$Wc_c" ||
echo 'zsh2.2/scripts/aproto: original size 755, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/scripts/fproto ==============
if test -f 'zsh2.2/scripts/fproto' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/scripts/fproto (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/scripts/fproto (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/scripts/fproto' &&
X#! /bin/sh
X# prototype generator
Xsed -n '/\/\*\*\/$/{N;s/^\([^(]*\).*\/\*\*\/.\(.*\)/\1 DCLPROTO((\2))/p;}' $1 | sed -e 's/;/,/g' -e 's/,))$/));/' -e 's/(({))$/((void));/'
X
SHAR_EOF
chmod 0755 zsh2.2/scripts/fproto ||
echo 'restore of zsh2.2/scripts/fproto failed'
Wc_c="`wc -c < 'zsh2.2/scripts/fproto'`"
test 173 -eq "$Wc_c" ||
echo 'zsh2.2/scripts/fproto: original size 173, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/scripts/ctoz ==============
if test -f 'zsh2.2/scripts/ctoz' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/scripts/ctoz (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/scripts/ctoz (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/scripts/ctoz' &&
X#! /bin/sh
X#
X# ctoz - alias conversion tool
X# This file is part of zsh, the Z shell.
X# (c) 1991 Paul Falstad
X#
X# This is a quick script to convert csh aliases to zsh aliases/functions.
X# Pipe the output of csh's alias command through this; it will generate
X# a series of alias/function definitions on stdout, suitable for
X# processing by zsh (probably also ksh or bash).
X#
X# This is not perfect, but it gets most common aliases; it should manage to
X# cut down a lot of the busy work.
X#
Xsed -e 's/ (\(.*\))/ \1/' >/tmp/cz$$.1
Xgrep ! /tmp/cz$$.1 >/tmp/cz$$.2
Xgrep -v ! /tmp/cz$$.1 >/tmp/cz$$.3
Xsed -e "s/'/'"\\\\"''"/g -e 's/^\([^ ]*\) \(.*\)$/alias \1='"'\2'/" \
X /tmp/cz$$.3
Xsed -e 's/![:#]*/$/g' -e 's/^\([^ ]*\) \(.*\)$/\1 () { \2 }/' /tmp/cz$$.2
Xrm /tmp/cz$$.?
X#
X# in case your mailer eats tabs, here it is again, with the tabs
X# marked with a T:
X#
X#sed -e 's/T(\(.*\))/T\1/' >/tmp/cz$$.1
X#grep ! /tmp/cz$$.1 >/tmp/cz$$.2
X#grep -v ! /tmp/cz$$.1 >/tmp/cz$$.3
X#sed -e "s/'/'"\\\\"''"/g -e 's/^\([^T]*\)T\(.*\)$/alias \1='"'\2'/" \
X# /tmp/cz$$.3
X#sed -e 's/![:#]*/$/g' -e 's/^\([^T]*\)T\(.*\)$/\1 () { \2 }/' /tmp/cz$$.2
X#rm /tmp/cz$$.?
SHAR_EOF
chmod 0644 zsh2.2/scripts/ctoz ||
echo 'restore of zsh2.2/scripts/ctoz failed'
Wc_c="`wc -c < 'zsh2.2/scripts/ctoz'`"
test 1137 -eq "$Wc_c" ||
echo 'zsh2.2/scripts/ctoz: original size 1137, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/scripts/fooz ==============
if test -f 'zsh2.2/scripts/fooz' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/scripts/fooz (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/scripts/fooz (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/scripts/fooz' &&
Xalias -- 0='vi'
Xalias -- a='alias'
Xalias -- a.out='./a.out'
Xalias -- c='cp'
Xalias -- gnu='telnet gnu.ai.mit.edu'
Xalias -- grep='egrep'
Xalias -- gz='gdb zsh'
Xalias -- j='jobs -l'
Xalias -- k='kill'
Xalias -- l='ls -AF'
Xalias -- lock='lock -p -600'
Xalias -- lsd='ls -d */'
Xalias -- m='make'
Xalias -- main='./main'
Xalias -- man='woman'
Xalias -- mm='less'
Xalias -- more='less'
Xalias -- nw='l -ltr | tail'
Xalias -- pd='pushd'
Xalias -- pop='popd'
Xalias -- ps='sps'
Xalias -- pwrite='talk'
Xalias -- rn='h /usr/princeton/bin/rn.4.1'
Xalias -- rtfm='man'
Xalias -- strings='strings -'
Xalias -- t='cat'
Xalias -- talk='h talk'
Xalias -- v='mv'
Xalias -- where='hostname; echo >/dev/null'
Xalias -- whm='who | mm'
Xalias -- wm='w | mm'
X320 () { $* | fgrep -f /u/pfalstad/src/cs320/cs320list }
Xacx () { chmod 755 $* }
Xcx () { chmod +x $* }
Xf () { $* | fgrep -f /u/pfalstad/.friends }
Xk9 () { kill -9 $* }
Xmere () { nroff <$1 -man -Tman | less -s }
Xnrable () { ls -AFltr $* | grep -v r..r.. }
Xrable () { ls -AFltr $* | grep r..r.. }
Xexport ATTRIBUTION='%f wrote:'
Xexport CAD_HOME='/u/cad/magic'
Xexport COSMOS='/u/cad/cosmos'
Xexport HOME='/u/pfalstad'
Xexport LESS='-ainx3'
Xexport LM_LICENSE_FILE='/u/cs475/Mentor/etc/license_file'
Xexport LOGNAME='pfalstad'
Xexport MAIL='/usr/spool/mail/pfalstad'
Xexport MAILCALL='NEW MAIL! '
Xexport MANPATH='/usr/man:/usr/princeton/man:/u/cad/man'
Xexport NAME='Paul Falstad'
Xexport OCTTOOLS='/u/cad/octtools'
Xexport ORGANIZATION='The E. Henry Thripshaw Fan Club'
Xexport PATH='/u/pfalstad/scr:/u/pfalstad/bin/sun4:/usr/princeton/bin:/usr/ucb:/usr/bin:/bin:/u/maruchck/scr:/u/cs320/bin:/u/subbarao/bin:/u/maruchck/bin:/usr/hosts:/usr/princeton/bin/X11:/usr/etc:/etc'
Xexport PRINTER='dod'
Xexport PWD='/n/homeserver/c/pfalstad/zsh2.1/scripts'
Xexport RNINIT='/u/pfalstad/.rninit'
Xexport SCS='/u/cs475/Mentor'
Xexport SCS_LICENSE_CLASS='2'
Xexport SHELL='/u/pfalstad/bin/sun4/zsh'
Xexport TERM='vt100'
Xexport TERMCAP='d0|vt100|vt100-am|vt100am|dec-vt100:do=^J:co#80:li#24:cl=50\E[;H\E[2J:sf=5\ED:le=^H:bs:am:cm=5\E[%i%d;%dH:nd=2\E[C:up=2\E[A:ce=3\E[K:cd=50\E[J:so=2\E[7m:se=2\E[m:us=2\E[4m:ue=2\E[m:md=2\E[1m:mr=2\E[7m:mb=2\E[5m:me=2\E[m:is=\E>\E[?1l\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:rf=/usr/share/lib/tabset/vt100:rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:ks=\E[?1h\E=:ke=\E[?1l\E>:ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^H:ho=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:pt:sr=5\EM:vt#3:xn:sc=\E7:rc=\E8:cs=\E[%i%d;%dr:'
Xexport USER='pfalstad'


Xexport YOUSAID='In %C you wrote:'

Xexport _='/u/pfalstad/zsh2.1/scripts/c2z'
XDISPLAY='phoenix:0.0'
XHOSTTYPE='sun4'
Xcdpath=(/u/pfalstad /u/pfalstad/src/cs320 /u/pfalstad/src)
Xedit=
XHISTSIZE='200'
XHOME='/u/pfalstad'
Xmail=(30 /usr/spool/mail/pfalstad)
Xpath=(/u/pfalstad/scr /u/pfalstad/bin/sun4 /usr/princeton/bin /usr/ucb /usr/bin /bin /u/maruchck/scr /u/cs320/bin /u/subbarao/bin /u/maruchck/bin /usr/hosts /usr/princeton/bin/X11 /usr/etc /etc)
Xprompt='c phoenix% '
Xshell='/bin/csh'
Xsetopt globdots
Xterm='vt100'
Xuser='pfalstad'
Xvi=
SHAR_EOF
chmod 0644 zsh2.2/scripts/fooz ||
echo 'restore of zsh2.2/scripts/fooz failed'
Wc_c="`wc -c < 'zsh2.2/scripts/fooz'`"
test 2958 -eq "$Wc_c" ||
echo 'zsh2.2/scripts/fooz: original size 2958, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/scripts/c2z ==============
if test -f 'zsh2.2/scripts/c2z' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/scripts/c2z (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/scripts/c2z (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/scripts/c2z' &&
X#! /bin/sh
X#
X# c2z - environment conversion tool
X# Contributed by Bart Schaefer
X# (Tweaked a bit by Paul Falstad)
X#
X# This is a quick script to convert csh aliases to zsh aliases/functions.
X# It also converts the csh environment and local variables to zsh. c2z
X# uses the csh to parse its own dot-files, then processes csh output to
X# convert the csh settings to zsh.
X#
X# When run as a zsh fuction, c2z runs csh as if it were an interactive
X# shell whenever the parent zsh is interactive. When run as a shell
X# script, the -i switch can be used to force this behavior.
X#
X# The -l (login) switch causes csh to run as if it were a login shell.
X# This is done "properly" if c2z is used as a zsh function, otherwise
X# it's faked by explicitly sourcing .login. Use with caution if your
X# .login initializes an X server or does other one-time-only startup
X# procedures.
X#
X# usage:
X# c2z [-i] [-l]
X#
X# You can use this script in your .zshrc or .zlogin files to load your
X# regular csh environment into zsh; for example, in .zlogin:
X#
X# . =(c2z -l)
X#
X# This is not perfect, but it gets most common aliases and variables.
X# It's also rather time-consuming to do this every time you log in.
X# However, if you're moving from csh to zsh for the first time, this
X# can get you started with a familiar environment right away.
X#
X# In case your mailer eats tabs, $T is set to expand to a tab.
X#
XT="`echo x | tr x '\011'`"
X
X# If we're zsh, we can run "- csh" to get the complete environment.
X#
XMINUS=""
XLOGIN=""
XINTERACT=""
Xcase "$VERSION" in
Xzsh*)
X case $1 in
X -l*) MINUS="-" ;;
X -i*) INTERACT="-i" ;;
X esac
X if [[ -o INTERACTIVE ]]; then INTERACT="-i"; fi
X setopt nobanghist
X ;;
X*)
X case $1 in
X -l*) LOGIN="source ~/.login" ;;
X -i*) INTERACT="-i" ;;
X esac
X ;;
Xesac
X
X( eval $MINUS csh $INTERACT ) <<EOF 2>&1 >/dev/null
X$LOGIN
Xalias >! /tmp/cz$$.a
Xsetenv >! /tmp/cz$$.e
Xset >! /tmp/cz$$.v
XEOF
X
X# save stdin
Xexec 9<&0
X
X# First convert aliases
Xexec < /tmp/cz$$.a
X
X# Taken straight from ctoz except for $T and "alias --"
Xsed -e 's/'"$T"'(\(.*\))/'"$T"'\1/' >/tmp/cz$$.1
Xgrep ! /tmp/cz$$.1 >/tmp/cz$$.2
Xgrep -v ! /tmp/cz$$.1 >/tmp/cz$$.3
Xsed -e "s/'/'"\\\\"''"/g \
X -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/alias -- \1='"'\2'/" \
X /tmp/cz$$.3
Xsed -e 's/![:#]*/$/g' \
X -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/\1 () { \2 }/' \
X /tmp/cz$$.2
X
X# Next, convert environment variables
Xexec < /tmp/cz$$.e
X
X# Would be nice to deal with embedded newlines, e.g. in TERMCAP, but ...
Xsed -e '/^SHLVL/d' \
X -e "s/'/'"\\\\"''"/g \
X -e "s/^\([A-Za-z0-9_]*=\)/export \1'/" \
X -e "s/$/'/"
X
X# Finally, convert local variables
Xexec < /tmp/cz$$.v
X
Xsed -e 's/'"$T"'/=/' \
X -e "s/'/'"\\\\"''"/g \
X -e '/^[A-Za-z0-9_]*=[^(]/{
X s/=/='"'/"'
X s/$/'"'/"'
X }' |
Xsed -e '/^argv=/d' -e '/^cwd=/d' -e '/^filec=/d' -e '/^status=/d' \
X -e '/^histchars=/s//HISTCHARS=/' \
X -e '/^history=/s//HISTSIZE=/' \
X -e '/^home=/s//HOME=/' \
X -e '/^ignoreeof=/s/.*/setopt ignoreeof/' \
X -e '/^noclobber=/s/.*/setopt noclobber/' \
X -e '/^notify=/d' \
X -e '/^showdots=/s/.*/setopt globdots/' \
X -e '/^savehist=/s//HISTFILE=\~\/.zhistory SAVEHIST=/' \
X -e '/^autolist=/s/.*/setopt autolist/' \
X -e '/^correct=[cmd]*/s//setopt autocorrect/' \
X -e '/^who=/s//WATCHFMT=/'
X
X
Xexec 0<&9
X
Xrm /tmp/cz$$.?
Xexit
SHAR_EOF
chmod 0755 zsh2.2/scripts/c2z ||
echo 'restore of zsh2.2/scripts/c2z failed'
Wc_c="`wc -c < 'zsh2.2/scripts/c2z'`"
test 3299 -eq "$Wc_c" ||
echo 'zsh2.2/scripts/c2z: original size 3299, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/scripts/c2z.orig ==============
if test -f 'zsh2.2/scripts/c2z.orig' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/scripts/c2z.orig (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/scripts/c2z.orig (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/scripts/c2z.orig' &&
X#! /bin/sh
X#
X# c2z - environment conversion tool
X# Contributed by Bart Schaefer
X#
X# This is a quick script to convert csh aliases to zsh aliases/functions.
X# It also converts the csh environment and local variables to zsh. c2z
X# uses the csh to parse its own dot-files, then processes csh output to
X# convert the csh settings to zsh.
X#
X# When run as a zsh fuction, c2z runs csh as if it were an interactive
X# shell whenever the parent zsh is interactive. When run as a shell
X# script, the -i switch can be used to force this behavior.
X#
X# The -l (login) switch causes csh to run as if it were a login shell.
X# This is done "properly" if c2z is used as a zsh function, otherwise
X# it's faked by explicitly sourcing .login. Use with caution if your
X# .login initializes an X server or does other one-time-only startup
X# procedures.
X#
X# usage:
X# c2z [-i] [-l]
X#
X# You can use this script in your .zshrc or .zlogin files to load your
X# regular csh environment into zsh; for example, in .zlogin:
X#
X# . =(c2z -l)
X#
X# This is not perfect, but it gets most common aliases and variables.
X# It's also rather time-consuming to do this every time you log in.
X# However, if you're moving from csh to zsh for the first time, this
X# can get you started with a familiar environment right away.
X#
X# In case your mailer eats tabs, $T is set to expand to a tab.
X#
XT="`echo x | tr x '\011'`"
X
X# If we're zsh, we can run "- csh" to get the complete environment.
X#
XMINUS=""
XLOGIN=""
XINTERACT=""
Xcase "$VERSION" in
Xzsh*)
X case $1 in
X -l*) MINUS="-" ;;
X -i*) INTERACT="-i" ;;
X esac
X if [[ -o INTERACTIVE ]]; then INTERACT="-i"; fi
X setopt nobanghist
X ;;
X*)
X case $1 in
X -l*) LOGIN="source ~/.login" ;;
X -i*) INTERACT="-i" ;;
X esac
X ;;
Xesac
X
X( eval $MINUS csh $INTERACT ) <<EOF 2>&1 >/dev/null
X$LOGIN
Xalias >! /tmp/cz$$.a
Xsetenv >! /tmp/cz$$.e
Xset >! /tmp/cz$$.v
XEOF
X
X# First convert aliases
Xexec < /tmp/cz$$.a
X
X# Taken straight from ctoz except for $T and "alias --"
Xsed -e 's/'"$T"'(\(.*\))/'"$T"'\1/' >/tmp/cz$$.1
Xgrep ! /tmp/cz$$.1 >/tmp/cz$$.2
Xgrep -v ! /tmp/cz$$.1 >/tmp/cz$$.3
Xsed -e "s/'/'"\\\\"''"/g \
X -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/alias -- \1='"'\2'/" \
X /tmp/cz$$.3
Xsed -e 's/![:#]*/$/g' \
X -e 's/^\([^'"$T"']*\)'"$T"'\(.*\)$/\1 () { \2 }/' \
X /tmp/cz$$.2
X
X# Next, convert environment variables
Xexec < /tmp/cz$$.e
X
X# Would be nice to deal with embedded newlines, e.g. in TERMCAP, but ...
Xsed -e '/^SHLVL/d' \
X -e "s/'/'"\\\\"''"/g \
X -e "s/^\([A-Za-z0-9_]*=\)/export \1'/" \
X -e "s/$/'/"
X
X# Finally, convert local variables
Xsed -e '
Xexec < /tmp/cz$$.v
X
Xsed -e 's/'"$T"'/=/' \
X -e "s/'/'"\\\\"''"/g \
X -e '/^[A-Za-z0-9_]*=[^(]/{
X s/=/='"'/"'
X s/$/'"'/"'
X }'
X
Xrm /tmp/cz$$.?
Xexit
SHAR_EOF
chmod 0755 zsh2.2/scripts/c2z.orig ||
echo 'restore of zsh2.2/scripts/c2z.orig failed'
Wc_c="`wc -c < 'zsh2.2/scripts/c2z.orig'`"
test 2736 -eq "$Wc_c" ||
echo 'zsh2.2/scripts/c2z.orig: original size 2736, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/src/buildzsh ==============
if test ! -d 'zsh2.2/src'; then
echo 'x - creating directory zsh2.2/src'
mkdir 'zsh2.2/src'
fi
if test -f 'zsh2.2/src/buildzsh' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/src/buildzsh (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/src/buildzsh (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/src/buildzsh' &&
X#! /bin/sh
Xecho
Xecho 'Building config.h...
X'
Xexec >config.h
Xcat <<'foo'
X/* this file is created automatically by buildzsh */
X
X/* define this if you are sysvish */
Xfoo
Xif test -f /usr/include/sys/resource.h
Xthen echo '/* #define SYSV */'; echo 'looks like a BSDish system...' >&2
Xelse echo '#define SYSV'; echo 'looks like a SYSVish system...' >&2
Xfi
Xecho
Xif grep ULTRIX /usr/include/stdio.h >/dev/null 2>&1
Xthen echo '/* ULTRIX termios is weird... */
X/* #define TERMIOS */'; echo 'using sgttyb...' >&2
Xelse
Xif test -f /usr/include/termios.h && test ! -f /hp-ux
Xthen echo '#define TERMIOS
X/* #define TTY_NEEDS_DRAINING */
X/* #define CLOBBERS_TYPEAHEAD */'
Xecho 'using termios...' >&2
Xelse
Xif grep sgttyb /usr/include/sys/ioctl.h >/dev/null 2>&1
Xthen echo '/* #define TERMIO */'
Xelse echo '#define TERMIO'
Xecho 'using termio...' >&2
Xfi
Xecho '#define TTY_NEEDS_DRAINING
X#define CLOBBERS_TYPEAHEAD'
Xecho 'using sgttyb...' >&2
Xfi
Xfi
Xecho
Xif test -f /usr/include/stdlib.h
Xthen echo '#define HAS_STDLIB'; echo 'using <stdlib.h>...' >&2
Xelse echo '/*#define HAS_STDLIB*/'; echo 'not using <stdlib.h>...' >&2
Xfi
Xecho
Xif test -f /usr/include/string.h
Xthen echo '#define HAS_STRING'; echo 'using <string.h>...' >&2
Xelse echo '/*#define HAS_STRING*/'; echo 'using <strings.h>...' >&2
Xecho '#define strchr index
X#define strrchr rindex
X#define memcpy(dst, src, n) bcopy(src, dst, n)
X#define memset(dst, ch, n) bfill(dst, n, ch)
X#define memcmp(s1, s2, n) bcopy(s1, s2, n)'
Xfi
Xecho
Xif test -f /usr/include/locale.h
Xthen echo '#define HAS_LOCALE'; echo 'using <locale.h>...' >&2
Xelse echo '/*#define HAS_LOCALE*/'; echo 'not using <locale.h>...' >&2
Xfi
Xecho
Xecho '/* define this if you have a host field in utmp */'
Xif grep ut_host /usr/include/utmp.h >/dev/null
Xthen echo '#define UTMP_HOST'; echo 'host field in utmp...' >&2
Xelse echo '/* #define UTMP_HOST */'; echo 'no host field in utmp...' >&2
Xfi
Xecho
Xecho '/* define this if you have WAITPID */'
Xif man 2 wait 2>/dev/null | sed 's/_.//g' | grep waitpid >/dev/null
Xthen echo '#define WAITPID'; echo 'using waitpid()...' >&2
Xelse echo '/* #define WAITPID */'; echo 'not using waitpid()...' >&2
Xfi
Xecho
Xecho '/* define this if you have SELECT */'
Xif grep FD_SET /usr/include/sys/types.h >/dev/null ||
X test -f /usr/include/sys/select.h
Xthen echo '#define HAS_SELECT'; echo 'using select()...' >&2
Xelse echo '/* #define HAS_SELECT */'; echo 'not using select()...' >&2
Xfi
Xecho
Xecho '/* define this if you have <sys/select.h> */'
Xif test -f /usr/include/sys/select.h
Xthen echo '#define HAS_SYS_SELECT'
Xelse echo '/* #define HAS_SYS_SELECT */'
Xfi
Xecho "
X/* we can't just test for S_IFIFO or check to see if the mknod worked,
X because the NeXTs sold by a vendor which will remain nameless will
X happily create the FIFO for you, and then panic when you try to do
X something weird with them, because they aren't supported by the OS. */
X"
Xif test -f /mach
Xthen echo '#define NO_FIFOS'; echo 'no FIFOs...' >&2
Xelse echo '/* #define NO_FIFOS */'; echo 'using FIFOs...' >&2
Xfi
Xecho
Xecho '/* define this if you have strftime() */'
Xif man 3 strftime 2>/dev/null | grep return >/dev/null
Xthen echo '#define HAS_STRFTIME'; echo 'using strftime()...' >&2
Xelse echo '/* #define HAS_STRFTIME */'; echo 'not using strftime()...' >&2
Xfi
Xecho
Xif man tcsetpgrp 2>/dev/null | grep process >/dev/null
Xthen echo '#define HAS_TCSETPGRP'; echo 'using tcsetpgrp()...' >&2
Xelse echo '/* #define HAS_TCSETPGRP */'; echo 'not using tcsetpgrp()...' >&2
Xfi
Xecho
Xif grep tcgetattr /usr/include/termios.h >/dev/null 2>/dev/null ||
X grep tcgetattr /usr/include/sys/termios.h >/dev/null 2>/dev/null ||
X grep tcgetattr /usr/include/sys/termio.h >/dev/null 2>/dev/null
Xthen echo '#define HAS_TCCRAP'; echo 'using tcgetattr() and friends...' >&2
Xelse echo '/* #define HAS_TCCRAP */'; echo 'not using tcgetattr()...' >&2
Xfi
Xecho
Xif test -f /bin/hinv
Xthen echo '/* SGI setpgid() is weird... setpgrp() is better anyway */
X/* #define HAS_SETPGID */'; echo 'using setpgrp()...' >&2
Xelif man setpgid 2>/dev/null | grep process >/dev/null
Xthen echo '#define HAS_SETPGID'; echo 'using setpgid()...' >&2
Xelse echo '/* #define HAS_SETPGID */'; echo 'using setpgrp()...' >&2
Xfi
Xecho
Xif test ! -f /hp-ux && man sigrelse 2>/dev/null | grep signal >/dev/null
Xthen echo '#define HAS_SIGRELSE'; echo 'using sigrelse()...' >&2
Xelse echo '/* #define HAS_SIGRELSE */'; echo 'using sigblock()...' >&2
Xfi
Xecho
Xecho '/* define this if you have RFS */'
Xif test -d /../.CONTROL
Xthen echo '#define HAS_RFS'; echo 'you seem to have RFS...' >&2
Xelse echo '/* #define HAS_RFS */'; echo 'no RFS, it seems...' >&2
Xfi
Xecho
Xecho '/* define this if you have a working getrusage and wait3 */'
Xif test -f /hp-ux
Xthen echo '/* #define HAS_RUSAGE */'; echo 'no getrusage...' >&2
Xelif test -f /usr/include/sys/resource.h
Xthen echo '#define HAS_RUSAGE'; echo 'has getrusage...' >&2
Xelse echo '/* #define HAS_RUSAGE */'; echo 'no getrusage...' >&2
Xfi
Xecho '
X/* define this if your signal handlers return void */'
Xif grep SIG_DFL /usr/include/signal.h /usr/include/sys/signal.h |
X grep void >/dev/null
Xthen echo '#define SIGVOID'; echo 'signal handlers return void...' >&2
Xelse echo '/* #define SIGVOID */'; echo 'signal handlers return int...' >&2
Xfi
Xcat <<'foo'
X#ifdef sgi
X#undef SIGVOID
X#endif
Xfoo
Xecho
Xecho '/* define this if signal handlers need to be reset each time */'
Xif grep SIGTSTP /usr/include/signal.h /usr/include/sys/signal.h >/dev/null
Xthen echo '/* #define RESETHANDNEEDED */'
Xecho 'signal handlers need no resetting...' >&2
Xelse echo '#define RESETHANDNEEDED'
Xecho 'signal handlers need to be reset...' >&2
Xfi
Xecho
Xcat <<'foo'
X#ifdef SIGVOID
X#define HANDTYPE void
X#else
X#define HANDTYPE int
X#define INTHANDTYPE
X#endif
X
X/* a string corresponding to the host type */
Xfoo
Xecho '#define HOSTTYPE "' | tr -d '\012'
Xhost=`(tcsh -fc 'echo $HOSTTYPE' || arch) 2>/dev/null`
Xcase $host in
X'') if grep ULTRIX /usr/include/stdio.h >/dev/null 2>&1
X then host=ultrix
X elif test -f /bin/hinv
X then host=iris
X elif test -d /NextApps
X then host=next
X elif test $machine
X then host=$machine
X else
X echo 1>&2 '
X
XI cannot figure out what sort of host this is. Please enter one
Xshort alphanumeric string describing this host. (This will be used
Xto set the $HOSTTYPE variable, so '"you don't have to be very
Xaccurate if you're not in a multivendor environment.)
X"
X echo "? " | tr -d '\012' 1>&2
X read host
X echo ' ' 1>&2
X fi
X ;;
Xesac
Xecho $host'"'
Xecho "using host type $host..." >&2
Xecho
Xecho '/* the default editor for the fc builtin */'
Xecho '#define DEFFCEDIT "vi"'
Xecho
Xif grep UTMP_FILE /usr/include/utmp.h >/dev/null
Xthen :
Xelse
Xecho '/* the path of wtmp */'
Xecho '#define WTMP_FILE "' | tr -d '\012'
Xif test -f /etc/wtmp
Xthen echo /etc/wtmp
Xelif test -f /usr/etc/wtmp
Xthen echo /usr/etc/wtmp
Xelif test -f /var/adm/wtmp
Xthen echo /var/adm/wtmp
Xelif test -f /usr/adm/wtmp
Xthen echo /usr/adm/wtmp
Xelse echo /dev/null
Xfi | tr -d '\012'
Xecho '"
X
X/* the path of utmp */
X#define UTMP_FILE "/etc/utmp"
X'
Xfi
Xcat <<'foo'
X/* default prefix for temporary files */
X#define DEFTMPPREFIX "/tmp/zsh"
X
X/* define if you prefer "suspended" to "stopped" */
X#define USE_SUSPENDED
X
X/* the file to source whenever zsh is run; if undefined, don't source
X anything */
X#define GLOBALZSHRC "/etc/zshrc"
X
X/* the file to source whenever zsh is run as a login shell; if
X undefined, don't source anything */
X#define GLOBALZLOGIN "/etc/zlogin"
X
X/* the file to source whenever zsh is run as a login shell, before
X zshrc is read; if undefined, don't source anything */
X#define GLOBALZPROFILE "/etc/zprofile"
X
X/* the default HISTSIZE */
X#define DEFAULT_HISTSIZE 30
X
X#define _BSD_SIGNALS /* this could be an iris, you never know */
X#define _BSD /* this could be HP-UX, you never know */
X#define _BSD_INCLUDES /* this could be AIX, you never know */
X
X/* if your compiler doesn't like void *, change this to char *
X and ignore all the warnings.
X*/
X
Xtypedef void *vptr;
X
X#define JOB_CONTROL
Xfoo
Xexec 1>&2
Xecho
Xecho 'Building signals.h...' | tr -d '\012'
Xecho `csh -fc 'kill -l'` | tr ' ' '\012' >signals.h
Xlct=`wc -l < signals.h`
Xcp signals.h signams.h
X(
Xecho '/* this file is created automatically by buildzsh */
X/* if all this is wrong, blame csh ;-) */
X
X#define SIGCOUNT '"$lct"'
X
X#ifdef GLOBALS
X
Xchar *sigmsg[SIGCOUNT+2] = {
X "done",'
Xsed -e 's/^/SIG/' -e '/SIGHUP/s//hangup/
X/SIGINT/s//interrupt/
X/SIGQUIT/s//quit/
X/SIGILL/s//illegal instruction/
X/SIGTRAP/s//trace trap/
X/SIGIOT/s//IOT instruction/
X/SIGABRT/s//abort/
X/SIGEMT/s//EMT instruction/
X/SIGFPE/s//floating point exception/
X/SIGKILL/s//killed/
X/SIGBUS/s//bus error/
X/SIGSEGV/s//segmentation fault/
X/SIGSYS/s//bad system call/
X/SIGPIPE/s//broken pipe/
X/SIGTERM/s//terminated/
X/SIGPWR/s//power fail/
X/SIGVTALRM/s//virtual time alarm/
X/SIGCONT/s//continued/
X/SIGXCPU/s//cpu limit exceeded/
X/SIGXFSZ/s//filesize limit exceeded/' -e 's/.*/ "&",/' signals.h
Xecho ' NULL
X};
X
Xchar *sigs[SIGCOUNT+4] = {
X "EXIT",' ) >sigtmp.h
Xmv sigtmp.h signals.h
Xif grep SIGSTOP signals.h >/dev/null
Xthen ed signals.h <<'foo' >/dev/null 2>&1
X/SIGSTOP/c
X#ifdef USE_SUSPENDED
X "suspended (signal)",
X#else
X "stopped (signal)",
X#endif
X.
X/SIGTSTP/c
X#ifdef USE_SUSPENDED
X "suspended",
X#else
X "stopped",
X#endif
X.
X/SIGTTIN/c
X#ifdef USE_SUSPENDED
X "suspended (tty input)",
X#else
X "stopped (tty input)",
X#endif
X.
X/SIGTTOU/c
X#ifdef USE_SUSPENDED
X "suspended (tty output)",
X#else
X "stopped (tty output)",
X#endif
X.
Xw
Xq
Xfoo
Xfi
X(sed 's/.*/ "&",/' signams.h
Xecho ' "ERR",
X "DEBUG",
X NULL
X};
X
X#else
X
Xextern char *sigs[SIGCOUNT+4],*sigmsg[SIGCOUNT+2];
X
X#endif') >>signals.h
Xrm signams.h
Xecho done
Xecho 'Building Makefile...' | tr -d '\012'
Xexec >Makefile
Xcat <<'foo'
X#! /bin/make -f
X# Makefile for zsh
X# generated by buildzsh
X
XOBJS=builtin.o cond.o exec.o glob.o hist.o init.o jobs.o lex.o loop.o \
Xmath.o mem.o params.o parse.o subst.o table.o text.o utils.o watch.o \
Xzle_bindings.o zle_hist.o zle_main.o zle_misc.o zle_move.o zle_refresh.o \
Xzle_tricky.o zle_utils.o zle_vi.o zle_word.o
X
XBINDIR=/usr/local/bin
XMANDIR=/usr/local/man/man1
X
X# debugging flags
X#CFLAGS=-g -Wreturn-type -Wunused -Wpointer-arith -DQDEBUG
X#CC=gcc -traditional
X
XCC=cc
Xfoo
Xif test -f /usr/include/ndir.h -a ! -f /usr/lib/libBSD.a
Xthen echo 'CFLAGS= -O -Aa'
Xelif strings /usr/bin/cc 2>/dev/null | grep cckr >/dev/null 2>&1
Xthen echo 'CFLAGS= -O -cckr'
Xelse echo 'CFLAGS= -O'
Xfi
Xif test -f /bin/hinv
Xthen
Xif grep '^\+' /etc/passwd >/dev/null
Xthen echo 'LIBS= -lcurses -lmalloc -lbsd -lsun'
Xelse echo 'LIBS= -lcurses -lmalloc -lbsd'
Xfi
Xelif test -f /usr/lib/libcposix.a
Xthen echo 'LIBS= -lcposix -ltermcap'
Xelif test -f /usr/lib/libBSD.a
Xthen echo 'LIBS= -ltermcap -lBSD'
Xelif test -f /usr/lib/libtermcap.a || test -f /usr/ucblib/libtermcap.a
Xthen
X if grep 'Property of IBM' /usr/include/stdio.h >/dev/null 2>&1
X then echo 'LIBS= -lcurses'
X else echo 'LIBS= -ltermcap'
X fi
Xelse echo 'LIBS= -lcurses'
Xfi
Xcat <<'foo'
X
XZSHPATH=zsh
X
X.c.o:
X $(CC) $(CFLAGS) -c $<
X
Xall: $(ZSHPATH)
X
X$(ZSHPATH): $(OBJS)
X $(CC) -o $(ZSHPATH) $(OBJS) $(LIBS) $(LFLAGS)
X
Xtags: /tmp
X ctags *.[cy]
X
X# I hate this next line
X$(OBJS): config.h zsh.h zle.h signals.h ztype.h funcs.h
X
Xclean:
X rm -f *.o zsh core
X
Xcleanall:
X rm -f *.o zsh core Makefile signals.h config.h
X
Xinstall: zsh
X install -s -m 755 zsh $(BINDIR)
X install -m 444 ../man/man1/zsh.1 $(MANDIR)
Xfoo
Xexec 1>&2
Xcat <<'foo'
Xdone
X
XYou may want to look at the files I just created (config.h, Makefile,
Xand signals.h) to make sure they are correct. Or you may just want
Xto go ahead and try running make now to see what happens.
X
Xfoo
Xecho 'Shall I execute make now?' | tr -d '\012'
Xread reply
Xecho
Xcase "$reply" in
X[yY]*) exec make ;;
Xesac
X
SHAR_EOF
chmod 0755 zsh2.2/src/buildzsh ||
echo 'restore of zsh2.2/src/buildzsh failed'
Wc_c="`wc -c < 'zsh2.2/src/buildzsh'`"
test 11626 -eq "$Wc_c" ||
echo 'zsh2.2/src/buildzsh: original size 11626, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/src/builtin.c ==============
if test -f 'zsh2.2/src/builtin.c' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/src/builtin.c (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/src/builtin.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/src/builtin.c' &&
X/*
SHAR_EOF
true || echo 'restore of zsh2.2/src/builtin.c failed'
fi
echo 'End of zsh2.2 part 5'
echo 'File zsh2.2/src/builtin.c is continued in part 6'
echo 6 > _shar_seq_.tmp

Paul Falstad

unread,
May 13, 1992, 11:59:47 AM5/13/92
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 29, Issue 102
Archive-name: zsh2.2/part06

Environment: BSD
Supersedes: zsh2.1: Volume 24, Issue 1-19

#!/bin/sh
# this is aa.06 (part 6 of zsh2.2)


# do not concatenate these parts, unpack them in order with /bin/sh

# file zsh2.2/src/builtin.c continued


#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 6; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then

echo 'x - still skipping zsh2.2/src/builtin.c'
else
echo 'x - continuing file zsh2.2/src/builtin.c'


sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.2/src/builtin.c' &&

X *
X * builtin.c - builtin commands
X *
X * This file is part of zsh, the Z shell.
X *
X * This software is Copyright 1992 by Paul Falstad
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made.
X *
X * The author make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk.
X *
X */
X
X#include "zsh.h"
X#include <sys/errno.h>
X
X#define makecond() allocnode(N_COND)
X
X/* builtin flags */
X
X#define BINF_PLUSOPTS 1 /* +xyz legal */
X#define BINF_R 2 /* this is r (fc -e -) */
X#define BINF_PRINTOPTS 4
X#define BINF_SETOPTS 8
X#define BINF_FCOPTS 16
X#define BINF_TYPEOPT 32
X#define BINF_TYPEOPTS (BINF_TYPEOPT|BINF_PLUSOPTS)
X#define BINF_ECHOPTS 64
X
X/* builtin funcs */
X
X#define BIN_TYPESET 0
X#define BIN_BG 1
X#define BIN_FG 2
X#define BIN_JOBS 3
X#define BIN_WAIT 4
X#define BIN_DISOWN 5
X#define BIN_BREAK 6
X#define BIN_CONTINUE 7
X#define BIN_EXIT 8
X#define BIN_RETURN 9
X#define BIN_SHIFT 10
X#define BIN_CD 11
X#define BIN_POPD 12
X#define BIN_PUSHD 13
X#define BIN_PRINT 14
X#define BIN_EVAL 15
X#define BIN_SCHED 16
X#define BIN_FC 17
X#define BIN_PUSHLINE 18
X#define BIN_LOGOUT 19
X#define BIN_BUILTIN 20
X#define BIN_TEST 21
X#define BIN_BRACKET 22
X
Xstruct bincmd {
X char *name;
X int (*handlerfunc) DCLPROTO((char *,char **,char *,int));
X int minargs; /* min # of args */
X int maxargs; /* max # of args, or -1 for no limit */
X int flags; /* BINF_flags (see above) */
X int funcid; /* xbins (see above) for overloaded handlerfuncs */
X char *optstr; /* string of legal options */
X char *defopts; /* options set by default for overloaded handlerfuncs */
X };
X
X/* structure for foo=bar assignments */
X
Xstruct asgment {
X struct asgment *next;
X char *name,*value;
X };
X
Xstatic char *auxdata;
Xstatic int auxlen;
Xstatic int showflag = 0,showflag2 = 0;
X
Xstruct bincmd builtins[] = {
X "[",bin_test,0,-1,0,BIN_BRACKET,NULL,NULL,
X ".",bin_dot,1,-1,0,0,NULL,NULL,
X ":",bin_colon,0,-1,0,0,NULL,NULL,
X "alias",bin_alias,0,-1,0,0,"ga",NULL,
X "autoload",bin_typeset,0,-1,BINF_TYPEOPTS,0,"tx","fu",
X "bg",bin_fg,0,-1,0,BIN_BG,NULL,NULL,
X "bindkey",bin_bindkey,0,-1,0,0,"asvemdrl",NULL,
X "break",bin_break,0,1,0,BIN_BREAK,NULL,NULL,
X "builtin",NULL,0,0,0,BIN_BUILTIN,NULL,NULL,
X "bye",bin_break,0,1,0,BIN_EXIT,NULL,NULL,
X "cd",bin_cd,0,2,0,BIN_CD,NULL,NULL,
X "chdir",bin_cd,0,2,0,BIN_CD,NULL,NULL,
X "compctl",bin_compctl,0,-1,0,0,NULL,NULL,
X "continue",bin_break,0,1,0,BIN_CONTINUE,NULL,NULL,
X "declare",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfilrtux",NULL,
X "dirs",bin_dirs,0,-1,0,0,"v",NULL,
X "disable",bin_disable,1,-1,0,0,NULL,NULL,
X "disown",bin_fg,1,-1,0,BIN_DISOWN,NULL,NULL,
X "echo",bin_print,0,-1,BINF_PRINTOPTS|BINF_ECHOPTS,BIN_PRINT,"n","-",
X "echotc",bin_echotc,1,-1,0,0,NULL,NULL,
X "enable",bin_enable,1,-1,0,0,NULL,NULL,
X "eval",bin_eval,0,-1,0,BIN_EVAL,NULL,NULL,
X "exit",bin_break,0,1,0,BIN_EXIT,NULL,NULL,
X "export",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfilrtu","x",
X "false",bin_let,0,0,0,0,NULL,NULL,
X "fc",bin_fc,0,-1,BINF_FCOPTS,BIN_FC,"nlreRWAdD",NULL,
X "fg",bin_fg,0,-1,0,BIN_FG,NULL,NULL,
X "functions",bin_typeset,0,-1,BINF_TYPEOPTS,0,"tu","f",
X "getln",bin_read,0,-1,0,0,NULL,"zr",
X "getopts",bin_getopts,2,-1,0,0,NULL,NULL,
X "hash",bin_hash,2,2,0,0,"r",NULL,
X "history",bin_fc,0,-1,0,BIN_FC,"nrdD","l",
X "integer",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZlrtux","i",
X "jobs",bin_fg,0,-1,0,BIN_JOBS,"lpZ",NULL,
X "kill",bin_kill,0,-1,0,0,NULL,NULL,
X "let",bin_let,1,-1,0,0,NULL,NULL,
X "limit",bin_limit,0,-1,0,0,"sh",NULL,
X "local",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfilrtux",NULL,
X "log",bin_log,0,0,0,0,NULL,NULL,
X "logout",bin_break,0,1,0,BIN_LOGOUT,NULL,NULL,
X "popd",bin_cd,0,2,0,BIN_POPD,NULL,NULL,
X "print",bin_print,0,-1,BINF_PRINTOPTS,BIN_PRINT,"RDPnrslzNu0123456789p-",NULL,
X "pushd",bin_cd,0,2,0,BIN_PUSHD,NULL,NULL,
X "pushln",bin_print,0,-1,BINF_PRINTOPTS,BIN_PRINT,NULL,"-nz",
X "pwd",bin_pwd,0,0,0,0,NULL,NULL,
X "r",bin_fc,0,-1,BINF_R,BIN_FC,"nrl",NULL,
X "read",bin_read,0,-1,0,0,"rzu0123456789p",NULL,
X "readonly",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfiltux","r",
X "rehash",bin_rehash,0,0,0,0,"f",NULL,
X "return",bin_break,0,1,0,BIN_RETURN,NULL,NULL,
X "sched",bin_sched,0,-1,0,0,NULL,NULL,
X "set",bin_set,0,-1,BINF_SETOPTS|BINF_PLUSOPTS,0,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZaefghijklnosuvwxy",NULL,
X "setopt",bin_setopt,0,-1,BINF_PLUSOPTS,0,"0123456789BCDEFGHIJKLMNOPQRSTUVWXYZaefghijklmnosuvwxy",NULL,
X "shift",bin_break,0,1,0,BIN_SHIFT,NULL,NULL,
X "source",bin_dot,1,-1,0,0,NULL,NULL,
X "suspend",bin_suspend,0,0,0,0,"f",NULL,
X "test",bin_test,0,-1,0,BIN_TEST,NULL,NULL,
X "ttyctl",bin_ttyctl,0,0,0,0,"fu",NULL,
X "times",bin_times,0,0,0,0,NULL,NULL,
X "trap",bin_trap,0,-1,0,0,NULL,NULL,
X "true",bin_colon,0,0,0,0,NULL,NULL,
X "type",bin_whence,0,-1,0,0,"pfa","v",
X "typeset",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfilrtux",NULL,
X "ulimit",bin_ulimit,0,1,0,0,"HSacdfmnt",NULL,
X "umask",bin_umask,0,1,0,0,NULL,NULL,
X "unalias",bin_unalias,1,-1,0,0,NULL,NULL,
X "unfunction",bin_unhash,1,-1,0,0,NULL,NULL,
X "unhash",bin_unhash,1,-1,0,0,NULL,NULL,
X "unlimit",bin_unlimit,0,-1,0,0,"h",NULL,
X "unset",bin_unset,1,-1,0,0,NULL,NULL,
X "unsetopt",bin_setopt,0,-1,BINF_PLUSOPTS,1,"0123456789BCDEFGHIJKLMNOPQRSTUWXYZabefghijklmnosuvwxy",NULL,
X "vared",bin_vared,1,1,0,0,NULL,NULL,
X "wait",bin_fg,0,-1,0,BIN_WAIT,NULL,NULL,
X "whence",bin_whence,0,-1,0,0,"pvcfa",NULL,
X "which",bin_whence,0,-1,0,0,"pa","c",
X NULL,NULL,0,0,0,0,NULL,NULL
X };
X
X/* print options */
X
Xstatic void prtopt()
X{
Xstruct option *opp;
X
X if (isset(KSHOPTIONPRINT)) {
X printf("Current option settings\n");
X for (opp = optns; opp->name; opp++)
X printf("%-20s%s\n", opp->name,
X (opts[opp->id] == OPT_SET) ? "on" : "off");
X } else
X for (opp = optns; opp->name; opp++)
X if (opts[opp->id] == OPT_SET)
X puts(opp->name);
X}
X
X/* add builtins to the command hash table */
X
Xvoid addbuiltins() /**/
X{
Xstruct cmdnam *c;
Xstruct bincmd *b;
Xint t0;
X
X for (t0 = 0, b = builtins; b->name; b++,t0++)
X {
X c = (Cmdnam) zcalloc(sizeof *c);
X c->type = BUILTIN;
X c->u.binnum = t0;
X addhperm(b->name,c,cmdnamtab,freecmdnam);
X }
X}
X
X/* enable */
X
Xint bin_enable(name,argv,ops,whocares) /**/
Xchar *name;char **argv;char *ops;int whocares;
X{
Xstruct cmdnam *c;
Xstruct bincmd *b;
Xint t0,ret = 0;
X
X for (; *argv; argv++)
X {
X for (t0 = 0, b = builtins; b->name; b++,t0++)
X if (!strcmp(*argv,b->name))
X break;
X if (!b->name)
X {
X zerrnam(name,"no such builtin: %s",*argv,0);
X ret = 1;
X }
X else
X {
X c = (Cmdnam) zcalloc(sizeof *c);
X c->type = BUILTIN;
X c->u.binnum = t0;
X addhperm(b->name,c,cmdnamtab,freecmdnam);
X }
X }
X return ret;
X}
X
X/* :, true */
X
Xint bin_colon(name,argv,ops,whocares) /**/
Xchar *name;char **argv;char *ops;int whocares;
X{
X return 0;
X}
X
X/* break, bye, continue, exit, logout, return, shift */
X
Xint bin_break(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xint num = -1;
X
X if (*argv)
X num = matheval(*argv);
X if ((func == BIN_BREAK || func == BIN_CONTINUE) && !loops)
X {
X if (func == BIN_CONTINUE)
X zerrnam(name,"not in loop",NULL,0);
X return 1;
X }
X switch (func)
X {
X case BIN_CONTINUE:
X contflag = 1;
X case BIN_BREAK:
X breaks = (num == -1) ? 1 : num;
X if (breaks > loops) breaks = loops;
X break;
X case BIN_LOGOUT:
X if (!islogin)
X {
X zerrnam(name,"not login shell",NULL,0);
X return 1;
X }
X case BIN_EXIT:
X zexit((num == -1) ? lastval : num);
X break;
X case BIN_RETURN:
X retflag = 1;
X return lastval = (num == -1) ? lastval : num;
X case BIN_SHIFT:
X {
X char **s;
X
X if (num == -1)
X num = 1;
X if (num > arrlen(pparams))
X num = arrlen(pparams);
X permalloc();
X s = arrdup(pparams+num);
X heapalloc();
X freearray(pparams);
X pparams = s;
X break;
X }
X }
X return 0;
X}
X
X/* bg, disown, fg, jobs, wait */
X
Xint bin_fg(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xint job,lng,firstjob = -1,retval = 0;
X
X if (ops['Z']) { if (*argv) strcpy(hackzero,*argv); return 0; }
X lng = (ops['l']) ? 1 : (ops['p']) ? 2 : 0;
X if ((func == BIN_FG || func == BIN_BG) && !jobbing)
X {
X zerrnam(name,"no job control in this shell.",NULL,0);
X return 1;
X }
X if (unset(NOTIFY)) scanjobs();
X if (!(jobtab[curjob].stat & STAT_INUSE))
X {
X curjob = prevjob; setprevjob();
X if (!(jobtab[curjob].stat & STAT_INUSE))
X curjob = prevjob; setprevjob();
X }
X if (func == BIN_JOBS)
X stopmsg = 2;
X if (!*argv)
X if (func == BIN_FG || func == BIN_BG)
X {
X if (curjob == -1 || curjob == thisjob)
X {
X zerrnam(name,"no current job",NULL,0);
X return 1;
X }
X firstjob = curjob;
X }
X else if (func == BIN_JOBS)
X {
X for (job = 0; job != MAXJOB; job++)
X if (job != thisjob && jobtab[job].stat)
X printjob(job+jobtab,lng);
X return 0;
X }
X else
X {
X for (job = 0; job != MAXJOB; job++)
X if (job != thisjob && jobtab[job].stat)
X waitjob(job);
X return lastval;
X }
X for (; (firstjob != -1) || *argv; ( void ) (*argv && argv++))
X {
X int stopped,ocj = thisjob;
X
X if (func == BIN_WAIT && isanum(*argv)) {
X waitforpid((long) atoi(*argv));
X retval = lastval;
X thisjob = ocj;
X continue;
X }
X job = (*argv) ? getjob(*argv,name) : firstjob;
X firstjob = -1;
X if (job == -1)
X break;
X if (!(jobtab[job].stat & STAT_INUSE))
X {
X zerrnam(name,"no such job: %d",0,job);
X return 1;
X }
X switch (func)
X {
X case BIN_FG:
X case BIN_BG:
X if (stopped = (jobtab[job].stat & STAT_STOPPED))
X makerunning(jobtab+job);
X else if (func == BIN_BG)
X {
X zerrnam(name,"job already in background",NULL,0);
X thisjob = ocj;
X return 1;
X }
X if (curjob == job)
X {
X curjob = prevjob;
X prevjob = (func == BIN_BG) ? -1 : job;
X }
X if (prevjob == job)
X prevjob = -1;
X if (prevjob == -1)
X setprevjob();
X if (curjob == -1)
X {
X curjob = prevjob;
X setprevjob();
X }
X printjob(jobtab+job,(stopped) ? -1 : 0);
X if (func == BIN_FG)
X {
X thisjob = job;
X if (strcmp(jobtab[job].pwd,pwd))
X {
X printf("(pwd : ");
X printdir(jobtab[job].pwd);
X printf(")\n");
X }
X fflush(stdout);
X attachtty(jobtab[job].gleader);
X }
X if (stopped)
X killpg(jobtab[job].gleader,SIGCONT);
X if (func == BIN_FG)
X waitjobs();
X break;
X case BIN_JOBS:
X printjob(job+jobtab,lng);
X break;
X case BIN_WAIT:
X waitjob(job);
X retval = lastval;
X break;
X case BIN_DISOWN:
X {
X static struct job zero;
X jobtab[job] = zero;
X break;
X }
X }
X thisjob = ocj;
X }
X return retval;
X}
X
X/* false, let */
X
Xint bin_let(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xlong val = 0;
X
X while (*argv)
X val = matheval(*argv++);
X return !val;
X}
X
X/* print the directory stack */
X
Xstatic void pdstack()
X{
XLknode node;
X
X printdir(pwd);
X for (node = firstnode(dirstack); node; incnode(node))
X {
X putchar(' ');
X printdir(getdata(node));
X }
X putchar('\n');
X}
X
X/* exit the shell */
X
Xint zexit(val) /**/
Xint val;
X{
X if (isset(MONITOR))
X if (!stopmsg) {
X checkjobs();
X if (stopmsg) {
X stopmsg = 2;
X return 1;
X }
X } else killrunjobs();
X savehistfile(getsparam("HISTFILE"),0,0);
X if (islogin && unset(NORCS))
X sourcehome(".zlogout");
X if (sigtrapped[SIGEXIT])
X dotrap(SIGEXIT);
X exit(val); return 0;
X}
X
X/* identify an option name */
X
Xint optlookup(s) /**/
Xchar *s;
X{
Xchar *t;
Xstruct option *o;
X
X t = s = strdup(s);
X while (*t)
X if (*t == '_')
X chuck(t);
X else {
X *t = tulower(*t);
X t++;
X }
X for (o = optns; o->name; o++)
X if (!strcmp(o->name,s))
X return o->id;
X return -1;
X}
X
X/* setopt, unsetopt */
X
Xint bin_setopt(nam,args,ops,isun) /**/
Xchar *nam;char **args;char *ops;int isun;
X{
Xstruct option *opp;
Xint c;
X
X if (!ops['@'] && !*args) {
X if (!isun)
X prtopt();
X return 0;
X }
X for (opp = optns; opp->name; opp++)
X if (ops[opp->id] == 1+isun)
X opts[opp->id] = OPT_SET;
X else if (ops[opp->id] == 2-isun)
X opts[opp->id] = OPT_UNSET;
X while (*args) {
X c = optlookup(*args++);
X if (c != -1) {
X if (c == INTERACTIVE || c == MONITOR)
X zerrnam(nam,"can't change that option",NULL,0);
X else
X opts[c] = (isun) ? OPT_UNSET : OPT_SET;
X } else {
X zerrnam(nam,"no such option: %s",args[-1],0);
X return 1;
X }
X }
X return 0;
X}
X
X/* execute func on each member of the hash table ht */
X
Xvoid listhtable(ht,func) /**/
XHashtab ht;HFunc func;
X{
Xint t0;
Xstruct hashnode *hn;
X
X for (t0 = ht->hsize-1; t0 >= 0; t0--)
X for (hn = ht->nodes[t0]; hn; hn = hn->next)
X func(hn->nam,(char *) hn);
X}
X
X/* print a shell function (used with listhtable) */
X
Xvoid pshfunc(s,cc) /**/
Xchar *s;Cmdnam cc;
X{
Xchar *t;
X
X if (cc->type != SHFUNC)
X return;
X if (showflag && (cc->flags & showflag2) != showflag2)
X return;
X if (cc->flags & PMFLAG_u)
X printf("undefined ");
X if (cc->flags & PMFLAG_t)
X printf("traced ");
X if (!cc->u.list || !showflag) {
X printf("%s ()\n",s);
X return;
X }
X t = getpermtext((vptr) (cc->u.list));
X printf("%s () {\n\t%s\n}\n",s,t);
X free(t);
X}
X
Xvoid niceprint(s) /**/
Xchar *s;
X{
X niceprintf(s,stdout);
X}
X
Xvoid niceprintf(s,f) /**/
Xchar *s;FILE *f;
X{
X for (; *s; s++)
X {
X if (isprint(*s))
X fputc(*s,f);
X else if (*s == '\n')
X {
X putc('\\',f);
X putc('n',f);
X }
X else
X {
X putc('^',f);
X fputc(*s | 0x40,f);
X }
X }
X}
X
Xint bin_umask(nam,args,ops,func) /**/
Xchar *nam;char **args;char *ops;int func;
X{
Xint um;
Xchar *s = *args;
X
X um = umask(0);
X umask(um);
X if (!s)
X {
X printf("%03o\n",um);
X return 0;
X }
X if (idigit(*s))
X {
X um = zstrtol(s,&s,8);
X if (*s)
X {
X zerrnam(nam,"bad umask",NULL,0);
X return 1;
X }
X }
X else
X {
X int whomask,op,mask;
X
X for (;;)
X {
X if (*s == 'u')
X s++, whomask = 0100;
X else if (*s == 'g')
X s++, whomask = 0010;
X else if (*s == 'o')
X s++, whomask = 0001;
X else
X whomask = 0111;
X op = *s++;
X if (!(op == '+' || op == '-' || op == '='))
X {
X zerrnam(nam,"bad symbolic mode operator: %c",NULL,op);
X return 1;
X }
X mask = whomask;
X if (*s == 'r')
X mask *= 04;
X else if (*s == 'w')
X mask *= 02;
X else if (*s != 'x')
X {
X zerrnam(nam,"bad symbolic mode permission: %c",NULL,*s);
X return 1;
X }
X if (op == '+')
X um |= mask;
X else if (op == '-')
X um &= ~mask;
X else /* op == '=' */
X um = (um & ~(whomask*07)) | mask;
X if (*++s == ',')
X s++;
X else
X break;
X }
X if (*s)
X {
X zerrnam(nam,"bad character in symbolic mode: %c",NULL,*s);
X return 1;
X }
X }
X umask(um);
X return 0;
X}
X
X/* type, whence, which */
X
Xint bin_whence(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
Xstruct cmdnam *chn;
Xstruct alias *a;
Xint retval = 0;
Xint csh = ops['c'],all = ops['a'];
Xint v = ops['v'] || csh;
Xchar *cnam;
X
X for (; *argv; argv++) {
X if (!ops['p'] && (a = (Alias) gethnode(*argv,aliastab))) {
X if (a->cmd < 0)
X printf((csh) ? "%s: shell reserved word\n" :
X (v) ? "%s is a reserved word\n" : "%s\n",*argv);
X else if (!v)
X puts(a->text);
X else if (a->cmd)
X printf((csh) ? "%s: aliased to %s\n" :
X "%s is an alias for %s\n",*argv,a->text);
X else
X printf((csh) ? "%s: globally aliased to %s\n" :
X "%s is a global alias for %s\n",*argv,a->text);
X retval = 0;
X if (!all) continue;
X }
X if (!ops['p'] && (chn = (Cmdnam) gethnode(*argv,cmdnamtab)) &&
X (chn->type == SHFUNC || chn->type == BUILTIN)) {
X if (chn->type == SHFUNC) {
X if (csh || ops['f']) {
X showflag = 1; showflag2 = 0;
X pshfunc(*argv,chn);
X } else {
X printf((v) ? "%s is a function\n" : "%s\n",*argv);
X }
X } else
X printf((csh) ? "%s: shell built-in command\n" :
X (v) ? "%s is a shell builtin\n" : "%s\n",*argv);
X retval = 0;
X if (!all) continue;
X }
X if (all) {
X char **pp,buf[MAXPATHLEN],*z;
X for (pp = path; *pp; pp++) {
X z = buf;
X strucpy(&z,*pp);
X *z++ = '/';
X strcpy(z,*argv);
X if (iscom(buf)) {
X if (v && !csh) printf("%s is %s\n",*argv,buf);
X else puts(buf);
X retval = 0;
X }
X }
X } else if (!(cnam = findcmd(*argv))) {
X if (v) printf("%s not found\n",*argv);
X retval = 1;
X break;
X } else {
X if (v && !csh) printf("%s is %s\n",*argv,cnam);
X else puts(cnam);
X retval = 0;
X }
X }
X return retval;
X}
X
X/* cd, chdir, pushd, popd */
X
Xint bin_cd(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
Xchar *dest;
X
X if (func == BIN_CD && isset(AUTOPUSHD))
X func = BIN_PUSHD;
X dest = cd_get_dest(nam,argv,ops,func);
X if (!dest) return 1;
X dest = cd_do_chdir(nam,dest);
X if (!dest) return 1;
X cd_new_pwd(func,dest);
X return 0;
X}
X
Xchar *cd_get_dest(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
Xchar *dest;
X
X if (!argv[0])
X if (func == BIN_CD || (func == BIN_PUSHD && isset(PUSHDTOHOME)
X || !full(dirstack)))
X dest = home;
X else
X dest = getnode(dirstack);
X else if (!argv[1]) {
X Lknode n;
X int dd;
X
X if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '-' : '+')) {
X dd = atoi(argv[0]+1)-1;
X if (dd < 0) {
X zerrnam(nam,"bad directory specification",NULL,0);
X return NULL;
X }
X for (n = firstnode(dirstack); n && dd; dd--, incnode(n));
X if (!n) {
X zerrnam(nam,"no such entry in dir stack",NULL,0);
X return NULL;
X }
X dest = remnode(dirstack,n);
X } else if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '+' : '-')) {
X dd = atoi(argv[0]+1);
X for (n = lastnode(dirstack); n != (Lknode) dirstack && dd;
X dd--, n = prevnode(n));
X if (n == (Lknode) dirstack) {
X zerrnam(nam,"no such entry in dir stack",NULL,0);
X return NULL;
X }
X dest = remnode(dirstack,n);
X } else {
X if (!strcmp(argv[0],"-")) printdircr(dest = oldpwd);
X else dest = argv[0];
X }
X } else {
X char *u;
X int len1,len2,len3;
X
X if (!(u = ztrstr(pwd,argv[0]))) {
X zerrnam(nam,"string not in pwd: %s",argv[0],0);
X return NULL;
X }
X len1 = strlen(argv[0]);
X len2 = strlen(argv[1]);
X len3 = u-pwd;
X dest = alloc(len3+len2+strlen(u+len1)+1);
X strncpy(dest,pwd,len3);
X strcpy(dest+len3,argv[1]);
X strcat(dest,u+len1);
X printdircr(dest);
X }
X return dest;
X}
X
Xchar *cd_do_chdir(cnam,dest) /**/
Xchar *cnam; char *dest;
X{
Xint hasdot = 0, eno = ENOENT;
Xchar **pp,*ret;
X
X if (*dest == '/') {
X if (ret = cd_try_chdir(NULL,dest)) return ret;
X zerrnam(cnam,"%e: %s",dest,errno);
X return NULL;
X }
X for (pp = cdpath; *pp; pp++)
X if ((*pp)[0] == '.' && (*pp)[1] == '\0') hasdot = 1;
X if (!hasdot) {
X if (ret = cd_try_chdir(NULL,dest)) return ret;
X if (errno != ENOENT) eno = errno;
X }
X for (pp = cdpath; *pp; pp++) {
X if (ret = cd_try_chdir(*pp,dest)) {
X if (strcmp(*pp,".")) {
X printdircr(ret);
X }
X return ret;
X }
X if (errno != ENOENT) eno = errno;
X }
X if (isset(CDABLEVARS)) {
X char *s = getsparam(dest);
X if (s && *s == '/' && chdir(s) != -1) {
X printdircr(s);
X return s;
X }
X if (errno != ENOENT) eno = errno;
X }
X zerrnam(cnam,"%e: %s",dest,eno);
X return NULL;
X}
X
Xchar *cd_try_chdir(pfix,dest) /**/
Xchar *pfix; char *dest;
X{
Xstatic char buf[MAXPATHLEN], buf2[MAXPATHLEN];
Xchar *s;
Xint dotsct;
X
X if (pfix) sprintf(buf,"%s/%s",(!strcmp("/",pfix)) ? "" : pfix,dest);
X else strcpy(buf,dest);
X dotsct = fixdir(buf2,buf);
X if (buf2[0] == '/') return (chdir(buf2) == -1) ? NULL : buf2;
X if (!dotsct) {
X if (chdir((*buf2) ? buf2 : ".") == -1) return NULL;
X if (*buf2) sprintf(buf,"%s/%s",(!strcmp("/",pwd)) ? "" : pwd,buf2);
X else strcpy(buf,pwd);
X return buf;
X }
X strcpy(buf,pwd);
X s = buf+strlen(buf)-1;
X while (dotsct--) while (s != buf) if (*--s == '/') break;
X if (s == buf || *buf2) s++;
X strcpy(s,buf2);
X if (chdir(buf) != -1 || chdir(dest) != -1) return buf;
X return NULL;
X}
X
Xint fixdir(d,s) /**/
Xchar *d; char *s;
X{
Xint ct = 0;
Xchar *d0 = d;
X
X#ifdef HAS_RFS
X if (*s == '/' && s[1] == '.' && s[2] == '.') {
X *d++ = '/'; *d++ = '.'; *d++ = '.';
X s += 3;
X }
X#endif
X for (;;) {
X if (*s == '/') {
X *d++ = *s++;
X while (*s == '/') s++;
X }
X if (!*s) {
X while (d > d0+1 && d[-1] == '/') d--;
X *d = '\0';
X return ct;
X }
X if (s[0] == '.' && s[1] == '.' && (s[2] == '\0' || s[2] == '/')) {
X if (d > d0+1) {
X for (d--; d > d0+1 && d[-1] != '/'; d--);
X } else ct++;
X s += 2; if (*s) s++;
X } else if (s[0] == '.' && (s[1] == '/' || s[1] == '\0')) {
X s++; if (*s) s++;
X } else {
X while (*s != '/' && *s != '\0') *d++ = *s++;
X }
X }
X}
X
Xvoid cd_new_pwd(func,s) /**/
Xint func; char *s;
X{
XParam pm;
XList l;
X
X oldpwd = pwd;
X if (isset(CHASELINKS))
X pwd = findpwd(s);
X else
X pwd = ztrdup(s);
X if ((pm = gethnode("PWD", paramtab)) &&
X (pm->flags & PMFLAG_x) && pm->env)
X pm->env = replenv(pm->env,pwd);
X if ((pm = gethnode("OLDPWD", paramtab)) &&
X (pm->flags & PMFLAG_x) && pm->env)
X pm->env = replenv(pm->env,oldpwd);
X if (func == BIN_PUSHD) {
X permalloc();
X if (isset(PUSHDIGNOREDUPS)) {
X Lknode n;
X for (n = firstnode(dirstack); n; incnode(n))
X if (!strcmp(oldpwd,getdata(n))) {
X free(remnode(dirstack,n)); break;
X }
X }
X pushnode(dirstack,oldpwd);
X heapalloc();
X }
X if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE))
X pdstack();
X if (l = getshfunc("chpwd")) {
X fflush(stdout); fflush(stderr);
X doshfuncnoval(dupstruct(l),NULL,0);
X }
X if (dirstacksize != -1 && countnodes(dirstack) >= dirstacksize) {
X if (dirstacksize < 2)
X dirstacksize = 2;
X else
X free(remnode(dirstack,lastnode(dirstack)));
X }
X}
X
Xvoid convertwd(s,t,off) /**/
Xchar *s; char *t; int off;
X{
Xchar *u,*start;
X
X *t++ = '/';
X start = t;
X while (off--) *t++ = *s++;
X for (;;) {
X while (*s == '/') s++;
X for (u = s; *u && *u != '/'; u++);
X if (!strncmp(s,".",u-s)) {
X ;
X } else if (!strncmp(s,"..",u-s)) {
X while (t != start && *--t != '/');
X } else {
X if (t != start) *t++ = '/';
X struncpy(&t,s,u-s);
X }
X if (!*u) break;
X s = u;
X }
X *t = '\0';
X}
X
Xint bin_rehash(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
X newcmdnamtab();
X if (ops['f']) fullhash();
X return 0;
X}
X
Xint bin_hash(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xstruct cmdnam *chn;
X
X chn = (Cmdnam) zcalloc(sizeof *chn);
X chn->type = EXCMD;
X chn->pcomp = NULL; /* this is probably a bug ! */
X chn->u.nam = ztrdup(argv[1]);
X addhnode(ztrdup(argv[0]),chn,cmdnamtab,freecmdnam);
X return 0;
X}
X
X/* != 0 if s is a prefix of t */
X
Xint prefix(s,t) /**/
Xchar *s;char *t;
X{
X while (*s && *t && *s == *t) s++,t++;
X return (!*s);
X}
X
X/* convert %%, %1, %foo, %?bar? to a job number */
X
Xint getjob(s,prog) /**/
Xchar *s;char *prog;
X{
Xint t0,retval;
X
X if (*s != '%')
X goto jump;
X s++;
X if (*s == '%' || *s == '+' || !*s)
X {
X if (curjob == -1)
X {
X zerrnam(prog,"no current job",NULL,0);
X retval = -1; goto done;
X }
X retval = curjob; goto done;
X }
X if (*s == '-')
X {
X if (prevjob == -1)
X {
X zerrnam(prog,"no previous job",NULL,0);
X retval = -1; goto done;
X }
X retval = prevjob; goto done;
X }
X if (idigit(*s))
X {
X t0 = atoi(s);
X if (t0 && t0 < MAXJOB && jobtab[t0].stat && t0 != thisjob)
X { retval = t0; goto done; }
X zerrnam(prog,"no such job",NULL,0);
X retval = -1; goto done;
X }
X if (*s == '?')
X {
X struct process *pn;
X
X for (t0 = MAXJOB-1; t0 >= 0; t0--)
X if (jobtab[t0].stat && t0 != thisjob)
X for (pn = jobtab[t0].procs; pn; pn = pn->next)
X if (ztrstr(pn->text,s+1))
X { retval = t0; goto done; }
X zerrnam(prog,"job not found: %s",s,0);
X retval = -1; goto done;
X }
Xjump:
X if ((t0 = findjobnam(s)) != -1)
X { retval = t0; goto done; }
X zerrnam(prog,"job not found: %s",s,0);
X retval = -1;
Xdone:
X return retval;
X}
X
X/* find a job named s */
X
Xint findjobnam(s) /**/
Xchar *s;
X{
Xint t0;
X
X for (t0 = MAXJOB-1; t0 >= 0; t0--)
X if (jobtab[t0].stat && jobtab[t0].procs && t0 != thisjob &&
X jobtab[t0].procs->text && prefix(s,jobtab[t0].procs->text))
X return t0;
X return -1;
X}
X
Xint isanum(s) /**/
Xchar *s;
X{
X while (*s == '-' || idigit(*s)) s++;
X return *s == '\0';
X}
X
Xint bin_kill(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
Xint sig = SIGTERM;
Xint retval = 0;
X
X if (*argv && **argv == '-') {
X if (idigit((*argv)[1]))
X sig = atoi(*argv+1);
X else {
X if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
X printf("%s",sigs[1]);
X for (sig = 2; sig != SIGCOUNT; sig++)
X printf(" %s",sigs[sig]);
X putchar('\n');
X return 0;
X }
X for (sig = 0; sig != SIGCOUNT; sig++)
X if (!strcmp(sigs[sig],*argv+1)) break;
X if (sig == SIGCOUNT) {
X zerrnam(nam,"unknown signal: SIG%s",*argv+1,0);
X zerrnam(nam,"type kill -l for a List of signals",NULL,0);
X return 1;
X }
X }
X argv++;
X }
X for (; *argv; argv++) {
X if (**argv == '%') {
X int p = getjob(*argv,"kill");
X
X if (p == -1) {
X retval = 1;
X continue;
X }
X if (killjb(jobtab+p,sig) == -1) {
X zerrnam("kill","kill failed: %e",NULL,errno);
X retval = 1;
X continue;
X }
X if (jobtab[p].stat & STAT_STOPPED) {
X if (sig == SIGCONT)
X jobtab[p].stat &= ~STAT_STOPPED;
X if (sig != SIGKILL && sig != SIGCONT && sig != SIGTSTP
X && sig != SIGTTOU && sig != SIGTTIN && sig != SIGSTOP)
X killjb(jobtab+p,SIGCONT);
X }
X } else if (!isanum(*argv)) {
X zerrnam("kill","illegal pid: %s",*argv,0);
X } else if (kill(atoi(*argv),sig) == -1) {
X zerrnam("kill","kill failed: %e",NULL,errno);
X retval = 1;
X }
X }
X return 0;
X}
X
Xstatic char *recs[] = {
X "cputime","filesize","datasize","stacksize","coredumpsize",
X "resident","descriptors"
X };
X
Xint bin_limit(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
X#ifndef RLIM_INFINITY
X zerrnam(nam,"not available on this system",NULL,0);
X return 1;
X#else
Xchar *s;
Xint hard = ops['h'],t0,lim;
Xlong val;
X
X if (ops['s'])
X {
X if (*argv)
X zerrnam(nam,"arguments after -s ignored",NULL,0);
X for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
X if (setrlimit(t0,limits+t0) < 0)
X zerrnam(nam,"setrlimit failed: %e",NULL,errno);
X return 0;
X }
X if (!*argv)
X {
X showlimits(hard,-1);
X return 0;
X }
X while (s = *argv++)
X {
X for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++)
X if (!strncmp(recs[t0],s,strlen(s)))
X {
X if (lim != -1)
X lim = -2;
X else
X lim = t0;
X }
X if (lim < 0)
X {
X zerrnam("limit",
X (lim == -2) ? "ambiguous resource specification: %s"
X : "no such resource: %s",s,0);
X return 1;
X }
X if (!(s = *argv++))
X {
X showlimits(hard,lim);
X return 0;
X }
X if (!lim)
X {
X val = zstrtol(s,&s,10);
X if (*s)
X if ((*s == 'h' || *s == 'H') && !s[1])
X val *= 3600L;
X else if ((*s == 'm' || *s == 'M') && !s[1])
X val *= 60L;
X else if (*s == ':')
X val = val*60+zstrtol(s+1,&s,10);
X else
X {
X zerrnam("limit","unknown scaling factor: %s",s,0);
X return 1;
X }
X }
X#ifdef RLIMIT_NOFILE
X else if (lim == RLIMIT_NOFILE)
X val = zstrtol(s,&s,10);
X#endif
X else
X {
X val = zstrtol(s,&s,10);
X if (!*s || ((*s == 'k' || *s == 'K') && !s[1]))
X val *= 1024L;
X else if ((*s == 'M' || *s == 'm') && !s[1])
X val *= 1024L*1024;
X else
X {
X zerrnam("limit","unknown scaling factor: %s",s,0);
X return 1;
X }
X }
X if (hard)
X if (val > limits[lim].rlim_max && geteuid())
X {
X zerrnam("limit","can't raise hard limits",NULL,0);
X return 1;
X }
X else
X {
X limits[lim].rlim_max = val;
X if (limits[lim].rlim_max < limits[lim].rlim_cur)
X limits[lim].rlim_cur = limits[lim].rlim_max;
X }
X else
X if (val > limits[lim].rlim_max)
X {
X zerrnam("limit","limit exceeds hard limit",NULL,0);
X return 1;
X }
X else
X limits[lim].rlim_cur = val;
X }
X return 0;
X#endif
X}
X
Xint bin_unlimit(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
X#ifndef RLIM_INFINITY
X zerrnam(nam,"not available on this system",NULL,0);
X return 1;
X#else
Xint hard = ops['h'],t0,lim;
X
X if (hard && geteuid())
X {
X zerrnam(nam,"can't remove hard limits",NULL,0);
X return 1;
X }
X if (!*argv)
X {
X for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
X {
X if (hard)
X limits[t0].rlim_max = RLIM_INFINITY;
X else
X limits[t0].rlim_cur = limits[t0].rlim_max;
X }
X return 0;
X }
X for (; *argv; argv++)
X {
X for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++)
X if (!strncmp(recs[t0],*argv,strlen(*argv)))
X {
X if (lim != -1)
X lim = -2;
X else
X lim = t0;
X }
X if (lim < 0)
X {
X zerrnam(nam,
X (lim == -2) ? "ambiguous resource specification: %s"
X : "no such resource: %s",*argv,0);
X return 1;
X }
X if (hard)
X limits[lim].rlim_max = RLIM_INFINITY;
X else
X limits[lim].rlim_cur = limits[lim].rlim_max;
X }
X return 0;
X#endif
X}
X
Xvoid showlimits(hard,lim) /**/
Xint hard;int lim;
X{
Xint t0;
Xlong val;
X
X#ifdef RLIM_INFINITY
X for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
X if (t0 == lim || lim == -1)
X {
X printf("%-16s",recs[t0]);
X val = (hard) ? limits[t0].rlim_max : limits[t0].rlim_cur;
X if (val == RLIM_INFINITY)
X printf("unlimited\n");
X else if (!t0)
X printf("%d:%02d:%02d\n",(int) (val/3600),
X (int) (val/60) % 60,(int) (val % 60));
X#ifdef RLIMIT_NOFILE
X else if (t0 == RLIMIT_NOFILE)
X printf("%d\n",(int) val);
X#endif
X else if (val >= 1024L*1024L)
X printf("%ldMb\n",val/(1024L*1024L));
X else
X printf("%ldKb\n",val/1024L);
X }
X#endif
X}
X
Xint bin_sched(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
Xchar *s = *argv++;
Xtime_t t;
Xlong h,m;
Xstruct tm *tm;
Xstruct schedcmd *sch,*sch2,*schl;
Xint t0;
X
X if (s && *s == '-')
X {
X t0 = atoi(s+1);
X
X if (!t0)
X {
X zerrnam("sched","usage for delete: sched -<item#>.",NULL,0);
X return 1;
X }
X for (schl = (struct schedcmd *) &schedcmds, sch = schedcmds, t0--;
X sch && t0; sch = (schl = sch)->next, t0--);
X if (!sch)
X {
X zerrnam("sched","not that many entries",NULL,0);
X return 1;
X }
X schl->next = sch->next;
X free(sch->cmd);
X free(sch);
X return 0;
X }
X if (!s)
X {
X char tbuf[40];
X
X for (t0 = 1, sch = schedcmds; sch; sch = sch->next,t0++)
X {
X t = sch->time;
X tm = localtime(&t);
X ztrftime(tbuf,20,"%a %b %e %k:%M:%S",tm);
X printf("%3d %s %s\n",t0,tbuf,sch->cmd);
X }
X return 0;
X }
X else if (!*argv)
X {
X zerrnam("sched","not enough arguments",NULL,0);
X return 1;
X }
X if (*s == '+')
X {
X h = zstrtol(s+1,&s,10);
X if (*s != ':')
X {
X zerrnam("sched","bad time specifier",NULL,0);
X return 1;
X }
X m = zstrtol(s+1,&s,10);
X if (*s)
X {
X zerrnam("sched","bad time specifier",NULL,0);
X return 1;
X }
X t = time(NULL)+h*3600+m*60;
X }
X else
X {
X h = zstrtol(s,&s,10);
X if (*s != ':')
X {
X zerrnam("sched","bad time specifier",NULL,0);
X return 1;
X }
X m = zstrtol(s+1,&s,10);
X if (*s && *s != 'a' && *s != 'p')
X {
X zerrnam("sched","bad time specifier",NULL,0);
X return 1;
X }
X t = time(NULL);
X tm = localtime(&t);
X t -= tm->tm_sec+tm->tm_min*60+tm->tm_hour*3600;
X if (*s == 'p')
X h += 12;
X t += h*3600+m*60;
X if (t < time(NULL))
X t += 3600*24;
X }
X sch = zcalloc(sizeof *sch);
X sch->time = t;
X sch->cmd = ztrdup(spacejoin(argv));
X sch->next = NULL;
X for (sch2 = (struct schedcmd *) &schedcmds; sch2->next; sch2 = sch2->next);
X sch2->next = sch;
X return 0;
X}
X
Xint bin_eval(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
Xchar *s = ztrdup(spacejoin(argv));
XList list;
X
X hungets(s);
X free(s);
X strinbeg();
X if (!(list = parse_list()))
X {
X hflush();
X strinend();
X return 1;
X }
X strinend();
X runlist(list);
X return lastval;
X}
X
X/* get the history event associated with s */
X
Xint fcgetcomm(s) /**/
Xchar *s;
X{
Xint cmd;
X
X if (cmd = atoi(s))
X {
X if (cmd < 0)
X cmd = curhist+cmd+1;
X return cmd;
X }
X cmd = hcomsearch(s);
X if (cmd == -1)
X zerrnam("fc","event not found: %s",s,0);
X return cmd;
X}
X
X/* perform old=new substituion */
X
Xint fcsubs(sp,sub) /**/
Xchar **sp;struct asgment *sub;
X{
Xchar *s1,*s2,*s3,*s4,*s = *sp,*s5;
Xint subbed = 0;
X
X while (sub)
X {
X s1 = sub->name;
X s2 = sub->value;
X sub = sub->next;
X s5 = s;
X while (s3 = (char *) ztrstr(s5,s1))
X {
X s4 = alloc(1+(s3-s)+strlen(s2)+strlen(s3+strlen(s1)));
X ztrncpy(s4,s,s3-s);
X strcat(s4,s2);
X s5 = s4+strlen(s4);
X strcat(s4,s3+strlen(s1));
X s = s4;
X subbed = 1;
X }
X }
X *sp = s;
X return subbed;
X}
X
X/* print a series of history events to a file */
X
Xint fclist(f,n,r,D,d,first,last,subs) /**/
XFILE *f;int n;int r;int D;int d;int first;int last;struct asgment *subs;
X{
Xint done = 0;
Xchar *s,*hs;
XHistent ent;
X
X if (!subs) done = 1;
X for (;;) {
X hs = quietgetevent(first);
X if (!hs) {
X zerrnam("fc","no such event: %d",NULL,first);
X return 1;
X }
X s = makehstr(hs);
X done |= fcsubs(&s,subs);
X if (n) fprintf(f,"%5d ",first);
X ent = NULL;
X if (d) {
X struct tm *ltm;
X
X if (!ent) ent = gethistent(first);
X ltm = localtime(&ent->stim);
X fprintf(f,"%2d:%02d ",ltm->tm_hour,ltm->tm_min);
X }
X if (D) {
X long diff;
X
X if (!ent) ent = gethistent(first);
X diff = (ent->ftim) ? ent->ftim-ent->stim : 0;
X fprintf(f,"%d:%02d ",diff/60,diff%60);
X }
X if (f == stdout) {
X niceprintf(s,f);
X putc('\n',f);
X } else fprintf(f,"%s\n",s);
X if (first == last) break;
X (r) ? first-- : first++;
X }
X if (f != stdout) fclose(f);
X if (!done) {
X zerrnam("fc","no substitutions performed",NULL,0);
X return 1;
X }
X return 0;
X}
X
Xint fcedit(ename,fn) /**/
Xchar *ename;char *fn;
X{
X if (!strcmp(ename,"-"))
X return 1;
X return !zyztem(ename,fn);
X}
X
X/* fc, history, r */
X
Xint bin_fc(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
Xint first = -1,last = -1,retval,minflag = 0;
Xchar *s;
Xstruct asgment *asgf = NULL,*asgl = NULL;
X
X if (!interact) {
X zerrnam(nam,"not interactive shell",NULL,0);
X return 1;
X }
X if (!(ops['l'] && unset(HISTNOSTORE))) remhist();
X if (ops['R']) {
X readhistfile(*argv ? *argv : getsparam("HISTFILE"),1);
X return 0;
X }
X if (ops['W']) {
X savehistfile(*argv ? *argv : getsparam("HISTFILE"),1,0);
X return 0;
X }
X if (ops['A']) {
X savehistfile(*argv ? *argv : getsparam("HISTFILE"),1,1);
X return 0;
X }
X while (*argv && equalsplit(*argv,&s)) {
X struct asgment *a = (struct asgment *) alloc(sizeof *a);
X
X if (!asgf) asgf = asgl = a;
X else {
X asgl->next = a;
X asgl = a;
X }
X a->name = *argv;
X a->value = s;
X argv++;
X }
X if (*argv) {
X minflag = **argv == '-';
X first = fcgetcomm(*argv);
X if (first == -1) return 1;
X argv++;
X }
X if (*argv) {
X last = fcgetcomm(*argv);
X if (last == -1) return 1;
X argv++;
X }
X if (*argv) {
X zerrnam("fc","too many arguments",NULL,0);
X return 1;
X }
X if (first == -1) first = (ops['l']) ? curhist-16 : curhist;
X if (last == -1) last = (ops['l']) ? curhist : first;
X if (first < firsthist()) first = firsthist();
X if (last == -1) last = (minflag) ? curhist : first;
X if (ops['l'])
X retval = fclist(stdout,!ops['n'],ops['r'],ops['D'],ops['d'],
X first,last,asgf);
X else {
X FILE *out;
X char *fil = gettemp();
X
X out = fopen(fil,"w");
X if (!out)
X zerrnam("fc","can't open temp file: %e",NULL,errno);
X else {
X retval = 1;
X if (!fclist(out,0,ops['r'],0,0,first,last,asgf))
X if (fcedit(auxdata ? auxdata : fceditparam,fil))
X if (stuff(fil))
X zerrnam("fc","%e: %s",s,errno);
X else
X retval = 0;
X }
X unlink(fil);
X }
X return retval;
X}
X
Xint bin_suspend(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
X if (islogin && !ops['f']) {
X zerrnam(name,"can't suspend login shell",NULL,0);
X return 1;
X }
X if (jobbing) {
X signal(SIGPIPE,SIG_DFL);
X signal(SIGTTIN,SIG_DFL);
X signal(SIGTSTP,SIG_DFL);
X signal(SIGTTOU,SIG_DFL);
X }
X kill(0,SIGTSTP);
X if (jobbing) {
X while (gettygrp() != mypgrp) {
X sleep(1);
X if (gettygrp() != mypgrp) kill(0,SIGTTIN);
X }
X signal(SIGTTOU,SIG_IGN);
X signal(SIGTSTP,SIG_IGN);
X signal(SIGTTIN,SIG_IGN);
X signal(SIGPIPE,SIG_IGN);
X }
X return 0;
X}
X
Xint bin_alias(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xstruct alias *an;
Xstruct asgment *asg;
Xint incm = !(ops['a'] || ops['g']),ret = 0;
X
X showflag = !incm;
X if (!*argv)
X listhtable(aliastab,(HFunc) printalias);
X else while (asg = getasg(*argv++))
X {
X if (asg->value)
X addhnode(ztrdup(asg->name),mkanode(ztrdup(asg->value),incm),
X aliastab,freeanode);
X else if (an = (Alias) gethnode(asg->name,aliastab))
X printalias(asg->name,an);
X else
X ret = 1;
X }
X return ret;
X}
X
X/* print an alias; used with listhtable */
X
Xvoid printalias(s,a) /**/
Xchar *s;struct alias *a;
X{
X if (a->cmd >= 0 && !(showflag && a->cmd))
X printf("%s=%s\n",s,a->text);
X}
X
X/* print a param; used with listhtable */
X
Xvoid printparam(s,p) /**/
Xchar *s;Param p;
X{
X if (showflag > 0 && !(p->flags & showflag))
X return;
X if (!showflag)
X {
X int fgs = p->flags;
X
X if (fgs & PMFLAG_i) printf("integer ");
X if (fgs & PMFLAG_A) printf("array ");
X if (fgs & PMFLAG_L) printf("left justified %d ",p->ct);
X if (fgs & PMFLAG_R) printf("right justified %d ",p->ct);
X if (fgs & PMFLAG_Z) printf("zero filled %d ",p->ct);
X if (fgs & PMFLAG_l) printf("lowercase ");
X if (fgs & PMFLAG_u) printf("uppercase ");
X if (fgs & PMFLAG_r) printf("readonly ");
X if (fgs & PMFLAG_t) printf("tagged ");
X if (fgs & PMFLAG_x) printf("exported ");
X }
X if (showflag2)
X printf("%s\n",s);
X else
X {
X char *t,**u;
X
X printf("%s=",s);
X switch (p->flags & PMTYPE)
X {
X case PMFLAG_s:
X if (p->gets.cfn && (t = p->gets.cfn(p)))
X puts(t);
X else
X putchar('\n');
X break;
X case PMFLAG_i: printf("%ld\n",p->gets.ifn(p)); break;
X case PMFLAG_A:
X putchar('(');
X u = p->gets.afn(p);
X if (!*u)
X printf(")\n");
X else
X {
X while (u[1])
X printf("%s ",*u++);
X printf("%s)\n",*u);
X }
X break;
X }
X }
X}
X
X/* autoload, declare, export, functions, integer, local, readonly, typeset */
X
Xint bin_typeset(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xint on = 0,off = 0,roff,bit = 1,retcode = 0;
Xchar *optstr = "LRZilurtx";
Xstruct param *pm;
Xstruct asgment *asg;
X
X for (; *optstr; optstr++,bit <<= 1)
X if (ops[*optstr] == 1)
X on |= bit;
X else if (ops[*optstr] == 2)
X off |= bit;
X roff = off;
X if (ops['f']) {
X on &= PMFLAG_t|PMFLAG_u;
X off &= PMFLAG_t|PMFLAG_u;
X showflag = (ops['f'] == 1);
X if (ops['@'] && ((off & ~PMFLAG_t) || (on & ~(PMFLAG_u|PMFLAG_t)))) {
X zerrnam(name,"invalid option(s)",NULL,0);
X return 1;
X }
X showflag2 = 0;
X if (!*argv) {
X showflag2 = off|on;
X listhtable(cmdnamtab,(HFunc) pshfunc);
X } else for (; *argv; argv++) {
X Cmdnam cc;
X
X if ((cc = (Cmdnam) gethnode(*argv,cmdnamtab)) && cc->type == SHFUNC)
X if (on|off) cc->flags = (cc->flags | on) & (~off);
X else pshfunc(*argv,cc);
X else if (on & PMFLAG_u) {
X cc = (Cmdnam) zcalloc(sizeof *cc);
X cc->type = SHFUNC;
X cc->flags = on;
X addhnode(ztrdup(*argv),cc,cmdnamtab,freecmdnam);
X } else
X retcode = 1;
X }
X return retcode;
X }
X if (on & PMFLAG_L)
X off |= PMFLAG_R;
X if (on & PMFLAG_R)
X off |= PMFLAG_L;
X if (on & PMFLAG_u)
X off |= PMFLAG_l;
X if (on & PMFLAG_l)
X off |= PMFLAG_u;
X on &= ~off;
X showflag = showflag2 = 0;
X if (!*argv) {
X showflag = on|off;
X showflag2 = roff;
X listhtable(paramtab,(HFunc) printparam);
X } else while (asg = getasg(*argv++)) {
X if (asg->value && *asg->value == '~') {
X *asg->value = Tilde;
X singsub(&asg->value);
X }
X pm = (Param) gethnode(asg->name,paramtab);
X if (pm) {
X if (!on && !roff && !asg->value) {
X printparam(asg->name,pm);
X continue;
X }
X pm->flags = (pm->flags | on) & ~off;
X if ((on & (PMFLAG_L | PMFLAG_R | PMFLAG_Z | PMFLAG_i))
X && (pmtype(pm) != PMFLAG_A))
X pm->ct = auxlen;
X if (pmtype(pm) != PMFLAG_A) {
X if (pm->flags & PMFLAG_x) {
X if (!pm->env)
X pm->env = addenv(asg->name,
X (asg->value) ? asg->value : getsparam(asg->name));
X } else if (pm->env) {
X delenv(pm->env);
X free(pm->env);
X pm->env = NULL;
X }
X if (asg->value)
X setsparam(asg->name,ztrdup(asg->value));
X }
X } else {
X if (locallist && !(on & PMFLAG_x)) {
X permalloc();
X addnode(locallist,ztrdup(asg->name));
X heapalloc();
X }
X createparam(ztrdup(asg->name),
X ztrdup((asg->value) ? asg->value : ""),on);
X pm = (Param) gethnode(asg->name,paramtab);
X pm->ct = auxlen;
X }
X }
X return 0;
X}
X
X/* convert s with escape sequences */
X
Xchar *escsubst(s,nnl) /**/
Xchar *s; int *nnl;
X{
Xchar *t = alloc(strlen(s)+1),*ret = t;
X
X for (; *s; s++)
X if (*s == '\\' && s[1])
X switch (*++s) {
X case 'b': *t++ = '\b'; break;
X case 'c': *nnl |= 1; break;
X case 'e': *t++ = '\033'; break;
X case 'f': *t++ = '\f'; break;
X case 'n': *t++ = '\n'; break;
X case 'r': *t++ = '\r'; break;
X case 't': *t++ = '\t'; break;
X case 'v': *t++ = '\v'; break;
X case '\\': *t++ = '\\'; break;
X case '0': *t++ = zstrtol(s,&s,8); s--; break;
X default: *t++ = '\\'; *t++ = *s; break;
X }
X else *t++ = *s;
X *t = '\0';
X return ret;
X}
X
X/* echo, print, pushln */
X
Xint bin_print(name,args,ops,func) /**/
Xchar *name;char **args;char *ops;int func;
X{
Xint nnl = 0, fd;
XHistent ent;
XFILE *fout = stdout;
X
X if (ops['z']) {
X permalloc();
X pushnode(bufstack,ztrdup(spacejoin(args)));
X heapalloc();
X return 0;
X }
X if (ops['s']) {
X permalloc();
X ent = gethistent(++curhist);
X ent->lex = ztrdup(join(args,HISTSPACE));
X ent->lit = ztrdup(join(args,' '));
X ent->stim = ent->ftim = time(NULL);
X heapalloc();
X return 0;
X }
X if (ops['R'])
X ops['r'] = 1;
X if (ops['u'] || ops['p']) {
X if (ops['u']) {
X for (fd = 0; fd < 10; fd++) if (ops[fd+'0']) break;
X if (fd == 10) fd = 0;
X } else fd = coprocout;
X if ((fd = dup(fd)) < 0) {
X zerrnam(name,"bad file number",NULL,0);
X return 1;
X }
X if ((fout = fdopen(fd,"w")) == 0) {
X zerrnam(name,"bad mode on fd",NULL,0);
X return 1;
X }
X }
X for (; *args; args++) {
X if (!ops['r']) *args = escsubst(*args,&nnl);
X if (ops['D']) fprintdir(*args,fout);
X else if (ops['P']) {
X int junk;
X fputs(putprompt(*args,&junk),fout);
X } else fputs(*args,fout);
X if (args[1]) fputc(ops['l'] ? '\n' : ops['0'] ? '\0' : ' ',fout);
X }
X if (!(ops['n'] || nnl)) fputc(ops['N'] ? '\0' : '\n',fout);
X if (fout != stdout) fclose(fout);
X return 0;
X}
X
Xint bin_dirs(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
XLklist l;
X
X if (ops['v'])
X {
X Lknode node;
X int t0 = 1;
X
X printf("0\t");
X printdir(pwd);
X for (node = firstnode(dirstack); node; incnode(node))
X {
X printf("\n%d\t",t0++);
X printdir(getdata(node));
X }
X putchar('\n');
X return 0;
X }
X if (!*argv)
X {
X pdstack();
X return 0;
X }
X permalloc();
X l = newlist();
X if (!*argv)
X {
X heapalloc();
X return 0;
X }
X while (*argv)
X addnode(l,ztrdup(*argv++));
X freetable(dirstack,freestr);
X dirstack = l;
X heapalloc();
X return 0;
X}
X
Xint bin_unalias(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xint ret = 0;
Xvptr dat;
X
X while (*argv)
X {
X if (dat = remhnode(*argv++,aliastab))
X freeanode(dat);
X else
X ret = 1;
X }
X return ret;
X}
X
Xint bin_disable(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
XCmdnam chn;
X
X while (*argv) {
X if (!strncmp(*argv,"TRAP",4))
X unsettrap(getsignum(*argv+4));
X chn = zalloc(sizeof *chn);
X chn->type = DISABLED;
X addhnode(ztrdup(*argv++),chn,cmdnamtab,freecmdnam);
X }
X return 0;
X}
X
Xint bin_unhash(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xvptr dat;
X
X while (*argv) {
X if (!strncmp(*argv,"TRAP",4)) unsettrap(getsignum(*argv+4));
X if (dat = remhnode(*argv++,cmdnamtab)) freecmdnam(dat);
X }
X return 0;
X}
X
Xint bin_unset(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xint retval = 0;
Xchar *s;
X
X while (s = *argv++)
X if (gethnode(s,paramtab))
X unsetparam(s);
X else
X retval = 1;
X return retval;
X}
X
Xstatic char *zbuf;
Xstatic int readfd;
X
Xint zread() /**/
X{
Xchar cc;
X
X if (zbuf)
X return (*zbuf) ? *zbuf++ : EOF;
X if (read(readfd,&cc,1) != 1)
X return EOF;
X return cc;
X}
X
Xint bin_read(name,args,ops,func) /**/
Xchar *name;char **args;char *ops;int func;
X{
Xchar *reply,*pmpt;
Xint bsiz,c,gotnl = 0;
Xchar *buf,*bptr;
X
X reply = (*args) ? *args++ : "REPLY";
X if (ops['u'] && !ops['p']) {
X for (readfd = 0; readfd < 10; ++readfd) if (ops[readfd+'0']) break;
X if (readfd == 10) readfd = 0;
X } else if (ops['p']) readfd = coprocin;
X else {
X attachtty((jobtab[thisjob].gleader) ? jobtab[thisjob].gleader : mypgrp);
X readfd = 0;
X if (isatty(0)) {
X for (pmpt = reply; *pmpt && *pmpt != '?'; pmpt++);
X if (*pmpt++) {
X write(2,pmpt,strlen(pmpt));
X pmpt[-1] = '\0';
X }
X }
X#if 0
X else if (isset(SHINSTDIN) && unset(INTERACTIVE)) {
X if (isatty(1)) readfd = 1;
X else if (isatty(2)) readfd = 2;
X }
X#endif
X }
X zbuf = (!ops['z']) ? NULL :
X (full(bufstack)) ? (char *) getnode(bufstack) : NULL;
X while (*args) {
X buf = bptr = zalloc(bsiz = 64);
Xredo:
X for(;;) {
X if (gotnl) break;
X c = zread();
X if (!ops['r'] && c == '\n' && bptr != buf && bptr[-1] == '\\') {
X bptr--;
X continue;
X }
X if (c == EOF || isep(c) || c == '\n') break;
X *bptr++ = c;
X if (bptr == buf+bsiz) {
X buf = realloc(buf,bsiz *= 2);
X bptr = buf+(bsiz/2);
X }
X }
X if (c == EOF) {
X if (readfd == coprocin) {
X close(coprocin);
X close(coprocout);
X coprocin = coprocout = -1;
X }
X return 1;
X }
X if (c == '\n') gotnl = 1;
X if (bptr == buf) goto redo;
X *bptr = '\0';
X setsparam(reply,buf);
X reply = *args++;
X }
X buf = bptr = zalloc(bsiz = 64);
X if (!gotnl)
X for (;;) {
X c = zread();
X if (!ops['r'] && c == '\n' && bptr != buf && bptr[-1] == '\\') {
X bptr--;
X continue;
X }
X if (c == EOF || (c == '\n' && !zbuf)) break;
X *bptr++ = c;
X if (bptr == buf+bsiz) {
X buf = realloc(buf,bsiz *= 2);
X bptr = buf+(bsiz/2);
X }
X }
X *bptr = '\0';
X setsparam(reply,buf);
X if (c == EOF) {
X if (readfd == coprocin) {
X close(coprocin);
X close(coprocout);
X coprocin = coprocout = -1;
X }
X return 1;
X }
X return 0;
X}
X
Xint bin_vared(name,args,ops,func) /**/
Xchar *name;char **args;char *ops;int func;
X{
Xchar *s;char *t;
Xstruct param *pm;
X
X if (!(s = getsparam(args[0]))) {
X zerrnam(name,"no such variable: %s",args[0],0);
X return 1;
X }
X permalloc();
X pushnode(bufstack,ztrdup(s));
X heapalloc();
X t = (char *) zleread((unsigned char *)"> ",NULL,2);
X if (!t || errflag)
X return 1;
X if (t[strlen(t)-1] == '\n')
X t[strlen(t)-1] = '\0';
X pm = gethnode(args[0],paramtab);
X if (pmtype(pm) == PMFLAG_A)
X setaparam(args[0],spacesplit(t));
X else
X setsparam(args[0],t);
X return 0;
X}
X
X#define fset(X) (flags & X)
X
X/* execute a builtin handler function after parsing the arguments */
X
Xint execbin(args,cnode) /**/
XLklist args;Cmdnam cnode;
X{
Xstruct bincmd *b;
Xchar ops[128],*arg,*pp,*name,**argv,**oargv,*optstr;
Xint t0,flags,sense,argc = 0,op;
XLknode n;
X
X auxdata = NULL;
X auxlen = 0;
X for (t0 = 0; t0 != 128; t0++)
X ops[t0] = 0;
X name = ugetnode(args);
X b = builtins+cnode->u.binnum;
X
X/* the 'builtin' builtin is handled specially */
X
X if (b->funcid == BIN_BUILTIN)
X {
X if (!(name = ugetnode(args)))
X {
X zerrnam("builtin","command name expected",NULL,0);
X return 1;
X }
X for (t0 = 0, b = builtins; b->name; b++,t0++)
X if (!strcmp(name,b->name))
X break;
X if (!b->name)
X {
X zerrnam("builtin","no such builtin: %s",name,0);
X return 1;
X }
X }
X flags = b->flags;
X arg = ugetnode(args);
X optstr = b->optstr;
SHAR_EOF
true || echo 'restore of zsh2.2/src/builtin.c failed'
fi
echo 'End of zsh2.2 part 6'
echo 'File zsh2.2/src/builtin.c is continued in part 7'
echo 7 > _shar_seq_.tmp

Paul Falstad

unread,
May 13, 1992, 12:00:14 PM5/13/92
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 29, Issue 103
Archive-name: zsh2.2/part07

Environment: BSD
Supersedes: zsh2.1: Volume 24, Issue 1-19

#!/bin/sh
# this is aa.07 (part 7 of zsh2.2)


# do not concatenate these parts, unpack them in order with /bin/sh

# file zsh2.2/src/builtin.c continued
#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 7; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping zsh2.2/src/builtin.c'
else
echo 'x - continuing file zsh2.2/src/builtin.c'
sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.2/src/builtin.c' &&

X if (flags & BINF_ECHOPTS && arg && strcmp(arg,"-n"))
X optstr = NULL;
X if (optstr)
X while (arg &&
X ((sense = *arg == '-') || fset(BINF_PLUSOPTS) && *arg == '+') &&
X (fset(BINF_PLUSOPTS) || !atoi(arg)))
X {
X pp = arg;
X if (arg[1] == '-')
X arg++;
X if (!arg[1])
X {
X ops['-'] = 1;
X if (!sense)
X ops['+'] = 1;
X }
X else
X ops['@'] = 1;
X op = -1;
X while (*++arg)
X if (strchr(b->optstr,op = *arg))
X ops[*arg] = (sense) ? 1 : 2;
X else
X break;
X if (*arg)
X {
X zerr("bad option: %c",NULL,*arg);
X return 1;
X }
X arg = ugetnode(args);
X if (fset(BINF_SETOPTS) && op == 'o')
X {
X int c;
X
X if (!arg)
X prtopt();
X else
X {
X c = optlookup(arg);
X if (c == -1)
X {
X zerr("bad option: %s",arg,0);


X return 1;
X }
X else
X {

X ops[c] = ops['o'];


X arg = ugetnode(args);
X }

X }
X }
X if ((fset(BINF_PRINTOPTS) && ops['R']) || ops['-'])
X break;
X if (fset(BINF_SETOPTS) && ops['A'])
X {
X auxdata = arg;
X arg = ugetnode(args);
X break;
X }
X if (fset(BINF_FCOPTS) && op == 'e')
X {
X auxdata = arg;


X arg = ugetnode(args);
X }

X if (fset(BINF_TYPEOPT) && (op == 'L' || op == 'R' ||
X op == 'Z' || op == 'i') && arg && idigit(*arg))
X {
X auxlen = atoi(arg);


X arg = ugetnode(args);
X }

X }
X if (fset(BINF_R))
X auxdata = "-";
X if (pp = b->defopts)
X while (*pp)
X ops[*pp++] = 1;
X if (arg)
X {
X argc = 1;
X n = firstnode(args);
X while (n)
X argc++,incnode(n);
X }
X oargv = argv = (char **) ncalloc(sizeof(char **) * (argc+1));
X if (*argv++ = arg)
X while (*argv++ = ugetnode(args));
X argv = oargv;
X if (errflag)
X return 1;
X if (argc < b->minargs || (argc > b->maxargs && b->maxargs != -1)) {
X zerrnam(name,(argc < b->minargs)
X ? "not enough arguments" : "too many arguments",NULL,0);
X return 1;
X }
X if (isset(XTRACE)) {
X char **pp = argv;
X fprintf(stderr,"%s%s",(prompt4) ? prompt4 : "",name);
X while (*pp) fprintf(stderr," %s",*pp++);
X fputc('\n',stderr);
X fflush(stderr);
X }
X return (*(b->handlerfunc))(name,argv,ops,b->funcid);
X}
X
Xstruct asgment *getasg(s) /**/
Xchar *s;
X{
Xstatic struct asgment asg;
X
X if (!s)
X return NULL;
X if (*s == '=')
X {
X zerr("bad assignment",NULL,0);
X return NULL;
X }
X asg.name = s;
X for (; *s && *s != '='; s++);
X if (*s)
X {
X *s = '\0';
X asg.value = s+1;
X }
X else
X asg.value = NULL;
X return &asg;
X}
X
X/* ., source */
X
Xint bin_dot(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

Xchar **old,*old0;
Xint ret;
Xchar buf[MAXPATHLEN];
Xchar *s,**t,*enam;
X
X if (!*argv)
X return 0;
X old = pparams;
X old0 = argzero;
X if (argv[1]) {
X permalloc();
X pparams = arrdup(argv+1);
X heapalloc();
X }
X enam = argzero = ztrdup(*argv);
X errno = ENOENT;
X ret = 1;
X for (s = argzero; *s; s++)
X if (*s == '/') {
X ret = source(argzero);
X break;
X }
X if (!*s) {
X for (t = path; *t; t++)
X if ((*t)[0] == '.' && !(*t)[1]) {
X ret = source(argzero);
X break;
X } else {
X sprintf(buf,"%s/%s",*t,argzero);
X if (access(buf,F_OK) == 0) {
X ret = source(enam = buf);
X break;
X }
X }
X if (!*t && access(argzero,F_OK) == 0)
X ret = source(enam = argzero);
X }
X if (argv[1]) {
X freearray(pparams);
X pparams = old;
X }
X if (ret) zerrnam(name,"%e: %s",enam,errno);
X free(argzero);
X argzero = old0;


X return ret;
X}
X

Xint bin_set(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

Xstruct option *opp;
Xchar **x;
X
X if (((ops['+'] && ops['-']) || !ops['-']) && !ops['@'] && !*argv)
X {
X showflag = ~0;
X showflag2 = ops['+'];
X listhtable(paramtab,(HFunc) printparam);


X }
X for (opp = optns; opp->name; opp++)

X if (ops[opp->id] == 1)


X opts[opp->id] = OPT_SET;

X else if (ops[opp->id] == 2)


X opts[opp->id] = OPT_UNSET;

X if (!*argv && !ops['-'])
X return 0;
X permalloc();
X x = arrdup(argv);
X heapalloc();


X if (ops['A'])

X setaparam(auxdata,x);
X else {
X freearray(pparams);
X pparams = x;


X }
X return 0;
X}
X

X#define pttime(X) printf("%dm%ds",(X)/3600,(X)/60%60)
X
Xint bin_times(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

Xstruct tms buf;
X
X if (times(&buf) == -1)
X return 1;
X pttime(buf.tms_utime);
X putchar(' ');
X pttime(buf.tms_stime);
X putchar('\n');
X pttime(buf.tms_cutime);
X putchar(' ');
X pttime(buf.tms_cstime);


X putchar('\n');
X return 0;
X}
X

Xint bin_getopts(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

Xchar *optstr = *argv++,*var = *argv++;
Xchar **args = (*argv) ? argv : pparams;
Xstatic int optcind = 1,quiet;
Xchar *str,optbuf[3],*opch = optbuf+1;
X
X if (zoptind < 1) zoptind = 1;
X optbuf[0] = '+'; optbuf[1] = optbuf[2] = '\0';
X if (optarg) free(optarg);
X optarg = ztrdup("");
X setsparam(var,ztrdup(""));
X if (*optstr == ':') {
X quiet = 1;
X optstr++;
X }
X if (zoptind > arrlen(args)) return 1;
X str = args[zoptind-1];
X if (*str != '+' && *str != '-' || optcind >= strlen(str) ||
X !strcmp("--",str)) {
X if (*str == '+' || *str == '-')
X zoptind++;
X optcind = 0;
X return 1;
X }
X if (!optcind)
X optcind = 1;
X *opch = str[optcind++];
X if (!args[zoptind-1][optcind]) {
X zoptind++;
X optcind = 0;
X }
X for (; *optstr; optstr++)
X if (*opch == *optstr)
X break;
X if (!*optstr) {
X setsparam(var,ztrdup("?"));
X if (quiet) {
X free(optarg); optarg = ztrdup(opch);
X return 0;
X }
X zerr("bad option: %c",NULL,*opch); errflag = 0;
X return 0;
X }
X setsparam(var,ztrdup(opch-(*str == '+')));
X if (optstr[1] == ':') {
X if (!args[zoptind-1]) {
X if (quiet) {
X free(optarg); optarg = ztrdup(opch);
X setsparam(var,ztrdup(":"));
X return 0;
X }
X setsparam(var,ztrdup("?"));
X zerr("argument expected after %c option",NULL,*opch); errflag = 0;
X return 0;
X }
X free(optarg);
X optarg = ztrdup(args[zoptind-1]+optcind);
X zoptind++;
X optcind = 0;


X }
X return 0;
X}
X

X/* get a signal number from a string */
X
Xint getsignum(s) /**/
Xchar *s;
X{
Xint x = atoi(s),t0;
X
X if (idigit(*s) && x >= 0 && x < VSIGCOUNT)
X return x;
X for (t0 = 0; t0 != VSIGCOUNT; t0++)
X if (!strcmp(s,sigs[t0]))


X return t0;
X return -1;
X}
X

Xint bin_trap(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

XList l;
Xchar *arg;
X
X if (!*argv) {
X int t0;
X
X for (t0 = 0; t0 != VSIGCOUNT; t0++)
X if (sigtrapped[t0])
X if (!sigfuncs[t0])
X printf("TRAP%s () {}\n",sigs[t0]);
X else {
X char *s = getpermtext((vptr) sigfuncs[t0]);
X printf("TRAP%s () {\n\t%s\n}\n",sigs[t0],s);
X free(s);


X }
X return 0;
X }

X if (!strcmp(*argv,"-")) {
X int t0;
X
X argv++;
X if (!*argv)
X for (t0 = 0; t0 != VSIGCOUNT; t0++) unsettrap(t0);
X else
X while (*argv) unsettrap(getsignum(*argv++));
X return 0;
X }
X arg = *argv++;
X if (!*arg) l = NULL;
X else if (!(l = parselstring(arg))) {
X zerrnam(name,"couldn't parse trap command",NULL,0);
X popheap();
X return 1;
X }
X for (; *argv; argv++) {
X int sg = getsignum(*argv);
X if (sg == -1) {
X zerrnam(name,"undefined signal: %s",*argv,0);
X break;
X }
X settrap(sg,l);
X }
X if (l) popheap();
X return errflag;
X}
X
Xvoid printulimit(lim,hard) /**/
Xint lim;int hard;
X{
Xlong t0;
X
X#ifdef RLIM_INFINITY
X t0 = (hard) ? limits[lim].rlim_max : limits[lim].rlim_cur;
X switch (lim)
X {
X case RLIMIT_CPU: printf("cpu time (seconds) "); break;
X case RLIMIT_FSIZE: printf("file size (blocks) "); t0 /= 512; break;
X case RLIMIT_DATA: printf("data seg size (kbytes) "); t0 /= 1024; break;
X case RLIMIT_STACK: printf("stack size (kbytes) "); t0 /= 1024; break;
X case RLIMIT_CORE: printf("core file size (blocks) "); t0 /= 512; break;
X#ifdef RLIMIT_RSS
X case RLIMIT_RSS: printf("resident set size (kbytes) "); t0 /= 1024; break;
X#endif
X#ifdef RLIMIT_NOFILE
X case RLIMIT_NOFILE: printf("file descriptors "); break;
X#endif
X }
X printf("%ld\n",t0);
X#endif
X}
X
Xint bin_ulimit(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

Xint res,hard;
X
X#ifndef RLIM_INFINITY
X zerrnam(name,"not available on this system",NULL,0);
X return 1;
X#else
X hard = ops['H'];
X if (ops['a'] || !ops['@'])
X res = -1;
X else if (ops['t'])
X res = RLIMIT_CPU;
X else if (ops['f'])
X res = RLIMIT_FSIZE;
X else if (ops['d'])
X res = RLIMIT_DATA;
X else if (ops['s'])
X res = RLIMIT_STACK;
X else if (ops['c'])
X res = RLIMIT_CORE;
X#ifdef RLIMIT_RSS
X else if (ops['m'])
X res = RLIMIT_RSS;
X#endif
X#ifdef RLIMIT_NOFILE
X else if (ops['n'])
X res = RLIMIT_NOFILE;
X#endif
X else
X {
X zerrnam(name,"no such limit",NULL,0);
X return 1;
X }
X if (res == -1)
X if (*argv)
X {
X zerrnam(name,"no arguments required after -a",NULL,0);


X return 1;
X }
X else
X {

X int t0;
X


X for (t0 = 0; t0 != RLIM_NLIMITS; t0++)

X printulimit(t0,hard);


X return 0;
X }
X if (!*argv)

X printulimit(res,hard);
X else if (strcmp(*argv,"unlimited"))
X {
X long t0;
X
X t0 = atol(*argv);
X switch(res)
X {
X case RLIMIT_FSIZE: case RLIMIT_CORE: t0 *= 512; break;
X case RLIMIT_DATA: case RLIMIT_STACK:
X#ifdef RLIMIT_RSS
X case RLIMIT_RSS:
X#endif
X t0 *= 1024; break;
X }
X if (hard)
X {
X if (t0 > limits[res].rlim_max && geteuid())
X {
X zerrnam(name,"can't raise hard limits",NULL,0);
X return 1;
X }
X limits[res].rlim_max = t0;
X }
X else
X {
X if (t0 > limits[res].rlim_max)
X {
X if (geteuid())
X {
X zerrnam(name,"value exceeds hard limit",NULL,0);
X return 1;
X }
X limits[res].rlim_max = limits[res].rlim_cur = t0;
X }
X else
X limits[res].rlim_cur = t0;


X }
X }
X else
X {

X if (hard)
X {
X if (geteuid())
X {
X zerrnam(name,"can't remove hard limits",NULL,0);
X return 1;
X }
X limits[res].rlim_max = RLIM_INFINITY;
X }
X else
X limits[res].rlim_cur = limits[res].rlim_max;


X }
X return 0;
X#endif
X}
X

Xint putraw(c) /**/
Xint c;
X{
X putchar(c);


X return 0;
X}
X

Xint bin_echotc(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

Xchar *s,buf[2048],*t,*u;
Xint num,argct,t0;
X
X s = *argv++;
X if (!termok)
X return 1;
X if ((num = tgetnum(s)) != -1)
X {
X printf("%d\n",num);
X return 0;
X }
X u = buf;
X t = tgetstr(s,&u);
X if (!t || !*t)
X {
X zerrnam(name,"no such capability: %s",s,0);
X return 1;
X }
X for (argct = 0, u = t; *u; u++)
X if (*u == '%')
X {
X if (u++, (*u == 'd' || *u == '2' || *u == '3' || *u == '.' ||
X *u == '+'))
X argct++;
X }
X if (arrlen(argv) != argct)
X {
X zerrnam(name,(arrlen(argv) < argct) ? "not enough arguments" :
X "too many arguments",NULL,0);
X return 1;
X }
X if (!argct)
X tputs(t,1,putraw);
X else
X {
X t0 = (argv[1]) ? atoi(argv[1]) : atoi(*argv);
X tputs(tgoto(t,atoi(*argv),t0),t0,putraw);


X }
X return 0;
X}
X

Xint bin_pwd(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

X printf("%s\n",pwd);


X return 0;
X}
X

X#define TEST_END 0
X#define TEST_INPAR 1
X#define TEST_OUTPAR 2
X#define TEST_STR 3
X#define TEST_AND 4
X#define TEST_OR 5
X#define TEST_NOT 6
X
Xstatic char **tsp;
Xstatic int *tip;
X
Xint bin_test(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

Xchar **s;
Xint cnt,*arr,*ap;
XCond c;
X
X if (func == BIN_BRACKET)
X {
X for (s = argv; *s; s++);
X if (s == argv || strcmp(s[-1],"]"))
X {
X zerrnam(name,"']' expected",NULL,0);
X return 1;
X }
X s[-1] = NULL;
X }
X for (s = argv, cnt = 0; *s; s++,cnt++);
X ap = arr = alloc((cnt+1)*sizeof *arr);
X for (s = argv; *s; s++,ap++)
X if (!strcmp(*s,"("))
X *ap = TEST_INPAR;
X else if (!strcmp(*s,")"))
X *ap = TEST_OUTPAR;
X else if (!strcmp(*s,"-a"))
X *ap = TEST_AND;
X else if (!strcmp(*s,"-o"))
X *ap = TEST_OR;
X else if (!strcmp(*s,"!"))
X *ap = TEST_NOT;
X else
X *ap = TEST_STR;
X *ap = TEST_END;
X tsp = argv;
X tip = arr;
X c = partest(0);
X if (*tip != TEST_END || errflag)
X {
X zerrnam(name,"parse error",NULL,0);
X return 1;
X }
X return (c) ? !evalcond(c) : 1;
X}
X
XCond partest(level) /**/
Xint level;
X{
XCond a,b;
X
X switch (level)
X {
X case 0:
X a = partest(1);
X if (*tip == TEST_OR)
X {
X tip++,tsp++;
X b = makecond();
X b->left = a;
X b->right = partest(0);
X b->type = COND_OR;
X return b;
X }
X return a;
X case 1:
X a = partest(2);
X if (*tip == TEST_AND)
X {
X tip++,tsp++;
X b = makecond();
X b->left = a;
X b->right = partest(1);
X b->type = COND_AND;
X return b;
X }
X return a;
X case 2:
X if (*tip == TEST_NOT)
X {
X tip++,tsp++;
X b = makecond();
X b->left = partest(2);
X b->type = COND_NOT;
X return b;
X }
X case 3:
X if (*tip == TEST_INPAR)
X {
X tip++,tsp++;
X b = partest(0);
X if (*tip != TEST_OUTPAR)
X {
X zerrnam("test","parse error",NULL,0);
X return NULL;
X }
X tip++,tsp++;
X return b;
X }
X if (tip[0] != TEST_STR)
X {
X zerrnam("test","parse error",NULL,0);
X return NULL;
X }
X else if (tip[1] != TEST_STR)
X {
X b = makecond();
X if (!strcmp(*tsp,"-t"))
X {
X b->left = strdup("1");
X b->type = 't';
X }
X else
X {
X b->left = tsp[0];
X b->type = 'n';
X }
X tip++,tsp++;
X return b;
X }
X else if (tip[2] != TEST_STR)
X {
X b = par_cond_double(tsp[0],tsp[1]);
X tip += 2,tsp += 2;
X return b;
X }
X else
X {
X b = par_cond_triple(tsp[0],tsp[1],tsp[2]);
X tip += 3,tsp += 3;
X return b;
X }
X }


X return NULL;
X}
X

Xint bin_compctl(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

Xint flags = 0;
XCompctl cc = NULL;
Xchar *usrkeys = NULL;
X
X for (; *argv && **argv == '-'; argv++)
X while (*++(*argv)) switch(**argv) {
X case 'c': flags |= CC_COMMPATH; break;
X case 'f': flags |= CC_FILES; break;
X case 'h': flags |= CC_HOSTS; break;
X case 'o': flags |= CC_OPTIONS; break;
X case 'v': flags |= CC_VARS; break;
X case 'b': flags |= CC_BINDINGS; break;
X case 'k':
X flags |= CC_USRKEYS;
X if ((*argv)[1]) { usrkeys = (*argv)+1; *argv = ""-1; }


X else if (!argv[1]) {

X zerrnam(name,"variable name expected after -k",NULL,0);
X return 1;
X } else { usrkeys = *++argv; *argv = ""-1; }
X break;
X case 'C': cc = &cc_compos; break;
X case 'D': cc = &cc_default; break;
X default: zerrnam(name,"bad option: %c",NULL,**argv); return 1;
X }
X if (cc) {
X cc->mask = flags;
X if (cc->keyvar) free(cc->keyvar);
X cc->keyvar = ztrdup(usrkeys);
X }
X if (!*argv) {
X if (!cc) {
X showflag = flags;
X listhtable(compctltab,(HFunc) printcompctl);
X printcompctl("COMMAND",&cc_compos);
X printcompctl("DEFAULT",&cc_default);


X }
X return 0;
X }

X compctl_process(argv,flags,usrkeys);


X return 0;
X}
X

Xvoid printcompctl(s,cc) /**/
Xchar *s;Compctl cc;
X{
Xchar *css = "fchovb";
X
X if (cc->mask & showflag) {
X puts(s);
X } else if (!showflag) {
X int flags = cc->mask;
X printf("%s -",s);
X while (*css) {
X if (flags & 1) putchar(*css);
X css++; flags >>= 1;
X }
X if (flags & 1) printf("k %s",cc->keyvar);


X putchar('\n');
X }
X}
X

Xvoid compctl_process(s,mask,uk) /**/
Xchar **s;int mask;char *uk;
X{
XCompctl cc;


X
X for (;*s;s++) {

X cc = zalloc(sizeof *cc);
X cc->mask = mask; cc->keyvar = ztrdup(uk);
X addhnode(ztrdup(*s),cc,compctltab,freecompctl);
X }
X}
X
Xint bin_ttyctl(name,argv,ops,func) /**/


Xchar *name;char **argv;char *ops;int func;
X{

X if (ops['f'] || !ops['@']) ttyfrozen = 1;
X else if (ops['u']) ttyfrozen = 0;


X return 0;
X}
X

SHAR_EOF
echo 'File zsh2.2/src/builtin.c is complete' &&
chmod 0644 zsh2.2/src/builtin.c ||


echo 'restore of zsh2.2/src/builtin.c failed'

Wc_c="`wc -c < 'zsh2.2/src/builtin.c'`"
test 61945 -eq "$Wc_c" ||
echo 'zsh2.2/src/builtin.c: original size 61945, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/src/cond.c ==============
if test -f 'zsh2.2/src/cond.c' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/src/cond.c (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/src/cond.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/src/cond.c' &&
X/*
X *
X * cond.c - evaluate conditional expressions


X *
X * This file is part of zsh, the Z shell.
X *
X * This software is Copyright 1992 by Paul Falstad
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made.
X *
X * The author make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk.
X *
X */
X
X#include "zsh.h"
X

Xint evalcond(c) /**/
XCond c;
X{
Xstruct stat *st;
X
X switch (c->type)
X {
X case COND_NOT: return !evalcond(c->left);
X case COND_AND: return evalcond(c->left) && evalcond(c->right);
X case COND_OR: return evalcond(c->left) || evalcond(c->right);
X }
X singsub((char **) &c->left);
X untokenize(c->left);
X if (c->right)
X {
X singsub((char **) &c->right);
X if (c->type != COND_STREQ && c->type != COND_STRNEQ)
X untokenize(c->right);
X }
X switch (c->type)
X {
X case COND_STREQ: return matchpat(c->left,c->right);
X case COND_STRNEQ: return !matchpat(c->left,c->right);
X case COND_STRLT: return strcmp(c->left,c->right) < 0;
X case COND_STRGTR: return strcmp(c->left,c->right) > 0;
X case 'e': case 'a': return(doaccess(c->left,F_OK));
X case 'b': return(S_ISBLK(dostat(c->left)));
X case 'c': return(S_ISCHR(dostat(c->left)));
X case 'd': return(S_ISDIR(dostat(c->left)));
X case 'f': return(S_ISREG(dostat(c->left)));
X case 'g': return(!!(dostat(c->left) & S_ISGID));
X case 'k': return(!!(dostat(c->left) & S_ISVTX));
X case 'n': return(!!strlen(c->left));
X case 'o': return(optison(c->left));
X case 'p': return(S_ISFIFO(dostat(c->left)));
X case 'r': return(doaccess(c->left,R_OK));
X case 's': return((st = getstat(c->left)) && !!(st->st_size));
X case 'S': return(S_ISSOCK(dostat(c->left)));
X case 'u': return(!!(dostat(c->left) & S_ISUID));
X case 'w': return(doaccess(c->left,W_OK));
X case 'x': return(doaccess(c->left,X_OK));
X case 'z': return(!strlen(c->left));
X case 'h': case 'L': return(S_ISLNK(dolstat(c->left)));
X case 'O': return((st = getstat(c->left)) && st->st_uid == geteuid());
X case 'G': return((st = getstat(c->left)) && st->st_gid == getegid());
X case 't': return isatty(matheval(c->left));
X case COND_EQ: return matheval(c->left) == matheval(c->right);
X case COND_NE: return matheval(c->left) != matheval(c->right);
X case COND_LT: return matheval(c->left) < matheval(c->right);
X case COND_GT: return matheval(c->left) > matheval(c->right);
X case COND_LE: return matheval(c->left) <= matheval(c->right);
X case COND_GE: return matheval(c->left) >= matheval(c->right);
X case COND_NT: case COND_OT:
X {
X time_t a;
X if (!(st = getstat(c->left)))
X return 0;
X a = st->st_mtime;
X if (!(st = getstat(c->right)))
X return 0;
X return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
X }
X case COND_EF:
X {
X dev_t d;
X ino_t i;
X
X if (!(st = getstat(c->left)))
X return 0;
X d = st->st_dev;
X i = st->st_ino;
X if (!(st = getstat(c->right)))
X return 0;
X return d == st->st_dev && i == st->st_ino;
X }
X default: zerr("bad cond structure",NULL,0);


X }
X return 0;
X}
X

Xint doaccess(s,c) /**/
Xchar *s;int c;
X{
X return !access(s,c);
X}
X
Xstatic struct stat st;
X
Xstruct stat *getstat(s) /**/
Xchar *s;
X{
X if (!strncmp(s,"/dev/fd/",8))
X {
X if (fstat(atoi(s+8),&st))
X return NULL;
X }
X else if (stat(s,&st))
X return NULL;
X return &st;
X}
X
Xunsigned short dostat(s) /**/
Xchar *s;
X{
Xstruct stat *st;
X
X if (!(st = getstat(s)))
X return 0;
X return st->st_mode;
X}
X
X/* p...@aaii.oz; needed since dostat now uses "stat" */
X
Xunsigned short dolstat(s) /**/
Xchar *s;
X{
X if (lstat(s, &st) < 0)
X return 0;
X return st.st_mode;
X}
X
Xint optison(s) /**/
Xchar *s;
X{
Xint i;
X
X if (strlen(s) == 1)
X return opts[*s];
X if ((i = optlookup(s)) != -1)
X return opts[i];
X zerr("no such option: %s",s,0);


X return 0;
X}
X

SHAR_EOF
chmod 0644 zsh2.2/src/cond.c ||
echo 'restore of zsh2.2/src/cond.c failed'
Wc_c="`wc -c < 'zsh2.2/src/cond.c'`"
test 4064 -eq "$Wc_c" ||
echo 'zsh2.2/src/cond.c: original size 4064, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/src/exec.c ==============
if test -f 'zsh2.2/src/exec.c' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/src/exec.c (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/src/exec.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/src/exec.c' &&
X/*
X *
X * exec.c - command execution


X *
X * This file is part of zsh, the Z shell.
X *
X * This software is Copyright 1992 by Paul Falstad
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made.
X *
X * The author make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk.
X *
X */
X
X#include "zsh.h"
X#include <sys/errno.h>

X#ifdef __hpux
X#include <ndir.h>
X#else
X#include <sys/dir.h>
X#endif
X
X#define execerr() { if (forked) exit(1); \
X closemnodes(mfds); errflag = 1; return; }
X
Xstatic Lklist args;
Xstatic Cmdnam cn;
X
X/* parse list in a string */
X
XList parselstring(s) /**/
Xchar *s;
X{
XList l;
X
X hungets(s);
X strinbeg();
X pushheap();
X if (!(l = parse_list())) {
X strinend();
X hflush();
X popheap();
X return NULL;
X }
X strinend();
X return l;
X}
X
X/* execute a string */
X
Xvoid execstring(s) /**/
Xchar *s;
X{
XList l;
X
X if (l = parselstring(s)) {
X execlist(l);
X popheap();
X }
X}
X
X/* fork and set limits */
X
Xint phork() /**/
X{
Xint pid,t0;
X
X if (thisjob >= MAXJOB-1) {
X zerr("job table full",NULL,0);
X return -1;
X }
X pid = fork();
X if (pid == -1) {
X zerr("fork failed: %e",NULL,errno);
X return -1;
X }
X#ifdef RLIM_INFINITY
X if (!pid)


X for (t0 = 0; t0 != RLIM_NLIMITS; t0++)

X setrlimit(t0,limits+t0);
X#endif
X return pid;
X}
X
X/* execute a current shell command */
X
Xint execcursh(cmd) /**/
XCmd cmd;
X{
X runlist(cmd->u.list);
X cmd->u.list = NULL;


X return lastval;
X}
X

X/* execve after handling $_ and #! */
X
X#define POUNDBANGLIMIT 64
X
Xint zexecve(pth,argv) /**/
Xchar *pth;char **argv;
X{
Xint eno;
Xstatic char buf[MAXPATHLEN*2];
Xchar **eep;
X
X for (eep = environ; *eep; eep++)
X if (**eep == '_' && (*eep)[1] == '=') break;
X buf[0] = '_';
X buf[1] = '=';
X if (*pth == '/') strcpy(buf+2,pth);
X else sprintf(buf+2,"%s/%s",pwd,pth);
X if (!*eep) eep[1] = NULL;
X *eep = buf;
X execve(pth,argv,environ);
X if ((eno = errno) == ENOEXEC) {
X char buf[POUNDBANGLIMIT+1],*ptr,*ptr2,*argv0;
X int fd,ct,t0;
X
X if ((fd = open(pth,O_RDONLY)) >= 0) {
X argv0 = *argv;
X *argv = pth;
X ct = read(fd,buf,POUNDBANGLIMIT);
X close(fd);
X if (ct > 0) {
X if (buf[0] == '#')
X if (buf[1] == '!') {
X for (t0 = 0; t0 != ct; t0++)
X if (buf[t0] == '\n')
X buf[t0] = '\0';
X buf[POUNDBANGLIMIT] = '\0';
X for (ptr = buf+2; *ptr && *ptr == ' '; ptr++);
X for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++);
X if (*ptr) {
X *ptr = '\0';
X argv[-2] = ptr2;
X argv[-1] = ptr+1;
X execve(ptr2,argv-2,environ);
X } else {
X argv[-1] = ptr2;
X execve(ptr2,argv-1,environ);
X }
X } else {
X argv[-1] = "sh";
X execve("/bin/sh",argv-1,environ);
X }
X else {
X for (t0 = 0; t0 != ct; t0++)
X if (!buf[t0]) break;
X if (t0 == ct) {
X argv[-1] = "sh";
X execve("/bin/sh",argv-1,environ);
X }
X }
X } else eno = errno;
X *argv = argv0;
X } else eno = errno;
X }
X return eno;
X}
X
X#define MAXCMDLEN (MAXPATHLEN*4)
X
X/* execute an external command */
X
Xvoid execute(dash) /**/
Xint dash;
X{
Xchar **argv,*arg0,**pp;
Xchar *z,*s,buf[MAXCMDLEN],buf2[MAXCMDLEN];
Xint ee = 0,eno = 0;
X
X if (!full(args)) {
X zerr("no command",NULL,0);
X _exit(1);
X }
X cn = (Cmdnam) gethnode(peekfirst(args),cmdnamtab);
X if (cn && cn->type == DISABLED)
X cn = NULL;
X if (s = zgetenv("STTY"))
X zyztem("stty",s);
X arg0 = peekfirst(args);
X if (z = zgetenv("ARGV0")) {
X setdata(firstnode(args),ztrdup(z));
X delenv(z-6);
X } else if (dash) {
X sprintf(buf2,"-%s",arg0);
X setdata(firstnode(args),ztrdup(buf2));
X }
X argv = makecline(args);
X fixsigs();
X if (strlen(arg0) > MAXPATHLEN) {
X zerr("command too long: %s",arg0,0);
X _exit(1);
X }
X for (s = arg0; *s; s++)
X if (*s == '/') {
X errno = zexecve(arg0,argv);
X if (arg0 == s || unset(PATHDIRS)) {
X zerr("%e: %s",arg0,errno);
X _exit(1);
X }
X break;
X }
X if (cn && ISEXCMD(cn->type)) {
X for (pp = path; pp < cn->pcomp; pp++)
X if (**pp == '.' && (*pp)[1] == '\0') {
X ee = zexecve(arg0,argv);
X if (ee != ENOENT) eno = ee;
X } else if (**pp != '/') {


X z = buf;
X strucpy(&z,*pp);
X *z++ = '/';

X strcpy(z,arg0);
X ee = zexecve(buf,argv);
X if (ee != ENOENT) eno = ee;
X }
X ee = zexecve(cn->u.nam,argv);
X if (ee != ENOENT) eno = ee;
X }
X for (pp = path; *pp; pp++)
X if ((*pp)[0] == '.' && !(*pp)[1]) {
X ee = zexecve(arg0,argv);
X if (ee != ENOENT) eno = ee;
X } else {


X z = buf;
X strucpy(&z,*pp);
X *z++ = '/';

X strcpy(z,arg0);
X ee = zexecve(buf,argv);
X if (ee != ENOENT) eno = ee;
X }
X if (eno) zerr("%e: %s",arg0,eno);
X else zerr("command not found: %s",arg0,0);
X _exit(1);
X}
X
X#define try(X) { if (iscom(X)) return ztrdup(X); }
X
X/* get the full pathname of an external command */
X
Xchar *findcmd(arg0) /**/
Xchar *arg0;
X{
Xchar **pp;
Xchar *z,*s,buf[MAXCMDLEN];
X
X cn = (Cmdnam) gethnode(arg0,cmdnamtab);
X if (!cn && isset(HASHCMDS)) hashcmd(arg0,path);
X if (cn && cn->type == DISABLED) cn = NULL;
X if (strlen(arg0) > MAXPATHLEN) return NULL;
X for (s = arg0; *s; s++)
X if (*s == '/') {
X try(arg0);
X if (arg0 == s || unset(PATHDIRS)) {
X return NULL;
X }
X break;
X }
X if (cn && ISEXCMD(cn->type)) {
X for (pp = path; pp < cn->pcomp; pp++)
X if (**pp != '/') {


X z = buf;
X strucpy(&z,*pp);
X *z++ = '/';

X strcpy(z,arg0);
X try(buf);
X }
X try(cn->u.nam);
X }


X for (pp = path; *pp; pp++) {
X z = buf;
X strucpy(&z,*pp);
X *z++ = '/';

X strcpy(z,arg0);
X try(buf);
X }


X return NULL;
X}
X

Xint iscom(s) /**/
Xchar *s;
X{
Xstruct stat statbuf;
X
X return (access(s,X_OK) == 0 && stat(s,&statbuf) >= 0 &&
X S_ISREG(statbuf.st_mode));
X}
X
Xint isrelative(s) /**/
Xchar *s;
X{
X if (*s != '/') return 1;


X for (; *s; s++)

X if (*s == '.' && s[-1] == '/' &&
X (s[1] == '/' || s[1] == '\0' ||
X (s[1] == '.' && (s[2] == '/' || s[2] == '\0')))) return 1;


X return 0;
X}
X

Xint hashcmd(arg0,pp) /**/
Xchar *arg0;char **pp;
X{
Xchar *s,buf[MAXPATHLEN];
Xchar **pq;
XDIR *dir;
Xstruct direct *de;
X
X for (; *pp; pp++)
X if (**pp == '/') {
X s = buf;
X strucpy(&s,*pp);
X *s++ = '/';
X strcpy(s,arg0);
X if (iscom(buf)) break;
X }
X if (!*pp || isrelative(*pp)) return 0;
X cn = (Cmdnam) zcalloc(sizeof *cn);
X cn->type = EXCMD;
X cn->pcomp = pp;
X cn->u.nam = ztrdup(buf);
X addhnode(ztrdup(arg0),cn,cmdnamtab,freecmdnam);
X if (unset(HASHDIRS)) return 1;
X for (pq = pathchecked; pq <= pp; pq++) {
X if (isrelative(*pq) || !(dir = opendir(*pq))) continue;
X readdir(dir); readdir(dir);
X while (de = readdir(dir)) addhcmdnode(de->d_name,pq);
X closedir(dir);
X }
X pathchecked = pp+1;


X return 1;
X}
X

Xvoid fullhash() /**/
X{
Xchar **pq;
XDIR *dir;
Xstruct direct *de;
X
X for (pq = pathchecked; *pq; pq++) {
X if (isrelative(*pq) || !(dir = opendir(*pq))) continue;
X readdir(dir); readdir(dir);
X while (de = readdir(dir)) addhcmdnode(de->d_name,pq);
X closedir(dir);
X }
X pathchecked = pq;
X}
X
Xvoid execlist(list) /**/
XList list;
X{
X if (breaks) return;
X if (!list) return;
X simplifyright(list);
X switch(list->type) {
X case SYNC:
X case ASYNC:
X execlist2(list->left,list->type,!list->right);
X if (sigtrapped[SIGDEBUG])
X dotrap(SIGDEBUG);
X if (sigtrapped[SIGERR] && lastval)
X dotrap(SIGERR);
X if (list->right && !retflag)
X execlist(list->right);


X break;
X }
X}
X

Xvoid execlist2(list,type,last1) /**/
XSublist list;int type;int last1;
X{
X if (!list) return;
X switch(list->type) {
X case END:
X execpline(list,type,last1);
X break;
X case ORNEXT:
X if (!execpline(list,SYNC,0)) execlist2(list->right,type,last1);
X else while (list = list->right)
X if (list->type == ANDNEXT) {
X execlist2(list->right,type,last1);
X return;
X }
X break;
X case ANDNEXT:
X if (execpline(list,SYNC,0)) execlist2(list->right,type,last1);
X else while (list = list->right)
X if (list->type == ORNEXT) {
X execlist2(list->right,type,last1);
X return;


X }
X break;
X }
X}
X

Xint execpline(l,how,last1) /**/
XSublist l;int how;int last1;
X{
Xint ipipe[2],opipe[2];
X
X if (!l) return 0;
X ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0;
X blockchld();
X if ((thisjob = getfreejob()) == -1)
X return 1;
X initjob();
X if (how == TIMED) {
X jobtab[thisjob].stat |= STAT_TIMED;
X how = SYNC;
X }
X if (l->flags & PFLAG_COPROC) {
X how = ASYNC;
X if (coprocin >= 0) {


X close(coprocin);
X close(coprocout);
X }

X mpipe(ipipe);
X mpipe(opipe);
X coprocin = ipipe[0];
X coprocout = opipe[1];
X }
X execpline2(l->left,how,opipe[0],ipipe[1],last1);
X if (how == ASYNC) {
X if (l->flags & PFLAG_COPROC) close(ipipe[1]);
X spawnjob();
X unblockchld();
X return 1;
X } else {
X waitjobs();
X unblockchld();
X if (l->flags & PFLAG_NOT) lastval = !lastval;
X return !lastval;
X }
X}
X
Xvoid execpline2(pline,how,input,output,last1) /**/
XPline pline;int how;int input;int output;int last1;
X{
Xint pid;
Xint pipes[2];
X
X if (breaks)
X return;
X if (!pline)
X return;
X if (pline->type == END) {
X execcmd(pline->left,input,output,how==ASYNC,last1);
X pline->left = NULL;
X } else {
X mpipe(pipes);
X if (pline->left->type >= CURSH && how == SYNC) {
X
X /* if we are doing "foo | bar" where foo is a current
X shell command, do foo in a subshell and do
X the rest of the pipeline in the current shell. */
X
X if (!(pid = fork())) {
X close(pipes[0]);
X entersubsh(how==ASYNC);
X exiting = 1;
X execcmd(pline->left,input,pipes[1],how==ASYNC,0);
X _exit(lastval);
X } else if (pid == -1)
X zerr("fork failed: %e",NULL,errno);
X else {
X char *text = getjobtext((vptr) pline->left);
X addproc(pid,text);
X }
X } else {
X /* otherwise just do the pipeline normally. */
X execcmd(pline->left,input,pipes[1],how==ASYNC,0);
X }
X pline->left = NULL;
X close(pipes[1]);
X if (pline->right) {
X execpline2(pline->right,how,pipes[0],output,last1);
X close(pipes[0]);
X }
X }
X}
X
X/* make the argv array */
X
Xchar **makecline(list) /**/
Xstruct lklist *list;


X{
Xint ct = 0;

XLknode node;
Xchar **argv,**ptr;
X
X if (isset(XTRACE)) {
X fprintf(stderr,"%s",(prompt4) ? prompt4 : "");
X for (node = firstnode(list); node; incnode(node),ct++);
X ptr = argv = 2+(char **) ncalloc((ct+4)*sizeof(char *));
X for (node = firstnode(list); node; incnode(node))
X if (*(char *) getdata(node)) {
X *ptr++ = getdata(node);
X untokenize(getdata(node));
X fputs(getdata(node),stderr);
X if (nextnode(node))
X fputc(' ',stderr);
X }
X *ptr = NULL;
X fputc('\n',stderr);
X fflush(stderr);
X return(argv);
X } else {
X for (node = firstnode(list); node; incnode(node),ct++);
X ptr = argv = 2+(char **) ncalloc((ct+4)*sizeof(char *));
X for (node = firstnode(list); node; incnode(node))
X if (*(char *) getdata(node)) {
X *ptr++ = getdata(node);
X untokenize(getdata(node));
X }
X *ptr = NULL;
X return(argv);
X }
X}
X
X/* untokenize the command line and remove null arguments */
X
Xvoid fixcline(l) /**/
XLklist l;
X{
XLknode node,next;
X
X for (node = firstnode(l); node; node = next) {
X next = nextnode(node);
X if (!*(char *) getdata(node)) uremnode(l,node);
X else untokenize(getdata(node));
X }
X}
X
Xvoid untokenize(s) /**/
Xchar *s;
X{


X for (; *s; s++)

X if (itok(*s))
X if (*s == Nularg) chuck(s--);
X else *s = ztokens[*s-Pound];
X}
X
X/* nonzero if we shouldn't clobber a file */
X
Xint dontclob(f) /**/
Xstruct redir *f;
X{
Xstruct stat buf;
X
X if (unset(NOCLOBBER) || f->type & 1) return 0;
X if (stat(f->name,&buf) == -1) return 1;
X return S_ISREG(buf.st_mode);
X}
X
X/* close an multio (success) */
X
Xvoid closemn(mfds,fd) /**/
Xstruct multio **mfds;int fd;
X{
X if (mfds[fd]) {
X if (mfds[fd]->ct > 1)
X if (mfds[fd]->rflag == 0)
X catproc(mfds[fd]);
X else
X teeproc(mfds[fd]);
X mfds[fd] = NULL;
X }
X}
X
X/* close all the mnodes (failure) */
X
Xvoid closemnodes(mfds) /**/
Xstruct multio **mfds;
X{
Xint t0,t1;
X
X for (t0 = 0; t0 != 10; t0++)
X if (mfds[t0]) {
X for (t1 = 0; t1 != mfds[t0]->ct; t1++)
X close(mfds[t0]->fds[t1]);
X mfds[t0] = NULL;
X }
X}
X
X/* add a fd to an multio */
X/* an multio is a list of fds associated with a certain fd.
X thus if you do "foo >bar >ble", the multio for fd 1 will have
X two fds, the result of open("bar",...), and the result of
X open("ble",....). */
X
Xvoid addfd(forked,save,mfds,fd1,fd2,rflag) /**/
Xint forked;int *save;struct multio **mfds;int fd1;int fd2;int rflag;
X{
Xint pipes[2];
X
X if (!mfds[fd1]) { /* starting a new multio */
X mfds[fd1] = (struct multio *) alloc(sizeof(struct multio));
X if (!forked && fd1 != fd2 && fd1 < 10)
X save[fd1] = movefd(fd1);
X redup(fd2,fd1);
X mfds[fd1]->ct = 1;
X mfds[fd1]->fds[0] = fd1;
X mfds[fd1]->rflag = rflag;
X } else {
X if (mfds[fd1]->rflag != rflag) {
X zerr("file mode mismatch on fd %d",NULL,fd1);
X return;
X }
X if (mfds[fd1]->ct == 1) { /* split the stream */
X mfds[fd1]->fds[0] = movefd(fd1);
X mfds[fd1]->fds[1] = movefd(fd2);
X mpipe(pipes);
X mfds[fd1]->pipe = pipes[1-rflag];
X redup(pipes[rflag],fd1);
X mfds[fd1]->ct = 2;
X } else /* add another fd to an already split stream */
X mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2);
X }
X}
X
Xvoid addvars(l,export) /**/
XLklist l;int export;
X{
Xstruct varasg *v;
XLklist vl;
X
X while (full(l)) {
X char **arr,**ptr;
X
X v = (struct varasg *) ugetnode(l);
X singsub(&v->name);
X if (errflag)
X return;
X untokenize(v->name);
X if (v->type == PMFLAG_s) {
X vl = newlist();
X addnode(vl,v->str);
X } else
X vl = v->arr;
X prefork(vl);
X if (errflag)
X return;
X postfork(vl,1);
X if (errflag)
X return;
X if (v->type == PMFLAG_s && (!full(vl) || !nextnode(firstnode(vl)))) {
X Param pm;
X char *val;
X
X if (!full(vl))
X pm = setsparam(v->name,val = ztrdup(""));
X else {
X untokenize(peekfirst(vl));
X pm = setsparam(v->name,val = ztrdup(ugetnode(vl)));
X }
X if (export && !(pm->flags & PMFLAG_x))
X addenv(v->name,val);
X continue;
X }
X ptr = arr = (char **) zalloc(sizeof(char **)*(countnodes(vl)+1));
X while (full(vl)) {
X char *pp;
X pp = ugetnode(vl);
X if (*pp) {
X *ptr = ztrdup(pp);
X untokenize(*ptr++);
X }
X }
X *ptr = NULL;
X setaparam(v->name,arr);
X }
X}
X
Xvoid execcmd(cmd,input,output,bkg,last1) /**/
XCmd cmd;int input;int output;int bkg;int last1;
X{
Xint type;
Xlong pid = 0;
Xint save[10],t0;
Xstruct redir *fn;
Xstruct multio *mfds[10];
Xint fil,forked = 0,iscursh = 0,nullexec = 0;
Xchar *text;
X
X args = cmd->args;
X cn = NULL;
X for (t0 = 0; t0 != 10; t0++) {
X save[t0] = 0;
X mfds[t0] = NULL;
X }
X if ((type = cmd->type) == SIMPLE && !full(args))
X if (full(cmd->redir))
X if (cmd->flags & CFLAG_EXEC) {
X nullexec = 1;
X } else if (!*nullcmd) {
X zerr("redirection with no command",NULL,0);
X errflag = lastval = 1;
X return;
X } else if (*readnullcmd &&
X ((Redir)peekfirst(cmd->redir))->type == READ &&
X !nextnode(firstnode(cmd->redir))) {
X addnode(args,strdup(readnullcmd));
X } else
X addnode(args,strdup(nullcmd));
X else {
X addvars(cmd->vars,0);
X return;
X }
X if (full(args) && *(char *) peekfirst(args) == '%') {
X insnode(args,(Lknode) args,strdup((bkg) ? "bg" : "fg"));
X bkg = 0;
X }
X if (isset(AUTORESUME) && !bkg && !full(cmd->redir) && full(args) &&
X !input && type == SIMPLE && !nextnode(firstnode(args))) {
X if (unset(NOTIFY)) scanjobs();
X if (findjobnam(peekfirst(args)) != -1)
X pushnode(args,strdup("fg"));
X }
X if (unset(RMSTARSILENT) && interact && isset(SHINSTDIN) &&
X type == SIMPLE && full(args) && nextnode(firstnode(args)) &&
X !strcmp(peekfirst(args),"rm")) {
X char *s = getdata(nextnode(firstnode(args)));
X int l = strlen(s);
X
X if (s[0] == Star && !s[1])
X checkrmall(pwd);
X else if (l > 2 && s[l-2] == '/' && s[l-1] == Star) {
X char t = s[l-2];
X s[l-2] = 0;
X checkrmall(s);
X s[l-2] = t;
X }
X }
X if (jobbing) { /* get the text associated with this command */
X char *s;
X s = text = getjobtext((vptr) cmd);
X } else text = NULL;
X prefork(args); /* do prefork substitutions */
X if (errflag) {
X lastval = 1;
X return;
X }
X if (full(args) && ((char*)peekfirst(args))[0] == Inbrack &&
X ((char*)peekfirst(args))[1] == '\0')
X ((char*)peekfirst(args))[0] = '[';
X if (type == SIMPLE && full(args) && !(cmd->flags & CFLAG_COMMAND)) {
X char *s,*t;
X cn = (Cmdnam) gethnode(t = s = peekfirst(args),cmdnamtab);
X if (!cn && isset(HASHCMDS) && strcmp(t,"..")) {
X while (*t && *t != '/') t++;
X if (!*t) hashcmd(s,pathchecked);
X }
X }
X if (type == SIMPLE && !cn && isset(AUTOCD) && isset(SHINSTDIN) &&
X full(args) && !full(cmd->redir) &&
X !nextnode(firstnode(args)) && cancd(peekfirst(args))) {
X pushnode(args,strdup("cd"));
X cn = (Cmdnam) gethnode("cd",cmdnamtab);
X }
X
X /* this is nonzero if cmd is a current shell procedure */
X
X iscursh = (type >= CURSH) || (type == SIMPLE && cn &&
X (cn->type == BUILTIN || cn->type == SHFUNC));
X
X /* if this command is backgrounded or (this is an external
X command and we are not exec'ing it) or this is a builtin
X with output piped somewhere, then fork. If this is the
X last stage in a subshell pipeline, don't fork, but make
X the rest of the function think we forked. */
X
X if (bkg || !(iscursh || (cmd->flags & CFLAG_EXEC)) ||
X (cn && (cn->type == BUILTIN || cn->type == SHFUNC) && output)) {
X int synch[2];
X
X pipe(synch);
X pid = (last1 && execok()) ? 0 : phork();
X if (pid == -1) {
X close(synch[0]);
X close(synch[1]);
X return;
X }
X if (pid) {
X close(synch[1]);
X read(synch[0],"foo",1);
X close(synch[0]);
X if (pid == -1)
X zerr("%e",NULL,errno);
X else {
X if (bkg) lastpid = pid;
X ( void ) addproc(pid,text);
X }
X return;
X }
X close(synch[0]);
X entersubsh(bkg);
X close(synch[1]);
X forked = 1;
X }
X if (bkg && isset(BGNICE))
X nice(5);
X
X /* perform postfork substitutions */
X postfork(args,!(cmd->flags & CFLAG_NOGLOB));
X if (errflag) {
X lastval = 1;
X goto err;
X } else {
X char *s;
X while (full(args) && (s = peekfirst(args)) && !*s) ugetnode(args);
X }
X
X if (input) /* add pipeline input/output to mnodes */
X addfd(forked,save,mfds,0,input,0);
X if (output)
X addfd(forked,save,mfds,1,output,1);
X spawnpipes(cmd->redir); /* do process substitutions */
X while (full(cmd->redir))
X if ((fn = (struct redir*) ugetnode(cmd->redir))->type == INPIPE) {
X if (fn->fd2 == -1)
X execerr();
X addfd(forked,save,mfds,fn->fd1,fn->fd2,0);
X } else if (fn->type == OUTPIPE) {
X if (fn->fd2 == -1)
X execerr();
X addfd(forked,save,mfds,fn->fd1,fn->fd2,1);
X } else {
X if (!(fn->type == HERESTR || fn->type == CLOSE || fn->type ==
X MERGE || fn->type == MERGEOUT))
X if (xpandredir(fn,cmd->redir))
X continue;
X if (errflag) execerr();
X if (fn->type == HERESTR) {
X fil = getherestr(fn);
X if (fil == -1) {
X if (errno != EINTR)
X zerr("%e",NULL,errno);
X execerr();
X }
X addfd(forked,save,mfds,fn->fd1,fil,0);
X } else if (fn->type == READ) {
X fil = open(fn->name,O_RDONLY);
X if (fil == -1) {
X if (errno != EINTR)
X zerr("%e: %s",fn->name,errno);
X execerr();
X }
X addfd(forked,save,mfds,fn->fd1,fil,0);
X } else if (fn->type == CLOSE) {
X if (!forked && fn->fd1 < 10)
X save[fn->fd1] = movefd(fn->fd1);
X closemn(mfds,fn->fd1);
X close(fn->fd1);
X } else if (fn->type == MERGE || fn->type == MERGEOUT) {
X if (fn->fd2 == FD_COPROC)
X fn->fd2 = (fn->type == MERGEOUT) ? coprocout : coprocin;
X if (!forked && fn->fd1 < 10)
X save[fn->fd1] = movefd(fn->fd1);
X closemn(mfds,fn->fd1);
X fil = dup(fn->fd2);
X addfd(forked,save,mfds,fn->fd1,fil,fn->type == MERGEOUT);
X } else {
X if (fn->type >= APP)
X fil = open(fn->name,
X (isset(NOCLOBBER) && !(fn->type & 1)) ?
X O_WRONLY|O_APPEND : O_WRONLY|O_APPEND|O_CREAT,0666);
X else
X fil = open(fn->name,dontclob(fn) ?
X O_WRONLY|O_CREAT|O_EXCL : O_WRONLY|O_CREAT|O_TRUNC,0666);
X if (fil == -1) {
X if (errno != EINTR)
X zerr("%e: %s",fn->name,errno);
X execerr();
X }
X addfd(forked,save,mfds,fn->fd1,fil,1);
X }
X }
X
X /* we are done with redirection. close the mnodes, spawning
X tee/cat processes as necessary. */
X for (t0 = 0; t0 != 10; t0++)
X closemn(mfds,t0);
X
X if (nullexec)
X return;
X if (unset(NOEXEC))
X if (type >= CURSH)
X {
X static int (*func[]) DCLPROTO((Cmd)) = {
X execcursh,exectime,execfuncdef,execfor,execwhile,
X execrepeat,execif,execcase,execselect,execcond };
X
X fixcline(args);
X lastval = (func[type-CURSH])(cmd);
X }
X else if (iscursh) /* builtin or shell function */
X {
X if (cmd->vars)
X addvars(cmd->vars,0);
X fixcline(args);
X if (cn && cn->type == SHFUNC)
X execshfunc(cmd,cn);
X else
X {
X if (forked) closem();
X lastval = execbin(args,cn);
X if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
X lastval && !subsh) {
X fprintf(stderr,"zsh: exit %d\n",lastval);
X }
X fflush(stdout);
X if (ferror(stdout))
X {
X zerr("write error: %e",NULL,errno);
X clearerr(stdout);
X }


X }
X }
X else
X {

X if (cmd->vars)
X addvars(cmd->vars,1);
X if (type == SIMPLE)
X {
X closem();
X execute(cmd->flags & CFLAG_DASH);
X }
X else /* ( ... ) */
X execlist(cmd->u.list);
X }
Xerr:
X if (forked)
X _exit(lastval);
X fixfds(save);
X}
X
X/* restore fds after redirecting a builtin */
X
Xvoid fixfds(save) /**/
Xint *save;
X{
Xint t0;
X
X for (t0 = 0; t0 != 10; t0++)
X if (save[t0])
X redup(save[t0],t0);
X}
X
Xvoid entersubsh(bkg) /**/
Xint bkg;
X{
X if (!jobbing)
X {
X if (bkg && isatty(0))
X {
X close(0);
X if (open("/dev/null",O_RDWR))
X {
X zerr("can't open /dev/null: %e",NULL,errno);
X _exit(1);
X }
X }
X }
X else if (!jobtab[thisjob].gleader)
X {
X jobtab[thisjob].gleader = getpid();
X setpgrp(0L,jobtab[thisjob].gleader);
X if (!bkg)
X attachtty(jobtab[thisjob].gleader);
X }
X else
X setpgrp(0L,jobtab[thisjob].gleader);
X subsh = 1;
X if (SHTTY != -1)
X {
X close(SHTTY);
X SHTTY = -1;
X }
X if (jobbing)
X {
X signal(SIGTTOU,SIG_DFL);
X signal(SIGTTIN,SIG_DFL);
X signal(SIGTSTP,SIG_DFL);
X signal(SIGPIPE,SIG_DFL);
X }
X if (interact)
X {
X signal(SIGTERM,SIG_DFL);
X if (sigtrapped[SIGINT])
X signal(SIGINT,SIG_IGN);
X }
X if (!sigtrapped[SIGQUIT])
X signal(SIGQUIT,SIG_DFL);
X opts[MONITOR] = OPT_UNSET;
X clearjobtab();
X}
X
X/* close all internal shell fds */
X
Xvoid closem() /**/
X{
Xint t0;
X
X for (t0 = 10; t0 != NOFILE; t0++)
X close(t0);
X}
X
X/* convert here document into a here string */
X
Xchar *gethere(str,typ) /**/
Xchar *str;int typ;
X{
Xchar pbuf[256];
Xint qt = 0,siz = 0,l,strip = 0;
Xchar *s,*t,*bptr;
X
X for (s = str; *s; s++)
X if (*s == Nularg)
X qt = 1;
X untokenize(str);
X if (typ == HEREDOCDASH)
X {
X strip = 1;
X while (*str == '\t')
X str++;
X }
X t = ztrdup("");
X for(;;)
X {
X char *u,*v;
X
X if (!hgets(pbuf,256))
X break;
X bptr = pbuf;
X if (strip)
X while (*bptr == '\t')
X bptr++;
X for (u = bptr, v = str; *u != '\n' && *v; u++,v++)
X if (*u != *v)
X break;
X if (!(*u == '\n' && !*v))
X {
X l = strlen(bptr);
X if (!qt && l > 1 && bptr[l-1] == '\n' && bptr[l-2] == '\\')
X bptr[l -= 2] = '\0';
X t = realloc(t,siz+l+1);
X strncpy(t+siz,bptr,l);
X siz += l;
X }


X else
X break;
X }

X t[siz] = '\0';
X if (siz && t[siz-1] == '\n')
X t[siz-1] = '\0';
X if (!qt)
X for (s = t; *s; s++)
X if (*s == '$') {
X *s = Qstring;


X } else if (*s == '`') {

X *s = Qtick;
X } else if (*s == '(') {
X *s = Inpar;
X } else if (*s == ')') {
X *s = Outpar;
X } else if (*s == '\\' &&
X (s[1] == '$' || s[1] == '`')) chuck(s);
X s = strdup(t);
X free(t);


X return s;
X}
X

X/* open here string fd */
X
Xint getherestr(fn) /**/
Xstruct redir *fn;
X{
XLklist fake;
Xchar *s = gettemp(),*t;
Xint fd;
X
X fake = newlist();
X addnode(fake,fn->name);
X prefork(fake);
X if (!errflag)
X postfork(fake,1);
X if (errflag)
X return -1;
X if ((fd = open(s,O_CREAT|O_WRONLY,0600)) == -1)
X return -1;
X while (t = ugetnode(fake))
X {
X untokenize(t);
X write(fd,t,strlen(t));
X if (full(fake))
X write(fd," ",1);
X }
X write(fd,"\n",1);
X close(fd);
X fd = open(s,O_RDONLY);
X unlink(s);
X return fd;
X}
X
Xvoid catproc(mn) /**/
Xstruct multio *mn;
X{
Xint len,t0;
Xchar *buf;
X
X if (phork())
X {
X for (t0 = 0; t0 != mn->ct; t0++)
X close(mn->fds[t0]);
X close(mn->pipe);
X return;
X }
X closeallelse(mn);
X buf = zalloc(4096);
X for (t0 = 0; t0 != mn->ct; t0++)
X while (len = read(mn->fds[t0],buf,4096))
X write(mn->pipe,buf,len);
X _exit(0);
X}
X
Xvoid teeproc(mn) /**/
Xstruct multio *mn;
X{
Xint len,t0;
Xchar *buf;
X
X if (phork())
X {
X for (t0 = 0; t0 != mn->ct; t0++)
X close(mn->fds[t0]);
X close(mn->pipe);
X return;
X }
X buf = zalloc(4096);
X closeallelse(mn);
X while ((len = read(mn->pipe,buf,4096)) > 0)
X for (t0 = 0; t0 != mn->ct; t0++)
X write(mn->fds[t0],buf,len);
X _exit(0);
X}
X
Xvoid closeallelse(mn) /**/
Xstruct multio *mn;
X{
Xint t0,t1;
X
X for (t0 = 0; t0 != NOFILE; t0++)
X if (mn->pipe != t0)
X {
X for (t1 = 0; t1 != mn->ct; t1++)
X if (mn->fds[t1] == t0)
X break;
X if (t1 == mn->ct)
X close(t0);
X }
X}
X
Xlong int zstrtol(s,t,base) /**/
Xchar *s;char **t;int base;


X{
Xint ret = 0;
X

X if (base <= 10)
X for (; *s >= '0' && *s < ('0'+base); s++)
X ret = ret*base+*s-'0';
X else
X for (; idigit(*s) || (*s >= 'a' && *s < ('a'+base-10))
X || (*s >= 'A' && *s < ('A'+base-10)); s++)
X ret = ret*base+(idigit(*s) ? (*s-'0') : (*s & 0x1f)+9);
X if (t)
X *t = (char *) s;


X return ret;
X}
X

X/* $(...) */
X
XLklist getoutput(cmd,qt) /**/
Xchar *cmd;int qt;
X{
XList list;
Xint pipes[2];
X
X if (*cmd == '<') {
X int stream;
X char *fi,*s,x;
X
X for (cmd++; *cmd == ' '; cmd++);
X for (s = cmd; *s && *s != ' '; s++)
X if (*s == '\\') s++;
X else if (*s == '$') *s = String;
X x = *s;
X *s = '\0';
X fi = strdup(cmd);
X *s = x;
X if (*fi == '~')
X *fi = Tilde;
X else if (*fi == '=')
X *fi = Equals;
X singsub(&fi);
X if (errflag)
X return NULL;
X stream = open(fi,O_RDONLY);
X if (stream == -1) {
X zerr("%e: %s",fi,errno);
X return NULL;
X }
X return readoutput(stream,qt);
X }
X if (!(list = parselstring(cmd)))
X return NULL;
X mpipe(pipes);
X if (phork())
X {
X popheap();
X close(pipes[1]);
X /* chldsuspend(); */
X return readoutput(pipes[0],qt);
X }
X subsh = 1;
X close(pipes[0]);
X redup(pipes[1],1);
X entersubsh(0);
X signal(SIGTSTP,SIG_IGN);
X exiting = 1;
X execlist(list);
X close(1);
X exit(0); return NULL;
X}
X
X/* read output of command substitution */
X
XLklist readoutput(in,qt) /**/
Xint in;int qt;
X{
XLklist ret;
Xchar *buf,*ptr;
Xint bsiz,c,cnt = 0;
XFILE *fin;
X
X fin = fdopen(in,"r");
X ret = newlist();
X ptr = buf = ncalloc(bsiz = 64);
X while ((c = fgetc(fin)) != EOF)
X if (!qt && isep(c)) {
X if (cnt) {
X *ptr = '\0';
X addnode(ret,buf);
X ptr = buf = ncalloc(bsiz = 64);
X cnt = 0;
SHAR_EOF
true || echo 'restore of zsh2.2/src/exec.c failed'
fi
echo 'End of zsh2.2 part 7'
echo 'File zsh2.2/src/exec.c is continued in part 8'
echo 8 > _shar_seq_.tmp

Paul Falstad

unread,
May 13, 1992, 12:02:40 PM5/13/92
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 29, Issue 104
Archive-name: zsh2.2/part08

Environment: BSD
Supersedes: zsh2.1: Volume 24, Issue 1-19

#!/bin/sh
# this is aa.08 (part 8 of zsh2.2)


# do not concatenate these parts, unpack them in order with /bin/sh

# file zsh2.2/src/exec.c continued


#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck

if test "$Scheck" != 8; then


echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then

echo 'x - still skipping zsh2.2/src/exec.c'
else
echo 'x - continuing file zsh2.2/src/exec.c'


sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.2/src/exec.c' &&

X ptr = buf;
X }
X } else {
X *ptr++ = c;
X if (++cnt == bsiz) {
X char *pp = ncalloc(bsiz *= 2);
X
X memcpy(pp,buf,cnt);
X ptr = (buf = pp)+cnt;
X }
X }
X if (ptr != buf && ptr[-1] == '\n')
X ptr[-1] = '\0';
X else
X *ptr = '\0';
X if (cnt) addnode(ret,buf);
X fclose(fin);


X return ret;
X}
X

X/* =(...) */
X
Xchar *getoutputfile(cmd) /**/
Xchar *cmd;
X{
X#ifdef WAITPID
Xint pid;
X#endif
Xchar *nam = gettemp(),*str;
Xint tfil;
XList list;
X
X if (thisjob == -1)
X return NULL;
X for (str = cmd; *str && *str != Outpar; str++);
X if (!*str)
X zerr("oops.",NULL,0);
X *str = '\0';


X if (!(list = parselstring(cmd)))
X return NULL;

X permalloc();
X if (!jobtab[thisjob].filelist)
X jobtab[thisjob].filelist = newlist();
X addnode(jobtab[thisjob].filelist,ztrdup(nam));
X heapalloc();
X#ifdef WAITPID
X if (pid = phork())
X {
X popheap();
X waitpid(pid,NULL,WUNTRACED);
X return nam;
X }
X#else
X if (waitfork()) {
X popheap();
X return nam;
X }
X#endif
X subsh = 1;
X close(1);
X entersubsh(0);
X tfil = creat(nam,0666);


X exiting = 1;
X execlist(list);
X close(1);
X exit(0); return NULL;
X}
X

X/* get a temporary named pipe */
X
Xchar *namedpipe() /**/
X{
X#ifndef NO_FIFOS
Xchar *tnam = gettemp();
X
X if (mknod(tnam,0010666,0) < 0) return NULL;
X return tnam;
X#else
X return NULL;
X#endif
X}
X
X/* <(...) */
X
Xchar *getoutproc(cmd) /**/
Xchar *cmd;
X{
X#ifdef NO_FIFOS
X zerr("doesn't look like your system supports FIFOs.",NULL,0);
X return NULL;
X#else
XList list;
Xint fd;
Xchar *pnam,*str;
X
X if (thisjob == -1)
X return NULL;
X for (str = cmd; *str && *str != Outpar; str++);
X if (!*str)
X zerr("oops.",NULL,0);
X *str = '\0';
X pnam = namedpipe();
X if (!pnam) return NULL;
X permalloc();
X if (!jobtab[thisjob].filelist)
X jobtab[thisjob].filelist = newlist();
X addnode(jobtab[thisjob].filelist,ztrdup(pnam));
X heapalloc();


X if (!(list = parselstring(cmd)))
X return NULL;

X if (phork())
X {
X popheap();

X return pnam;
X }
X entersubsh(1);
X closem();
X fd = open(pnam,O_WRONLY);
X if (fd == -1)
X {
X zerr("can't open %s: %e",pnam,errno);
X _exit(0);
X }
X redup(fd,1);
X fd = open("/dev/null",O_RDONLY);
X redup(fd,0);


X exiting = 1;
X execlist(list);
X close(1);

X _exit(0); return NULL;
X#endif
X}
X
X/* >(...) */
X
Xchar *getinproc(cmd) /**/
Xchar *cmd;
X{
X#ifdef NO_FIFOS
X zerr("doesn't look like your system supports FIFOs.",NULL,0);
X return NULL;
X#else
XList list;
Xint pid,fd;
Xchar *pnam,*str;
X
X if (thisjob == -1)
X return NULL;
X for (str = cmd; *str && *str != Outpar; str++);
X if (!*str)
X zerr("oops.",NULL,0);
X *str = '\0';
X pnam = namedpipe();
X if (!pnam) return NULL;
X permalloc();
X if (!jobtab[thisjob].filelist)
X jobtab[thisjob].filelist = newlist();
X addnode(jobtab[thisjob].filelist,ztrdup(pnam));
X heapalloc();


X if (!(list = parselstring(cmd)))
X return NULL;

X if (pid = phork())
X {
X popheap();
X return pnam;
X }
X entersubsh(1);
X closem();
X fd = open(pnam,O_RDONLY);
X redup(fd,0);


X exiting = 1;
X execlist(list);

X _exit(0); return NULL;
X#endif
X}
X
X/* > >(...) (does not use named pipes) */
X
Xint getinpipe(cmd) /**/
Xchar *cmd;


X{
XList list;
Xint pipes[2];

Xchar *str = cmd;
X
X for (str = cmd; *str && *str != Outpar; str++);
X if (!*str)
X zerr("oops.",NULL,0);
X *str = '\0';
X if (!(list = parselstring(cmd+2)))
X return -1;


X mpipe(pipes);
X if (phork())
X {
X popheap();
X close(pipes[1]);

X return pipes[0];
X }
X close(pipes[0]);
X closem();
X entersubsh(1);
X redup(pipes[1],1);


X exiting = 1;
X execlist(list);

X _exit(0); return 0;
X}
X
X/* < <(...) */
X
Xint getoutpipe(cmd) /**/
Xchar *cmd;


X{
XList list;
Xint pipes[2];

Xchar *str;
X
X for (str = cmd; *str && *str != Outpar; str++);
X if (!*str)
X zerr("oops.",NULL,0);
X *str = '\0';
X if (!(list = parselstring(cmd+2)))
X return -1;
X strinend();


X mpipe(pipes);
X if (phork())
X {
X popheap();

X close(pipes[0]);
X return pipes[1];
X }
X close(pipes[1]);
X closem();
X entersubsh(1);
X redup(pipes[0],0);


X exiting = 1;
X execlist(list);

X _exit(0); return 0;
X}
X
X/* run a list, saving the current job num */
X
Xvoid runlist(l) /**/
XList l;
X{
Xint cj = thisjob;
X
X execlist(l);
X thisjob = cj;
X}
X
Xchar *gettemp() /**/
X{
X return mktemp(dyncat(tmpprefix,"XXXXXX"));
X}
X
X/* my getwd; all the other ones I tried confused the SIGCHLD handler */
X
Xchar *zgetwd() /**/
X{
Xstatic char buf0[MAXPATHLEN];
Xchar buf3[MAXPATHLEN],*buf2 = buf0+1;
Xstruct stat sbuf;
Xstruct direct *de;
XDIR *dir;
Xino_t ino = -1;
Xdev_t dev = -1;
X
X holdintr();
X buf2[0] = '\0';
X buf0[0] = '/';
X for(;;)
X {
X if (stat(".",&sbuf) < 0)
X {
X chdir(buf0);
X noholdintr();
X return ztrdup(".");
X }
X ino = sbuf.st_ino;
X dev = sbuf.st_dev;
X if (stat("..",&sbuf) < 0)
X {
X chdir(buf0);
X noholdintr();
X return ztrdup(".");
X }
X if (sbuf.st_ino == ino && sbuf.st_dev == dev)
X {
X chdir(buf0);
X noholdintr();
X return ztrdup(buf0);
X }
X dir = opendir("..");
X if (!dir)
X {
X chdir(buf0);
X noholdintr();
X return ztrdup(".");
X }
X chdir("..");


X readdir(dir); readdir(dir);
X while (de = readdir(dir))

X if (de->d_ino == ino)
X {
X lstat(de->d_name,&sbuf);
X if (sbuf.st_dev == dev)
X goto match;
X }
X rewinddir(dir);


X readdir(dir); readdir(dir);
X while (de = readdir(dir))

X {
X lstat(de->d_name,&sbuf);
X if (sbuf.st_dev == dev)
X goto match;
X }
X noholdintr();
X closedir(dir);
X return ztrdup(".");
Xmatch:
X strcpy(buf3,de->d_name);
X if (*buf2)
X strcat(buf3,"/");
X strcat(buf3,buf2);
X strcpy(buf2,buf3);
X closedir(dir);
X }
X}
X
X/* open pipes with fds >= 10 */
X
Xvoid mpipe(pp) /**/
Xint *pp;
X{
X pipe(pp);
X pp[0] = movefd(pp[0]);
X pp[1] = movefd(pp[1]);
X}
X
X/* do process substitution with redirection */
X
Xvoid spawnpipes(l) /**/
XLklist l;
X{
XLknode n = firstnode(l);
XRedir f;
X
X for (; n; incnode(n))
X {
X f = (Redir) getdata(n);
X if (f->type == OUTPIPE)
X {
X char *str = f->name;
X f->fd2 = getoutpipe(str);
X }
X if (f->type == INPIPE)
X {
X char *str = f->name;
X f->fd2 = getinpipe(str);
X }
X }
X}
X
X/* perform time ... command */
X
Xint exectime(cmd) /**/
XCmd cmd;
X{
Xint jb = thisjob;
X
X if (!cmd->u.pline) { shelltime(); return 0; }
X execpline(cmd->u.pline,TIMED,0);
X thisjob = jb;


X return lastval;
X}
X

X/* define a function */
X
Xint execfuncdef(cmd) /**/
XCmd cmd;
X{
XCmdnam cc;
Xchar *s;
X
X permalloc();
X while (s = ugetnode(cmd->args))
X {
X cc = (Cmdnam) zalloc(sizeof *cc);


X cc->type = SHFUNC;

X cc->flags = 0;
X if (!cmd->u.list)
X cc->u.list = NULL;
X else
X cc->u.list = (List) dupstruct(cmd->u.list);
X addhnode(ztrdup(s),cc,cmdnamtab,freecmdnam);
X if (!strncmp(s,"TRAP",4))
X {
X int t0 = getsignum(s+4);
X
X if (t0 != -1)
X settrap(t0,cmd->u.list);
X }
X }
X heapalloc();


X return 0;
X}
X

X/* evaluate a [[ ... ]] */
X
Xint execcond(cmd) /**/
XCmd cmd;
X{
X return !evalcond(cmd->u.cond);
X}
X
Xvoid execshfunc(cmd,cn) /**/
XCmd cmd;Cmdnam cn;
X{
XList l;
X
X if (errflag) return;
X l = cn->u.list;
X if (!l) {
X char *nam;
X
X if (!(cn->flags & PMFLAG_u)) return;
X if (!(l = getfpfunc(nam = peekfirst(cmd->args)))) {
X zerr("function not found: %s",nam,0);


X lastval = 1;
X return;
X }

X cn->flags &= ~PMFLAG_u;
X permalloc();
X cn->u.list = (List) dupstruct(l);
X heapalloc();
X }
X doshfunc(l,cmd->args,cn->flags);
X}
X
Xvoid doshfuncnoval(list,args,flags) /**/
XList list; Lklist args; int flags;
X{
Xint val = lastval;
X
X doshfunc(list,args,flags);
X lastval = val;
X}
X
Xvoid doshfunc(list,args,flags) /**/
XList list; Lklist args; int flags;
X{
Xchar **tab,**x,*oargv0;
Xint oxtr = opts[XTRACE],opev = opts[PRINTEXITVALUE],xexittr;
XLklist olist;
Xchar *s;
XList xexitfn;
X
X xexittr = sigtrapped[SIGEXIT];
X xexitfn = sigfuncs[SIGEXIT];
X tab = pparams;
X oargv0 = argzero;
X zoptind = 1;
X if (flags & PMFLAG_t) opts[XTRACE] = OPT_SET;
X opts[PRINTEXITVALUE] = OPT_UNSET;
X if (args) {
X pparams = x = (char **) zcalloc(((sizeof *x)*(1+countnodes(args))));
X argzero = ztrdup(ugetnode(args));
X while (*x = ugetnode(args))
X *x = ztrdup(*x), x++;
X } else {
X pparams = zcalloc(sizeof *pparams);
X argzero = ztrdup(argzero);
X }
X permalloc();
X olist = locallist;
X locallist = newlist();
X heapalloc();
X runlist(dupstruct(list));
X while (s = getnode(locallist)) unsetparam(s);
X free(locallist);
X locallist = olist;
X retflag = 0;
X freearray(pparams);
X free(argzero);
X argzero = oargv0;
X pparams = tab;
X if (sigfuncs[SIGEXIT] && sigfuncs[SIGEXIT] != xexitfn) {
X dotrap(SIGEXIT);
X freestruct(sigfuncs[SIGEXIT]);
X }
X sigtrapped[SIGEXIT] = xexittr;
X sigfuncs[SIGEXIT] = xexitfn;
X opts[XTRACE] = oxtr;
X opts[PRINTEXITVALUE] = opev;
X}
X
X/* search fpath for an undefined function */
X
XList getfpfunc(s) /**/
Xchar *s;
X{
Xchar **pp = fpath,buf[MAXPATHLEN];
Xint fd;


X
X for (; *pp; pp++)

X {
X sprintf(buf,"%s/%s",*pp,s);
X if (!access(buf,R_OK) && (fd = open(buf,O_RDONLY)) != -1)
X {
X int len = lseek(fd,0,2);
X
X if (len == -1)
X close(fd);
X else
X {
X char *d;
X
X lseek(fd,0,0);
X d = zcalloc(len+1);
X if (read(fd,d,len) != len)
X {
X free(d);
X close(fd);
X }
X else
X {
X close(fd);
X return parselstring(d);
X }
X }
X }
X }
X return NULL;
X}
X
X/* check to see if AUTOCD applies here */
X
Xint cancd(s)


Xchar *s;
X{
Xchar *t;
X

X if ((t = getsparam(s)) && *t == '/') return 1;


X if (*s != '/')

X {
X char sbuf[MAXPATHLEN],**cp;
X
X if (cancd2(s))
X return 1;
X if (access(s,X_OK) == 0)
X return 0;
X for (cp = cdpath; *cp; cp++)
X {
X sprintf(sbuf,"%s/%s",*cp,s);
X if (cancd2(sbuf))
X return 1;
X }
X return 0;
X }
X return cancd2(s);
X}
X
Xint cancd2(s)
Xchar *s;
X{
Xstruct stat buf;
X
X return !(access(s,X_OK) || stat(s,&buf) || !S_ISDIR(buf.st_mode));
X}
X
SHAR_EOF
echo 'File zsh2.2/src/exec.c is complete' &&
chmod 0644 zsh2.2/src/exec.c ||


echo 'restore of zsh2.2/src/exec.c failed'

Wc_c="`wc -c < 'zsh2.2/src/exec.c'`"
test 35818 -eq "$Wc_c" ||
echo 'zsh2.2/src/exec.c: original size 35818, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/src/funcs.h ==============
if test -f 'zsh2.2/src/funcs.h' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/src/funcs.h (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/src/funcs.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/src/funcs.h' &&
Xstruct asgment;
Xstruct utmp;
X
X#include "builtin.pro"
X#include "cond.pro"
X#include "exec.pro"
X#include "glob.pro"
X#include "hist.pro"
X#include "init.pro"
X#include "jobs.pro"
X#include "lex.pro"
X#include "loop.pro"
X#include "math.pro"
X#include "mem.pro"
X#include "params.pro"
X#include "parse.pro"
X#include "subst.pro"
X#include "table.pro"
X#include "text.pro"
X#include "utils.pro"
X#include "watch.pro"
X#include "zle_hist.pro"
X#include "zle_main.pro"
X#include "zle_misc.pro"
X#include "zle_move.pro"
X#include "zle_refresh.pro"
X#include "zle_tricky.pro"
X#include "zle_utils.pro"
X#include "zle_vi.pro"
X#include "zle_word.pro"
X
Xchar *mktemp DCLPROTO((char *));
X#ifndef HAS_STDLIB
Xchar *malloc DCLPROTO((int));
Xchar *realloc DCLPROTO((char *,int));
Xchar *calloc DCLPROTO((int,int));
X#endif
Xchar *ttyname DCLPROTO((int));
X
Xextern char PC, *BC, *UP;
Xextern short ospeed;
Xextern int tgetent DCLPROTO((char *bp, char *name));
Xextern int tgetnum DCLPROTO((char *id));
Xextern int tgetflag DCLPROTO((char *id));
Xextern char *tgetstr DCLPROTO((char *id, char **area));
Xextern char *tgoto DCLPROTO((char *cm, int destcol, int destline));
Xextern int tputs DCLPROTO((char *cp, int affcnt, int (*outc)()));
SHAR_EOF
chmod 0644 zsh2.2/src/funcs.h ||
echo 'restore of zsh2.2/src/funcs.h failed'
Wc_c="`wc -c < 'zsh2.2/src/funcs.h'`"
test 1185 -eq "$Wc_c" ||
echo 'zsh2.2/src/funcs.h: original size 1185, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/src/glob.c ==============
if test -f 'zsh2.2/src/glob.c' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/src/glob.c (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/src/glob.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/src/glob.c' &&
X/*
X *
X * glob.c - filename generation


X *
X * This file is part of zsh, the Z shell.
X *
X * This software is Copyright 1992 by Paul Falstad
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made.
X *
X * The author make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk.
X *
X */
X
X#include "zsh.h"
X

X#ifdef __hpux
X#include <ndir.h>
X#else

X#ifdef SYSV
X#define direct dirent
X#else
X#include <sys/dir.h>
X#endif
X#endif
X#include <sys/errno.h>
X
X#define exists(X) (access(X,0) == 0 || readlink(X,NULL,0) == 0)
X
Xstatic int mode; /* != 0 if we are parsing glob patterns */
Xstatic int pathpos; /* position in pathbuf */
Xstatic int matchsz; /* size of matchbuf */
Xstatic int matchct; /* number of matches found */
Xstatic char pathbuf[MAXPATHLEN]; /* pathname buffer */
Xstatic char **matchbuf; /* array of matches */
Xstatic char **matchptr; /* &matchbuf[matchct] */
Xstatic Comp exclude; /* pattern to exclude */
X
X/* max # of qualifiers */
X
X#define QUALCT 16
X
Xstatic int (*qualfuncs[QUALCT])DCLPROTO((struct stat *,long));
Xstatic long qualdata[QUALCT];
Xstatic int qualsense[QUALCT];
Xstatic int qualct;
Xstatic int gf_nullglob,gf_markdirs,gf_noglobdots;
X
X/* pathname component in filename patterns */
X
Xstruct complist {
X Complist next;
X Comp comp;
X int closure; /* 1 if this is a (foo/)# */
X };
Xstruct comp {
X Comp left,right,next;
X char *str;
X int closure,last;
X };
X
Xvoid glob(list,np) /**/
XLklist list;Lknode *np;
X{
XLknode node = prevnode(*np);
XLknode next = nextnode(*np);
Xint sl; /* length of the pattern */
Xchar *ostr; /* the pattern before the parser chops it up */
XComplist q; /* pattern after parsing */
Xchar *str = getdata(*np); /* the pattern */
X
X sl = strlen(str);
X ostr = strdup(str);
X uremnode(list,*np);
X qualct = 0;
X gf_nullglob = isset(NULLGLOB);
X gf_markdirs = isset(MARKDIRS);
X gf_noglobdots = unset(GLOBDOTS);
X if (str[sl-1] == Outpar) /* check for qualifiers */
X {
X char *s;
X int sense = 0;
X long data;
X int (*func) DCLPROTO((struct stat *,long));
X
X for (s = str+sl-2; s != str; s--)
X if (*s == Bar || *s == Outpar || *s == Inpar)
X break;
X if (*s == Inpar)
X {
X *s++ = '\0';
X func = NULL;
X while (*s != Outpar)
X {
X func = NULL;
X if (idigit(*s))
X {
X func = qualflags;
X data = 0;
X while (idigit(*s))
X data = data*010+(*s++-'0');
X }
X else switch ((int)(unsigned char)(*s++))
X {
X case (int)(unsigned char)Hat: case '^': sense = 1-sense; break;
X#ifdef S_IFLNK
X case '@': func = qualmode; data = S_IFLNK; break;
X#endif
X#ifdef S_IFSOCK
X case '=': func = qualmode; data = S_IFSOCK; break;
X#endif
X#ifdef S_IFIFO
X case 'p': func = qualmode; data = S_IFIFO; break;
X#endif
X case '/': func = qualmode; data = S_IFDIR; break;
X case '.': func = qualmode; data = S_IFREG; break;
X case '%': func = qualisdev; break;
X case (int)(unsigned char)Star: func = qualiscom; break;
X case 'R': func = qualflags; data = 0004; break;
X case 'W': func = qualflags; data = 0002; break;
X case 'X': func = qualflags; data = 0001; break;
X case 'r': func = qualflags; data = 0400; break;
X case 'w': func = qualflags; data = 0200; break;
X case 'x': func = qualflags; data = 0100; break;
X case 's': func = qualflags; data = 04000; break;
X case 'S': func = qualflags; data = 02000; break;
X case 'd': func = qualdev; data = qgetnum(&s); break;
X case 'l': func = qualnlink; data = qgetnum(&s); break;
X case 'U': func = qualuid; data = geteuid(); break;
X case 'G': func = qualgid; data = getegid(); break;
X case 'u': func = qualuid; data = qgetnum(&s); break;
X case 'g': func = qualgid; data = qgetnum(&s); break;
X case 'M': gf_markdirs = !sense; break;
X case 'N': gf_nullglob = !sense; break;
X case 'D': gf_noglobdots = sense; break;
X default: zerr("unknown file attribute",NULL,0); return;
X }
X if (func)
X {
X if (qualct == QUALCT-1)
X {
X zerr("too many qualifiers",NULL,0);
X return;
X }
X qualfuncs[qualct] = func;
X qualsense[qualct] = sense;
X qualdata[qualct] = data;
X qualct++;
X }


X if (errflag)
X return;
X }

X }
X }
X else if ((str[sl-1] == '/') && !((str[sl-2] == Star)&&
X (str[sl-3] == Star)&&(str[sl-4] == Star)&&
X (str[sl-5]==Star))) /* foo/ == foo(/) */
X {
X str[sl-1] = '\0';
X qualfuncs[0] = qualmode;
X qualdata[0] = S_IFDIR;
X qualsense[0] = 0;
X qualct = 1;
X }
X qualfuncs[qualct] = NULL;
X if (*str == '/') /* pattern has absolute path */
X {
X str++;
X pathbuf[0] = '/';
X pathbuf[pathpos = 1] = '\0';
X }
X else /* pattern is relative to pwd */
X pathbuf[pathpos = 0] = '\0';
X q = parsepat(str);
X if (!q || errflag) /* if parsing failed */
X {
X if (isset(NOBADPATTERN))
X {
X insnode(list,node,ostr);
X return;
X }
X errflag = 0;
X zerr("bad pattern: %s",ostr,0);
X return;
X }
X matchptr = matchbuf = (char **) zalloc((matchsz = 16)*sizeof(char *));
X matchct = 0;
X scanner(q); /* do the globbing */
X if (matchct)
X badcshglob |= 2;
X else if (!gf_nullglob)
X if (isset(CSHNULLGLOB)) {
X badcshglob |= 1;
X } else if (unset(NONOMATCH)) {
X zerr("no matches found: %s",ostr,0);
X free(matchbuf);
X return;
X } else {
X *matchptr++ = strdup(ostr);
X matchct = 1;
X }
X qsort(&matchbuf[0],matchct,sizeof(char *),notstrcmp);
X matchptr = matchbuf;
X while (matchct--) /* insert matches in the arg list */
X insnode(list,node,*matchptr++);
X free(matchbuf);
X *np = (next) ? prevnode(next) : lastnode(list);
X}
X
X/* get number after qualifier */
X
Xlong qgetnum(s) /**/
Xchar **s;
X{
Xlong v = 0;
X
X if (!idigit(**s))
X {
X zerr("number expected",NULL,0);
X return 0;
X }
X while (idigit(**s))
X v = v*10+*(*s)++-'0';
X return v;
X}
X
Xint notstrcmp(a,b) /**/
Xchar **a;char **b;
X{
Xchar *c = *b,*d = *a;
Xint x1,x2;
X
X for (; *c == *d && *c; c++,d++);
X x1 = atoi(c); x2 = atoi(d);
X if (x1==x2 || unset(NUMERICGLOBSORT))
X return ((int) (unsigned char) *c-(int) (unsigned char) *d);
X return x1-x2;
X}
X
Xint forstrcmp(a,b) /**/
Xchar **a;char **b;
X{
Xchar *c = *b,*d = *a;
X
X for (; *c == *d && *c; c++,d++);
X return ((int) (unsigned char) *d-(int) (unsigned char) *c);
X}
X
X/* add a match to the list */
X
Xvoid insert(s) /**/
Xchar *s;
X{
Xstruct stat buf;
Xint statted = 0;
X
X if (exclude && domatch(s,exclude,gf_noglobdots)) return;
X if (gf_markdirs && !lstat(s,&buf) && S_ISDIR(buf.st_mode)) {
X char *t;
X int ll = strlen(s);
X
X t = ncalloc(ll+2);
X strcpy(t,s);
X t[ll] = '/';
X t[ll+1] = '\0';
X s = t;
X statted = 1;
X }
X if (qualct) { /* do the (X) (^X) stuff */
X int (**fptr)DCLPROTO((struct stat *,long)) = qualfuncs;
X int *sptr = qualsense;
X long *lptr = qualdata;
X struct stat buf;
X
X if (statted || lstat(s,&buf) >= 0)
X while (*fptr) if (!(!!((*fptr++)(&buf,*lptr++)) ^ *sptr++)) return;
X }
X *matchptr++ = s;
X if (++matchct == matchsz) {
X matchbuf = (char **) realloc((char *) matchbuf,
X sizeof(char **)*(matchsz *= 2));
X matchptr = matchbuf+matchct;
X }
X}
X
X/* check to see if str is eligible for filename generation */
X
Xint haswilds(str) /**/
Xchar *str;
X{
X if ((*str == Inbrack || *str == Outbrack) && !str[1]) return 0;
X if (str[0] == '%') return 0;
X for (; *str; str++)
X if (*str == Pound || *str == Hat || *str == Star ||
X *str == Bar || *str == Inbrack || *str == Inang ||
X *str == Quest) return 1;


X return 0;
X}
X

X/* check to see if str is eligible for brace expansion */
X
Xint hasbraces(str) /**/
Xchar *str;
X{
Xint mb,bc,cmct1,cmct2;
Xchar *lbr = NULL;
X
X if (str[0] == Inbrace && str[1] == Outbrace)
X return 0;
X if (isset(BRACECCL)) {
X for (mb = bc = 0; *str; ++str)
X if (*str == Inbrace) {
X if (++bc > mb)
X mb = bc;
X }
X else if (*str == Outbrace)
X if (--bc < 0)
X return(0);
X return(mb && bc == 0);
X }
X for (mb = bc = cmct1 = cmct2 = 0; *str; str++)
X {
X if (*str == Inbrace)
X {
X if (!bc)
X lbr = str;
X bc++;
X if (str[4] == Outbrace && str[2] == '-') /* {a-z} */
X {
X cmct1++;
X if (bc == 1)
X cmct2++;
X }
X }
X else if (*str == Outbrace)
X {
X bc--;
X if (!bc)
X {
X if (!cmct2)
X {
X *lbr = '{';
X *str = '}';
X }
X cmct2 = 0;
X }
X }
X else if (*str == Comma && bc)
X {
X cmct1++;
X if (bc == 1)
X cmct2++;
X }
X if (bc > mb)
X mb = bc;
X if (bc < 0)
X return 0;
X }
X return (mb && bc == 0 && cmct1);
X}
X
X/* expand stuff like >>*.c */
X
Xint xpandredir(fn,tab) /**/
Xstruct redir *fn;Lklist tab;
X{
XLklist fake;
Xchar *nam;
Xstruct redir *ff;


Xint ret = 0;
X

X fake = newlist();
X addnode(fake,fn->name);
X prefork(fake);
X if (!errflag)
X postfork(fake,1);

X if (errflag) return 0;
X if (full(fake) && !nextnode(firstnode(fake))) {
X fn->name = peekfirst(fake);
X untokenize(fn->name);
X } else
X while (nam = ugetnode(fake)) {
X ff = alloc(sizeof *ff);
X *ff = *fn;
X ff->name = nam;
X addnode(tab,ff);


X ret = 1;
X }

X return ret;
X}
X

X/* concatenate s1 and s2 in dynamically allocated buffer */
X
Xchar *dyncat(s1,s2) /**/
Xchar *s1;char *s2;
X{
Xchar *ptr;
X
X ptr = ncalloc(strlen(s1)+strlen(s2)+1);
X strcpy(ptr,s1);
X strcat(ptr,s2);
X return ptr;
X}
X
X/* concatenate s1, s2, and s3 in dynamically allocated buffer */
X
Xchar *tricat(s1,s2,s3) /**/
Xchar *s1;char *s2;char *s3;
X{
Xchar *ptr;
X
X ptr = zalloc(strlen(s1)+strlen(s2)+strlen(s3)+1);
X strcpy(ptr,s1);
X strcat(ptr,s2);
X strcat(ptr,s3);
X return ptr;
X}
X
X/* brace expansion */
X
Xvoid xpandbraces(list,np) /**/
XLklist list;Lknode *np;
X{
XLknode node = (*np),last = prevnode(node);
Xchar *str = getdata(node),*str3 = str,*str2;
Xint prev, bc, comma;
X
X for (; *str != Inbrace; str++);
X for (str2 = str, bc = comma = 0; *str2; ++str2)
X if (*str2 == Inbrace)
X ++bc;
X else if (*str2 == Outbrace) {
X if (--bc == 0)
X break;
X }
X else if (bc == 1 && *str2 == Comma)
X ++comma;
X if (!comma && !bc && isset(BRACECCL)) { /* {a-mnop} */
X char ccl[256], *p;
X unsigned char c1,c2,lastch;
X
X uremnode(list,node);
X memset(ccl, 0, sizeof(ccl) / sizeof(ccl[0]));
X for (p = str + 1, lastch = 0; p < str2; ) {
X if (itok(c1 = *p++))
X c1 = ztokens[c1 - (unsigned char)Pound];
X if (itok(c2 = *p))
X c2 = ztokens[c2 - (unsigned char)Pound];
X if (c1 == '-' && lastch && p < str2 && lastch <= c2) {
X while (lastch < c2)
X ccl[lastch++] = 1;
X lastch = 0;
X }
X else
X ccl[lastch = c1] = 1;
X }
X strcpy(str + 1, str2 + 1);
X for (p = ccl+255; p-- > ccl; )
X if (*p) {
X *str = p - ccl;
X insnode(list, last, strdup(str3));
X }
X *np = nextnode(last);
X return;
X }
X if (str[2] == '-' && str[4] == Outbrace) /* {a-z} */
X {
X char c1,c2;
X
X uremnode(list,node);
X chuck(str);
X c1 = *str;
X chuck(str);
X chuck(str);
X c2 = *str;
X chuck(str);
X if (itok(c1))
X c1 = ztokens[c1-Pound];
X if (itok(c2))
X c2 = ztokens[c2-Pound];
X if (c1 < c2)
X for (; c2 >= c1; c2--) /* {a-z} */
X {
X *str = c2;
X insnode(list,last,strdup(str3));
X }
X else
X for (; c2 <= c1; c2++) /* {z-a} */
X {
X *str = c2;
X insnode(list,last,strdup(str3));
X }
X *np = nextnode(last);
X return;
X }
X prev = str-str3;
X str2 = getparen(str++);
X if (!str2)
X {
X zerr("how did you get this error?",NULL,0);
X return;
X }
X uremnode(list,node);
X node = last;
X for(;;)
X {
X char *zz,*str4;
X int cnt;
X
X for (str4 = str, cnt = 0; cnt || *str != Comma && *str !=
X Outbrace; str++)
X if (*str == Inbrace)
X cnt++;
X else if (*str == Outbrace)
X cnt--;
X else if (!*str)
X exit(10);
X zz = zalloc(prev+(str-str4)+strlen(str2)+1);
X ztrncpy(zz,str3,prev);
X strncat(zz,str4,str-str4);
X strcat(zz,str2);
X insnode(list,node,zz);
X incnode(node);
X if (*str != Outbrace)
X str++;


X else
X break;
X }

X *np = nextnode(last);
X}
X
X/* get closing paren, given pointer to opening paren */
X
Xchar *getparen(str) /**/
Xchar *str;
X{
Xint cnt = 1;
Xchar typein = *str++,typeout = typein+1;
X
X for (; *str && cnt; str++)
X if (*str == typein)
X cnt++;
X else if (*str == typeout)
X cnt--;
X if (!str && cnt)
X return NULL;
X return str;
X}
X
X/* check to see if a matches b (b is not a filename pattern) */
X
Xint matchpat(a,b) /**/
Xchar *a;char *b;
X{
XComp c;
Xint val,len;
Xchar *b2;
X
X remnulargs(b);
X len = strlen(b);
X b2 = alloc(len+3);
X strcpy(b2+1,b);
X b2[0] = Inpar;
X b2[len+1] = Outpar;
X b2[len+2] = '\0';
X c = parsereg(b2);
X if (!c)
X {
X zerr("bad pattern: %s",b,0);
X return 0;
X }
X val = domatch(a,c,0);
X return val;
X}
X
X/* do the ${foo%%bar}, ${foo#bar} stuff */
X/* please do not laugh at this code. */
X
Xvoid getmatch(sp,pat,dd) /**/
Xchar **sp;char *pat;int dd;
X{
XComp c;
Xchar *t,*lng = NULL,cc,*s = *sp;
X
X remnulargs(pat);
X c = parsereg(pat);
X if (!c)
X {
X zerr("bad pattern: %s",pat,0);
X return;
X }
X if (!(dd & 2))
X {
X for (t = s; t==s || t[-1]; t++)
X {
X cc = *t;
X *t = '\0';
X if (domatch(s,c,0))
X {
X if (!(dd & 1))
X {
X *t = cc;
X t = strdup(t);
X *sp = t;
X return;
X }
X lng = t;
X }
X *t = cc;
X }
X if (lng)
X {
X t = strdup(lng);
X *sp = t;
X return;


X }
X }
X else
X {

X for (t = s+strlen(s); t >= s; t--)
X {
X if (domatch(t,c,0))
X {
X if (!(dd & 1))
X {
X cc = *t;
X *t = '\0';
X *sp = strdup(*sp);
X *t = cc;
X return;
X }
X lng = t;
X }
X }
X if (lng)
X {
X cc = *lng;
X *lng = '\0';
X *sp = strdup(*sp);
X *lng = cc;
X return;
X }
X }
X}
X
X/* add a component to pathbuf */
X
Xstatic int addpath(s)
Xchar *s;
X{
X if (strlen(s)+pathpos >= MAXPATHLEN) return 0;
X while (pathbuf[pathpos++] = *s++);
X pathbuf[pathpos-1] = '/';
X pathbuf[pathpos] = '\0';


X return 1;
X}
X

Xchar *getfullpath(s) /**/
Xchar *s;
X{
Xstatic char buf[MAXPATHLEN];
X
X strcpy(buf,pathbuf);
X strcat(buf,s);


X return buf;
X}
X

X/* do the globbing */
X
Xvoid scanner(q) /**/
XComplist q;
X{
XComp c;
Xint closure;
X
X if (closure = q->closure) /* (foo/)# */
X if (q->closure == 2) /* (foo/)## */
X q->closure = 1;
X else
X scanner(q->next);
X if (c = q->comp)
X {
X if (!(c->next || c->left) && !haswilds(c->str))
X if (q->next)
X {
X int oppos = pathpos;
X


X if (errflag)
X return;

X if (q->closure && !strcmp(c->str,".")) return;
X if (!addpath(c->str)) return;
X if (!closure || exists(pathbuf))
X scanner((q->closure) ? q : q->next);
X pathbuf[pathpos = oppos] = '\0';
X }
X else
X {
X char *s;
X
X if (exists(s = getfullpath(c->str)))
X insert(strdup(s));
X }
X else
X {
X char *fn;
X int dirs = !!q->next;
X struct direct *de;
X DIR *lock = opendir((*pathbuf) ? pathbuf : ".");
X
X if (lock == NULL)
X return;
X readdir(lock); readdir(lock); /* skip . and .. */
X while (de = readdir(lock))
X {
X if (errflag)
X break;
X fn = &de->d_name[0];
X if (domatch(fn,c,gf_noglobdots))
X {
X int oppos = pathpos;
X
X if (dirs)
X {
X if (closure)
X {
X int type3;
X struct stat buf;
X
X if (lstat(getfullpath(fn),&buf) == -1)
X {
X if (errno != ENOENT && errno != EINTR &&
X errno != ENOTDIR)
X {
X zerr("%e: %s",fn,errno);
X errflag = 0;
X }
X continue;
X }
X type3 = buf.st_mode & S_IFMT;
X if (type3 != S_IFDIR)
X continue;
X }
X if (addpath(fn))
X scanner((q->closure) ? q : q->next); /* scan next level */
X pathbuf[pathpos = oppos] = '\0';
X }
X else insert(dyncat(pathbuf,fn));
X }
X }
X closedir(lock);
X }
X }
X else
X zerr("no idea how you got this error message.",NULL,0);
X}
X
X/* do the [..(foo)..] business */
X
Xint minimatch(pat,str) /**/
Xchar **pat;char **str;
X{
Xchar *pt = *pat+1,*s = *str;
X
X for (; *pt != Outpar; s++,pt++)
X if ((*pt != Quest || !*s) && *pt != *s)
X {
X *pat = getparen(*pat)-1;
X return 0;
X }
X *str = s-1;


X return 1;
X}
X

Xstatic char *pptr;
Xstatic Comp tail = 0;
Xstatic int first;
X
Xint domatch(str,c,fist) /**/
Xchar *str;Comp c;int fist;
X{
X pptr = str;
X first = fist;
X return doesmatch(c);
X}
X
X/* see if current pattern matches c */
X
Xint doesmatch(c) /**/
XComp c;
X{
Xchar *pat = c->str;
X
X if (c->closure == 1) {
X char *saves = pptr;
X
X if (first && *pptr == '.') return 0;
X if (doesmatch(c->next)) return 1;
X pptr = saves;
X first = 0;
X }
X for(;;)
X {
X if (!pat || !*pat)
X {
X char *saves;
X int savei;
X
X if (errflag)
X return 0;
X saves = pptr;
X savei = first;
X if (c->left || c->right)
X if (!doesmatch(c->left))


X if (c->right)
X {

X pptr = saves;
X first = savei;
X if (!doesmatch(c->right))
X return 0;
X }
X else
X return 0;
X if (c->closure)
X return doesmatch(c);
X if (!c->next)
X return (!c->last || !*pptr);
X return doesmatch(c->next);
X }
X if (first && *pptr == '.' && *pat != '.')
X return 0;
X if (*pat == Star) /* final * is not expanded to ?#; returns success */
X {
X while (*pptr) pptr++;
X return 1;
X }
X first = 0;
X if (*pat == Quest && *pptr)
X {
X pptr++;
X pat++;
X continue;
X }
X if (*pat == Hat)
X return 1-doesmatch(c->next);
X if (*pat == Inbrack) {
X if (!*pptr) break;
X if (pat[1] == Hat || pat[1] == '^') {
X pat[1] = Hat;
X for (pat += 2; *pat != Outbrack && *pat; pat++)
X if (*pat == '-' && pat[-1] != Hat && pat[1] != Outbrack) {
X if (pat[-1] <= *pptr && pat[1] >= *pptr)
X break;
X } else if (*pptr == *pat) break;
X if (!*pat) {
X zerr("something is very wrong.",NULL,0);
X return 0;
X }
X if (*pat != Outbrack)
X break;
X pat++;
X pptr++;
X continue;
X } else {
X for (pat++; *pat != Outbrack && *pat; pat++)
X if (*pat == Inpar) {
X if (minimatch(&pat,&pptr))
X break;
X } else if (*pat == '-' && pat[-1] != Inbrack &&
X pat[1] != Outbrack) {
X if (pat[-1] <= *pptr && pat[1] >= *pptr)
X break;
X } else if (*pptr == *pat) break;
X if (!pat || !*pat) {
X zerr("oh dear. that CAN'T be right.",NULL,0);
X return 0;
X }
X if (*pat == Outbrack)
X break;
X for (pptr++; *pat != Outbrack; pat++);
X pat++;
X continue;
X }
X }
X if (*pat == Inang)
X {
X int t1,t2,t3;
X char *ptr;
X
X if (*++pat == Outang) /* handle <> case */
X {
X ( void ) zstrtol(pptr,&ptr,10);
X if (ptr == pptr)
X break;
X pptr = ptr;
X pat++;
X }
X else
X {
X t1 = zstrtol(pptr,&ptr,10);
X if (ptr == pptr)
X break;
X pptr = ptr;
X t2 = zstrtol(pat,&ptr,10);
X if (*ptr != '-')
X exit(31);
X t3 = zstrtol(ptr+1,&pat,10);
X if (!t3)
X t3 = -1;
X if (*pat++ != Outang)
X exit(21);
X if (t1 < t2 || (t3 != -1 && t1 > t3))
X break;
X }
X continue;
X }
X if (*pptr == *pat)
X {
X pptr++;
X pat++;
X continue;
X }
X break;


X }
X return 0;
X}
X

XComplist parsepat(str) /**/
Xchar *str;
X{
Xchar *s;
X
X exclude = NULL;
X if (isset(EXTENDEDGLOB)) {
X s = str+strlen(str);
X while (s-- > str) {
X if (*s == Tilde && s[1]) {
X *s++ = '\0';
X exclude = parsereg(s);
X if (!exclude) return NULL;


X break;
X }
X }
X }

X mode = 0;
X pptr = str;
X return parsecomplist();
X}
X
XComp parsereg(str) /**/
Xchar *str;
X{
X mode = 1;
X pptr = str;
X return parsecompsw();
X}
X
XComplist parsecomplist() /**/
X{
XComp c1;
XComplist p1;
X
X if (pptr[0] == Star && pptr[1] == Star &&
X (pptr[2] == '/' ||
X (pptr[2] == Star && pptr[3] == Star && pptr[4] == '/'))) {
X pptr += 3;
X if (pptr[-1] == Star) pptr += 2;
X p1 = (Complist) alloc(sizeof *p1);
X p1->next = parsecomplist();
X p1->comp = (Comp) alloc(sizeof *p1->comp);
X p1->comp->last = 1;
X p1->comp->str = strdup("*");
X *p1->comp->str = Star;
X p1->closure = 1;
X return p1;
X }
X if (*pptr == Inpar)
X {
X char *str;
X int pars = 1;
X
X for (str = pptr+1; *str && pars; str++)
X if (*str == Inpar)
X pars++;
X else if (*str == Outpar)
X pars--;
X if (str[0] != Pound || str[-1] != Outpar || str[-2] != '/')
X goto kludge;
X pptr++;
X if (!(c1 = parsecompsw()))
X return NULL;
X if (pptr[0] == '/' && pptr[1] == Outpar && pptr[2] == Pound)
X {
X int pdflag = 0;
X
X pptr += 3;
X if (*pptr == Pound)
X {
X pdflag = 1;
X pptr++;
X }
X p1 = (Complist) alloc(sizeof *p1);
X p1->comp = c1;
X p1->closure = 1+pdflag;
X p1->next = parsecomplist();
X return (p1->comp) ? p1 : NULL;


X }
X }
X else
X {

Xkludge:
X if (!(c1 = parsecompsw()))
X return NULL;
X if (*pptr == '/' || !*pptr)
X {
X int ef = *pptr == '/';
X
X p1 = (Complist) alloc(sizeof *p1);
X p1->comp = c1;
X p1->closure = 0;
X p1->next = (*pptr == '/') ? (pptr++,parsecomplist()) : NULL;
X return (ef && !p1->next) ? NULL : p1;
X }
X }
X errflag = 1;


X return NULL;
X}
X

XComp parsecomp() /**/
X{
XComp c = (Comp) alloc(sizeof *c),c1,c2;
Xchar *s = c->str = alloc(MAXPATHLEN*2),*ls = NULL;
X
X c->next = tail;
X
X while (*pptr && (mode || *pptr != '/') && *pptr != Bar &&
X *pptr != Outpar)
X {
X if (*pptr == Hat)
X {
X *s++ = Hat;
X *s++ = '\0';
X pptr++;
X if (!(c->next = parsecomp()))
X return NULL;
X return c;
X }
X if (*pptr == Star && pptr[1] && (mode || pptr[1] != '/'))
X {
X *s++ = '\0';
X pptr++;
X c1 = (Comp) alloc(sizeof *c1);
X *(c1->str = strdup("?")) = Quest;
X c1->closure = 1;
X if (!(c2 = parsecomp())) return NULL;
X c1->next = c2;
X c->next = c1;
X return c;
X }
X if (*pptr == Inpar)
X {
X int pars = 1;
X char *startp = pptr, *endp;
X Comp stail = tail;
X int dpnd = 0;
X
X for (pptr = pptr+1; *pptr && pars; pptr++)
X if (*pptr == Inpar)
X pars++;
X else if (*pptr == Outpar)
X pars--;
X if (pptr[-1] != Outpar)
X {
X errflag = 1;
X return NULL;
X }
X if (*pptr == Pound)
X {
X dpnd = 1;
X pptr++;
X if (*pptr == Pound)
X {
X pptr++;
X dpnd = 2;
X }
X }
X if (!(c1 = parsecomp())) return NULL;
X tail = c1;
X endp = pptr;
X pptr = startp;
X pptr++;
X *s++ = '\0';
X c->next = (Comp) alloc(sizeof *c);
X c->next->left = parsecompsw();
X c->next->closure = dpnd;
X c->next->next = (Comp) alloc(sizeof *c);
X pptr = endp;
X tail = stail;
X return c;
X }
X if (*pptr == Pound)


X {
X *s = '\0';

X pptr++;
X if (!ls)
X return NULL;
X if (*pptr == Pound)
X {
X pptr++;
X c->next = c1 = (Comp) alloc(sizeof *c);
X c1->str = strdup(ls);
X }
X else
X c1 = c;
X c1->next = c2 = (Comp) alloc(sizeof *c);
X c2->str = strdup(ls);
X c2->closure = 1;
X c2->next = parsecomp();
X if (!c2->next)
X return NULL;
X *ls++ = '\0';
X return c;
X }
X ls = s;
X if (*pptr == Inang)
X {
X int dshct;
X
X dshct = (pptr[1] == Outang);
X *s++ = *pptr++;
X while (*pptr && (*s++ = *pptr++) != Outang)
X if (s[-1] == '-')
X dshct++;
X else if (!idigit(s[-1]))
X break;
X if (s[-1] != Outang || dshct != 1)
X return NULL;
X }
X else if (*pptr == Inbrack)
X {
X while (*pptr && (*s++ = *pptr++) != Outbrack);
X if (s[-1] != Outbrack)
X return NULL;
X }
X else if (itok(*pptr) && *pptr != Star && *pptr != Quest)
X *s++ = ztokens[*pptr++-Pound];
X else
X *s++ = *pptr++;
X }
X if (*pptr == '/' || !*pptr)
X c->last = 1;
X *s++ = '\0';
X return c;
X}
X
XComp parsecompsw() /**/
X{
XComp c1,c2,c3;
X
X c1 = parsecomp();
X if (!c1)
X return NULL;
X if (*pptr == Bar)
X {
X c2 = (Comp) alloc(sizeof *c2);
X pptr++;
X c3 = parsecompsw();
X if (!c3)
X return NULL;
X c2->str = strdup("");
X c2->left = c1;
X c2->right = c3;
X return c2;
X }
X return c1;
X}
X
X/* tokenize and see if ss matches tt */
X
Xint patmatch(ss,tt) /**/
Xchar *ss;char *tt;
X{
Xchar *s = ss,*t;


X
X for (; *s; s++)

X if (*s == '\\')
X chuck(s);
X else
X for (t = ztokens; *t; t++)
X if (*t == *s)
X {
X *s = (t-ztokens)+Pound;
X break;
X }
X return matchpat(ss,tt);
X}
X
X/* remove unnecessary Nulargs */
X
Xvoid remnulargs(s) /**/
Xchar *s;
X{
Xint nl = *s;
Xchar *t = s;
X
X while (*s)


X if (*s == Nularg)

X chuck(s);
X else
X s++;
X if (!*t && nl)
X {
X t[0] = Nularg;
X t[1] = '\0';
X }
X}
X
X/* qualifier functions */
X
Xint qualdev(buf,dv) /**/
Xstruct stat *buf;long dv;
X{
X return buf->st_dev == dv;
X}
X
Xint qualnlink(buf,ct) /**/
Xstruct stat *buf;long ct;
X{
X return buf->st_nlink == ct;
X}
X
Xint qualuid(buf,uid) /**/
Xstruct stat *buf;long uid;
X{
X return buf->st_uid == uid;
X}
X
Xint qualgid(buf,gid) /**/
Xstruct stat *buf;long gid;
X{
X return buf->st_gid == gid;
X}
X
Xint qualisdev(buf,junk) /**/
Xstruct stat *buf;long junk;
X{
X junk = buf->st_mode & S_IFMT;
X return junk == S_IFBLK || junk == S_IFCHR;
X}
X
Xint qualmode(buf,mod) /**/
Xstruct stat *buf;long mod;
X{
X return (buf->st_mode & S_IFMT) == mod;
X}
X
Xint qualflags(buf,mod) /**/
Xstruct stat *buf;long mod;
X{
X return buf->st_mode & mod;
X}
X
Xint qualiscom(buf,mod) /**/
Xstruct stat *buf;long mod;
X{
X return (buf->st_mode & (S_IFMT|S_IEXEC)) == (S_IFREG|S_IEXEC);
X}
X
SHAR_EOF
chmod 0644 zsh2.2/src/glob.c ||
echo 'restore of zsh2.2/src/glob.c failed'
Wc_c="`wc -c < 'zsh2.2/src/glob.c'`"
test 24554 -eq "$Wc_c" ||
echo 'zsh2.2/src/glob.c: original size 24554, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.2/src/hist.c ==============
if test -f 'zsh2.2/src/hist.c' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.2/src/hist.c (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.2/src/hist.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.2/src/hist.c' &&
X/*
X *
X * hist.c - history expansion


X *
X * This file is part of zsh, the Z shell.
X *
X * This software is Copyright 1992 by Paul Falstad
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made.
X *
X * The author make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk.
X *
X */
X
X#include "zsh.h"
X

X#define HEAPSIZE 4096
X
Xstruct hp {
X Hp next;
X char *pool,*ptr;
X int free,histno;
X};
X
Xstatic Hp hp_lit, hp_lex;
Xstatic Histent curhistent;
X
Xstatic int lastc;
X
X/* add a character to the current history word */
X
Xvoid hwaddc(c) /**/
Xint c;
X{
X if (hlastw && hline && (!(errflag || lexstop) || c == HISTSPACE)) {
X if (c == '!' && unset(NOBANGHIST)) hwaddc('\\');
X *hptr++ = c;
X if (hptr-hline >= hlinesz) {
X int ll,flag = 0,oldsiz = hlinesz;
X
X ll = hptr-hlastw;
X if (curhistent->lex == hline) flag = 1;
X hline = hp_realloc(&hp_lex,hline,oldsiz,hlinesz = oldsiz+16);
X if (flag) curhistent->lex = hline;
X hptr = hline+oldsiz;
X hlastw = hptr-ll;
X }
X }
X}
X
X#define habort() { errflag = lexstop = 1; return ' '; }
X
X/* get a character after performing history substitution */
X
Xint hgetc() /**/
X{
Xint c,ev,farg,larg,argc,marg = -1,cflag = 0,bflag = 0;
Xchar buf[256],*ptr;
Xchar *sline,*eline;
X
Xtailrec:
X c = hgetch();
X if (stophist || alstackind)
X {
X hwaddc(c);
X return c;
X }
X if (isfirstch && c == hatchar)
X {
X isfirstch = 0;
X hungetch(hatchar);
X hungets(":s");
X c = bangchar;
X goto hatskip;
X }
X if (c != ' ')
X isfirstch = 0;
X if (c == '\\') {
X int g = hgetch();
X
X if (g != bangchar)
X hungetch(g);
X else {
X hwaddc(bangchar);
X return bangchar;
X }
X }
X if (c != bangchar)
X {
X hwaddc(c);
X return c;
X }
Xhatskip:
X *hptr = '\0';
X if ((c = hgetch()) == '{')
X {
X bflag = cflag = 1;
X c = hgetch();
X }
X if (c == '\"')
X {
X stophist = 1;
X goto tailrec;
X }
X if (!cflag && inblank(c) || c == '=' || c == '(' || lexstop)
X {
X if (lexstop)
X lexstop = 0;
X else
X hungetch(c);
X hwaddc(bangchar);
X return bangchar;
X }
X cflag = 0;
X ptr = buf;
X
X /* get event number */
X
X if (c == '?')
X {
X for(;;)
X {
X c = hgetch();
X if (c == '?' || c == '\n' || lexstop)
X break;
X else
X *ptr++ = c;
X }
X if (c != '\n' && !lexstop)
X c = hgetch();
X *ptr = '\0';
X ev = hconsearch(hsubl = ztrdup(buf),&marg);
X if (ev == -1)
X {
X herrflush();
X zerr("no such event: %s",buf,0);
X habort();


X }
X }
X else
X {

X int t0;
X

X for (;;)
X {

X if (inblank(c) || c == ';' || c == ':' || c == '^' || c == '$' ||
X c == '*' || c == '%' || c == '}' || lexstop)
X break;
X if (ptr != buf) {
X if (c == '-') break;
X if ((idigit(buf[0]) || buf[0] == '-') && !idigit(c)) break;
X }
X *ptr++ = c;
X if (c == '#' || c == bangchar)
X {
X c = hgetch();
X break;
X }
X c = hgetch();
X }
X *ptr = 0;
X if (!*buf)
X ev = defev;
X else if (t0 = atoi(buf))
X ev = (t0 < 0) ? curhist+t0 : t0;
X else if (*buf == bangchar)
X ev = curhist-1;
X else if (*buf == '#')
X ev = curhist;
X else if ((ev = hcomsearch(buf)) == -1)
X {
X zerr("event not found: %s",buf,0);
X while (c != '\n' && !lexstop)
X c = hgetch();
X habort();
X }
X }
X
X /* get the event */
X
X if (!(eline = getevent(defev = ev)))
X habort();
X
X /* extract the relevant arguments */
X
X argc = getargc(eline);
X if (c == ':')
X {
X cflag = 1;
X c = hgetch();
X }
X if (c == '*')
X {
X farg = 1;
X larg = argc;
X cflag = 0;
X }
X else
X {
X hungetch(c);
X larg = farg = getargspec(argc,marg);
X if (larg == -2)
X habort();
X if (farg != -1)
X cflag = 0;
X c = hgetch();
X if (c == '*')
X {
X cflag = 0;
X larg = argc;
X }
X else if (c == '-')
X {
X cflag = 0;
X larg = getargspec(argc,marg);
X if (larg == -2)
X habort();
X if (larg == -1)
X larg = argc-1;
X }
X else
X hungetch(c);
X }
X if (farg == -1)
X farg = 0;
X if (larg == -1)
X larg = argc;
X if (!(sline = getargs(eline,farg,larg)))
X habort();
X
X /* do the modifiers */
X
X for(;;)
X {
X c = (cflag) ? ':' : hgetch();
X cflag = 0;
X if (c == ':')
X {
X int gbal = 0;
X
X if ((c = hgetch()) == 'g')
X {
X gbal = 1;
X c = hgetch();
X }
X switch(c)
X {
X case 'p':
X histdone = HISTFLAG_DONE|HISTFLAG_NOEXEC;
X break;
X case 'h':
X if (!remtpath(&sline))
X {
X herrflush();
X zerr("modifier failed: h",NULL,0);
X habort();
X }
X break;
X case 'e':
X if (!rembutext(&sline))
X {
X herrflush();
X zerr("modifier failed: e",NULL,0);
X habort();
X }
X break;
X case 'r':
X if (!remtext(&sline))
X {
X herrflush();
X zerr("modifier failed: r",NULL,0);
X habort();
X }
X break;
X case 't':
X if (!remlpaths(&sline))
X {
X herrflush();
X zerr("modifier failed: t",NULL,0);
X habort();
X }
X break;
X case 's':
X {
X int del;
X char *ptr1,*ptr2;
X
X del = hgetch();
X ptr1 = hdynread2(del);
X if (!ptr1)
X habort();
X ptr2 = hdynread2(del);
X if (strlen(ptr1))
X {
X if (hsubl)
X free(hsubl);
X hsubl = ptr1;
X }
X if (hsubr)
X free(hsubr);
X hsubr = ptr2;
X }
X case '&':
X if (hsubl && hsubr)
X subst(&sline,hsubl,hsubr,gbal);
X else
X {
X herrflush();
X zerr("no previous substitution with &",NULL,0);
X habort();
X }
X break;
X case 'q':
X quote(&sline);
X break;
X case 'x':
X quotebreak(&sline);
X break;
X case 'l':
X downcase(&sline);
X break;
X case 'u':
X upcase(&sline);
X break;
X default:
X herrflush();
X zerr("illegal modifier: %c",NULL,c);
X habort();
X break;
X }
X }
X else
X {
X if (c != '}' || !bflag)
X hungetch(c);
X if (c != '}' && bflag)
X {
X zerr("'}' expected",NULL,0);
X habort();


X }
X break;
X }
X }
X

X /* stuff the resulting string in the input queue and start over */
X
X lexstop = 0;
X if (alstackind != MAXAL)
X {
X hungets(HISTMARK);
X alstack[alstackind++] = NULL;
X }
X for (ptr = sline; *ptr; ptr++) {
X if (ptr[0] == '\\' && ptr[1] == '!') chuck(ptr);
X }
X hungets(sline);
X histdone |= HISTFLAG_DONE;
X if (isset(HISTVERIFY)) histdone |= HISTFLAG_NOEXEC|HISTFLAG_RECALL;
X goto tailrec;
X}
X
X/* reset the alias stack for lexrestore () */
X
Xvoid clearalstack() /**/
X{
XAlias ix;
X
X while (alstackind)
X {
X ix = alstack[--alstackind];
X ix->inuse = 0;
X }
X}
X
X/* get a character without history expansion */
X
Xint hgetch() /**/
X{
Xunsigned char *line,*pmpt,*pmpt2 = NULL;
Xint plen;
X
Xstart:
X if (inbufct)
X {
X inbufct--;
X if ((lastc = *inbufptr++) == ALPOP)
X {
X Alias ix;
X char *t;
X
X if (!alstackind)
X {
X zerr("alias stack underflow",NULL,0);
X errflag = lexstop = 1;
X return lastc = ' ';
X }
X ix = alstack[--alstackind];
X if (ix)
X {
X ix->inuse = 0;
X t = ix->text;
X if (*t && t[strlen(t)-1] == ' ')
X alstat = ALSTAT_MORE;
X else
X alstat = ALSTAT_JUNK;
X }
X goto start;
X }
X if (itok(lastc))
X goto start;
X return lastc;
X }
X if (strin || errflag)
X {
X lexstop = 1;
X return lastc = ' ';
X }
X if (interact && isset(SHINSTDIN))
X if (!isfirstln)
X pmpt = (unsigned char *)putprompt(prompt2,&plen);
X else
X {
X int foo;
X
X pmpt = (unsigned char *)putprompt(prompt,&plen);
X pmpt2 = (unsigned char *)((rprompt) ? putprompt(rprompt,&foo) : NULL);
X }
X if (!(interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE))) {
X char *lbuf;
X if (interact && isset(SHINSTDIN))
X write(2,pmpt,strlen((char *) pmpt));
X line = (unsigned char *)fgets(lbuf = zalloc(256),256,bshin);
X if (!line) free(lbuf);
X } else
X line = zleread(pmpt,pmpt2,plen);
X if (!line) {
X lexstop = 1;
X return lastc = ' ';
X }
X if (errflag) {
X free(line);
X lexstop = errflag = 1;
X return lastc = ' ';
X }
X if (interact && isset(SHINSTDIN)) {
X char *s = curhistent->lit;
X curhistent->lit = hp_concat(s,(char*)line);
X }
X if (isfirstln) spaceflag = *line == ' ';
X if (isset(VERBOSE)) {
X fputs((char *) line,stderr);
X fflush(stderr);
X }
X if (*line && line[strlen((char *) line)-1] == '\n')
X {
X lineno++;
X if (interact && isset(SUNKEYBOARDHACK) && isset(SHINSTDIN) &&
X SHTTY != -1 && *line && line[1] &&
X line[strlen((char *) line)-2] == '`')
X {
X int ct;
X unsigned char *ptr;
X
X for (ct = 0, ptr = line; *ptr; ptr++)
X if (*ptr == '`')
X ct++;
X if (ct & 1)
X {
X ptr[-2] = '\n';
X ptr[-1] = '\0';
X }
X }
X }
X isfirstch = 1;
X hungets((char*)line);
X free(line);
X goto start;
X}
X
X/* Read one line of at most n-1 chars from the input queue */
X
Xchar *hgets(buf, n) /**/
Xchar *buf;int n;
X{
Xint l;
X
X for (l = 0; l < n-1; l++)
X if ((buf[l] = hgetch()) == '\n' || lexstop)
X break;
X buf[l+(lexstop?0:1)] = 0;
X
X return (!lexstop || l) ? buf : NULL;
X}
X
X/* put a string in the input queue */
X
Xvoid hungets(str) /**/
Xchar *str;
X{
Xint slen = strlen(str);
X
X/* shrink inbuf if it gets too big */
X
X if (!inbufct && inbufsz > 65536)
X {
X free(inbuf);
X inbuf = zalloc(inbufsz = 256);
X inbufptr = inbuf+inbufsz;
X inbufct = 0;
X }
X if (slen+inbufct > inbufsz)
X {
X char *x;
X
X while (slen+inbufct > inbufsz)
X inbufsz *= 4;
X x = zalloc(inbufsz);
X memcpy(x+inbufsz-inbufct,inbufptr,inbufct);
X inbufptr = x+inbufsz-inbufct;
X free(inbuf);
X inbuf = x;
X }
X memcpy(inbufptr -= slen,str,slen);
X inbufct += slen;
X}
X
X/* unget a char and remove it from hline */
X
Xvoid hungetc(c) /**/
Xint c;
X{
X if (lexstop)
X return;
X if (hlastw) {
SHAR_EOF
true || echo 'restore of zsh2.2/src/hist.c failed'
fi
echo 'End of zsh2.2 part 8'
echo 'File zsh2.2/src/hist.c is continued in part 9'
echo 9 > _shar_seq_.tmp