Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

v35i051: zsh - The Z Shell, version 2.3.1, Part01/22

95 views
Skip to first unread message

The Zsh Mailing List

unread,
Feb 20, 1993, 4:18:54 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 51
Archive-name: zsh/part01
Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

Zsh is a shell designed for interactive use, although it is also a
powerful scripting language. Many of the useful features of bash,
ksh, and tcsh were incorporated into zsh; many original features were
added. See the doc/intro.{troff,txt} document for more details.

Zsh was originally written by Paul Falstad, who has transferred the
current development of the shell to the zsh mailing list:

zsh-...@cs.uow.edu.au

To subscribe to the list, send a request to "zsh-r...@cs.uow.edu.au".
This release consists of patches contributed to the mailing list, and
the mailing list is continuing to work on zsh 2.4 as you read this.

--------
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.
# Contents: README doc dots func help man man/man1 scripts src
# src/params.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:50 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 1 (of 22)."'
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(22439 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
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.3.1.
X
XTo get this shell running, cd into the src directory and type
X"buildzsh". Someone recently tested it on the following machines,
Xwhere it compiled just by running this script:
X
XApollo (Motorola & PRISM) running Domain SR10.4 cc 6.9
XBBN TC2000 running nX 3.0.1, 3.1.0
XCCI Tahoe running BSD 4.3-tahoe
XDEC (various) running Ultrix 4.2, 4.2A
XDEC Alpha running OSF-1
XFujitsu F2600 running SVR4
XHP 9000 (various) running HP-UX 7.0x, 8.0x, 9.01
XIBM RS6000 running AIX 3.2
XMIPS running RISC/OS 4.x
XNeXT running NeXTSTEP 2.x, 3.0
XSGI running IRIX 4.0.5
XSequent running DYNIX (additional work needed for DYNIX/PTX)
XSony running NeWS/OS 3.2 (BSD 4.3)
XSun-3, Sun-4 running SunOS 4.0.3, 4.1.x
X
XZsh was originally written by Paul Falstad, who has transferred the
Xcurrent development of the shell to the zsh mailing list:
X
X zsh-...@cs.uow.edu.au
X
XTo subscribe to the list, send a request to "zsh-r...@cs.uow.edu.au".
XThis release consists of patches contributed to the mailing list, and
Xthe mailing list is continuing to work on zsh 2.4.
X
XThe following people contributed patches for the 2.3 release:
X
XHans Albertsson Tero Kivinen
XEric Arnold Karsten Kuenne
XBas de Bakker Ben Liblit
XMarc Boucher Rick Lyons
XCarlos Carvalho Jim Mattson
XRobert Clare Jean-Jacques Moreau
XDaniel Dignam J.B. Nicholson-Owens
XStephen Dum Rick Ohnemus
XCarl Edman Wolf N. Paul
XChristian Finger Bart Schaefer
XBrian Gregory Dwight Shih
XJohn Guthrie Peter Stephenson
XJohan Hagman Klaus Wacker
XJonathan Hardwick Irving Wolfe
X
XTabstops are 3 spaces. If you're going to look at this code, run it
Xthough "expand -3" first, or set your tab stops every 3 spaces.
X
XModification history:
X
X2.3.1-2.3.0:
Xo fewer compilation warnings
Xo parsing error in function definition fixed
Xo problems with '.' in vi-mode fixed
Xo parsing bug with ! and coproc fixed
Xo strange while loop behavior fixed
Xo "TRAPx TRAPy {}; unfunction TRAPy" fixed
Xo array-size checking for integers was off by one (fixed)
X
X2.3.0-2.2.0:
Xo improved portability
Xo fewer compilation warnings
Xo texinfo documentation
Xo several memory leaks fixed, and a few references to freed memory eliminated
Xo several parsing bugs fixed, and now less illegal syntax is accepted
Xo improved (i.e. repaired) signal handling
Xo RFS support
Xo rc files reorganized (see INVOCATION in the man page)
Xo ksh compatibility mode when zsh is invoked as "ksh"
Xo nested variables (e.g. echo ${${var#?}%?})
Xo stringized array variables ("$a" where a is an array)
Xo can now set array slices and array elements by subscript
Xo 4 new glob identifiers:
X - a[[-|+]n] files accessed within last n days (-), files accessed
X more than n days ago (+), or files accessed n days ago.
X - m[[-|+]n] as above for modified files.
X - c[[-|+]n] as above for the modification of an inode of a file.
X - L[[-|+]n] files less than n bytes (-), more than n bytes (+),
X or exactly n bytes in length.
Xo new prompt escapes and new syntax for numeric arguments to prompt escapes
X (e.g. %C3 -> %3C)
Xo %R and %r now only recognized in spell-checking prompts
Xo watch notme (like watch all, except for the user's own activity)
Xo hash table listings (from set, alias, compctl...) are now sorted
Xo New arguments to fc builtin:
X -f print full time stamp (including date)
X -E print date in European format (dd.mm.yyyy)
X -I incremental history update (with -A or -W)
Xo new EXTENDEDHISTORY option for saving timestamps to history file
Xo new {up,down}-line-or-search keybindings
Xo cd processing (chpwd, etc.) no longer occurs if new directory is the
X same as the previous one
Xo filename completion works on named directories
Xo named directories now have to be strings
Xo username lookup more efficient, new username lookup routine for NIS
Xo sample run-help function to make use of the help directory
Xo sample zed function (use the zle line editor to edit a file)
Xo If compctl is just -h for a command, hostname completion will now be
X performed after an @. Compctl is set to just -h for commands in hostcmds.
Xo zsh no longer forks /bin/sh for any shell commands (e.g. STTY)
Xo old AUTOREMOVESLASH option documented and repaired.
Xo lexically significant quotes and backslashes are now retained by builtins
Xo backslashes now end variable names and suffice in a here document
X terminator to inhibit interpretation of the here document
Xo answering 'n' to 'remove all files in <arg>?' just removes the individual
X argument from the rm command line, as long as other arguments remain
Xo ALLEXPORT now exports existing variables when they are modified
Xo whitespace now handled properly by read builtin
Xo ${#@} and ${#*} are now recognized
Xo colon modifers now work with array variables
X (except :x and :q, which only pretend to work)
Xo ${...=...} handling fixed
Xo cd xx/.. no longer takes you to first directory of $cdpath
Xo return in a loop in a function now exits the function
Xo return from a function in a loop no longer exits the loop
Xo several fixes to 'fc' builtin
Xo 'noglob rm *' no longer prompts for confirmation
Xo changes to cdpath, manpath, etc. are now reflected in the environment
Xo vibackwardkillword fixed to use vi style words
Xo not found message no longer printed if 'whence -a foo' doesn't find anything
Xo current dir is removed from directory stack if PUSHD_IGNORE_DUPS is set
Xo cd now complains of invalid directory stack arguments
Xo extra files are no longer left open on nullexec
Xo exit status is set correctly for shells started '-c'
Xo consistent handling of -i and -m options
Xo null arguments are now included in array expansion
Xo job text corrected for coprocesses
Xo a quoted command substitution that returns no text is no longer discarded
X (e.g. set a "`echo`" b ; echo $#)
Xo IFS allows null fields
Xo read of more variables than available in the input no longer blocks shell
Xo dups of nonexistent file handles fixed
Xo confusion regarding controlling terminal fixed
Xo canonical directory naming fixed
Xo zsh no longer hangs on backquote expansion (e.g. echo `pwd`)
Xo echo foo >>(cat) now redirects stdin before closing the pipe
Xo problems with zsh not exiting fixed
Xo bad patterns now work when NOBADPATTERN is set
Xo exporting of special shell variables fixed
Xo history references now work only in interactive shells
Xo history file no longer saved if history is not established
Xo killing a command in a loop now kills the loop
Xo compctl -k now essentially ignores non-array arguments
Xo transpose-chars now works on one character lines and on the second
X character of a line
Xo neg-argument now works for multiple digits
Xo statusline no longer trashed when searching in vi mode
Xo print -P can now be invoked from a signal handler without confusing zle
Xo prototype files automatically generated during compilation
Xo GLOBALZSHENV now defined by default as "/etc/zshenv"
Xo off-by-one error in compiling signal list fixed
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 occurrences 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 ($PATH 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
END_OF_FILE
if test 22439 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test ! -d 'doc' ; then
echo shar: Creating directory \"'doc'\"
mkdir 'doc'
fi
if test ! -d 'dots' ; then
echo shar: Creating directory \"'dots'\"
mkdir 'dots'
fi
if test ! -d 'func' ; then
echo shar: Creating directory \"'func'\"
mkdir 'func'
fi
if test ! -d 'help' ; then
echo shar: Creating directory \"'help'\"
mkdir 'help'
fi
if test ! -d 'man' ; then
echo shar: Creating directory \"'man'\"
mkdir 'man'
fi
if test ! -d 'man/man1' ; then
echo shar: Creating directory \"'man/man1'\"
mkdir 'man/man1'
fi
if test ! -d 'scripts' ; then
echo shar: Creating directory \"'scripts'\"
mkdir 'scripts'
fi
if test ! -d 'src' ; then
echo shar: Creating directory \"'src'\"
mkdir 'src'
fi
if test -f 'src/params.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/params.c'\"
else
echo shar: Extracting \"'src/params.c'\" \(26353 characters\)
sed "s/^X//" >'src/params.c' <<'END_OF_FILE'
X/*
X *
X * params.c - parameters
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 "version.h"
X#include <pwd.h>
X
X#define new(X) (X=(vptr)alloc(sizeof(*(X))))
X
Xstatic Param argvparam;
X
Xstruct iparam {
X struct hashnode *next; int canfree; char *nam; /* hash data */
X vptr value;
X int (*func1)(); /* set func */
X int (*func2)(); /* get func */
X int ct; /* output base or field width */
X int flags;
X vptr data; /* used by getfns */
X char *env; /* location in environment, if exported */
X char *ename; /* name of corresponding environment var */
X };
X
X#define IFN(X) ((int (*)())(X))
X
X/* put predefined params in hash table */
X
Xvoid setupparams() /**/
X{
Xstatic struct iparam pinit[] = {
X#define IPDEF1(A,B,C,D) {NULL,0,A,NULL,IFN(C),IFN(B),10,\
X PMFLAG_i|PMFLAG_SPECIAL|D,NULL,NULL,NULL}
X IPDEF1("#",poundgetfn,IFN(nullsetfn),PMFLAG_r),
X IPDEF1("ARGC",poundgetfn,IFN(nullsetfn),PMFLAG_r),
X IPDEF1("ERRNO",errnogetfn,IFN(nullsetfn),PMFLAG_r),
X IPDEF1("GID",gidgetfn,IFN(nullsetfn),PMFLAG_r),
X IPDEF1("HISTSIZE",histsizegetfn,histsizesetfn,0),
X IPDEF1("LITHISTSIZE",lithistsizegetfn,lithistsizesetfn,0),
X IPDEF1("RANDOM",randomgetfn,randomsetfn,0),
X IPDEF1("SECONDS",secondsgetfn,secondssetfn,0),
X IPDEF1("UID",uidgetfn,IFN(nullsetfn),PMFLAG_r),
X
X#define IPDEF2(A,B,C,D) {NULL,0,A,NULL,IFN(C),IFN(B),0,\
X PMFLAG_SPECIAL|D,NULL,NULL,NULL}
X IPDEF2("-",dashgetfn,IFN(nullsetfn),PMFLAG_r),
X IPDEF2("HISTCHARS",histcharsgetfn,histcharssetfn,0),
X IPDEF2("HOME",homegetfn,homesetfn,0),
X IPDEF2("TERM",termgetfn,termsetfn,0),
X IPDEF2("WORDCHARS",wordcharsgetfn,wordcharssetfn,0),
X IPDEF2("IFS",ifsgetfn,ifssetfn,0),
X IPDEF2("_",underscoregetfn,IFN(nullsetfn),PMFLAG_r),
X
X#define IPDEF3(A) {NULL,0,A,NULL,IFN(nullsetfn),IFN(strconstgetfn),0,PMFLAG_r|\
X PMFLAG_SPECIAL,NULL,NULL,NULL}
X IPDEF3("HOSTTYPE"),
X IPDEF3("VERSION"),
X
X#define IPDEF4(A,B) {NULL,0,A,NULL,IFN(nullsetfn),IFN(intvargetfn),10,\
X PMFLAG_r|PMFLAG_i|PMFLAG_SPECIAL,(vptr)B,NULL,NULL}
X IPDEF4("!",&lastpid),
X IPDEF4("$",&mypid),
X IPDEF4("?",&lastval),
X IPDEF4("status",&lastval),
X IPDEF4("LINENO",&lineno),
X IPDEF4("PPID",&ppid),
X
X#define IPDEF5(A,B) {NULL,0,A,NULL,IFN(intvarsetfn),IFN(intvargetfn),10,\
X PMFLAG_i|PMFLAG_SPECIAL,(vptr)B,NULL,NULL}
X IPDEF5("BAUD",&baud),
X IPDEF5("COLUMNS",&columns),
X IPDEF5("DIRSTACKSIZE",&dirstacksize),
X IPDEF5("LINES",&lines),
X IPDEF5("LISTMAX",&listmax),
X IPDEF5("LOGCHECK",&logcheck),
X IPDEF5("MAILCHECK",&mailcheck),
X IPDEF5("OPTIND",&zoptind),
X IPDEF5("PERIOD",&period),
X IPDEF5("REPORTTIME",&reporttime),
X IPDEF5("SAVEHIST",&savehist),
X IPDEF5("SHLVL",&shlvl),
X IPDEF5("TMOUT",&tmout),
X
X#define IPDEF6(A,B) {NULL,0,A,NULL,IFN(nullsetfn),IFN(strvargetfn),0,\
X PMFLAG_r|PMFLAG_SPECIAL,(vptr)B,NULL,NULL}
X IPDEF6("LOGNAME",&logname),
X IPDEF6("PWD",&pwd),
X IPDEF6("TTY",&ttystrname),
X IPDEF6("USERNAME",&username),
X
X#define IPDEF7(A,B) {NULL,0,A,NULL,IFN(strvarsetfn),IFN(strvargetfn),0,\
X PMFLAG_SPECIAL,(vptr)B,NULL,NULL}
X IPDEF7("FCEDIT",&fceditparam),
X IPDEF7("HOST",&hostnam),
X IPDEF7("OLDPWD",&oldpwd),
X IPDEF7("OPTARG",&optarg),
X IPDEF7("MAIL",&mailfile),
X IPDEF7("NULLCMD",&nullcmd),
X IPDEF7("POSTEDIT",&postedit),
X IPDEF7("prompt",&prompt),
X IPDEF7("PROMPT",&prompt),
X IPDEF7("PROMPT2",&prompt2),
X IPDEF7("PROMPT3",&prompt3),
X IPDEF7("PROMPT4",&prompt4),
X IPDEF7("READNULLCMD",&readnullcmd),
X IPDEF7("RPROMPT",&rprompt),
X IPDEF7("PS1",&prompt),
X IPDEF7("PS2",&prompt2),
X IPDEF7("PS3",&prompt3),
X IPDEF7("PS4",&prompt4),
X IPDEF7("RPS1",&rprompt),
X IPDEF7("SPROMPT",&sprompt),
X IPDEF7("TIMEFMT",&timefmt),
X IPDEF7("TMPPREFIX",&tmpprefix),
X IPDEF7("WATCHFMT",&watchfmt),
X IPDEF7("0",&argzero),
X
X#define IPDEF8(A,B,C) {NULL,0,A,NULL,IFN(colonarrsetfn),IFN(colonarrgetfn),0,\
X PMFLAG_SPECIAL,(vptr)C,NULL,B}
X IPDEF8("CDPATH","cdpath",&cdpath),
X IPDEF8("FIGNORE","fignore",&fignore),
X IPDEF8("FPATH","fpath",&fpath),
X IPDEF8("MAILPATH","mailpath",&mailpath),
X IPDEF8("MANPATH","manpath",&manpath),
X IPDEF8("WATCH","watch",&watch),
X IPDEF8("HOSTS","hosts",&hosts),
X IPDEF8("PSVAR","psvar",&psvar),
X IPDEF8("PATH",NULL,NULL),
X
X#define IPDEF9(A,B,C,D) {NULL,0,A,NULL,IFN(arrvarsetfn),IFN(arrvargetfn),0,\
X PMFLAG_A|PMFLAG_SPECIAL|C,(vptr)B,NULL,D}
X IPDEF9("cdpath",&cdpath,0,"CDPATH"),
X IPDEF9("fignore",&fignore,0,"FIGNORE"),
X IPDEF9("fpath",&fpath,0,"FPATH"),
X IPDEF9("mailpath",&mailpath,0,"MAILPATH"),
X IPDEF9("manpath",&manpath,0,"MANPATH"),
X IPDEF9("watch",&watch,0,"WATCH"),
X IPDEF9("hosts",&hosts,0,"HOSTS"),
X IPDEF9("psvar",&psvar,0,"PSVAR"),
X IPDEF9("signals",&sigptr,PMFLAG_r,NULL),
X IPDEF9("argv",&pparams,0,NULL),
X IPDEF9("*",&pparams,0,NULL),
X IPDEF9("@",&pparams,0,NULL),
X
X#define IPDEF10(A,C,D) {NULL,0,A,NULL,IFN(D),IFN(C),0,\
X PMFLAG_A|PMFLAG_SPECIAL,NULL,NULL,NULL}
X IPDEF10("path",pathgetfn,pathsetfn),
X IPDEF10("hostcmds",nullgetfn,hostcmdssetfn),
X IPDEF10("optcmds",nullgetfn,optcmdssetfn),
X IPDEF10("bindcmds",nullgetfn,bindcmdssetfn),
X IPDEF10("varcmds",nullgetfn,varcmdssetfn),
X {NULL,}
X };
Xstruct iparam *ip;
X
X for (ip = pinit; ip->nam; ip++) addhperm(ip->nam,ip,paramtab,(FFunc) 0);
X argvparam = gethnode("argv",paramtab);
X
X ((struct iparam *)gethnode("HOSTTYPE", paramtab))->data = ztrdup(HOSTTYPE);
X ((struct iparam *)gethnode("VERSION", paramtab))->data = ztrdup(VERSIONSTR);
X}
X
Xstatic int unsetflag;
X
Xstruct param *createparam(name,value,flags) /**/
Xchar *name;vptr value;int flags;
X{
Xstruct param *pm;
Xchar buf[20];
X
X pm = zcalloc(sizeof *pm);
X if (isset(ALLEXPORT))
X flags |= PMFLAG_x;
X pm->flags = flags;
X if ((flags & PMTYPE) == PMFLAG_s) {
X pm->u.str = value;
X pm->sets.cfn = strsetfn;
X pm->gets.cfn = strgetfn;
X } else if ((flags & PMTYPE) == PMFLAG_A) {
X pm->u.arr = value;
X pm->sets.afn = arrsetfn;
X pm->gets.afn = arrgetfn;
X } else {
X pm->u.val = (value) ? matheval(value) : 0;
X pm->sets.ifn = intsetfn;
X pm->gets.ifn = intgetfn;
X sprintf(buf,"%ld",pm->u.val);
X value = buf;
X }
X if (flags & PMFLAG_x)
X pm->env = addenv(name,value);
X addhnode(ztrdup(name),pm,paramtab,freepm);
X return pm;
X}
X
Xint isident(s) /**/
Xchar *s;
X{
Xchar *ss;
X
X for (ss = s; *ss; ss++) if (!iident(*ss)) break;
X if (!*ss) return 1;
X if (*ss != '[') return 0;
X (void) mathevalarg(++ss, &ss);
X if(*ss == ',' || *ss == Comma)
X (void) mathevalarg(++ss,&ss);
X if(*ss != ']' || ss[1]) return 0;
X return 1;
X}
X
XValue getvalue(pptr,bracks) /**/
Xchar **pptr;int bracks;
X{
Xchar *s = *pptr,*t = *pptr;
Xchar sav;
XValue v;
X
X if (idigit(*s)) while (idigit(*s)) s++;
X else if (iident(*s)) while (iident(*s)) s++;
X else if (*s == Quest) *s++ = '?';
X else if (*s == Pound) *s++ = '#';
X else if (*s == String) *s++ = '$';
X else if (*s == Qstring) *s++ = '$';
X else if (*s == Star) *s++ = '*';
X else if (*s == '#' || *s == '-' || *s == '?' || *s == '$' ||
X *s == '_' || *s == '!' || *s == '@' || *s == '*') s++;
X else return NULL;
X if (sav = *s) *s = '\0';
X if (idigit(*t) && *t != '0') {
X v = (Value) hcalloc(sizeof *v);
X v->pm = argvparam;
X v->a = v->b = atoi(t)-1;
X if (sav)
X *s = sav;
X } else {
X struct param *pm;
X int isvarat = !strcmp(t, "@");
X
X pm = gethnode(t,paramtab);
X if (sav)
X *s = sav;
X *pptr = s;
X if (!pm)
X return NULL;
X v = hcalloc(sizeof *v);
X if (pmtype(pm) == PMFLAG_A)
X v->isarr = isvarat ? -1 : 1;
X v->pm = pm;
X v->a = 0; v->b = -1;
X if (bracks && (*s == '[' || *s == Inbrack)) {
X int a,b;
X char *olds = s,*t;
X
X *s++ = '[';
X for (t = s; *t && *t != ']' && *t != Outbrack; t++)
X if (itok(*t))
X *t = ztokens[*t-Pound];
X if (*t == Outbrack)
X *t = ']';
X if ((s[0] == '*' || s[0] == '@') && s[1] == ']') {
X if (v->isarr) v->isarr = (s[0] == '*') ? 1 : -1;
X v->a = 0;
X v->b = -1;
X s += 2;
X } else {
X a = mathevalarg(s,&s);
X if (a > 0) a--;
X if (*s == ',' || *s == Comma) {
X s++;
X b = mathevalarg(s,&s);
X if (b > 0) b--;
X } else
X b = a;
X if (*s == ']') {
X s++;
X if (v->isarr && a == b)
X v->isarr = 0;
X v->a = a;
X v->b = b;
X } else
X s = olds;
X }
X }
X }
X if (!bracks && *s)
X return NULL;
X *pptr = s;
X return v;
X}
X
Xchar *getstrvalue(v) /**/
XValue v;
X{
Xchar *s,**ss;
Xstatic char buf[20];
X
X if (!v)
X return "";
X if (pmtype(v->pm) != PMFLAG_A) {
X if ((pmtype(v->pm) == PMFLAG_i))
X convbase(s = buf,v->pm->gets.ifn(v->pm),v->pm->ct);
X else
X s = v->pm->gets.cfn(v->pm);
X if (v->a == 0 && v->b == -1) return s;
X if (v->a < 0) v->a += strlen(s);
X if (v->b < 0) v->b += strlen(s);
X s = (v->a > strlen(s)) ? strdup("") : strdup(s+v->a);
X if (v->b < v->a) s[0] = '\0';
X else if (v->b-v->a < strlen(s)) s[v->b-v->a+1] = '\0';
X return s;
X }
X if (v->isarr) return spacejoin(v->pm->gets.afn(v->pm));
X
X ss = v->pm->gets.afn(v->pm);
X if (v->a < 0) v->a += arrlen(ss);
X s = (v->a >= arrlen(ss) || v->a < 0) ? "" : ss[v->a];
X return s;
X}
X
Xchar **getarrvalue(v) /**/
XValue v;
X{
Xchar **s;
Xstatic char *nular[] = { "", NULL };
X
X if (!v)
X return arrdup(nular);
X s = v->pm->gets.afn(v->pm);
X if (v->a == 0 && v->b == -1) return s;
X if (v->a < 0) v->a += arrlen(s);
X if (v->b < 0) v->b += arrlen(s);
X if (v->a > arrlen(s) || v->a < 0)
X s = arrdup(nular);
X else
X s = arrdup(s)+v->a;
X if (v->b < v->a) s[0] = NULL;
X else if (v->b-v->a < arrlen(s)) s[v->b-v->a+1] = NULL;
X return s;
X}
X
Xlong getintvalue(v) /**/
XValue v;
X{
Xchar **ss;
X
X if (!v || v->isarr)
X return 0;
X if (pmtype(v->pm) != PMFLAG_A) {
X if (pmtype(v->pm) == PMFLAG_i)
X return v->pm->gets.ifn(v->pm);
X return atol(v->pm->gets.cfn(v->pm));
X }
X ss = v->pm->gets.afn(v->pm);
X if (v->a < 0) v->a += arrlen(ss);
X if (v->a < 0 || v->a >= arrlen(ss)) return 0;
X return atol(ss[v->a]);
X}
X
Xvoid setstrvalue(v,val) /**/
XValue v;char *val;
X{
X if (v->pm->flags & PMFLAG_r) {
X free(val);
X return;
X }
X if (v->pm->env)
X v->pm->env = replenv(v->pm->env,val);
X else if (isset(ALLEXPORT)) {
X v->pm->flags |= PMFLAG_x;
X v->pm->env = addenv(v->pm->nam,val);
X }
X switch (pmtype(v->pm)) {
X case PMFLAG_s:
X if (v->a == 0 && v->b == -1)
X (v->pm->sets.cfn)(v->pm,val);
X else {
X char *z,*y,*x;
X
X z = strdup((v->pm->gets.cfn)(v->pm));
X if (v->a < 0) {
X v->a += strlen(z);
X if (v->a < 0) v->a = 0;
X }
X if (v->a > strlen(z)) v->a = strlen(z);
X if (v->b < 0) v->b += strlen(z);
X if (v->b < v->a) v->b = v->a;
X z[v->a] = '\0';
X y = z+v->b+1;
X x = zalloc(strlen(z)+strlen(y)+strlen(val)+1);
X strcpy(x,z);
X strcat(x,val);
X strcat(x,y);
X (v->pm->sets.cfn)(v->pm,x);
X }
X if (v->pm->flags & (PMFLAG_L|PMFLAG_R|PMFLAG_Z) && !v->pm->ct)
X v->pm->ct = strlen(val);
X break;
X case PMFLAG_i:
X (v->pm->sets.ifn)(v->pm,matheval(val));
X if (!v->pm->ct && lastbase != 1)
X v->pm->ct = lastbase;
X free(val);
X break;
X case PMFLAG_A:
X if (v->a != v->b)
X zerr("illegal array assignment",NULL,0);
X else {
X char **ss = (v->pm->gets.afn)(v->pm);
X int ac,ad,t0;
X
X ac = arrlen(ss);
X if (v->a < 0) {
X v->a += ac;
X if (v->a < 0) v->a = 0;
X }
X if (v->a >= ac) {
X char **st = ss;
X
X ad = v->a+1;
X ss = zalloc((ad+1)*sizeof *ss);
X for (t0 = 0; t0 != ac; t0++)
X ss[t0] = ztrdup(st[t0]);
X while (ac < ad)
X ss[ac++] = ztrdup("");
X ss[ac] = NULL;
X }
X if (ss[v->a]) free(ss[v->a]);
X ss[v->a] = val;
X (v->pm->sets.afn)(v->pm,ss);
X }
X break;
X }
X}
X
Xvoid setintvalue(v,val) /**/
XValue v;long val;
X{
Xchar buf[20];
X
X if (v->pm->flags & PMFLAG_r)
X return;
X sprintf(buf,"%ld",val);
X if (v->pm->env) {
X v->pm->env = replenv(v->pm->env,buf);
X }
X else if (isset(ALLEXPORT)) {
X v->pm->flags |= PMFLAG_x;
X v->pm->env = addenv(v->pm->nam,buf);
X }
X switch (pmtype(v->pm))
X {
X case PMFLAG_s:
X (v->pm->sets.cfn)(v->pm,ztrdup(buf));
X break;
X case PMFLAG_i:
X (v->pm->sets.ifn)(v->pm,val);
X if (!v->pm->ct && lastbase != -1)
X v->pm->ct = lastbase;
X break;
X case PMFLAG_A:
X zerr("attempt to assign integer to array",NULL,0);
X break;
X }
X}
X
Xvoid setintenv(s,val) /**/
Xchar *s; long val;
X{
XParam pm;
Xchar buf[20];
X
X if ((pm = gethnode(s,paramtab)) && pm->env) {
X sprintf(buf,"%ld",val);
X pm->env = replenv(pm->env,buf);
X }
X}
X
Xvoid setarrvalue(v,val) /**/
XValue v;char **val;
X{
X if (v->pm->flags & PMFLAG_r) {
X freearray(val);
X return;
X }
X if (pmtype(v->pm) != PMFLAG_A)
X {
X freearray(val);
X zerr("attempt to assign array value to non-array",NULL,0);
X return;
X }
X if (v->a == 0 && v->b == -1)
X (v->pm->sets.afn)(v->pm,val);
X else {
X char **ss = (v->pm->gets.afn)(v->pm);
X int ac,ad,t0;
X
X ac = arrlen(ss);
X if (v->a < 0) {
X v->a += ac;
X if (v->a < 0) v->a = 0;
X }
X if (v->b < 0) v->b += ac;
X if (v->b < v->a) v->b = v->a;
X t0 = arrlen(val) - (v->b - v->a + 1);
X if (v->b >= ac || t0 != 0) {
X char **st = ss;
X
X ad = (v->b > (ac - 1) ? v->b : (ac - 1)) + t0 + 1;
X ss = zalloc((ad+1)*sizeof *ss);
X for (t0 = 0; t0 < v->a; t0++)
X ss[t0] = ztrdup(t0 < ac ? st[t0] : "");
X while (*val) ss[t0++] = *val++;
X while (++v->b < ac) ss[t0++] = ztrdup(st[v->b]);
X ss[t0] = NULL;
X } else {
X for (t0 = v->a; t0 <= v->b; t0++) {
X if (ss[t0]) free(ss[t0]);
X ss[t0] = val[t0];
X }
X }
X (v->pm->sets.afn)(v->pm,ss);
X }
X}
X
Xint getparamtype(s,l) /**/
Xchar *s;int l;
X{
Xchar sav,*t = s;
XValue v;
X
X sav = t[l];
X t[l] = '\0';
X
X if (!(v = getvalue(&s,0)))
X return -1;
X
X t[l] = sav;
X return (pmtype(v->pm));
X}
X
Xchar *getsparamval(s,l) /**/
Xchar *s;int l;
X{
Xchar sav,*t = s;
XValue v;
X
X sav = t[l];
X t[l] = '\0';
X
X if (!(v = getvalue(&s,0)))
X return NULL;
X t[l] = sav;
X t = getstrvalue(v);
X return t;
X}
X
Xlong getiparam(s) /**/
Xchar *s;
X{
XValue v;
X
X if (!(v = getvalue(&s,0)))
X return 0;
X return getintvalue(v);
X}
X
Xchar *getsparam(s) /**/
Xchar *s;
X{
XValue v;
X
X if (!(v = getvalue(&s,0)))
X return NULL;
X return getstrvalue(v);
X}
X
Xchar **getaparam(s) /**/
Xchar *s;
X{
XValue v;
X
X if (!((v = getvalue(&s,0)) && v->isarr))
X return NULL;
X return getarrvalue(v);
X}
X
XParam setsparam(s,val) /**/
Xchar *s;char *val;
X{
XValue v;
Xchar *t = s;
Xchar *ss;
X
X if (!isident(s)) {
X zerr("not an identifier: %s",s,0);
X free(val);
X return NULL;
X }
X if (ss = strchr(s, '[')) {
X *ss = '\0';
X if (!(v = getvalue(&s,1)))
X createparam(t,zcalloc(sizeof val),PMFLAG_A);
X *ss = '[';
X v = getvalue(&t,1);
X } else {
X if (!(v = getvalue(&s,1)))
X return createparam(t,val,PMFLAG_s);
X if ((v->pm->flags & PMTYPE) != PMFLAG_s &&
X !(v->pm->flags & PMFLAG_SPECIAL)) {
X unsetparam(t);
X return createparam(t,val,PMFLAG_s);
X }
X }
X setstrvalue(v,val);
X return v->pm;
X}
X
XParam setaparam(s,val) /**/
Xchar *s;char **val;
X{
XValue v;
Xchar *t = s;
Xchar *ss;
X
X if (!isident(s))
X {
X zerr("not an identifier: %s",s,0);
X freearray(val);
X return NULL;
X }
X if(ss = strchr(s, '[')) {
X *ss = '\0';
X if (!(v = getvalue(&s,1)))
X createparam(t,zcalloc(sizeof val),PMFLAG_A);
X *ss = '[';
X v = getvalue(&t,1);
X } else {
X if (!(v = getvalue(&s,1)))
X return createparam(t,val,PMFLAG_A);
X if ((v->pm->flags & PMTYPE) != PMFLAG_A &&
X !(v->pm->flags & PMFLAG_SPECIAL)) {
X unsetparam(t);
X return createparam(t,val,PMFLAG_A);
X }
X }
X setarrvalue(v,val);
X return v->pm;
X}
X
XParam setiparam(s,val) /**/
Xchar *s;long val;
X{
XValue v;
Xchar *t = s;
XParam pm;
X
X if (!isident(s))
X {
X zerr("not an identifier: %s",s,0);
X return NULL;
X }
X if (!(v = getvalue(&s,0)))
X {
X pm = createparam(t,NULL,PMFLAG_i);
X pm->u.val = val;
X return pm;
X }
X setintvalue(v,val);
X return v->pm;
X}
X
Xvoid unsetparam(s) /**/
Xchar *s;
X{
XParam pm;
X
X if (!(pm = gethnode(s,paramtab)))
X return;
X if (pm->flags & PMFLAG_r)
X return;
X unsetflag = 1;
X switch (pmtype(pm))
X {
X case 0:
X (pm->sets.cfn)(pm,ztrdup(""));
X break;
X case PMFLAG_i:
X (pm->sets.ifn)(pm,0);
X break;
X case PMFLAG_A:
X (pm->sets.afn)(pm,mkarray(NULL));
X break;
X }
X if (pmtype(pm) == PMFLAG_s && (pm->flags & PMFLAG_x)) {
X delenv(pm->env);
X free(pm->env);
X if (pm->flags & PMFLAG_SPECIAL)
X pm->env = NULL;
X }
X if (!(pm->flags & PMFLAG_SPECIAL))
X freepm(remhnode(s,paramtab));
X unsetflag = 0;
X}
X
Xvoid intsetfn(pm,x) /**/
XParam pm;long x;
X{
X pm->u.val = x;
X}
X
Xlong intgetfn(pm) /**/
XParam pm;
X{
X return pm->u.val;
X}
X
Xvoid strsetfn(pm,x) /**/
XParam pm;char *x;
X{
X if (x)
X {
X if (pm->u.str)
X free(pm->u.str);
X pm->u.str = x;
X }
X}
X
Xchar *strgetfn(pm) /**/
XParam pm;
X{
X return pm->u.str;
X}
X
Xvoid nullsetfn(pm,x) /**/
XParam pm; char *x;
X{
X free(x);
X}
X
Xvoid arrsetfn(pm,x) /**/
XParam pm;char **x;
X{
Xint ct;
X
X if (x)
X {
X if (pm->u.arr && pm->u.arr != x)
X freearray(pm->u.arr);
X pm->u.arr = x;
X for (ct = 0; *x; x++,ct++);
X pm->ct = ct;
X }
X}
X
Xchar **arrgetfn(pm) /**/
XParam pm;
X{
X return pm->u.arr;
X}
X
Xvoid intvarsetfn(pm,x) /**/
XParam pm;long x;
X{
X *((long *) pm->data) = x;
X}
X
Xlong intvargetfn(pm) /**/
XParam pm;
X{
X return *((long *) pm->data);
X}
X
Xvoid strvarsetfn(pm,x) /**/
XParam pm;char *x;
X{
Xchar **q = ((char **) pm->data);
X
X if (*q) free(*q);
X *q = x;
X}
X
Xvoid strvarnonullsetfn(pm,x) /**/
XParam pm;char *x;
X{
Xchar **q = ((char **) pm->data);
X
X if (*q) free(*q);
X *q = (x) ? x : ztrdup("");
X}
X
Xchar *strvargetfn(pm) /**/
XParam pm;
X{
Xchar *s;
X
X s = *((char **) pm->data);
X if (!s) return "";
X return s;
X}
X
Xchar *strconstgetfn(pm) /**/
XParam pm;
X{
X return (char *) pm->data;
X}
X
Xvoid colonarrsetfn(pm,x) /**/
XParam pm;char *x;
X{
Xchar **s,**t,*u,*up;
X
X s = colonsplit(x);
X free(x);
X if (pm->data != &fignore)
X for (t = s; *t; t++) {
X u = *t;
X if (*u == '~') *u = Tilde;
X if (*u == '=') *u = Equals;
X up = hcalloc(strlen(u)+1);
X strcpy(up,u);
X u = up;
X filesub(&u);
X if (!*u) u = ".";
X free(*t);
X *t = ztrdup(u);
X }
X if (pm->data) {
X freearray(*((char ***) pm->data));
X *((char ***) pm->data) = s;
X if (pm->ename)
X arrfixenv(pm->ename,s);
X } else {
X freearray(path);
X path = s;
X newcmdnamtab();
X arrfixenv("PATH",s);
X }
X}
X
Xchar *colonarrgetfn(pm) /**/
XParam pm;
X{
X if ((char **) pm->data)
X return colonjoin(*(char ***) pm->data);
X else
X return colonjoin(path);
X}
X
Xchar **arrvargetfn(pm) /**/
XParam pm;
X{
X return *((char ***) pm->data);
X}
X
Xvoid arrvarsetfn(pm,x) /**/
XParam pm;char **x;
X{
X if ((*(char ***) pm->data) != x)
X freearray(*(char ***) pm->data);
X *((char ***) pm->data) = x;
X if (pm->ename)
X arrfixenv(pm->ename,x);
X}
X
Xchar **pathgetfn(pm) /**/
XParam pm;
X{
X return path;
X}
X
Xvoid pathsetfn(pm,x) /**/
XParam pm;char **x;
X{
X if (path != x) freearray(path);
X path = x;
X newcmdnamtab();
X arrfixenv("PATH",x);
X}
X
Xvoid hostcmdssetfn(pm,x) /**/
XParam pm;char **x;
X{
X compctl_process(x,CC_HOSTS,NULL);
X freearray(x);
X}
X
Xvoid optcmdssetfn(pm,x) /**/
XParam pm;char **x;
X{
X compctl_process(x,CC_OPTIONS,NULL);
X freearray(x);
X}
X
Xvoid bindcmdssetfn(pm,x) /**/
XParam pm;char **x;
X{
X compctl_process(x,CC_BINDINGS,NULL);
X freearray(x);
X}
X
Xvoid varcmdssetfn(pm,x) /**/
XParam pm;char **x;
X{
X compctl_process(x,CC_VARS,NULL);
X freearray(x);
X}
X
Xchar **nullgetfn(pm) /**/
XParam pm;
X{
Xstatic char *nl = NULL; return &nl;
X}
X
Xvoid unsettablesetfn(pm,x) /**/
XParam pm;char *x;
X{ ; }
X
Xlong poundgetfn(pm) /**/
XParam pm;
X{
X return arrlen(pparams);
X}
X
Xlong randomgetfn(pm) /**/
XParam pm;
X{
X return rand() & 0x7fff;
X}
X
Xvoid randomsetfn(pm,v) /**/
XParam pm;long v;
X{
X srand((unsigned int) v);
X}
X
Xlong secondsgetfn(pm) /**/
XParam pm;
X{
X return time(NULL)-shtimer;
X}
X
Xvoid secondssetfn(pm,x) /**/
XParam pm;long x;
X{
X shtimer = time(NULL)-x;
X}
X
Xlong uidgetfn(pm) /**/
XParam pm;
X{
X return getuid();
X}
X
Xlong gidgetfn(pm) /**/
XParam pm;
X{
X return getegid();
X}
X
Xchar *usernamegetfn(pm) /**/
XParam pm;
X{
Xstruct passwd *pwd;
X
X pwd = getpwuid(getuid());
X return pwd->pw_name;
X}
X
Xchar *hostgetfn(pm) /**/
XParam pm;
X{
Xstatic char hostnam[65];
Xstatic int got = 0;
X
X if (!got)
X {
X gethostname(hostnam,64);
X hostnam[64] = '\0';
X got = 1;
X }
X return hostnam;
X}
X
Xchar *ifsgetfn(pm) /**/
XParam pm;
X{
X return ifs;
X}
X
Xvoid ifssetfn(pm,x) /**/
XParam pm;char *x;
X{
X if (x) { free(ifs); ifs = x; }
X inittyptab();
X}
X
Xvoid histsizesetfn(pm,v) /**/
XParam pm;long v;
X{
X if ((histsiz = v) <= 2) histsiz = 2;
X resizehistents();
X}
X
Xlong histsizegetfn(pm) /**/
XParam pm;
X{
X return histsiz;
X}
X
Xvoid lithistsizesetfn(pm,v) /**/
XParam pm;long v;
X{
X if ((lithistsiz = v) <= 2) lithistsiz = 2;
X resizehistents();
X}
X
Xlong lithistsizegetfn(pm) /**/
XParam pm;
X{
X return lithistsiz;
X}
X
Xvoid mailchecksetfn(pm,x) /**/
XParam pm;long x;
X{
X mailcheck = (unsetflag) ? 600 : x;
X}
X
Xvoid pathasetfn(pm,x) /**/
XParam pm;char **x;
X{
X freearray(path);
X path = x;
X newcmdnamtab();
X}
X
Xchar **pathagetfn(pm) /**/
XParam pm;
X{
X return path;
X}
X
Xlong errnogetfn(pm) /**/
XParam pm;
X{
X return errno;
X}
X
Xchar *dashgetfn(pm) /**/
XParam pm;
X{
Xstatic char buf[100];
Xchar *val;
Xint t0;
X
X for (val = buf, t0 = ' ';t0 <= 'z'; t0++)
X if (isset(t0))
X *val++ = t0;
X *val = '\0';
X return buf;
X}
X
Xvoid histcharssetfn(pm,x) /**/
XParam pm;char *x;
X{
X if (x) {
X bangchar = x[0];
X hatchar = (bangchar) ? x[1] : '\0';
X hashchar = (hatchar) ? x[2] : '\0';
X free(x);
X }
X}
X
Xchar *histcharsgetfn(pm) /**/
XParam pm;
X{
Xstatic char buf[4];
X
X buf[0] = bangchar;
X buf[1] = hatchar;
X buf[2] = hashchar;
X buf[3] = '\0';
X return buf;
X}
X
Xchar *homegetfn(pm) /**/
XParam pm;
X{
X return home;
X}
X
Xvoid homesetfn(pm,x) /**/
XParam pm;char *x;
X{
X free(home);
X if (isset(CHASELINKS) && (home = xsymlink(x))) free(x);
X else home = x;
X}
X
Xchar *wordcharsgetfn(pm) /**/
XParam pm;
X{
X return wordchars;
X}
X
Xvoid wordcharssetfn(pm,x) /**/
XParam pm;char *x;
X{
X free(wordchars);
X if (x) wordchars = x;
X else wordchars = ztrdup(DEFWORDCHARS);
X inittyptab();
X}
X
Xchar *underscoregetfn(pm) /**/
XParam pm;
X{
Xchar *s,*t;
X
X if (!(s = qgetevent(curhist-1)))
X return "";
X for (t = s+strlen(s); t > s; t--)
X if (*t == HISTSPACE)
X break;
X if (t != s)
X t++;
X return t;
X}
X
Xchar *termgetfn(pm) /**/
XParam pm;
X{
X return term;
X}
X
Xvoid termsetfn(pm,x) /**/
XParam pm;char *x;
X{
X if (term) free(term);
X term = x;
X if (!interact || unset(USEZLE))
X return;
X if (tgetent(termbuf,term) != 1)
X {
X zerr("can't find termcap info for %s",term,0);
X errflag = 0;
X termok = 0;
X }
X else
X {
X char tbuf[1024],*pp;
X int t0;
X
X termok = 1;
X for (t0 = 0; t0 != TC_COUNT; t0++)
X {
X pp = tbuf;
X if (tcstr[t0])
X free(tcstr[t0]);
X /* AIX tgetstr() ignores second argument */
X if (!(pp = tgetstr(tccapnams[t0],&pp)))
X tcstr[t0] = NULL, tclen[t0] = 0;
X else
X {
X tcstr[t0] = zalloc(tclen[t0] = strlen(pp)+1);
X memcpy(tcstr[t0],pp,tclen[t0]);
X }
X }
X
X/* if there's no termcap entry for cursor left, use \b. */
X
X if (!tccan(TCLEFT))
X {
X tcstr[TCLEFT] = ztrdup("\b");
X tclen[TCLEFT] = 1;
X }
X
X/* if there's no termcap entry for clear, use ^L. */
X
X if (!tccan(TCCLEARSCREEN))
X {
X tcstr[TCCLEARSCREEN] = ztrdup("\14");
X tclen[TCCLEARSCREEN] = 1;
X }
X
X/* if the termcap entry for down is \n, don't use it. */
X
X if (tccan(TCDOWN) && tcstr[TCDOWN][0] == '\n')
X {
X tclen[TCDOWN] = 0;
X free(tcstr[TCDOWN]);
X tcstr[TCDOWN] = NULL;
X }
X
X/* if there's no termcap entry for cursor up, forget it.
X Use single line mode. */
X
X if (!tccan(TCUP))
X termok = 0;
X }
X}
X
Xvoid setparams() /**/
X{
Xchar **envp,**envp2,**envp3,*str;
Xchar buf[50];
Xstruct param *pm;
Xint ct;
X
X noerrs = 1;
X for (envp = environ, ct = 2; *envp; envp++,ct++);
X envp = environ;
X envp2 = envp3 = (char **) zalloc(sizeof(char *)*ct);
X for (; *envp; envp++)
X *envp2++ = ztrdup(*envp);
X *envp2 = NULL;
X envp = environ;
X environ = envp2 = envp3;
X for (; *envp; envp++,envp2++) {
X for (str = *envp; *str && *str != '='; str++);
X if (*str == '=') {
X char *iname = NULL;
X
X *str = '\0';
X pm = (isident(*envp) && !strchr(*envp, '[')) ?
X setsparam(iname = *envp,ztrdup(str+1)) : NULL;
X if (pm) {
X pm->flags |= PMFLAG_x;
X pm->env = *envp2;
X if (pm->flags & PMFLAG_SPECIAL)
X pm->env = replenv(pm->env,getsparam(iname));
X }
X *str = '=';
X }
X }
X pm = gethnode("HOME",paramtab);
X if (!(pm->flags & PMFLAG_x)) {
X pm->flags |= PMFLAG_x;
X pm->env = addenv("HOME",home);
X }
X pm = gethnode("PWD",paramtab);
X if (!(pm->flags & PMFLAG_x)) {
X pm->flags |= PMFLAG_x;
X pm->env = addenv("PWD",pwd);
X }
X pm = gethnode("LOGNAME",paramtab);
X if (!(pm->flags & PMFLAG_x)) {
X pm->flags |= PMFLAG_x;
X pm->env = addenv("LOGNAME",logname);
X }
X pm = gethnode("SHLVL",paramtab);
X if (!(pm->flags & PMFLAG_x))
X pm->flags |= PMFLAG_x;
X sprintf(buf,"%d",++shlvl);
X pm->env = addenv("SHLVL",buf);
X noerrs = 0;
X}
X
Xchar *mkenvstr(x,y) /**/
Xchar *x;char *y;
X{
Xchar *z;
Xint xl = strlen(x),yl = strlen(y);
X
X z = zalloc(xl+yl+2);
X strcpy(z,x);
X z[xl] = '=';
X strcpy(z+xl+1,y);
X z[xl+yl+1] = '\0';
X return z;
X}
X
Xvoid arrfixenv(s,t) /**/
Xchar *s;char **t;
X{
Xchar **ep;
Xint sl = strlen(s);
X
X for (ep = environ; *ep; ep++)
X if (!strncmp(*ep,s,sl) && (*ep)[sl] == '=') {
X char *u = colonjoin(t);
X replenv(*ep,u);
X break;
X }
X}
X
Xchar *replenv(e,value) /**/
Xchar *e;char *value;
X{
Xchar **ep;
X
X for (ep = environ; *ep; ep++)
X if (*ep == e)
X {
X char *s = e;
X
X while (*s++ != '=');
X *s = '\0';
X *ep = zalloc(strlen(e)+strlen(value)+2);
X strcpy(*ep,e);
X strcat(*ep,value);
X free(e);
X return *ep;
X }
X return NULL;
X}
X
Xchar *addenv(name,value) /**/
Xchar *name;char *value;
X{
Xchar **ep,**ep2,**ep3;
Xint envct;
X
X for (ep = environ; *ep; ep++)
X {
X char *s = *ep,*t = name;
X
X while (*s && *s == *t) s++,t++;
X if (*s == '=' && !*t)
X {
X free(*ep);
X return *ep = mkenvstr(name,value);
X }
X }
X envct = arrlen(environ);
X ep = ep2 = (char **) zalloc((sizeof (char *))*(envct+3));
X for (ep3 = environ; *ep2 = *ep3; ep3++,ep2++);
X *ep2 = mkenvstr(name,value);
X ep2[1] = NULL;
X free(environ);
X environ = ep;
X return *ep2;
X}
X
Xvoid delenv(x) /**/
Xchar *x;
X{
Xchar **ep;
X
X ep = environ;
X for (; *ep; ep++)
X if (*ep == x)
X break;
X if (*ep)
X for (; ep[0] = ep[1]; ep++);
X}
X
Xvoid convbase(s,v,base) /**/
Xchar *s;long v;int base;
X{
Xint digs = 0;
Xlong x;
X
X if (base <= 1)
X base = 10;
X x = v;
X if (x < 0)
X {
X x = -x;
X digs++;
X }
X for (; x; digs++)
X x /= base;
X if (!digs)
X digs = 1;
X s[digs--] = '\0';
X x = (v < 0) ? -v : v;
X while (digs >= 0)
X {
X int dig = x%base;
X s[digs--] = (dig < 10) ? '0'+dig : dig-10+'A';
X x /= base;
X }
X if (v < 0)
X s[0] = '-';
X}
END_OF_FILE
if test 26353 -ne `wc -c <'src/params.c'`; then
echo shar: \"'src/params.c'\" unpacked with wrong size!
fi
# end of 'src/params.c'
fi
echo shar: End of archive 1 \(of 22\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 22 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0

exit 0 # Just in case...

The Zsh Mailing List

unread,
Feb 20, 1993, 4:19:44 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 52
Archive-name: zsh/part02

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: doc/intro.troff.01 dots/zshrc
# Wrapped by mattson@odin on Sat Feb 6 14:41:51 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 2 (of 22)."'
if test -f 'doc/intro.troff.01' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'doc/intro.troff.01'\"
else
echo shar: Extracting \"'doc/intro.troff.01'\" \(49835 characters\)
sed "s/^X//" >'doc/intro.troff.01' <<'END_OF_FILE'
X.nr PI 0
X.nr HM .5i
X.nr FM .5i
X.de Ds
X.DS L
X.ft C
X..
X.de De
X.DE
X\fR
X..
X.de DZ
X.DE
X\fR
X..
X.TL
XAn Introduction to the Z Shell
X.AU
XPaul Falstad
X...@ttisms.com
X.PP
X\fBzsh\fR is a shell designed for interactive use, although it
Xis also a powerful scripting language. Many of the useful
Xfeatures of bash, ksh, and tcsh were incorporated into zsh;
Xmany original features were added.
XThis document details some of the unique features of zsh.
XIt assumes basic knowledge of the standard UNIX shells;
Xthe intent is to show a reader already familiar with one of the
Xother major shells what makes zsh more useful or more powerful.
XThis document is not at all comprehensive; read the manual entry
Xfor a description of the shell that is
Xcomplete and concise,
Xalthough somewhat overwhelming and devoid of examples.
X.SH
XFilename Generation
X.PP
XOtherwise known as \fIglobbing\fR, filename generation
Xis quite extensive in zsh. Of course, it has all the
Xbasics:
X.Ds
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.DZ
XAlso, if the \fIEXTENDEDGLOB\fR option is set,
Xsome new features are activated.
XFor example, the \fC^\fR character negates the pattern following it:
X.Ds
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.DZ
XAn expression of the form
X\fC<\fIx\fR\-\fIy\fC>\fR
Xmatches a range of integers:
X.Ds
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.DZ
XGrouping is possible:
X.Ds
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.DZ
XAlso, the string \fC**/\fR forces a recursive search of
Xsubdirectories:
X.Ds
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.De
X.PP
XIt is possible to exclude certain files from the patterns using
Xthe ~ character. A pattern of the form \fC*.c~bar.c\fP lists all
Xfiles matching \fC*.c\fP, except for the file \fCbar.c\fP.
X.Ds
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.De
X.PP
XOne can add a number of \fIqualifiers\fR to the end of
Xany of these patterns, to restrict matches to certain
Xfile types. A qualified pattern is of the form
X.DS
X\fIpattern\fC(\fR...\fC)\fR
X.De
Xwith single-letter qualifiers inside the parentheses.
X.Ds
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.DZ
XNote that \fC*(x)\fR and \fC*(*)\fR both match executables.
X\fC*(X)\fR matches files executable by others, as opposed to
X\fC*(x)\fR, which matches files executable by the owner.
X\fC*(R)\fR and \fC*(r)\fR match readable files;
X\fC*(W)\fR and \fC*(w)\fR, which checks for writable files.
X\fC*(W)\fR is especially important, since it checks for world-writable
Xfiles:
X.Ds
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.DZ
XYou can filter out the symbolic links with the \fC^\fR character:
X.Ds
X% l *(W^@)
Xrun240
X% l *(x)
Xfoo* link@ morestuff/ stuff/
X% l *(x^@/)
Xfoo*
X.DZ
XTo find all plain files, you can use \fC.\fR:
X.Ds
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.DZ
X\fC*(U)\fR matches all files owned by you.
XTo search for all files not owned by you, use \fC*(^U)\fR:
X.Ds
X% l -l *(^U)
X-rw------- 1 subbarao 29 May 23 18:13 sub
X.DZ
XThis searches for setuid files:
X.Ds
X% l -l *(s)
X-rwsr-xr-x 1 pfalstad 16 May 23 18:12 foo*
X.DZ
XThis checks for a certain user's files:
X.Ds
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.De
X.SH
XStartup Files
X.PP
XThere are five startup files that zsh will read commands from:
X.Ds
X$ZDOTDIR/.zshenv
X$ZDOTDIR/.zprofile
X$ZDOTDIR/.zshrc
X$ZDOTDIR/.zlogin
X$ZDOTDIR/.zlogout
X.DZ
XIf \fBZDOTDIR\fR is not set, then the value of \fBHOME\fR is used;
Xthis is the usual case.
X.\".KE <--- missing .KS or .KF above
X.PP
X\&\fC.zshenv\fR is sourced on all invocations of the shell,
Xunless the \fC-f\fR option is set. It should contain commands to set
Xthe command search path, plus other important environment
Xvariables.
X\&\fC.zshenv\fR should not contain commands that produce output
Xor assume the shell is attached to a tty.
X.PP
X\&\fC.zshrc\fR is sourced in interactive shells. It should contain
Xcommands to set up aliases, functions, options, key bindings, etc.
X.PP
X\&\fC.zlogin\fR is sourced in login shells. It should contain
Xcommands that should be executed only in login shells.
X\&\fC.zlogout\fR is sourced when login shells exit.
X\&\fC.zprofile\fR is similar to \fC.zlogin\fR, except that it is sourced before
X\&\fC.zshrc\fR.
X\&\fC.zprofile\fR is meant as an alternative to \fC.zlogin\fR for
Xksh fans;
Xthe two are not intended to be used together, although this
Xcould certainly be done if desired.
X\&\fC.zlogin\fR is not the place for alias definitions, options, environment
Xvariable settings, etc.;
Xas a general rule, it should not change the shell environment
Xat all. Rather, it should be used to set the terminal type
Xand run a series of external commands (\fCfortune\fR, \fCmsgs\fR, etc).
X.SH
XShell Functions
X.PP
Xzsh also allows you to create your own commands by defining shell
Xfunctions. For example:
X.Ds
X% yp () {
X> ypmatch $1 passwd.byname
X> }
X% yp pfalstad
Xpfalstad:*:3564:35:Paul John Falstad:/u/pfalstad:/usr/princeton/bin/zsh
X.DZ
XThis function looks up a user in the NIS password map.
XThe \fC$1\fR expands to the first argument to \fCyp\fR.
XThe function could have been equivalently defined in one of the following
Xways:
X.Ds
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.DZ
XNote that aliases are expanded when the function definition is
Xparsed, not when the function is executed. For example:
X.Ds
X% alias ypmatch=echo
X% yp pfalstad
Xpfalstad:*:3564:35:Paul John Falstad:/u/pfalstad:/usr/princeton/bin/zsh
X.DZ
XSince the alias was defined after the function was parsed, it has
Xno effect on the function's execution.
XHowever, if we define the function again with the alias in place:
X.Ds
X% function yp () { ypmatch $1 passwd.byname }
X% yp pfalstad
Xpfalstad passwd.byname
X.DZ
Xit is parsed with the new alias definition in place.
XTherefore, in general you must define aliases before functions.
X.\".KE <--- missing .KS or .KF above
X.PP
XWe can make the function take multiple arguments:
X.Ds
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.DZ
XThe \fCfor i\fR loops through each of the function's arguments,
Xsetting \fCi\fR equal to each of them in turn.
XWe can also make the function do something sensible
Xif no arguments are given:
X.Ds
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.DZ
X\fC$#\fR is the number of arguments supplied to the function.
XIf it is equal to zero, we print a usage message; otherwise,
Xwe loop through the arguments, and \fCypmatch\fR all of them.
X.\".KE <--- missing .KS or .KF above
X.PP
XHere's a function that selects a random line from a file:
X.Ds
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.De
X\fCrandline\fR has a local variable, \fCz\fR, that holds the number of
Xlines in the file. \fC$[RANDOM % z + 1]\fR expands to a random number
Xbetween 1 and \fCz\fR. An expression of the form \fC$[\fR...\fC]\fR
Xexpands to the value of the arithmetic expression within the brackets,
Xand the \fBRANDOM\fR variable returns a random number each time it
Xis referenced. \fC%\fR is the modulus operator, as in C.
XTherefore, \fCsed -n $[RANDOM%z+1]p\fR picks a random line from its
Xinput, from 1 to \fCz\fR.
X.PP
XFunction definitions can be viewed with the \fCfunctions\fR builtin:
X.Ds
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.DZ
XHere's another one:
X.Ds
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.DZ
XNote that this could also have been implemented as an alias:
X.Ds
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.De
X.PP
XInstead of defining a lot of functions in your \fC.zshrc\fR,
Xall of which you may not use,
Xit is often better to use the \fCautoload\fR builtin.
XThe idea is, you create a directory where function
Xdefinitions are stored, declare the names in
Xyour \fC.zshrc\fR, and tell the shell where to look for them.
XWhenever you reference a function, the shell
Xwill automatically load it into memory.
X.Ds
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.De
XThis idea has other benefits. By adding a \fC#!\fR header
Xto the files, you can make them double as shell scripts.
X(Although it is faster to use them as functions, since a
Xseparate process is not created.)
X.Ds
X% ed /tmp/funs/yp
X25
Xi
X#! /usr/local/bin/zsh
X.
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.De
XNow other people, who may not use zsh, or who don't want to
Xcopy all of your \fC.zshrc\fR, may use these functions as shell
Xscripts.
X.SH
XDirectories
X.PP
XOne nice feature of zsh is the way it prints directories.
XFor example, if we set the prompt like this:
X.Ds
Xphoenix% PROMPT='%~> '
X~> cd src
X~/src>
X.De
Xthe shell will print the current directory in the prompt,
Xusing the \fC~\fR character.
XHowever, zsh is smarter than most other shells in this respect:
X.Ds
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.De
XNote that zsh prints \fIother\fR users' directories
Xin the form \fC~user\fR. Also note that you can
Xset a parameter and use it as a directory name;
Xzsh will act as if \fCfoo\fR is a user
Xwith the login directory \fC/usr/princeton/common/src\fR.
XThis is convenient, especially if you're sick of seeing
Xprompts like this:
X.Ds
Xphoenix:/usr/princeton/common/src/X.V11R4/contrib/clients/xv/docs>
X.DZ
XIf you get stuck in this position, you can give the current
Xdirectory a short name, like this:
X.Ds
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.De
XWhen you reference a directory in the form \fC~inews\fR,
Xthe shell assumes that you want the directory displayed
Xin this form; thus simply typing \fCecho ~inews\fR or
X\fCcd ~inews\fR causes the prompt to be shortened.
XYou can define a shell function for this purpose:
X.Ds
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.De
XYou may want to add this one-line function to your \fC.zshrc\fR.
X
Xzsh can also put the current directory in your title bar,
Xif you are using a windowing system.
XOne way to do this is with the \fCchpwd\fR function, which is
Xautomatically executed by the shell whenever you change
Xdirectory. If you are using xterm, this will work:
X.Ds
Xchpwd () { print -Pn '^[]2;%~^G' }
X.De
XThe \fC-P\fR option tells \fCprint\fR to treat its arguments like a prompt
Xstring; otherwise the \fC%~\fR would not be expanded.
XThe \fC-n\fR option suppresses the terminating newline, as with \fCecho\fR.
X.PP
XIf you are using an IRIS \fCwsh\fR, do this:
X.Ds
Xchpwd () { print -Pn '^[P1.y%~^[\' }
X.DZ
XThe \fCprint -D\fR command has other uses. For example, to
Xprint the current directory to standard output in short form,
Xyou can do this:
X.Ds
X% print -D $PWD
X~subbarao/src
X.DZ
Xand to print each component of the path in short form:
X.Ds
X% print -D $path
X/bin /usr/bin ~locbin ~locbin/X11 ~/bin
X.De
X.SH
XDirectory Stacks
X.PP
XIf you use csh, you may know about directory stacks.
XThe \fCpushd\fR command puts the current directory on the
Xstack, and changes to a new directory; the \fCpopd\fR command
Xpops a directory off the stack and changes to it.
X.Ds
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.De
Xzsh's directory stack commands work similarly. One
Xdifference is the way \fCpushd\fR is handled if no arguments
Xare given. As in csh, this exchanges the top two elements
Xof the directory stack:
X.Ds
XZ /tmp> dirs
X/tmp ~
XZ /tmp> pushd
X~ /tmp
X.DZ
Xunless the stack only has one entry:
X.Ds
XZ ~> popd
X/tmp
XZ /tmp> dirs
X/tmp
XZ /tmp> pushd
X~ /tmp
X.DZ
Xor unless the \fIPUSHDTOHOME\fR option is set:
X.Ds
XZ ~> setopt pushdtohome
XZ ~> pushd
X~ ~ /tmp
X.De
X.PP
XAs an alternative to using directory stacks in this manner,
Xwe can get something like a \fIdirectory history\fR
Xby setting a few more options and parameters:
X.Ds
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.De
XNote that \fC=2\fR expanded to the second directory in the
Xhistory list, and that \fCcd -3\fR recalled the third
Xdirectory in the list.
X.PP
XYou may be wondering what all those options do.
X\fIAUTOPUSHD\fR made \fCcd\fR act like \fCpushd\fR.
X(\fCalias cd=pushd\fR is not sufficient, for various reasons.)
X\fIPUSHDMINUS\fR swapped the meaning of \fCcd +1\fR and
X\fCcd -1\fR; we want them to mean the opposite of what they mean in csh,
Xbecause it makes more sense in this scheme, and it's easier to type:
X.Ds
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.De
X\fIPUSHDSILENT\fR keeps the shell from printing
Xthe directory stack each time we do a \fCcd\fR,
Xand \fIPUSHDTOHOME\fR we mentioned earlier:
X.Ds
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.DZ
X\fBDIRSTACKSIZE\fR keeps the directory stack
Xfrom getting too large, much like \fIHISTSIZE\fR:
X.Ds
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.De
X.SH
XCommand/Process Substitution
X.PP
XCommand substitution in zsh can take two forms.
XIn the traditional form, a command enclosed in
Xbackquotes (\fC`\fR...\fC`\fR) is replaced on the command line with its output.
XThis is the form used by the older shells.
XNewer shells (like zsh) also provide another form,
X\fC$(\fR...\fC)\fR. This form is much easier to nest.
X.Ds
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.DZ
XMany common uses of command substitution, however, are
Xsuperseded by other mechanisms of zsh:
X.Ds
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.DZ
XA command name with a \fC=\fR prepended is replaced with its full
Xpathname. This can be very convenient. If it's not convenient
Xfor you, you can turn it off:
X.Ds
X% ls
X=foo =bar
X% ls =foo =bar
Xzsh: foo not found
X% setopt noequals
X% ls =foo =bar
X=foo =bar
X.De
X.PP
XAnother nice feature is process substitution:
X.Ds
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.De
XA command of the form \fC=(\fR...\fC)\fR is replaced with the name of a \fIfile\fR
Xcontaining its output. (A command substitution, on the other
Xhand, is replaced with the output itself.)
X\fCprint -l\fR is like \fCecho\fR, excepts that it prints its arguments
Xone per line, the way \fCfgrep\fR expects them:
X.Ds
X% print -l foo bar
Xfoo
Xbar
X.DZ
XWe could also have written:
X.Ds
X% who | fgrep -f =(echo 'root
X> lemke
X> shgchan
X> subbarao')
X.DZ
XUsing process substitution,
Xyou can edit the output of a command:
X.Ds
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.DZ
Xor easily read archived mail:
X.Ds
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.DZ
XNote that the shell creates a temporary file, and deletes it
Xwhen the command is finished.
X.Ds
X% diff =(ls) =(ls -F)
X3c3
X< fortune
X---
X> fortune*
X10c10
X< strfile
X---
X> strfile*
X.De
XIf you read zsh's man page, you may notice that \fC<(\fR...\fC)\fR
Xis another form of process substitution which is similar to
X\fC=(\fR...\fC)\fR.
XThere is an important difference between the two.
XIn the \fC<(\fR...\fC)\fR case, the shell creates a named pipe (FIFO)
Xinstead of a file. This is better, since it does not
Xfill up the file system; but it does not work in all cases.
XIn fact, if we had replaced \fC=(\fR...\fC)\fR with \fC<(\fR...\fC)\fR in
Xthe examples above, all of them would have stopped working
Xexcept for \fCfgrep -f <(\fR...\fC)\fR.
XYou can not edit a pipe, or open it as a mail folder;
X\fCfgrep\fR, however, has no problem with reading
Xa list of words from a pipe.
XYou may wonder why \fCdiff <(foo) bar\fR doesn't work, since
X\fCfoo | diff - bar\fR works; this is because \fCdiff\fR creates
Xa temporary file if it notices that one of its arguments
Xis \fC-\fR, and then copies its standard input to the temporary
Xfile.
X.SH
XAliasing
X.PP
XOften-used commands can be abbreviated with an alias:
X.Ds
X% alias uc=uncompress
X% ls
Xhanoi.Z
X% uc hanoi
X% ls
Xhanoi
X.DZ
Xor commands with certain desired options:
X.Ds
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\fR...
X.DZ
XAliases can also be used to replace old commands:
X.Ds
X% alias grep=egrep ps=sps make=gmake
X% alias whoami='echo root'
X% whoami
Xroot
X.DZ
Xor to define new ones:
X.Ds
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.De
X(The pattern \fC*(R)\fR matches all readable files in the current
Xdirectory, and \fC*(^R)\fR matches all unreadable files.)
X.PP
XMost other shells have aliases of this kind (\fIcommand\fR aliases).
XHowever, zsh also has \fIglobal\fR aliases, which are substituted
Xanywhere on a line.
XGlobal aliases can be used to abbreviate frequently-typed
Xusernames, hostnames, etc.
X.Ds
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.DZ
XHere are some more interesting uses.
X.Ds
X% alias -g M='| more' GF='| fgrep -f ~/.friends'
X% who M # \fIpipes the output of \fCwho\fI through \fCmore
X% who GF # \fIsee if your friends are on\fC
X% w GF # \fIsee what your friends are doing
X.DZ
XAnother example makes use of zsh's process substitution.
XIf you run NIS, and you miss being able to do this:
X.Ds
X% grep pfalstad /etc/passwd
X.DZ
Xyou can define an alias that will seem more natural
Xthan \fCypmatch pfalstad passwd\fR:
X.Ds
X% alias -g PASS='<(ypcat passwd)'
X% grep pfalstad PASS
Xpfalstad:*:3564:35:Paul John Falstad:/u/pfalstad:/usr/princeton/bin/zsh
X.DZ
XIf you're really crazy, you can even call it \fC/etc/passwd\fR:
X.Ds
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.De
XThe last example shows one of the perils of global aliases;
Xthey have a lot of potential to cause confusion.
XFor example, if you defined a global alias called \fC|\fR (which is
Xpossible), zsh would begin to act very strangely; every pipe
Xsymbol would be replaced with the text of your alias.
XTo some extent, global aliases are like macros in C;
Xdiscretion is advised in using them and in choosing names for them.
XUsing names in all caps is not a bad idea, especially
Xfor aliases which introduce shell metasyntax (like \fCM\fR and \fCGF\fR
Xabove).
X.PP
XNote that zsh aliases are not like csh aliases. The syntax for
Xdefining them is different, and they do not have arguments.
XAll your favorite csh aliases will probably not work under zsh.
XFor example, if you try:
X.Ds
Xalias rm mv '\e!* /tmp/wastebasket'
X.De
Xno aliases will be defined, but zsh will not report an error.
XIn csh, this line defines an alias that makes \fCrm\fR safe---files
Xthat are \fCrm\fR'd will be moved to a temporary directory instead
Xof instantly destroyed. In zsh's syntax, however, this line
Xasks the shell to print any existing alias definitions for \fCrm\fR, \fCmv\fR,
Xor \fC!* /tmp/wastebasket\fR. Since there are none, most likely,
Xthe shell will not print anything, although \fCalias\fR will
Xreturn a nonzero exit code.
XThe proper syntax is this:
X.Ds
Xalias rm='mv \e!* /tmp/wastebasket'
X.DZ
XHowever, this won't work either:
X.Ds
X% rm foo.dvi
Xzsh: no matches found: !*
X.DZ
XWhile this makes \fCrm\fR safe, it is certainly not what the user
Xintended. In zsh, you must use a shell function for this:
X.Ds
X% unalias rm
X% rm () { mv $* /tmp/wastebasket }
X% rm foo.dvi
X% ls /tmp/wastebasket
Xfoo.dvi
X.DZ
XWhile this is much cleaner and easier to read (I hope you will
Xagree), it is not csh-compatible. Therefore, a script to convert
Xcsh aliases and variables has been provided. You should only need to use it
Xonce, to convert all your csh aliases and parameters to zsh format:
X.Ds
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.De
XThe first two aliases were converted to regular zsh aliases, while
Xthe third, since it needed to handle arguments, was converted to
Xa function. \fCc2z\fR can convert most aliases to zsh format without
Xany problems. However, if you're using some really arcane csh tricks,
Xor if you have an alias with a name like \fCdo\fR (which is reserved
Xin zsh), you may have to fix some of the aliases by hand.
X.PP
XThe \fCc2z\fP script checks your csh setup, and produces a list
Xof zsh commands which replicate your aliases and parameter settings
Xas closely as possible. You could include its output in your
Xstartup file, \fC.zshrc\fP.
X.SH
XHistory
X.PP
XThere are several ways to manipulate history in zsh.
XOne way is to use csh-style \fC!\fR history:
X.Ds
X% /usr/local/bin/!:0 !-2*:s/foo/bar/ >>!$
X.De
XIf you don't want to use this, you can turn it off
Xby typing \fCsetopt nobanghist\fR.
X.PP
XAnother way is to use the \fCfc\fR command. For example,
Xif you type an erroneous command:
X.Ds
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\fR...
X.DZ
Xtyping \fCfc\fR will execute an editor on this command, allowing
Xyou to fix it. (The default editor is \fCvi\fR, by the way,
Xnot \fCed\fR).
X.Ds
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\fR...
X.DZ
XA variant of the \fCfc\fR command is \fCr\fR, which redoes the last
Xcommand, with optional changes:
X.Ds
X% echo foo
Xfoo
X% r
Xecho foo
Xfoo
X
X% echo foo
Xfoo
X% r foo=bar
Xecho bar
Xbar
X.De
X.SH
XCommand Line Editing
X.PP
Xzsh's command line editor, \fBZLE\fP, is quite powerful.
XIt is designed to emulate either emacs or vi; the default
Xis emacs. To set the bindings for vi mode, type \fCbindkey -v\fR.
X.PP
XIn addition to basic editing, the shell allows you to
Xrecall previous lines in the history. In emacs mode,
Xthis is done with \fI^P\fP (control-P):
X.Ds
X% ls ~
X- README file mail pub tmp
XMailboxes bin func nicecolors scr zsh
XNews etc iris notes src
X% echo foobar
Xfoobar
X% \fI^P\fC
X% echo foobar\fI^P\fC
X% ls ~_
X.De
XPressing \fI^P\fP once brings up the previous line (\fCecho foobar\fR);
Xpressing it again brings up the line before that (\fCls ~\fR).
XThe cursor is left at the end of the line, allowing you to
Xedit the line if desired before executing it.
XIn many cases, \fBZLE\fP eliminates the need for the \fCfc\fR command,
Xsince it is powerful enough to handle even multiline commands:
X.Ds
X% for i in a b c d e
X> do
X> echo $i
X> done
Xa
Xb
Xc
Xd
Xe
X% \fI^P\fC
X% for i in a b c d e
X do
X echo $i
X done_
X.DZ
XNow you can just move up to the part you want to change...
X.Ds
X% for i in \kxa\l'|\nxu\(ul' b c d e
X do
X echo $i
X done
X.DZ
Xchange it, and execute the new command.
X.Ds
X% for i in f g h i j
X do
X echo $i
X done
Xf
Xg
Xh
Xi
Xj
X.DZ
XAlso, you can search the history for a certain command using
X\fIESC-P\fR:
X.Ds
X% set \fIESC-P\fC
X% setopt autolist \fIESC-P\fC
X% setopt nocorrect_
X.DZ
XAnother way is to do an incremental search, emacs-style:
X.Ds
X% \fI^R\fC
X% _
Xi-search:
X
X% l\kxs\l'|\nxu\(ul' /usr/bin
Xi-search: l
X
X% date > foofile\kx.\l'|\nxu\(ul'c
Xi-search: le
X.DZ
XAnother useful feature of the editor is command and filename completion.
X.Ds
X% comp\fITAB\fC
X% compress _
X
X% ls /nic\fITAB\fC
X% ls /nicecolors _
X
X% ls /usr/pr\fITAB\fC
X% ls /usr/princeton/_
X
X% ls -l =com\fITAB\fC
X% ls -l =compress _
X.DZ
XIf the completion is ambiguous, the editor will beep.
XYou can list possible completions by pressing \fI^D\fP:
X.Ds
X% ls /vmu\fITAB \(embeep\(em\fC
X% ls /vmunix_
X% ls /vmunix\fI^D\fC
Xvmunix vmunix.old
Xvmunix.new.kernelmap.old vmunix.org
X.DZ
XOr, you could just set the \fIAUTOLIST\fR option:
X.Ds
X% setopt autolist
X% ls /vmu\fITAB \(embeep\(em\fC
Xvmunix vmunix.old
Xvmunix.new.kernelmap.old vmunix.org
X% ls /vmunix_
X.De
XAnother option you could set is \fIRECEXACT\fR, which causes
Xexact matches to be accepted, even if there are other possible
Xcompletions:
X.Ds
X% setopt recexact
X% ls /vmu\fITAB \(embeep\(em\fC
Xvmunix vmunix.old
Xvmunix.new.kernelmap.old vmunix.org
X% ls /vmunix_\fITAB\fC
X% ls /vmunix _
X.DZ
XThe \fIfignore\fR variable lists suffixes of files to ignore
Xduring completion.
X.Ds
X% ls foo\fITAB \(embeep\(em\fC
Xfoofile.c foofile.o
X% fignore=( .o \e~ .bak .junk )
X% ls foo\fITAB\fP
X% ls foofile.c _
X.De
XSince \fCfoofile.o\fR has a suffix that is in the \fCfignore\fR list,
Xit was not considered a possible completion of \fCfoo\fR.
X.PP
XUsername completion is also supported:
X.Ds
X% ls ~pfal\fITAB\fC
X% ls ~pfalstad/_
X.DZ
Xand parameter name completion:
X.Ds
X% echo $ORG\fITAB\fC
X% echo $ORGANIZATION _
X.DZ
Xand hostname completion, if you give the shell a list of hosts to
Xcomplete:
X.Ds
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 disk\fITAB\fC
X% telnet diskfarm.princeton.edu _
X
X% ftp uu\fITAB\fC
X% ftp uunet.uu.net _
X
X% mail subbarao@ph\fITAB\fC
X% mail subb...@phoenix.princeton.edu _
X.DZ
Xand option completion:
X.Ds
X% setopt nocl\fITAB\fC
X% setopt noclobber _
X.DZ
Xand binding completion:
X.Ds
X% bindkey '^X^X' pu\fITAB\fC
X% bindkey '^X^X' push-line _
X.De
X.PP
XThe \fCcompctl\fP command is used to control how completion works.
XFor example, to specify that certain commands show take
Xcommands as arguments, you use \fCcompctl -c\fP:
X.Ds
X% compctl -c man nohup
X% man upt\fITAB\fC
X% man uptime _
X.De
XTo specify that a command should complete filenames, you should use
X\fCcompctl -f\fP. This is the default. It can be combined with \fC-c\fP,
Xas well.
X.Ds
X% compctl -cf echo
X% echo upt\fITAB\fC
X% echo uptime _
X
X% echo fo\fITAB\fC
X% echo foo.c
X.De
XSimilarly, use \fC-h\fP to specify hostnames, \fC-o\fP to specify
Xoptions, \fC-v\fP to specify variables, and \fC-b\fP to specify bindings.
X.Ds
X% compctl -h rlogin
X% compctl -hfc rsh
X% compctl -b bindkey
X.De
XYou can also use \fC-k\fP to specify a custom list of keywords to use
Xin completion.
X.Ds
X% ftphosts=(ftp.uu.net wuarchive.wustl.edu)
X% compctl -k ftphosts ftp
X% ftp wu\fITAB\fC
X% ftp wuarchive.wustl.edu _
X
X% friends=(cpirazzi subbarao sukthnkr)
X% compctl -k friends mail finger su
X% finger cp\fITAB\fC
X% finger cpirazzi _
X.De
X.PP
XIn addition to completion, \fITAB\fP performs expansion
Xif possible.
X.Ds
X% ls *.c\fITAB\fC
X% ls foofile.c fortune.c rnd.c strfile.c unstr.c_
X.DZ
XFor example, suppose you have a bunch of weird files in an important
Xdirectory:
X.Ds
X% ls
X * * * ; & % $??foo dspfok foo.c
X !"foo"! ` \e ` foo rrr
X.DZ
XYou want to remove them, but you don't want to damage \fCfoo.c\fR.
XHere is one way to do this:
X.Ds
X% rm *\fITAB\fC
X% rm \e \e \e*\e \e*\e \e*\e \e \e \e!\e"foo\e"\e! \e;\e \e&\e %\e \e$'
X''
X'foo \e`\e \e\e\e \e` dspfok foo foo.c rrr_
X.DZ
XWhen you expand \fC*\fR, zsh inserts the names of all the files
Xinto the editing buffer, with proper shell quoting.
XNow, just move back and remove \fCfoo.c\fR from the buffer:
X.Ds
X% rm \e \e \e*\e \e*\e \e*\e \e \e \e!\e"foo\e"\e! \e;\e \e&\e %\e \e$'
X''
X'foo \e`\e \e\e\e \e` dspfok foo \kxr\l'|\nxu\(ul'rr
X.De
Xand press return.
XEverything except \fCfoo.c\fR will be deleted from the directory.
X.PP
XHere's another trick; let's say you have typed this command in:
X.Ds
X% gcc -o x.out foob.c -g -Wpointer-arith -Wtrigraphs_
X.De
Xand you forget which library you want. You need to escape
Xout for a minute and check by typing
X\fCls /usr/lib\fR, or some other such command;
Xbut you don't want to retype the whole command again,
Xand you can't press return now because the current command
Xis incomplete.
XIn zsh, you can put the line on the \fIbuffer stack\fR, using
X\fIESC-Q\fP, and type some other commands. The next time a prompt is printed,
Xthe \fCgcc\fR line will be popped off the stack and put
Xin the editing buffer automatically; you can then enter the
Xproper library name and press return (or, \fIESC-Q\fP again and look
Xfor some other libraries whose names you forgot).
X.PP
XA similar situation: what if you forget the option to gcc that
Xfinds bugs using AI techniques? You could either use \fIESC-Q\fP
Xagain, and type \fCman gcc\fR, or you could press \fIESC-H\fR, which
Xessentially does the same thing; it puts the current line on
Xthe buffer stack, and executes the command \fCrun-help gcc\fR,
Xwhere \fCrun-help\fR is an alias for \fCman\fR.
X.PP
XAnother interesting command is \fIESC-A\fR. This executes the
Xcurrent line, but retains it in the buffer, so that it appears
Xagain when the next prompt is printed.
XAlso, the cursor stays in the same place.
XThis is useful for executing a series of similar commands:
X.Ds
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.De
X.PP
XThe \fIESC-'\fR command is useful for managing the shell's quoting
Xconventions. Let's say you want to print this string:
X.Ds
Xdon't do that; type 'rm -rf \e*', with a \e before the *.
X.DZ
XAll that is necessary is to type it into the editing buffer:
X.Ds
X% don't do that; type 'rm -rf \e*', with a \e before the *.
X.DZ
Xpress \fIESC-'\fR (escape-quote):
X.Ds
X% 'don'\e''t do that; type '\e''rm -rf \e*'\e'', with a \e before the *.'
X.DZ
Xthen move to the beginning and add the \fCecho\fR command.
X.Ds
X% echo 'don'\e''t do that; type '\e''rm -rf \e*'\e'', with a \e before the *.'
Xdon't do that; type 'rm -rf \e*', with a \e before the *.
X.DZ
XLet's say you want to create an alias to do this \fCecho\fR command.
XThis can be done by recalling the line with \fI^P\fP and pressing \fIESC-'\fR again:
X.Ds
X% 'echo '\e''don'\e''\e'\e'''\e''t do that; type '\e''\e'\e'''\e''rm -rf
X\e*'\e''\e'\e'''\e'', with a \e before the *.'\e'''
X.DZ
Xand then move to the beginning and add the command to create
Xan alias.
X.Ds
X% alias zoof='echo '\e''don'\e''\e'\e'''\e''t do that; type '\e''\e'\e'''\e''rm
X-rf \e*'\e''\e'\e'''\e'', with a \e before the *.'\e'''
X% zoof
Xdon't do that; type 'rm -rf \e*', with a \e before the *.
X.De
X.PP
XAnother interesting option is \fIMENUCOMPLETE\fR. This affects the
Xway \fITAB\fP works. Let's look at the \fC/vmunix\fR example again:
X.Ds
X% setopt menucomplete
X% ls /vmu\fITAB\fC
X% ls /vmunix\fITAB\fC
X% ls /vmunix.new.kernelmap.old\fITAB\fC
X% ls /vmunix.old_
X.De
XEach time you press \fITAB\fP, it displays the next possible completion.
XIn this way, you can cycle through the possible completions until
Xyou find the one you want.
X.PP
XThe \fIAUTOMENU\fR option makes
Xa nice compromise between this method of completion and the regular
Xmethod. If you set this option, pressing the \fITAB\fP key repeatedly
Xafter an ambiguous completion will cycle through the possible
Xcompletions.
X.SH
XBindings
X.PP
XEach of the above editor commands was actually a function bound
Xby default to a certain key. The real names of the commands are:
X.Ds
X\fCexpand-or-complete \fITAB\fR
X\fCpush-line \fIESC-Q\fR
X\fCrun-help \fIESC-H\fR
X\fCaccept-and-hold \fIESC-A\fR
X\fCquote-line \fIESC-'\fR
X.DZ
XThese bindings are arbitrary; you could change them if you want.
XFor example, to bind \fCaccept-line\fR to \fI^Z\fP:
X.Ds
X% bindkey '^Z' accept-line
X.DZ
XAnother idea would be to bind the delete key to \fCdelete-char\fR;
Xthis might be convenient if you use \fI^H\fP for backspace.
X.Ds
X% bindkey '^?' delete-char
X.DZ
XOr, you could bind \fI^X\fP\fI^H\fP to \fCrun-help\fR:
X.Ds
X% bindkey '^X^H' run-help
X.DZ
XOther examples:
X.Ds
X% bindkey '^X^Z' universal-argument
X% bindkey ' ' magic-space
X% bindkey -s '^T' 'uptime
X> '
X.De
X\fCuniversal-argument\fR multiplies the next command by 4.
XThus \fI^X\fP\fI^Z\fP\fI^W\fP might delete the last four words on the line.
XIf you bind space to \fCmagic-space\fR, then csh-style history
Xexpansion is done on the line whenever you press the space bar.
X.PP
XThe \fC-s\fR flag to \fCbindkey\fR specifies that you are binding the key
Xto a string, not a command. Thus \fCbindkey -s '^T' 'uptime\en'\fR
Xlets you VMS lovers get the load average whenever you press \fI^T\fP.
X.PP
XIf you have a NeXT keyboard, the one with the \fC|\fR and \fC\e\fR keys
Xvery inconveniently placed, the following
Xbindings may come in handy:
X.Ds
X% bindkey -s '\ee/' '\e\e'
X% bindkey -s '\ee=' '|'
X.De
XNow you can type \fIALT-/\fP to get a backslash, and \fIALT-=\fP to
Xget a vertical bar. This only works inside zsh, of course;
X\fCbindkey\fR has no effect on the key mappings inside \fCtalk\fR
Xor \fCmail\fR, etc.
X.PP
XAnother use of the editor is to edit the value of variables.
XFor example, an easy way to change your path is to use
Xthe \fCvared\fR command:
X.Ds
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.De
XYou can now edit the path. When you press return, the contents
Xof the edit buffer will be assigned to \fBPATH\fR.
X.SH
XParameter Substitution
X.PP
XIn zsh, parameters are set like this:
X.Ds
X% foo=bar
X% echo $foo
Xbar
X.DZ
XSpaces before or after the \fC=\fR are frowned upon:
X.Ds
X% foo = bar
Xzsh: command not found: foo
X.DZ
XAlso, \fCset\fR doesn't work for setting parameters:
X.Ds
X% set foo=bar
X% set foo = bar
X% echo $foo
X
X%
X.De
XNote that no error message was printed. This is because both
Xof these commands were perfectly valid; the \fCset\fR builtin
Xassigns its arguments to the \fIpositional parameters\fR
X(\fC$1\fR, \fC$2\fR, etc.).
X.Ds
X% set foo=bar
X% echo $1
Xfoo=bar
X% set foo = bar
X% echo $3 $2
Xbar =
X.DZ
XIf you're really intent on using the csh syntax, define a
Xfunction like this:
X.Ds
X% set () {
X> eval "$1$2$3"
X> }
X% set foo = bar
X% set fuu=brrr
X% echo $foo $fuu
Xbar brrr
X.De
XBut then, of course you can't use the form of \fCset\fR with
Xoptions, like \fCset -F\fR (which turns off filename generation).
XAlso, the \fCset\fR command by itself won't list all the parameters
Xlike it should.
XTo get around that you need a \fCcase\fR statement:
X.Ds
X% set () {
X> case $1 in
X> -*|+*|'') builtin set $* ;;
X> *) eval "$1$2$3" ;;
X> esac
X> }
X.De
XFor the most part, this should make csh users happy.
X.PP
XThe following sh-style operators are supported in zsh:
X.Ds
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.DZ
XAlso, csh-style \fC:\fR modifiers may be appended to a parameter
Xsubstitution.
X.Ds
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.De
XThe equivalent constructs in ksh (which are also supported in zsh)
Xare a bit more general and easier to remember.
XWhen the shell expands \fC${foo#\fR\fIpat\fR\fC}\fR,
Xit checks to see if \fIpat\fR matches a substring at the beginning
Xof the value
Xof \fCfoo\fR. If so, it removes that portion of \fCfoo\fR, using the shortest
Xpossible match.
XWith \fC${foo##\fR\fIpat\fR\fC}\fR, the longest possible match is removed.
X\fC${foo%\fR\fIpat\fR\fC}\fR and \fC${foo%%\fR\fIpat\fR\fC}\fR remove the match
Xfrom the end.
XHere are the ksh equivalents of the \fC:\fR modifiers:
X.Ds
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.DZ
Xzsh also has upper/lowercase modifiers:
X.Ds
X% xx=Test
X% echo $xx:u
XTEST
X% echo $xx:l
Xtest
X.DZ
Xand a substitution modifier:
X.Ds
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.DZ
XOne possible source of confusion is the fact that in zsh,
Xthe result of parameter substitution is \fInot\fR split into
Xwords. Thus, this will not work:
X.Ds
X% srcs='glob.c exec.c init.c'
X% ls $srcs
Xglob.c exec.c init.c not found
X.DZ
XThis is considered a feature, not a bug.
XIf splitting were done by default, as it is in most other shells,
Xfunctions like this would not work properly:
X.Ds
X$ ll () { ls -F $* }
X$ ll 'fuu bar'
Xfuu not found
Xbar not found
X
X% ll 'fuu bar'
Xfuu bar not found
X.DZ
XOf course, a hackish workaround is available in sh (and zsh):
X.Ds
X% setopt shwordsplit
X% ll () { ls -F "$@" }
X% ll 'fuu bar'
Xfuu bar not found
X.DZ
XIf you like the sh behaviour, zsh can accomodate you:
X.Ds
X% ls ${=srcs}
Xexec.c glob.c init.c
X% setopt shwordsplit
X% ls $srcs
Xexec.c glob.c init.c
X.DZ
XAnother way to get the \fC$srcs\fR trick to work is to use an array:
X.Ds
X% unset srcs
X% srcs=( glob.c exec.c init.c )
X% ls $srcs
Xexec.c glob.c init.c
X.DZ
Xor an alias:
X.Ds
X% alias -g SRCS='exec.c glob.c init.c'
X% ls SRCS
Xexec.c glob.c init.c
X.DZ
XAnother option that modifies parameter expansion is
X\fIRCEXPANDPARAM\fR:
X.Ds
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.De
X.SH
XShell Parameters
X.PP
XThe shell has many predefined parameters that may be
Xaccessed. Here are some examples:
X.Ds
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.DZ
X(\fC$?\fR and \fC$status\fR are equivalent.)
X.Ds
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.DZ
X\fC~+\fR and \fC~-\fR are short for \fC$PWD\fR and \fC$OLDPWD\fR, respectively.
X.Ds
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.De
X.PP
XThe \fCcdpath\fR variable sets the search path for the \fCcd\fR command.
XIf you do not specify \fC.\fR somewhere in the path, it is assumed to
Xbe the first component.
X.Ds
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.DZ
X\fBPATH\fR and \fBpath\fR both set the search path for commands.
XThese two variables are equivalent, except that one is a string
Xand one is an array. If the user modifies \fBPATH\fR, the shell
Xchanges \fBpath\fR as well, and vice versa.
X.Ds
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.DZ
XThe same is true of \fBCDPATH\fR and \fBcdpath\fR:
X.Ds
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.DZ
END_OF_FILE
if test 49835 -ne `wc -c <'doc/intro.troff.01'`; then
echo shar: \"'doc/intro.troff.01'\" unpacked with wrong size!
fi
# end of 'doc/intro.troff.01'
fi
if test -f 'dots/zshrc' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dots/zshrc'\"
else
echo shar: Extracting \"'dots/zshrc'\" \(2291 characters\)
sed "s/^X//" >'dots/zshrc' <<'END_OF_FILE'
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-=' \|
END_OF_FILE
if test 2291 -ne `wc -c <'dots/zshrc'`; then
echo shar: \"'dots/zshrc'\" unpacked with wrong size!
fi
# end of 'dots/zshrc'
fi
echo shar: End of archive 2 \(of 22\).
cp /dev/null ark2isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:20:32 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 53
Archive-name: zsh/part03

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: doc/intro.txt.01 help/autoload src/Makefile.sample
# Wrapped by mattson@odin on Sat Feb 6 14:41:51 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 3 (of 22)."'
if test -f 'doc/intro.txt.01' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'doc/intro.txt.01'\"
else
echo shar: Extracting \"'doc/intro.txt.01'\" \(49646 characters\)
sed "s/^X//" >'doc/intro.txt.01' <<'END_OF_FILE'
X
X
X
X
X
X
X An Introduction to the Z Shell
X
X
X Paul Falstad
X p...@ttisms.com
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
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
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
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
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% telnet diskTAB

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
END_OF_FILE
if test 49646 -ne `wc -c <'doc/intro.txt.01'`; then
echo shar: \"'doc/intro.txt.01'\" unpacked with wrong size!
fi
# end of 'doc/intro.txt.01'
fi
if test -f 'help/autoload' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/autoload'\"
else
echo shar: Extracting \"'help/autoload'\" \(274 characters\)
sed "s/^X//" >'help/autoload' <<'END_OF_FILE'
X autoload [ name ... ]
X For each of the names (which are names of functions),
X create a function marked undefined. The fpath variable
X will be searched to find the actual function definition
X when the function is first referenced.
END_OF_FILE
if test 274 -ne `wc -c <'help/autoload'`; then
echo shar: \"'help/autoload'\" unpacked with wrong size!
fi
# end of 'help/autoload'
fi
if test -f 'src/Makefile.sample' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/Makefile.sample'\"
else
echo shar: Extracting \"'src/Makefile.sample'\" \(1851 characters\)
sed "s/^X//" >'src/Makefile.sample' <<'END_OF_FILE'
X#! /bin/make -f
X# Makefile for zsh
X# generated by buildzsh
X
XAUX=buildzsh
X
XSRC=builtin.c cond.c exec.c glob.c hist.c init.c jobs.c lex.c loop.c \
Xmath.c mem.c params.c parse.c subst.c table.c text.c utils.c watch.c \
Xzle_bindings.c zle_hist.c zle_main.c zle_misc.c zle_move.c zle_refresh.c \
Xzle_tricky.c zle_utils.c zle_vi.c zle_word.c
X
XHEADER=funcs.h zle.h zsh.h ztype.h
X
XPROTO=builtin.pro cond.pro exec.pro glob.pro hist.pro init.pro jobs.pro \
Xlex.pro loop.pro math.pro mem.pro params.pro parse.pro subst.pro table.pro \
Xtext.pro utils.pro watch.pro zle_bindings.pro zle_hist.pro zle_main.pro \
Xzle_misc.pro zle_move.pro zle_refresh.pro zle_tricky.pro zle_utils.pro \
Xzle_vi.pro zle_word.pro
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
XDFLAGS = # -DQDEBUG
X
X# For gcc 2.3.3
X# CC=gcc -fpcc-struct-return
X# CFLAGS= -O2 -g -Wall -Wno-implicit -Wno-parentheses -Wno-comment $(DFLAGS)
X
XCC=cc
XCFLAGS= -O
XLIBS= -ltermcap
X
XZSHPATH=zsh
X
X.SUFFIXES: .c .o .pro
X
X.c.o:
X $(CC) $(CFLAGS) $(DFLAGS) -c $<
X
X.c.pro:
X sed -n '/\/\*\*\/$$/{N;s/^\([^(]*\).*\/\*\*\/.\(.*\)/\1 DCLPROTO((\2))/p;}' $< | sed -e 's/;/,/g' -e 's/,))$$/));/' -e 's/(({))$$/((void));/' >$@
X
Xall: $(PROTO) $(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
Xparams.o: version.h
X
Xclean:
X rm -f *.o *.pro zsh core
X
Xcleanall:
X rm -f *.o *.pro 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)
END_OF_FILE
if test 1851 -ne `wc -c <'src/Makefile.sample'`; then
echo shar: \"'src/Makefile.sample'\" unpacked with wrong size!
fi
# end of 'src/Makefile.sample'
fi
echo shar: End of archive 3 \(of 22\).
cp /dev/null ark3isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:21:02 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 54
Archive-name: zsh/part04

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: FEATURES doc/zsh.texi.02
# Wrapped by mattson@odin on Sat Feb 6 14:41:51 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 4 (of 22)."'
if test -f 'FEATURES' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'FEATURES'\"
else
echo shar: Extracting \"'FEATURES'\" \(2684 characters\)
sed "s/^X//" >'FEATURES' <<'END_OF_FILE'
Xvery close to ksh/sh grammar, with csh additions
Xmost features of ksh, bash, and tcsh
X75 builtins, 80 options, 149 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
END_OF_FILE
if test 2684 -ne `wc -c <'FEATURES'`; then
echo shar: \"'FEATURES'\" unpacked with wrong size!
fi
# end of 'FEATURES'
fi
if test -f 'doc/zsh.texi.02' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'doc/zsh.texi.02'\"
else
echo shar: Extracting \"'doc/zsh.texi.02'\" \(49503 characters\)
sed "s/^X//" >'doc/zsh.texi.02' <<'END_OF_FILE'
Xassociativity of expressions in C. The following operators are
Xsupported (listed in decreasing order of precedence):
X
X@table @code
X@item + - ! ~ ++ --
Xunary plus/minus, logical NOT, complement, @{pre,post@}@{in,de@}crement
X@item &
Xlogical AND
X@item ^
Xlogical XOR
X@item |
Xlogical OR
X@item * / %
Xmultiplication, division, remainder
X@item + -
Xaddition, subtraction
X@item << >>
Xlogical shift left, shift right
X@item < > <= >=
Xcomparison
X@item == !=
Xequality and inequality
X@item &&
Xboolean AND
X@item || ^^
Xboolean OR, XOR
X@item ? :
Xternary operator
X@item = += -= *= /= %= &= ^= |= <<= >>= &&= ||= ^^=
Xassignment
X@item ,
Xcomma operator
X@end table
X
X@noindent
XThe operators @code{&&}, @code{||}, @code{&&=}, and @code{||=} are
Xshort-circuiting, and only one of the latter two expressions in a
Xternary operator is evaluated. Note the precedence of the logical AND,
XOR, and XOR operators.@refill
X
X@noindent
XNamed parameters can be referenced by name within an arithmetic
Xexpression without using the parameter substitution syntax.
X
X@cindex parameters, integer
X@cindex integer parameters
X@findex integer, use of
X@noindent
XAn internal integer representation of a named parameter can be specified
Xwith the @code{integer} builtin. Arithmetic evaluation is performed on
Xthe value of each assignment to a named parameter declared integer in
Xthis manner.@refill
X
X@findex let, use of
X@noindent
XSince many of the arithmetic operators require quoting, an alternative
Xform of the @code{let} command is provided. For any command which
Xbegins with a @code{((}, all the characters until a matching @code{))}
Xare treated as a quoted expression. More precisely, @code{(( @dots{} ))} is
Xequivalent to @code{let "@dots{}"}.@refill
X
X@node Conditional Expressions, Zsh Line Editor, Arithmetic Evaluation, Top
X@chapter Conditional Expressions
X@cindex conditional expressions
X@cindex expressions, conditional
X
X@noindent
XA @dfn{conditional expression} is used with the @code{[[} compound
Xcommand to test attributes of files and to compare strings. Each
Xexpression can be constructed from one or more of the following unary or
Xbinary expressions:@refill
X
X@table @code
X@item -a @var{file}
Xtrue if @var{file} exists.
X@item -b @var{file}
Xtrue if @var{file} exists and is a block special file.
X@item -c @var{file}
Xtrue if @var{file} exists and is a character special file.
X@item -d @var{file}
Xtrue if @var{file} exists and is a directory.
X@item -e @var{file}
Xtrue if @var{file} exists.
X@item -f @var{file}
Xtrue if @var{file} exists and is an ordinary file.
X@item -g @var{file}
Xtrue if @var{file} exists and has its setgid bit set.
X@item -h @var{file}
Xtrue if @var{file} exists and is a symbolic link.
X@item -k @var{file}
Xtrue if @var{file} exists and has its sticky bit set.
X@item -n @var{string}
Xtrue if length of @var{string} is non-zero.
X@item -o @var{option}
Xtrue if option named @var{option} is on.
X@item -p @var{file}
Xtrue if @var{file} exists and is a fifo special file or a pipe.
X@item -r @var{file}
Xtrue if @var{file} exists and is readable by current process.
X@item -s @var{file}
Xtrue if @var{file} exists and has size greater than zero.
X@item -t @var{fd}
Xtrue if file descriptor number @var{fd} is open and associated with a
Xterminal device (note: @var{fd} is not optional).@refill
X@item -u @var{file}
Xtrue if @var{file} exists and has its setuid bit set.
X@item -w @var{file}
Xtrue if @var{file} exists and is writable by current process.
X@item -x @var{file}
Xtrue if @var{file} exists and is executable by current process. If
X@var{file} exists and is a directory, then the current process has
Xpermission to search in the directory.@refill
X@item -z @var{string}
Xtrue if length of @var{string} is zero.
X@item -L @var{file}
Xtrue if @var{file} exists and is a symbolic link.
X@item -O @var{file}
Xtrue if @var{file} exists and is owned by the effective user id of this
Xprocess.
X@item -G @var{file}
Xtrue if @var{file} exists and its group matches the effective group id
Xof this process.
X@item -S @var{file}
Xtrue if @var{file} exists and is a socket.
X@item @var{file1} -nt @var{file2}
Xtrue if @var{file1} exists and is newer than @var{file2}.
X@item @var{file1} -ot @var{file2}
Xtrue if @var{file1} exists and is older than @var{file2}.
X@item @var{file1} -ef @var{file2}
Xtrue if @var{file1} and @var{file2} exist and refer to the same file.
X@item @var{string} = @var{pattern}
Xtrue if @var{string} matches @var{pattern}.
X@item @var{string} != @var{pattern}
Xtrue if @var{string} does not match @var{pattern}.
X@item @var{string1} < @var{string2}
Xtrue if @var{string1} comes before @var{string2} based on ASCII value of
Xtheir characters.@refill
X@item @var{string1} > @var{string2}
Xtrue if @var{string1} comes after @var{string2} based on ASCII value of
Xtheir characters.@refill
X@item @var{exp1} -eq @var{exp2}
Xtrue if @var{exp1} is equal to @var{exp2}.
X@item @var{exp1} -ne @var{exp2}
Xtrue if @var{exp1} is not equal to @var{exp2}.
X@item @var{exp1} -lt @var{exp2}
Xtrue if @var{exp1} is less than @var{exp2}.
X@item @var{exp1} -gt @var{exp2}
Xtrue if @var{exp1} is greater than @var{exp2}.
X@item @var{exp1} -le @var{exp2}
Xtrue if @var{exp1} is less than or equal to @var{exp2}.
X@item @var{exp1} -ge @var{exp2}
Xtrue if @var{exp1} is greater than or equal to @var{exp2}.
X@item ( @var{exp} )
Xtrue if @var{exp} is true.
X@item ! @var{exp}
Xtrue if @var{exp} is false.
X@item @var{exp1} && @var{exp2}
Xtrue if @var{exp1} and @var{exp2} are both true.
X@item @var{exp1} || @var{exp2}
Xtrue if either @var{exp1} or @var{exp2} is true.
X@end table
X
X@noindent
XIn each of the above expressions, if @var{file} is of the form
X@samp{/dev/fd/@var{n}}, where @var{n} is an integer, then the test
Xapplied to the open file whose descriptor number is @var{n} , even if
Xthe underlying system does not support the @file{/dev/fd}
Xdirectory.@refill
X
X@node Zsh Line Editor, Parameters, Conditional Expressions, Top
X@chapter Zsh Line Editor
X@cindex line editor
X@cindex editor, line
X
X@pindex ZLE, use of
X@noindent
XIf the @code{ZLE} option is set (it is by default) and the shell input is
Xattached to the terminal, the user is allowed to edit command lines.@refill
X
X@vindex TERM
X@pindex SINGLE_LINE_ZLE, use of
X@cindex ksh, editor mode
X@cindex editor, modes
X@noindent
XThere are two display modes. The first, multiline mode, is the default.
XIt only works if the @code{TERM} parameter is set to a valid terminal
Xtype that can move the cursor up. The second, single line mode, is used
Xif @code{TERM} is invalid or incapable of moving the cursor up, or if the
X@code{SINGLE_LINE_ZLE} option is set. This mode is similar to ksh, and
Xuses no termcap sequences.@refill
X
X@cindex bindings, key
X@cindex key bindings
X@findex bindkey, use of
X@vindex VISUAL
X@vindex EDITOR
X@noindent
XCommand bindings may be set using the @code{bindkey} builtin. There are
Xtwo keymaps---the main keymap and the alternate keymap. The alternate
Xkeymap is bound to @code{vi} command mode. The main keymap is bound to
X@code{emacs} mode by default. To bind the main keymap to @code{vi}
Xinsert mode, use @code{bindkey -v}, or set one of the @code{VISUAL} or
X@code{EDITOR} environment variables to a string containing
X@code{vi}.@refill
X
X@noindent
XThe following is a list of all the key commands and their default
Xbindings in emacs and vi command mode.
X
X@menu
X* Movement::
X* History Control::
X* Modifying Text::
X* Arguments::
X* Completion::
X* Miscellaneous::
X@end menu
X
X@node Movement, History Control, , Zsh Line Editor
X@section Movement
X
X@table @code
X@tindex vi-backward-blank-word
X@kindex B
X@item vi-backward-blank-word (unbound) (B)
XMove backward one word, where a word is defined as a series of non-blank
Xcharacters.
X@tindex backward-char
X@kindex CTRL-B
X@kindex ESC-[D
X@item backward-char (@ctrl{B} @key{ESC}-[D) (unbound)
XMove backward one character.
X@tindex vi-backward-char
X@kindex ESC-B
X@kindex ESC-b
X@item vi-backward-char (unbound) (h)
XMove backward one character, without changing lines.
X@tindex backward-word
X@item backward-word (@key{ESC}-B @key{ESC}-b) (unbound)
XMove to the beginning of the previous word.
X@tindex emacs-backward-word
X@item emacs-backward-word
XMove to the beginning of the previous word.
X@tindex vi-backward-word
X@kindex b
X@item vi-backward-word (unbound) (b)
XMove to the beginning of the previous word, vi-style.
X@tindex beginning-of-line
X@kindex CTRL-A
X@kindex 0
X@item beginning-of-line (@ctrl{A}) (0)
XMove to the beginning of the line. If already at the beginning of the
Xline, move to the beginning of the previous line, if any.
X@tindex vi-beginning-of-line
X@item vi-beginning-of-line
XMove to the beginning of the line, without changing lines.
X@tindex end-of-line
X@kindex CTRL-E
X@item end-of-line (@ctrl{E})
XMove to the end of the line. If already at the end of the line, move to
Xthe end of the next line, if any.
X@tindex vi-end-of-line
X@kindex $
X@item vi-end-of-line (unbound) ($)
XMove to the end of the line.
X@tindex vi-forward-blank-word
X@kindex W
X@item vi-forward-blank-word (unbound) (W)
XMove forward one word, where a word is defined as a series of non-blank
Xcharacters.
X@tindex vi-forward-blank-word-end
X@kindex E
X@item vi-forward-blank-word-end (unbound) (E)
XMove to the end of the current word, or, if at the end of the current
Xword, to the end of the next word, where a word is defined as a series
Xof non-blank characters.
X@tindex forward-char
X@kindex CTRL-F
X@kindex ESC-[C
X@item forward-char (@ctrl{F} @key{ESC}-[C)
XMove forward one character.
X@tindex vi-forward-char
X@kindex l
X@kindex SPACE
X@item vi-forward-char (unbound) (space l)
XMove forward one character.
X@tindex vi-find-next-char
X@kindex CTRL-X CTRL-F
X@kindex f
X@item vi-find-next-char (@ctrl{X}@ctrl{F}) (f)
XRead a character from the keyboard, and move to the next occurrence of
Xit in the line.
X@tindex vi-find-next-char-skip
X@kindex t
X@item vi-find-next-char-skip (unbound) (t)
XRead a character from the keyboard, and move to the position just before
Xthe next occurrence of it in the line.
X@tindex vi-find-prev-char
X@kindex F
X@item vi-find-prev-char (unbound) (F)
XRead a character from the keyboard, and move to the previous occurrence
Xof it in the line.
X@tindex vi-find-prev-char-skip
X@kindex T
X@item vi-find-prev-char-skip (unbound) (T)
XRead a character from the keyboard, and move to the position just after
Xthe previous occurrence of it in the line.
X@tindex vi-first-non-blank
X@kindex ^
X@item vi-first-non-blank (unbound) (^)
XMove to the first non-blank character in the line.
X@tindex vi-forward-word
X@kindex w
X@item vi-forward-word (unbound) (w)
XMove forward one word, vi-style.
X@tindex forward-word
X@kindex ESC-F
X@kindex ESC-f
X@item forward-word (@key{ESC}-F @key{ESC}-f) (unbound)
XMove to the beginning of the next word. The editor's idea of a word is
Xspecified with the @code{WORDCHARS} parameter.
X@tindex emacs-forward-word
X@item emacs-forward-word
XMove to the end of the next word.
X@tindex vi-forward-word-end
X@kindex e
X@item vi-forward-word-end (unbound) (e)
XMove to the end of the next word.
X@tindex vi-goto-column
X@kindex ESC-|
X@kindex |
X@item vi-goto-column (@key{ESC}-|) (|)
XMove to the column specified by the numeric argument.
X@tindex vi-goto-mark
X@kindex `
X@item vi-goto-mark (unbound) (`)
XMove to the specified mark.
X@tindex vi-goto-mark-line
X@kindex '
X@item vi-goto-mark-line (unbound) (')
XMove to beginning of the line containing the specified mark.
X@tindex vi-repeat-find
X@kindex ;
X@item vi-repeat-find (unbound) (;)
XRepeat the last @code{vi-find} command.
X@tindex vi-rev-repeat-find
X@kindex ,
X@item vi-rev-repeat-find (unbound) (,)
XRepeat the last @code{vi-find} command in the opposite direction.
X@end table
X
X@node History Control, Modifying Text, Movement, Zsh Line Editor
X@section History Control
X
X@table @code
X@kindex ESC-<
X@tindex beginning-of-buffer-or-history
X@item beginning-of-buffer-or-history (@key{ESC}-<)
XMove to the beginning of the buffer, or if already there, move to the
Xfirst event in the history list.
X@tindex beginning-of-line-hist
X@item beginning-of-line-hist
XMove to the beginning of the line. If already at the beginning of the
Xbuffer, move to the previous history line.
X@tindex beginning-of-history
X@item beginning-of-history
XMove to the first event in the history list.
X@tindex down-line-or-history
X@kindex CTRL-N
X@kindex ESC-[B
X@kindex +
X@kindex j
X@item down-line-or-history (@ctrl{N} @key{ESC}-[B) (+ j)
XMove down a line in the buffer, or if already at the bottom line, move
Xto the next event in the history list.
X@tindex down-line-or-search
X@item down-line-or-search
XMove down a line in the buffer, or if already at the bottom line,
Xsearch forward in the history for a line beginning with the first
Xword in the buffer.
X@tindex down-history
X@kindex CTRL-N
X@item down-history (unbound) (@ctrl{N})
XMove to the next event in the history list.
X@tindex end-of-buffer-or-history
X@kindex ESC->
X@item end-of-buffer-or-history (@key{ESC}->)
XMove to the end of the buffer, or if already there, move to the last
Xevent in the history list.
X@tindex end-of-line-hist
X@item end-of-line-hist
XMove to the end of the line. If already at the end of the buffer, move
Xto the next history line.
X@tindex end-of-history
X@item end-of-history
XMove to the last event in the history list.
X@tindex vi-fetch-history
X@kindex G
X@item vi-fetch-history (unbound) (G)
XFetch the history line specified by the numeric argument.
X@tindex history-incremental-search-backward
X@kindex CTRL-R
X@kindex CTRL-X r
X@item history-incremental-search-backward (@ctrl{R} @ctrl{X}r)
XSearch backward incrementally for a specified string. The string may
Xbegin with @code{^} to anchor the search to the beginning of the line.
X@tindex history-incremental-search-forward
X@kindex CTRL-S
X@kindex CTRL-X s
X@item history-incremental-search-forward (@ctrl{S} @ctrl{X}s)
XSearch forward incrementally for a specified string. The string may
Xbegin with @code{^} to anchor the search to the beginning of the line.
X@tindex history-search-backward
X@kindex ESC-P
X@kindex ESC-p
X@kindex K
X@item history-search-backward (@key{ESC}-P @key{ESC}-p) (K)
XSearch backward in the history for a line beginning with the first word
Xin the buffer.
X@tindex vi-history-search-backward
X@kindex /
X@item vi-history-search-backward (unbound) (/)
XSearch backward in the history for a specified string. The string may
Xbegin with @code{^} to anchor the search to the beginning of the line.
X@tindex history-search-forward
X@kindex ESC-N
X@kindex ESC-n
X@kindex J
X@item history-search-forward (@key{ESC}-N @key{ESC}-n) (J)
XSearch forward in the history for a line beginning with the first word
Xin the buffer.
X@tindex vi-history-search-forward
X@kindex ?
X@item vi-history-search-forward (unbound) (?)
XSearch forward in the history for a specified string. The string may
Xbegin with @code{^} to anchor the search to the beginning of the line.
X@tindex infer-next-history
X@kindex CTRL-X CTRL-N
X@item infer-next-history (@ctrl{X}@ctrl{N})
XSearch in the history list for a line matching the current one and fetch
Xthe event following it.
X@tindex insert-last-word
X@kindex ESC-_
X@kindex ESC-.
X@item insert-last-word (@key{ESC}-_ @key{ESC}-.)
XInsert the last word from the previous history event at the cursor
Xposition.
X@tindex vi-repeat-search
X@kindex n
X@item vi-repeat-search (unbound) (n)
XRepeat the last vi history search.
X@tindex vi-rev-repeat-search
X@kindex N
X@item vi-rev-repeat-search (unbound) (N)
XRepeat the last vi history
Xsearch, but in reverse.
X@tindex toggle-literal-history
X@pindex HIST_LIT, use of
X@kindex ESC-R
X@kindex ESC-r
X@item toggle-literal-history (@key{ESC}-R @key{ESC}-r)
XToggle between literal and lexical history. The default is lexical
Xhistory unless the @code{HIST_LIT} option is set.
X@kindex CTRL-P
X@kindex ESC-[A
X@kindex -
X@kindex k
X@tindex up-line-or-history
X@item up-line-or-history (@ctrl{P} @key{ESC}-[A) (- k)
XMove up a line in the buffer, or if already at the top line, move to the
Xprevious event in the history list.
X@tindex up-line-or-search
X@item up-line-or-search
XMove up a line in the buffer, or if already at the top line, search
Xbackward in the history for a line beginning with the first word in the
Xbuffer.
X@tindex up-history
X@kindex CTRL-P
X@item up-history (unbound) (@ctrl{P})
XMove to the previous event in the history list.
X@end table
X
X@node Modifying Text, Arguments, History Control, Zsh Line Editor
X@section Modifying Text
X
X@table @code
X@tindex vi-add-eol
X@kindex A
X@item vi-add-eol (unbound) (A)
XMove to the end of the line and enter insert mode.
X@tindex vi-add-next
X@kindex a
X@item vi-add-next (unbound) (a)
XMove forward one character and enter insert mode.
X@tindex backward-delete-char
X@kindex CTRL-H
X@kindex CTRL-?
X@item backward-delete-char (@ctrl{H} @ctrl{?}) (@ctrl{?})
XDelete the character behind the cursor.
X@tindex vi-backward-delete-char
X@kindex X
X@item vi-backward-delete-char (unbound) (X)
XDelete the character behind the cursor, without changing lines.
X@tindex backward-delete-word
X@item backward-delete-word
XDelete the word behind the cursor.
X@tindex backward-kill-line
X@item backward-kill-line
XKill from the beginning of the line to the cursor position.
X@tindex backward-kill-word
X@kindex CTRL-W
X@kindex ESC-CTRL-H
X@kindex ESC-CTRL-?
X@item backward-kill-word (@ctrl{W} @key{ESC}-@ctrl{H} @key{ESC}-@ctrl{?})
XKill the word behind the cursor.
X@tindex vi-backward-kill-word
X@kindex CTRL-W
X@item vi-backward-kill-word (unbound) (@ctrl{W})
XKill the word behind the cursor.
X@tindex capitalize-word
X@kindex ESC-C
X@kindex ESC-c
X@item capitalize-word (@key{ESC}-C @key{ESC}-c)
XCapitalize the current word and move past it.
X@tindex vi-change
X@kindex c
X@item vi-change (unbound) (c)
XRead a movement command from the keyboard, and kill from the cursor
Xposition to the endpoint of the movement. Then enter insert mode. If
Xthe command is @code{vi-change}, kill the current line.
X@tindex vi-change-eol
X@kindex C
X@item vi-change-eol (unbound) (C)
XKill to the end of the line and enter insert mode.
X@tindex vi-change-whole-line
X@kindex S
X@kindex s
X@item vi-change-whole-line (unbound) (S s)
XKill the current line and enter insert mode.
X@tindex copy-region-as-kill
X@kindex ESC-W
X@kindex ESC-w
X@item copy-region-as-kill (@key{ESC}-W @key{ESC}-w)
XCopy the area from the cursor to the mark to the kill buffer.
X@tindex copy-prev-word
X@kindex ESC-CTRL-_
X@item copy-prev-word (@key{ESC}-@ctrl{_})
XDuplicate the word behind the cursor.
X@tindex vi-delete
X@kindex d
X@item vi-delete (unbound) (d)
XRead a movement command from the keyboard, and kill from the cursor
Xposition to the endpoint of the movement. If the command is
X@code{vi-delete}, kill the current line.@refill
X@tindex delete-char
X@kindex x
X@item delete-char (unbound) (x)
XDelete the character under the cursor.
X@tindex vi-delete-char
X@item vi-delete-char (unbound) (x)
XDelete the character under the cursor.
X@tindex delete-word
X@kindex ESC-D
X@kindex ESC-d
X@item delete-word (@key{ESC}-D @key{ESC}-d)
XDelete the current word.
X@tindex down-case-word
X@kindex ESC-L
X@kindex ESC-l
X@item down-case-word (@key{ESC}-L @key{ESC}-l)
XConvert the current word to all lowercase and move past it.
X@tindex kill-word
X@item kill-word
XKill the current word.
X@tindex gosmacs-transpose-chars
X@item gosmacs-transpose-chars
XExchange the two characters behind the cursor.
X@kindex >
X@tindex vi-indent
X@item vi-indent (unbound) (>)
XIndent a number of lines.
X@kindex i
X@tindex vi-insert
X@item vi-insert (unbound) (i)
XEnter insert mode.
X@kindex I
X@tindex vi-insert-bol
X@item vi-insert-bol (unbound) (I)
XMove to the beginning of the line and enter insert mode.
X@tindex vi-join
X@kindex CTRL-X CTRL-J
X@item vi-join (@ctrl{X}@ctrl{J})
XJoin the current line with the next one.
X@tindex kill-line
X@kindex CTRL-K
X@kindex D
X@item kill-line (@ctrl{K}) (D)
XKill from the cursor to the end of the line.
X@tindex kill-region
X@item kill-region
XKill from the cursor to the mark.
X@tindex kill-buffer
X@kindex CTRL-X CTRL-K
X@kindex CTRL-U
X@item kill-buffer (@ctrl{X}@ctrl{K}) (@ctrl{U})
XKill the entire buffer.
X@tindex kill-whole-line
X@kindex CTRL-U
X@item kill-whole-line (@ctrl{U}) (unbound)
XKill the current line.
X@tindex vi-match-bracket
X@kindex CTRL-X CTRL-B
X@kindex %
X@item vi-match-bracket (@ctrl{X}@ctrl{B}) (%)
XMove to the bracket character (one of @code{@{@}}, @code{()}, or
X@code{[]}) that matches the one under the cursor.@refill
X@tindex vi-open-line-above
X@kindex O
X@item vi-open-line-above (unbound) (O)
XOpen a line above the cursor and enter insert mode.
X@tindex vi-open-line-below
X@kindex o
X@item vi-open-line-below (unbound) (o)
XOpen a line below the cursor and enter insert mode.
X@tindex vi-oper-swap-case
X@item vi-oper-swap-case
XRead a movement command from the keyboard, and swap the case of all
Xcharacters from the cursor position to the endpoint of the movement. If
Xthe movement command is @code{vi-oper-swap-case}, swap the case of all
Xcharacters on the current line.@refill
X@tindex overwrite-mode
X@kindex CTRL-X CTRL-O
X@item overwrite-mode (@ctrl{X}@ctrl{O})
XToggle between overwrite mode and insert mode.
X@tindex vi-put-after
X@kindex p
X@item vi-put-after (unbound) (p)
XInsert the contents of the kill buffer after the cursor.
X@tindex quoted-insert
X@kindex CTRL-V
X@item quoted-insert (@ctrl{V})
XInsert the next character typed into the buffer literally.
X@tindex quote-line
X@kindex ESC-'
X@item quote-line (@key{ESC}-')
XQuote the current line; that is, put a @code{'} character at the
Xbeginning and the end, and convert all @code{'} characters to @code{\'} @refill .
X@tindex quote-region
X@kindex ESC-"
X@item quote-region (@key{ESC}-")
XQuote the region from the cursor to the mark.
X@tindex vi-replace
X@kindex R
X@item vi-replace (unbound) (R)
XEnter overwrite mode.
X@tindex vi-repeat-change
X@kindex .
X@item vi-repeat-change (unbound) (.)
XRepeat the last vi mode text modification.
X@tindex vi-replace-chars
X@kindex r
X@item vi-replace-chars (unbound) (r)
XReplace the character under the cursor with a character read from the
Xkeyboard.
X@tindex self-insert
X@item self-insert (printable characters)
XPut a character in the buffer at the cursor position.
X@tindex self-insert-unmeta
X@kindex ESC-CTRL-I
X@kindex ESC-CTRL-J
X@kindex ESC-CTRL-M
X@item self-insert-unmeta (@key{ESC}-@ctrl{I} @key{ESC}-@ctrl{J} @key{ESC}-@ctrl{M})
XPut a character in the buffer after stripping the meta bit and
Xconverting @ctrl{M} to @ctrl{J}.
X@tindex vi-substitute
X@kindex s
X@item vi-substitute (unbound) (s)
XSubstitute the next character(s).
X@tindex vi-swap-case
X@kindex ~
X@item vi-swap-case (unbound) (~)
XSwap the case of the character under the cursor and move past it.
X@tindex transpose-chars
X@kindex CTRL-T
X@item transpose-chars (@ctrl{T})
XExchange the two characters to the left of the cursor if at end of line,
Xelse exchange the character under the cursor with the character to the
Xleft.
X@tindex transpose-words
X@kindex ESC-T
X@kindex ESC-t
X@item transpose-words (@key{ESC}-T @key{ESC}-t)
XExchange the current word with the one before it.
X@tindex vi-unindent
X@kindex <
X@item vi-unindent (unbound) (<)
XUnindent a number of lines.
X@tindex up-case-word
X@kindex ESC-U
X@kindex ESC-u
X@item up-case-word (@key{ESC}-U @key{ESC}-u)
XConvert the current word to all caps and move past it.
X@tindex yank
X@kindex CTRL-Y
X@kindex P
X@item yank (@ctrl{Y}) (P)
XInsert the contents of the kill buffer at the cursor position.
X@tindex yank-pop
X@kindex ESC-y
X@item yank-pop (@key{ESC}-y) (unbound)
XRemove the text just yanked, rotate the kill-ring, and yank the new top.
XOnly works following @code{yank} or @code{yank-pop}.
X@tindex vi-yank
X@kindex y
X@item vi-yank (unbound) (y)
XRead a movement command from the keyboard, and copy the region from the
Xcursor position to the endpoint of the movement into the kill buffer.
XIf the command is @code{vi-yank}, copy the current line.
X@kindex Y
X@tindex vi-yank-eol
X@item vi-yank-eol (unbound) (Y)
XCopy the region from the cursor position to the end of the line into the
Xkill buffer.
X@end table
X
X@node Arguments, Completion, Modifying Text, Zsh Line Editor
X@section Arguments
X
X@table @code
X@tindex digit-argument
X@kindex ESC-0
X@kindex ESC-9
X@kindex 0
X@kindex 9
X@item digit-argument (@key{ESC}-0@dots{}@key{ESC}-9) (0-9)
XStart a new numeric argument, or add to the current one.
X@tindex universal-argument
X@item universal-argument
XMultiply the argument of the next command by 4.
X@end table
X
X@node Completion, Miscellaneous, Arguments, Zsh Line Editor
X@section Completion
X
X@table @code
X@tindex accept-and-menu-complete
X@item accept-and-menu-complete
XIn a menu completion, insert the current completion into the buffer, and
Xadvance to the next possible completion.
X@tindex complete-word
X@kindex \
X@item complete-word (unbound) (\)
XAttempt completion on the current word.
X@tindex delete-char-or-list
X@kindex CTRL-D
X@item delete-char-or-list (@ctrl{D})
XDelete the character under the cursor. If the cursor is at the end of
Xthe line, list possible completions for the current word.
X@tindex execute-named-cmd
X@kindex ESC-x
X@item execute-named-cmd (@key{ESC}-x)
XRead the name of a editor command and execute it.
X@tindex execute-last-named-cmd
X@kindex ESC-z
X@item execute-last-named-cmd (@key{ESC}-z)
XRedo the last function executed
Xwith @code{execute-named-cmd}.
X@tindex expand-cmd-path
X@item expand-cmd-path
XExpand the current command to its full pathname.
X@tindex expand-or-complete
X@kindex TAB
X@kindex CTRL-X
X@item expand-or-complete (@key{TAB}) (@key{TAB} @ctrl{X})
XAttempt shell expansion on the current word. If that fails, attempt
Xcompletion.
X@tindex expand-history
X@kindex ESC-SPACE
X@kindex ESC-!
X@item expand-history (@key{ESC}-@key{SPACE} @key{ESC}-!)
XPerform history expansion on the edit buffer.
X@tindex expand-word
X@kindex CTRL-X *
X@item expand-word (@ctrl{X}*)
XAttempt shell expansion on the current word.
X@tindex list-choices
X@kindex ESC-CTRL-D
X@kindex CTRL-D
X@kindex =
X@item list-choices (@key{ESC}-@ctrl{D}) (@ctrl{D} =)
XList possible completions for the current word.
X@tindex list-expand
X@kindex CTRL-X g
X@kindex CTRL-X G
X@kindex CTRL-G
X@item list-expand (@ctrl{X}g @ctrl{X}G) (@ctrl{G})
XList the expansion of the current word.
X@tindex magic-space
X@item magic-space
XPerform history expansion and insert a space into the buffer. This is
Xintended to be bound to space.
X@tindex menu-complete
X@pindex MENU_COMPLETE, use of
X@item menu-complete
XLike @code{complete-word}, except that menu completion is used.
X@xref{Options}, for the @code{MENU_COMPLETE} option.@refill
X@tindex menu-expand-or-complete
X@item menu-expand-or-complete
XLike @code{expand-or-complete}, except that menu completion is used.
X@tindex reverse-menu-complete
X@item reverse-menu-complete
X@xref{Options}, for the @code{MENU_COMPLETE} option.
X@end table
X
X@node Miscellaneous, , Completion, Zsh Line Editor
X@section Miscellaneous
X
X@table @code
X@tindex accept-and-hold
X@kindex ESC-A
X@kindex ESC-a
X@item accept-and-hold (@key{ESC}-A @key{ESC}-a)
XPush the contents of the buffer on the buffer stack and execute it.
X@tindex accept-and-infer-next-history
X@item accept-and-infer-next-history
XExecute the contents of the buffer. Then search the history list for a
Xline matching the current one and push the event following onto the
Xbuffer stack.
X@tindex accept-line
X@kindex CTRL-J
X@kindex CTRL-M
X@item accept-line (@ctrl{J} @ctrl{M})
XExecute the contents of the buffer.
X@tindex accept-line-and-down-history
X@kindex CTRL-O
X@item accept-line-and-down-history (@ctrl{O})
XExecute the current line, and push the next history event on the the
Xbuffer stack.
X@tindex vi-cmd-mode
X@kindex CTRL-X CTRL-V
X@kindex CTRL-[
X@item vi-cmd-mode (@ctrl{X}@ctrl{V}) (@ctrl{[})
XEnter command mode; that is, use the alternate keymap. Yes, this is
Xbound by default in emacs mode.
X@tindex vi-caps-lock-panic
X@kindex H
X@kindex K
X@item vi-caps-lock-panic (unbound) (H K)
XHang until any lowercase key is pressed. This is for @code{vi} users
Xwithout the mental capacity to keep track of their caps lock key (like
Xthe author).@refill
X@tindex clear-screen
X@kindex CTRL-L
X@kindex ESC-CTRL-L
X@item clear-screen (@ctrl{L} @key{ESC}-@ctrl{L})
XClear the screen and redraw the prompt.
X@tindex exchange-point-and-mark
X@kindex CTRL-X CTRL-X
X@item exchange-point-and-mark (@ctrl{X}@ctrl{X})
XExchange the cursor position with the position of the mark.
X@tindex get-line
X@kindex ESC-G
X@kindex ESC-g
X@item get-line (@key{ESC}-G @key{ESC}-g)
XPop the top line off the buffer stack and insert it at the cursor
Xposition.
X@tindex pound-insert
X@kindex #
X@pindex INTERACTIVE_COMMENTS, use of
X@item pound-insert (unbound) (#)
XIf there is no @code{#} character at the beginning of the current line,
Xadd one. If there is one, remove it. In either case, accept the
Xcurrent line. The @code{INTERACTIVE_COMMENTS} option must be set for
Xthis to have any usefulness.@refill
X@tindex push-line
X@kindex CTRL-Q
X@kindex ESC-Q
X@kindex ESC-q
X@item push-line (@ctrl{Q} @key{ESC}-Q @key{ESC}-q)
XPush the current buffer onto the buffer stack and clear the buffer.
XNext time the editor starts up, the buffer will be popped off the top of
Xthe buffer stack and loaded into the editing buffer.
X@tindex redisplay
X@kindex CTRL-R
X@item redisplay (unbound) (@ctrl{R})
XRedisplays the edit buffer.
X@tindex run-help
X@kindex ESC-H
X@kindex ESC-h
X@item run-help (@key{ESC}-H @key{ESC}-h)
XPush the buffer onto the buffer stack, and execute the command
X@code{run-help @var{cmd}}, where @var{cmd} is the current command.
X@code{run-help} is normally aliased to @code{man}.@refill
X@tindex send-break
X@kindex CTRL-C
X@item send-break (@ctrl{C})
XAbort the parsing of the current line.
X@tindex vi-set-buffer
X@kindex "
X@item vi-set-buffer (unbound) (")
XSpecify a buffer to be used in the following command.
X@tindex vi-set-mark
X@kindex m
X@item vi-set-mark (unbound) (m)
XSet the specified mark at the cursor position.
X@tindex set-mark-command
X@kindex CTRL-@@
X@item set-mark-command (@ctrl{@@})
XSet the mark at the cursor position.
X@tindex spell-word
X@kindex ESC-$
X@kindex ESC-S
X@kindex ESC-s
X@item spell-word (@key{ESC}-$ @key{ESC}-S @key{ESC}-s)
XAttempt spelling correction on the current word.
X@tindex undefined-key
X@item undefined-key
XBeep.
X@tindex undo
X@kindex CTRL-_
X@kindex CTRL-X CTRL-U
X@kindex CTRL-X u
X@kindex u
X@item undo (@ctrl{_} @ctrl{X}@ctrl{U} @ctrl{X}u) (u)
XIncrementally undo the last text modification.
X@tindex which-command
X@kindex ESC-?
X@item which-command (@key{ESC}-?)
XPush the buffer onto the buffer stack, and execute the command
X@code{which-command @var{cmd}}, where @var{cmd} is the current command.
X@code{which-command} is normally aliased to @code{whence}.
X@end table
X
X@node Parameters, Options, Zsh Line Editor, Top
X@chapter Parameters
X@cindex parameters
X
X@findex typeset, use of
X@findex set, use of
X@noindent
XA parameter has a name, a value, and a number of attributes. A name may
Xbe any sequence of alphanumeric characters and @code{_}'s, or the single
Xcharacters @code{*}, @code{@@}, @code{#}, @code{?}, @code{-}, @code{$},
Xor @code{!}. The value may be either a @var{scalar} (a string), an
Xinteger, or an array. To assign a scalar or integer value to a
Xparameter, use the @code{typeset} builtin. To assign an array value,
Xuse @samp{set -A @var{name} @var{value} @dots{}}. The value of a parameter
Xmay also be assigned by writing:@refill
X
X@code{@var{name}=@var{value} @dots{}}
X
X@noindent
XIf the integer attribute, @code{-i}, is set for @var{name}, the
X@var{value} is subject to arithmetic evaluation.@refill
X
X@menu
X* Array Parameters::
X* Positional Parameters::
X* Parameters Set By The Shell::
X* Parameters Used By The Shell::
X@end menu
X
X@node Array Parameters, Positional Parameters, , Parameters
X@section Array Parameters
X
X@noindent
XThe value of an array parameter may be assigned by writing:
X
X@var{name}=(@var{value} @dots{}) @dots{}
X
X@cindex array elements
X@noindent
XIndividual elements of an array may be selected using a subscript. A
Xsubscript of the form @code{[@var{exp}]} selects the single element
X@var{exp}, where @var{exp} is an arithmetic expression. The elements
Xare numbered beginning with 1. A subscript of the form @code{[*]} or
X@code{[@@]} evaluates to all elements of an array; there is no
Xdifference between the two except when they appear within double quotes.
X@samp{$foo[*]} evaluates to @samp{$foo[1] $foo[2] @dots{}}, while
X@samp{$foo[@@]} evaluates to @samp{$foo[1]} @samp{$foo[2]}, etc. A
Xsubscript of the form @code{[@var{exp1},@var{exp2}]} selects all
Xelements in the range @var{exp1} to @var{exp2}, inclusive. If one of
Xthe subscripts evaluates to a negative number, say @code{-@var{n}}, then
Xthe @var{n}th element from the end of the array is used. Thus
X@samp{$foo[-3]} is the third element from the end of the array
X@code{foo}, and @samp{$foo[1,-1]} is the same as @samp{$foo[*]}.@refill
X
X@cindex substrings
X@noindent
XSubscripting may also be performed on non-array values, in which case
Xthe subscripts specify a substring to be extracted. For example, if
X@code{FOO} is set to @code{foobar}, then @code{echo $FOO[2,5]} prints
X@code{ooba}.@refill
X
X@node Positional Parameters, Parameters Set By The Shell, Array Parameters, Parameters
X@section Positional Parameters
X
X@noindent
XPositional parameters are set by the shell on invocation, by the
X@code{set} builtin, or by direct assignment. The parameter @var{n},
Xwhere @var{n} is a number, is the @var{n}th positional parameter. The
Xparameters @code{*}, @code{@@}, and @code{argv} are arrays containing all
Xthe positional parameters; thus @code{argv[@var{n}]}, etc., is equivalent
Xto simply @var{n}.@refill
X
X@node Parameters Set By The Shell, Parameters Used By The Shell, Positional Parameters, Parameters
X@section Parameters Set By The Shell
X
X@noindent
XThe following parameters are automatically set by the shell:
X
X@table @code
X@vindex !
X@item !
XThe process id of the last background command invoked.
X@vindex #
X@item #
XThe number of positional parameters in decimal.
X@vindex ARGC
X@item ARGC
XSame as @code{#}.
X@vindex $
X@item $
XThe process id of this shell.
X@vindex -
X@item -
XFlags supplied to the shell on invocation or by the @code{set} or
X@code{setopt} commands.
X@vindex *
X@item *
XAn array containing the positional parameters.
X@vindex argv
X@item argv
XSame as @code{*}.
X@vindex @@
X@item @@
XSame as @code{argv[@@]}.
X@vindex ?
X@item ?
XThe exit value returned by the last command.
X@vindex status
X@item status
XSame as @code{?}.
X@vindex _
X@item _
XThe last argument of the previous command. Also, this parameter is set
Xin the environment of every command executed to the full pathname of the
Xcommand.
X@vindex ERRNO
X@item ERRNO
XThe value of errno as set by the most recently failed system call. This
Xvalue is system dependent and is intended for debugging purposes.
X@vindex GID
X@item GID
XThe group id of the shell process.
X@vindex HOST
X@item HOST
XThe current hostname.
X@vindex HOSTTYPE
X@item HOSTTYPE
XA string corresponding to the type of the host the shell is running on.
X@vindex LINENO
X@item LINENO
XThe line number of the current line within the current script being
Xexecuted.
X@vindex OLDPWD
X@item OLDPWD
XThe previous working directory.
X@vindex OPTARG
X@item OPTARG
XThe value of the last option argument processed by the @code{getopts}
Xcommand.
X@vindex OPTIND
X@item OPTIND
XThe index of the last option argument processed by the @code{getopts}
Xcommand.
X@vindex PPID
X@item PPID
XThe process id of the parent of the shell.
X@vindex PWD
X@item PWD
XThe present working directory.
X@vindex RANDOM
X@item RANDOM
XA random integer from 0 to 32767, newly generated each time this
Xparameter is referenced. The random number generator can be seeded by
Xassigning a numeric value to @code{RANDOM}.
X@vindex SECONDS
X@item SECONDS
XThe number of seconds since shell invocation. If this parameter is
Xassigned a value, then the value returned upon reference will be the
Xvalue that was assigned plus the number of seconds since the assignment.
X@vindex SHLVL
X@item SHLVL
XIncremented by one each time a new shell is started.
X@vindex signals
X@item signals
XAn array containing the names of the signals.
X@vindex TTY
X@item TTY
XThe name of the tty associated with the shell, if any.
X@vindex UID
X@item UID
XThe user id of the shell process.
X@vindex USERNAME
X@item USERNAME
X@vindex LOGNAME
X@itemx LOGNAME
XThe username corresponding to the user id of the shell process.
X@vindex VERSION
X@item VERSION
XThe version number of this @code{zsh}.
X@end table
X
X@node Parameters Used By The Shell, , Parameters Set By The Shell, Parameters
X@section Parameters Used By The Shell
X
X@noindent
XThe following parameters are used by the shell:
X
X@table @code
X@vindex BAUD
X@item BAUD
XThe baud rate of the current connection. Used by the line editor update
Xmechanism to compensate for a slow terminal by delaying updates until
Xnecessary. This may be profitably set to a lower value in some
Xcircumstances, e.g. for slow modems dialing into a communications server
Xwhich is connected to a host via a fast link; in this case, this
Xvariable would be set by default to the speed of the fast link, and not
Xthe modem. This parameter should be set to the baud rate of the slowest
Xpart of the link for best performance.
X@vindex bindcmds
X@item bindcmds
XAn write-only array of command names which take line editor function
Xnames as arguments, and which therefore should allow binding completion.
X@vindex cdpath
X@vindex CDPATH
X@item cdpath (CDPATH)
XAn array (colon-separated list) of directories specifying the search
Xpath for the @code{cd} command.
X@vindex COLUMNS
X@item COLUMNS
XThe number of columns for this terminal session. Used for printing
Xselect lists and for the line editor.
X@vindex DIRSTACKSIZE
X@pindex AUTO_PUSHD, use of
X@item DIRSTACKSIZE
XThe maximum size of the directory stack. If the stack gets larger than
Xthis, it will be truncated automatically. This is useful with the
X@code{AUTO_PUSHD} option.
X@vindex FCEDIT
X@item FCEDIT
XThe default editor for the @code{fc} builtin.
X@vindex fignore
X@vindex FIGNORE
X@item fignore (FIGNORE)
XAn array (colon-separated list) containing the suffixes of files to be
Xignored during filename completion.
X@vindex fpath
X@vindex FPATH
X@item fpath (FPATH)
XAn array (colon-separated list) of directories specifying the search
Xpath for function definitions. This path is searched when a function
Xwith the @code{-u} attribute is referenced. If an executable file is
Xfound, then it is read and executed in the current environment.
X@vindex HISTCHARS
X@item HISTCHARS
XThree characters used by the shell's history and lexical analysis
Xmechanism. The first character signals the start of a history
Xsubstitution (default @code{!}). The second character signals the start
Xof a quick history substitution (default @code{^}). The third character
Xis the comment character (default @code{#}).@refill
X@vindex HISTFILE
X@item HISTFILE
XThe file to save the history in when an interactive shell exits. If
Xunset, the history is not saved.
X@vindex HISTSIZE
X@item HISTSIZE
XThe maximum size of the history list.
X@vindex HOME
X@item HOME
XThe default argument for the @code{cd} command.
X@vindex hostcmds
X@item hostcmds
XAn write-only array of command names which take hostnames as arguments,
Xand which should therefore allow hostname completion. This sort of
Xcompletion is also used in words containing a @code{@@} character.
X@vindex hosts
X@vindex HOSTS
X@item hosts (HOSTS)
XAn array (colon-separated list) of hostnames to use for hostname
Xcompletion.
X@vindex IFS
X@item IFS
XInternal field separators, normally space, tab, and newline, that are
Xused to separate words which result from command or parameter
Xsubstitution and words read by the @code{read} builtin.
X@vindex LINES
X@item LINES
XThe number of lines for this terminal session. Used for printing select
Xlists and for the line editor.
X@vindex LISTMAX
X@item LISTMAX
XIn the line editor, the number of filenames to list without asking
Xfirst.
X@vindex LITHISTSIZE
X@item LITHISTSIZE
XThe maximum size of the literal history list (before history expansion).
X@vindex LOGCHECK
X@item LOGCHECK
XThe interval in seconds between checks for login/logout activity using
Xthe @code{watch} parameter.
X@vindex MAIL
X@item MAIL
XIf this parameter is set and @code{mailpath} is not set, the shell looks
Xfor mail in the specified file.
X@vindex MAILCHECK
X@item MAILCHECK
XThe interval in seconds between checks for new mail.
X@vindex mailpath
X@vindex MAILPATH
X@item mailpath (MAILPATH)
XAn array (colon-separated list) of filenames to check for new mail.
XEach filename can be followed by a @code{?} and a message that will be
Xprinted. The sequence @code{$_} in the message will be replaced by the
Xname of the mail file. The default message is @samp{You have new
Xmail}.@refill
X@vindex manpath
X@vindex MANPATH
X@item manpath (MANPATH)
XAn array (colon-separated list) whose value is not used by the shell.
XThe @code{manpath} array can be useful, however, since setting it also
Xsets @code{MANPATH}, and vice versa.
X@vindex NULLCMD
X@item NULLCMD
XThe command name to assume if a redirection is specified with no
Xcommand. Defaults to @code{cat}. For sh/ksh-like behavior, change this
Xto @code{:}. For csh-like behavior, unset this parameter; the shell will
Xprint an error message if null commands are entered.
X@vindex optcmds
X@item optcmds
XAn write-only array of commands which take options as arguments, and
Xwhich therefore should allow option completion.
X@vindex path
X@vindex PATH
X@item path (PATH)
XAn array (colon-separated list) of directories to search for commands.
XWhen this parameter is set, each directory is scanned and all files
Xfound are put in a hash table.
X@vindex POSTEDIT
X@item POSTEDIT
XThis string is output whenever the line editor exits. It usually
Xcontains termcap strings to reset the terminal.
X@vindex PROMPT
X@item PROMPT
XThe primary prompt string, printed before a command is read; the default
Xis @samp{%m%# }. If the escape sequence takes an optional
Xinteger, it should appear between the @samp{%} and the next character of the
Xsequence. The following escape sequences are recognized:
X
X@table @code
X@item %d, %/
XPresent working directory (@code{$PWD}).
X@item %~
X@code{$PWD}. If it has a named directory as its prefix, that part is
Xreplaced by a @code{~} followed by the name of the directory. If it
Xstarts with @code{$HOME}, that part is replaced by a @code{~}.@refill
X@item %c, %, %C
XTrailing component of @code{$PWD}. An integer may follow the @samp{%} to get
Xmore than one component. Unless @code{%C} is used, tilde expansion is
Xperformed first.@refill
X@item !, %h, %!
XCurrent history event number
X@item %M
XThe full machine hostname.
X@item %m
XThe hostname up to the first @samp{.}. An integer may follow the @samp{%} to
Xspecify how many components of the hostname are desired.@refill
X@item %S (%s)
XStart (stop) standout mode.
X@item %U (%u)
XStart (stop) underline mode.
X@item %B (%b)
XStart (stop) boldface mode.
X@item %t
X@itemx %@@
XCurrent time of day, in 12-hour, am/pm format.
X@item %T
XCurrent time of day, in 24-hour format.
X@item %*
XCurrent time of day in 24-hour format, with seconds.
X@item %n
X@code{$USERNAME}.
X@item %w
XThe date in day-dd format.
X@item %W
XThe date in mm/dd/yy format.
X@item %D
XThe date in yy-mm-dd format.
X@item %D @{@var{string}@}
X@var{string} is formatted using the @code{strftime} function. See
X@code{strftime(3)} for more details, if your system has it.@refill
X@item %l
XThe line (tty) the user is logged in on.
X@item %?
XThe return code of the last command executed just before the prompt.
X@item %#
XA @code{#} if the shell is running as root, a @code{%} if not.
X@item %v
XThe value of the first element of the @code{psvar} array
Xparameter. Following the @samp{%} with an integer gives that element
Xof the array.@refill
X@item %@{@dots{}%@}
XInclude a string as a literal escape sequence. The string within the
Xbraces should not change the cursor position.
X@end table
X
X@vindex PROMPT2
X@item PROMPT2
XThe secondary prompt, printed when the shell needs more information to
Xcomplete a command. Recognizes the same escape sequences as
X@code{PROMPT}. The default is @samp{> }.@refill
X@vindex PROMPT3
X@item PROMPT3
XSelection prompt used within a @code{select} loop. Recognizes the same
Xescape sequences as @code{PROMPT}. The default is @samp{?# }.@refill
X@vindex PROMPT4
X@item PROMPT4
XThe execution trace prompt. Default is @samp{+ }.
X@vindex PS1
X@vindex PS2
X@vindex PS3
X@vindex PS4
X@item PS1, PS2, PS3, PS4
XSame as @code{PROMPT}, @code{PROMPT2}, @code{PROMPT3}, and @code{PROMPT4},
Xrespectively.@refill
X@vindex psvar
X@vindex PSVAR
X@item psvar (PSVAR)
XAn array (colon-separated list) whose first nine values can be used in
X@code{PROMPT} strings. Setting @code{psvar} also sets @code{PSVAR}, and vice
Xversa.
X@vindex prompt
X@item prompt
XSame as @code{PROMPT}.
X@vindex READNULLCMD
X@item READNULLCMD
XThe command name to assume if a single input redirection is specified
Xwith no command. Defaults to @code{more}.
X@vindex REPORTTIME
X@item REPORTTIME
XIf nonzero, commands whose combined user and system execution times
X(measured in seconds) are greater than this value have timing statistics
Xprinted for them.
X@vindex RPROMPT
X@vindex RPS1
X@item RPROMPT, RPS1
XThis prompt is displayed on the right-hand side of the screen when the
Xprimary prompt is being displayed on the left. This does not work if
Xthe @code{SINGLE_LINE_ZLE} option is set. Recognizes the same escape
Xsequences as @code{PROMPT}, except that termcap sequences like
X@code{%s}, etc., will not work.@refill
X@vindex SAVEHIST
X@item SAVEHIST
XThe maximum number of history events to save in the history file.
X@vindex SPROMPT
X@item SPROMPT
XThe prompt used for spelling correction. The sequence @code{%R} expands
Xto the string which presumably needs spelling correction, and @code{%r}
Xexpands to the proposed correction. All other @code{PROMPT} escapes are
Xalso allowed.@refill
X@vindex STTY
X@item STTY
XIf this parameter is set in a command's environment, the shell runs the
X@code{stty} command with the value of this parameter as arguments in
Xorder to set up the terminal before executing the command.@refill
X@vindex TIMEFMT
X@item TIMEFMT
XThe format of process time reports with the @code{time} keyword. The
Xdefault is @samp{%E real %U user %S system %P}. Recognizes the
Xfollowing escape sequences:@refill
X
X@table @code
X@item %U
XCPU seconds spent in user mode.
X@item %S
XCPU seconds spent in kernel mode.
X@item %E
XElapsed time in seconds.
X@item %P
XThe CPU percentage, computed as (%U+%S)/%E.
X@item %W
XNumber of times the process was swapped.
X@item %X
XThe average amount in (shared) text space used in Kbytes.
X@item %D
XThe average amount in (unshared) data/stack space used in Kbytes.
X@item %K
XThe total space used (%X+%D) in Kbytes.
X@item %M
XThe maximum memory the process had in use at any time in Kbytes.
X@item %F
XThe number of major page faults (page needed to be brought from
Xdisk).@refill
X@item %R
XThe number of minor page faults.
X@item %I
XThe number of input operations.
X@item %O
XThe number of output operations.
X@item %r
XThe number of socket messages received.
X@item %s
XThe number of socket messages sent.
X@item %k
XThe number of signals received.
X@item %w
XNumber of voluntary context switches (waits).
X@item %c
XNumber of involuntary context switches.
X@item %J
XThe name of this job.
X@end table
X
X@vindex TMOUT
X@item TMOUT
XIf this parameter is nonzero, the shell will terminate if a command is
Xnot entered within the specified number of seconds after issuing a
Xprompt.
X@vindex TMPPREFIX
X@item TMPPREFIX
XA pathname prefix which the shell will use for all temporary files.
X@vindex varcmds
X@item varcmds
XAn write-only array of command names which take parameter names as
Xarguments, and which therefore should allow parameter completion.
X@vindex watch
X@vindex WATCH
X@item watch (WATCH)
XAn array (colon-separated list) of login/logout events to report. If it
Xcontains the single word @samp{all}, then all login/logout events are
Xreported. If it contains the single word @samp{notme}, then all
Xlogin/logout events are reported except for those originating from
X@code{$USERNAME}. An entry in this list may consist of a username, an
X@code{@@} followed by a remote hostname, and a @code{%} followed by a
Xline (tty). Any or all of these components may be present in an entry;
Xif a login/logout event matches all of them, it is reported.@refill
X@vindex WATCHFMT
X@item WATCHFMT
XThe format of login/logout reports if the @code{watch} parameter is set.
XDefault is @samp{%n has %a %l from %m}. Recognizes the following escape
Xsequences:@refill
X
X@table @code
X@item %n
XThe name of the user that logged in/out.
X@item %a
XThe observed action, i.e. @samp{logged on} or @samp{logged off}.
X@item %l
XThe line (tty) the user is logged in on.
X@item %M
XThe full hostname of the remote host.
X@item %m
XThe hostname up to the first @samp{.}. If only the ip address is
Xavailable or the utmp field contains the name of an X-windows display,
Xthe whole name is printed.@refill
X@item %S (%s)
XStart (stop) standout mode.
X@item %U (%u)
XStart (stop) underline mode.
X@item %B (%b)
XStart (stop) boldface mode.
X@item %t
X@itemx %@@
XThe time, in 12-hour, am/pm format.
X@item %T
XThe time, in 24-hour format.
X@item %w
XThe date in day-dd format.
X@item %W
XThe date in mm/dd/yy format.
X@item %D
XThe date in yy-mm-dd format.
X@end table
X
X@vindex WORDCHARS
X@item WORDCHARS
XA list of nonalphanumeric characters considered part of a word by the
Xline editor.
X@vindex ZDOTDIR
X@item ZDOTDIR
XThe directory to search for shell startup files (@file{.zshrc}, etc), if
Xnot @code{$HOME}.@refill
X@end table
X
X@node Options, Shell Builtin Commands, Parameters, Top
X@chapter Options
X@cindex options
X
X@noindent
XThe following options may be set upon invocation of the shell, or with
Xthe @code{set} or @code{setopt} builtins:@refill
X
X@table @code
X@cindex export, automatic
X@pindex ALLEXPORT
X@item ALLEXPORT (-a)
END_OF_FILE
if test 49503 -ne `wc -c <'doc/zsh.texi.02'`; then
echo shar: \"'doc/zsh.texi.02'\" unpacked with wrong size!
fi
# end of 'doc/zsh.texi.02'
fi
echo shar: End of archive 4 \(of 22\).
cp /dev/null ark4isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:21:32 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 55
Archive-name: zsh/part05

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: doc/zsh.texi.01 help/TRAP help/fc
# Wrapped by mattson@odin on Sat Feb 6 14:41:52 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 5 (of 22)."'
if test -f 'doc/zsh.texi.01' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'doc/zsh.texi.01'\"
else
echo shar: Extracting \"'doc/zsh.texi.01'\" \(49503 characters\)
sed "s/^X//" >'doc/zsh.texi.01' <<'END_OF_FILE'
X\input texinfo.tex @c -*- texinfo -*-
X@c %**start of header
X@setfilename zsh.info
X@settitle zsh
X@c %**end of header
X@c v0.1, July 8th 1992. Added documentation for Rick's
X@c (pclink@@qld.tne.oz.au) four new glob qualifiers (a/m/c/L)
X@c v0.2, August 11th 1992. Added documentation for the new PSVAR
X@c variable, the f E and I flags for the fc command, and the
X@c appendhistory and extendedhistory options. Also corrected a typo in
X@c the description of the ${ := } modifier. Now current to zsh2.3beta
X@c (patch level 28).
X@c v0.3, August 21 1992. Unified to the zsh.1 (patchlevel 30) patches
X@c supplied by Hans Albertsson. This meant rewriting most of the extra
X@c text I added in v0.1 and v0.2, in order to match Hans'. Corrected
X@c some more typos ("is has" in several places).
X@c [ added to the archive sometime around here ]
X@c v0.4, November 1 1992. Added up-line-or-search to complement
X@c down-line-or-search. Moved information about availability and the
X@c mailing list to the end of the file, to match zsh.1. Should now be
X@c current to patchlevel 65.
X@c v0.5, February 5 1993. Has been kept mostly up-do-date by denizens
X@c of the mailing list. Final clean-up to conform to the new release
X@c of zsh version 2.3 (man page dated 1 February 1993), and to the new
X@c Texinfo standards (but should remain compatible with old Texinfo).
X@c Eventually I want to rewrite to use the new features of Texinfo v2.0
X@c and above, but we'll have to wait for the rest of the world to catch
X@c up first. <sigh>
X
X@setchapternewpage on
X
X@ifinfo
XThis is a texinfo version of the man page for the Z Shell, by Paul
XFalstad. It was converted from the original @code{zsh.1} file
Xdistributed with zsh v2.2.0. The conversion was done by Jonathan
XHardwick, @code{jch@@cs.cmu.edu}, who would love to hear of any errors
Xhe introduced or texinfo rules he broke. The text remains the work of
XPaul Falstad.@refill
X@end ifinfo
X
X@titlepage
X@sp 4
X@center @titlefont{The Z Shell}
X@sp 2
X@center Paul Falstad
X@center pf@@ttisms.com
X@sp 2
X@center 1 February 1993
X@page
X@vskip 0pt plus 1filll
XThis is a texinfo version of the man page for the Z Shell, by Paul
XFalstad. It was converted from the original @code{zsh.1} file
Xdistributed with zsh v2.2.0. The conversion was done by Jonathan
XHardwick, @code{jch@@cs.cmu.edu}, who would love to hear of any errors
Xhe introduced or texinfo rules he broke. The text remains the work of
XPaul Falstad.
X@end titlepage
X
X@node Top, Shell Grammar, (dir), (dir)
X@top zsh
X
X@menu
X* Shell Grammar::
X* Expansion::
X* Redirection::
X* Command Execution::
X* Functions::
X* Jobs & Signals::
X* History::
X* Arithmetic Evaluation::
X* Conditional Expressions::
X* Zsh Line Editor::
X* Parameters::
X* Options::
X* Shell Builtin Commands::
X* Invocation::
X* Wrapping Up::
X* Concept Index::
X* Variables Index::
X* Options Index::
X* Functions Index::
X* Editor Functions Index::
X* Keystroke Index::
X
X --- The Detailed Node Listing ---
X
XShell Grammar
X
X* Simple Commands & Pipelines::
X* Complex Commands::
X* Reserved Words::
X* Comments::
X* Aliasing::
X* Quoting::
X
XExpansion
X
X* Filename Expansion::
X* Process Substitution::
X* Parameter Expansion::
X* Command Substitution::
X* Arithmetic Expansion::
X* Brace Expansion::
X* Filename Generation::
X
XHistory
X
X* Event Designators::
X* Word Designators::
X* Modifiers::
X
XZsh Line Editor
X


X* Movement::
X* History Control::
X* Modifying Text::
X* Arguments::
X* Completion::
X* Miscellaneous::
X

XParameters
X


X* Array Parameters::
X* Positional Parameters::
X* Parameters Set By The Shell::
X* Parameters Used By The Shell::
X

XWrapping Up
X
X* See Also::
X* Files Used::
X* Availability::
X* Undocumented Features::
X@end menu
X
X@node Shell Grammar, Expansion, Top, Top
X@chapter Shell Grammar
X@cindex shell grammar
X@cindex grammar, shell
X
X@menu
X* Simple Commands & Pipelines::
X* Complex Commands::
X* Reserved Words::
X* Comments::
X* Aliasing::
X* Quoting::
X@end menu
X
X@node Simple Commands & Pipelines, Complex Commands, , Shell Grammar
X@section Simple Commands
X@cindex simple commands
X@cindex commands, simple
X
X@noindent
XA @dfn{simple command} is a sequence of optional parameter assignments
Xfollowed by blank-separated words, with optional redirections
Xinterspersed. The first word is the command to be executed, and the
Xremaining words, if any, are arguments to the command. If a command
Xname is given, the parameter assignments modify the environment of the
Xcommand when it is executed. The value of a simple command is its exit
Xstatus, or 128 plus the signal number if terminated by a signal.
X
X@findex exec
X@findex command
X@findex noglob
X@findex nocorrect
X@noindent
XIf a simple command is preceded by the word @code{exec}, it is executed
Xin the parent shell without forking. If preceded by @code{command}, the
Xcommand word is taken to be the name of an external command, rather than
Xa shell function or builtin. If preceded by @code{noglob}, filename
Xgeneration is not performed on any of the words. If preceded by a
X@code{-}, the command is executed with a @code{-} prepended to its
X@code{argv[0]} string. If preceded by @code{nocorrect}, spelling
Xcorrection is not done on any of the words.@refill
X
X@cindex pipeline
X@noindent
XA @dfn{pipeline} is a sequence of one or more commands separated by
X@code{|} or @code{|&}. @code{|&} is shorthand for @code{2>&1 |}. The
Xstandard output of each command is connected to the standard input of
Xthe next command in the pipeline.@refill
X
X@cindex pipeline, value of
X@noindent
XThe value of a pipeline is the value of the last command. If a pipeline
Xis preceded by a @code{!}, the value of that pipeline is the logical NOT
Xof the value of the last command.
X
X@findex coproc
X@cindex coprocesses
X@noindent
XIf a pipeline is preceded by @code{coproc}, it is executed as a
Xcoprocess; a two-way pipe is established between it and the parent
Xshell. The shell can read from or write to the coprocess by means of
Xthe @code{>&p} and @code{<&p} redirection operators.@refill
X
X@cindex sublist
X@noindent
XA @dfn{sublist} is a sequence of one or more pipelines separated by
X@code{&&} or @code{||}. If two pipelines are separated by @code{&&},
Xthe second pipeline is executed only if the first is successful (returns
Xa zero value). If two pipelines are separated by @code{||}, the second
Xis executed only if the first is unsuccessful (returns a nonzero
Xvalue).@refill
X
X@cindex list
X@noindent
XA @dfn{list} is a sequence of one or more sublists separated by, and
Xoptionally terminated by, @code{;}, @code{&}, or a newline. Normally
Xthe shell waits for each list to finish before executing the next one.
XIf a list is terminated by a @code{&}, the shell executes it in the
Xbackground, and does not wait for it to finish.@refill
X
X@node Complex Commands, Reserved Words, Simple Commands & Pipelines, Shell Grammar
X@section Complex Commands
X@cindex complex commands
X@cindex commands, complex
X
X@noindent
XA @dfn{complex command} is one of the following:
X
X@table @code
X@cindex for loops
X@cindex loops, for
X@findex for
X@item for @var{name} [ in @var{word} @dots{} ]
X@itemx do @var{list}
X@itemx done
XExpand the list of @var{word}s, and set the parameter @var{name} to each
Xof them in turn, executing @var{list} each time. If the @code{in}
X@var{word} is omitted, use the positional parameters instead of the
X@var{word}s.@refill
X
X@item for @var{name} [ in @var{word} @dots{} ] ; @var{sublist}
XThis is a shorthand for @code{for}. Though it may cause confusion, it
Xis included for convenience; its use in scripts is discouraged, unless
X@var{sublist} is a command of the form @{ @var{list} @}.@refill
X
X@findex foreach
X@item foreach @var{name} ( @var{word} @dots{} )
X@itemx @var{list}
X@itemx end
XAnother form of @code{for}.
X
X@item for @var{name} in @var{word} @dots{}
X@itemx @{
X@itemx @var{list}
X@itemx @}
XAnother form of @code{for}.
X
X@item for @var{name} ( @var{word} @dots{} ) @{
X@itemx @var{list}
X@itemx @}
XAnother form of @code{for}.
X
X@item for @var{name} ( @var{word} @dots{} ) @var{sublist}
XAnother form of @code{for}.
X
X@cindex selection, user
X@cindex user selection
X@findex select
X@item select @var{name} [ in @var{word} @dots{} ]
X@itemx do @var{list}
X@itemx done
XPrint the set of @var{word}s, each preceded by a number. If the
X@code{in} @var{word} is omitted, use the positional parameters. The
X@code{PROMPT3} prompt is printed and a line is read from standard input.
XIf this line consists of the number of one of the listed @var{word}s,
Xthen the parameter @var{name} is set to the @var{word} corresponding to
Xthis number. If this line is empty, the selection list is printed
Xagain. Otherwise, the value of the parameter @var{name} is set to null.
XThe contents of the line read from standard input is saved in the
Xparameter @code{REPLY}. @var{list} is executed for each selection until
Xa break or end-of-file is encountered.@refill
X
X@item select @var{name} [ in @var{word} ] ; @var{sublist}
XA short form of @code{select}.
X
X@findex case
X@cindex case selection
X@cindex selection, case
X@item case @var{word} in [ @var{pattern} ) @var{list} ;; ] @dots{}
X@itemx esac
XExecute the @var{list} associated with the first @var{pattern} that
Xmatches @var{word}, if any. The form of the patterns is the same as
Xthat used for filename generation. @xref{Filename Generation}.@refill
X
X@item case @var{word} @{ [ @var{pattern} ) @var{list} ;; ] @dots{}
X@itemx @}
XAnother form of @code{case}.
X
X@findex if
X@cindex if construct
X@item if @var{list}
X@itemx then @var{list}
X@itemx [ elif @var{list} ; then @var{list} ] @dots{}
X@itemx [ else @var{list} ]
X@itemx fi
XThe @code{if} @var{list} is executed, and, if it returns a zero exit
Xstatus, the @code{then} @var{list} is executed. Otherwise, the
X@code{elif} @var{list} is executed and, if its value is zero, the
X@code{then} @var{list} is executed. If each @code{elif} @var{list}
Xreturns nonzero, the @code{else} @var{list} is executed.@refill
X
X@item if ( @var{list} ) @var{sublist}
XA short form of @code{if}.
X
X@item if ( @var{list} ) @{
X@itemx @var{list}
X@itemx @} elif ( @var{list} ) @{
X@itemx @var{list}
X@itemx @} @dots{} else @{
X@itemx @var{list}
X@itemx @}
XAn alternate form of @code{if}.
X
X@findex while
X@cindex while loops
X@cindex loops, while
X@item while @var{list}
X@itemx do @var{list}
X@itemx done
XExecute the @code{do} @var{list} as long as the @code{while} @var{list}
Xreturns a zero exit status.@refill
X
X@item while ( @var{list} ) @{
X@itemx @var{list}
X@itemx @}
XAn alternate form of @code{while}.
X
X@findex until
X@cindex until loops
X@cindex loops, until
X@item until @var{list}
X@itemx do @var{list}
X@itemx done
XExecute the @code{do} @var{list} as long as @code{until} @var{list}
Xreturns a nonzero exit status.@refill
X
X@findex repeat
X@cindex repeat loops
X@cindex loops, repeat
X@item repeat @var{word}
X@itemx do @var{list}
X@itemx done
X@var{word} is expanded and treated as an arithmetic expression, which
Xmust evaluate to a number @var{n}. @var{list} is then executed @code{n}
Xtimes.@refill
X
X@item repeat @var{word} @var{sublist}
XThis is a short form of @code{repeat}.
X
X@cindex subshells
X@item ( @var{list} )
XExecute @var{list} in a subshell.
X
X@item @{ @var{list} @}
XExecute @var{list}.
X
X@item function @var{word} [ () ] @dots{} @{ @var{list} @}
X@itemx @var{word} @dots{} () @{ @var{list} @}
X@itemx @var{word} @dots{} () @var{sublist}
XDefine a function which is referenced by any one of @var{word}.
XNormally, only one @var{word} is provided; multiple @var{word}s are
Xusually only useful for setting traps. The body of the function is the
X@var{list} between the @code{@{} and @code{@}}.
X@xref{Functions}.@refill
X
X@cindex timing
X@item time [ @var{pipeline} ]
XThe @var{pipeline} is executed, and timing statistics are reported on
Xthe standard error in the form specified by the @code{TIMEFMT}
Xparameter. If @var{pipeline} is omitted, print statistics about the
Xshell process and its children.@refill
X
X@cindex testing conditional expression
X@item [[ @var{exp} ]]
XEvaluates the conditional expression @var{exp} and return a zero exit
Xstatus if it is true. @xref{Conditional Expressions}, for a description
Xof @var{exp}.@refill
X@end table
X
X@node Reserved Words, Comments, Complex Commands, Shell Grammar
X@section Reserved Words
X@cindex reserved words
X
X@findex unalias, use of
X@noindent
XThe following words are recognized as @dfn{reserved words} when used as
Xthe first word of a command unless quoted or removed using the
X@code{unalias} builtin:@refill
X
X@noindent
X@code{do} @code{done} @code{esac} @code{then} @code{elif} @code{else}
X@code{fi} @code{for} @code{case} @code{if} @code{while} @code{function}
X@code{repeat} @code{code} @code{time} @code{until} @code{exec}
X@code{command} @code{select} @code{coproc} @code{noglob} @code{-}
X@code{nocorrect} @code{foreach} @code{end} @refill
X
X@node Comments, Aliasing, Reserved Words, Shell Grammar
X@section Comments
X@cindex comments
X
X@vindex HISTCHARS, use of
X@pindex INTERACTIVE_COMMENTS, use of
X@noindent
XIn noninteractive shells, or in interactive shells with the
X@code{INTERACTIVE_COMMENTS} option set, a word beginning with the third
Xcharacter of the @code{HISTCHARS} parameter (@code{#} by default) causes
Xthat word and all the following characters up to a newline to be
Xignored.@refill
X
X@node Aliasing, Quoting, Comments, Shell Grammar
X@section Aliasing
X@cindex aliasing
X
X@findex alias, use of
X@cindex aliases, global
X@noindent
XEvery token in the shell input is checked to see if there is an alias
Xdefined for it. If so, it is replaced by the text of the alias if it is
Xin command position (if it could be the first word of a simple command),
Xor if the alias is global. If the text ends with a space, the next word
Xin the shell input is treated as though it were in command position for
Xpurposes of alias expansion. An alias is defined using the @code{alias}
Xbuiltin; global aliases may be defined using the @code{-g} option to
Xthat bulitin.@refill
X
X@noindent
XAlias substitution is done on the shell input before any other
Xsubstitution except history substitution. Therefore, if an alias is
Xdefined for the word @samp{foo}, alias substitution may be avoided by
Xquoting part of the word, e.g. @samp{\foo}. But there is nothing to
Xprevent an alias being defined for @samp{\foo} as well.@refill
X
X@node Quoting, , Aliasing, Shell Grammar
X@section Quoting
X@cindex quoting
X
X@noindent
XA character may be @dfn{quoted} (that is, made to stand for itself) by
Xpreceding it with a @code{\}. @code{\} followed by a newline is
Xignored. All characters enclosed between a pair of single quotes
X(@code{''}) are quoted. A single quote cannot appear within single
Xquotes. Inside double quotes (@code{""}), parameter and command
Xsubstitution occurs, and @code{\} quotes the characters @code{\},
X@code{`}, @code{"}, and @code{$}. @refill
X
X@node Expansion, Redirection, Shell Grammar, Top
X@chapter Expansion
X@cindex expansion
X
X@menu
X* Filename Expansion::
X* Process Substitution::
X* Parameter Expansion::
X* Command Substitution::
X* Arithmetic Expansion::
X* Brace Expansion::
X* Filename Generation::
X@end menu
X
X@noindent
XExpansion is performed on the command line after it has been parsed.
XThe types of expansions performed are @dfn{filename expansion},
X@dfn{process substitution}, @dfn{parameter expansion}, @dfn{command
Xsubstitution}, @dfn{arithmetic expansion}, @dfn{brace expansion}, and
X@dfn{filename generation}.@refill
X
X@node Filename Expansion, Process Substitution, , Expansion
X@section Filename Expansion
X@cindex filename expansion
X@cindex expansion, filename
X
X@noindent
XEach word is checked to see if it begins with an unquoted @code{~}. If
Xit does, then the word up to a @code{/} is checked to see if it matches
Xthe name of a named directory. If so, then the @code{~} and the matched
Xportion are replaced with the value of the named directory. A @code{~}
Xby itself or followed by a @code{/} is replaced by the value of the
X@code{HOME} parameter. A @code{~} followed by a @code{+} or a @code{-}
Xis replaced by the value of @code{PWD} or @code{OLDPWD},
Xrespectively.@refill
X
X@cindex directories, named
X@cindex named directories
X@noindent
XNamed directories are typically login directories for users on the
Xsystem. They may also be defined if the text after the @code{~} is the
Xname of a string shell parameter whose value begins with a @code{/}. In
Xcertain circumstances (in prompts, for instance), when the shell prints
Xa path, the path is checked to see if it has a named directory as its
Xprefix. If so, then the prefix portion is replaced with a @code{~}
Xfollowed by the name of the directory. The longest match is preferred.
X
X@noindent
XIf a word begins with an unquoted @code{=} and the @code{NO_EQUALS}
Xoption is not set, the remainder of the word is taken as the name of a
Xcommand or alias. If a command exists by that name, the word is
Xreplaced by the full pathname of the command. If an alias exists by
Xthat name, the word is replaced with the text of the alias. Otherwise
Xthe word is checked up to a @code{/} to see if it is a number or a
X@code{-}. If so, the matched portion is replaced with the @var{n}th
Xdirectory in the directory stack, where @var{n} is the number matched,
Xor the last directory in the directory stack if a @code{-} is
Xmatched.@refill
X
X@node Process Substitution, Parameter Expansion, Filename Expansion, Expansion
X@section Process Substitution
X@cindex process substitution
X@cindex substitution, process
X
X@noindent
XEach command argument of the form @code{<(@var{list})} or
X@code{>(@var{list})} or @code{=(@var{list})} is subject to process
Xsubstitution. In the case of the @code{<} or @code{>} forms, the shell
Xwill run process @var{list} asynchronously connected to a named pipe
X(FIFO). The name of this pipe will become the argument to the command.
XIf the form with @code{>} is selected then writing on this file will
Xprovide input for @var{list}. If @code{<} is used, then the file passed
Xas an argument will be a named pipe connected to the output of the
X@var{list} process. For example,@refill
X
X@code{paste <(cut -f1 @var{file1}) <(cut -f3 @var{file2}) | tee >(@var{process1}) >(@var{process2}) >/dev/null}
X
X@noindent
X@code{cut}s fields 1 and 3 from the files @var{file1} and @var{file2}
Xrespectively, @code{paste}s the results together, and sends it to the
Xprocesses @var{process1} and @var{process2}. Note that the file, which
Xis passed as an argument to the command, is a system pipe so programs
Xthat expect to @code{lseek(2)} on the file will not work. Also note
Xthat the previous example can be more compactly and efficiently written
Xas:@refill
X
X@code{paste <(cut -f1 @var{file1}) <(cut -f3 @var{file2}) >>(@var{process1}) >>(@var{process2})}
X
X@noindent
XThe shell uses pipes instead of FIFOs to implement the latter two
Xprocess substitutions in the above example.
X
X@cindex temporary files
X@cindex files, temporary
X@noindent
XIf @code{=} is used, then the file passed as an argument will be the name
Xof a temporary file containing the output of the @var{list} process.
XThis may be used instead of the @code{<} form for a program that expects
Xto @code{lseek(2)} on the input file.@refill
X
X@node Parameter Expansion, Command Substitution, Process Substitution, Expansion
X@section Parameter Expansion
X@cindex parameter expansion
X@cindex expansion, parameter
X
X@noindent
XThe character @code{$} is used to introduce parameter expansions.
X@xref{Parameters}, for a description of parameters.@refill
X
X@table @code
X@item $@{@var{name}@}
XThe value, if any, of the parameter @var{name} is substituted. The
Xbraces are required if @var{name} is followed by a letter, digit, or
Xunderscore that is not to be interpreted as part of its name. If
X@var{name} is an array parameter, then the values of each element of
X@var{name} is substituted, one element per word. Otherwise, the
Xexpansion results in one word only; no word splitting is done on the
Xresult.@refill
X
X@item $@{@var{name}:-@var{word}@}
XIf @var{name} is set and is non-null then substitute its value;
Xotherwise substitute @var{word}.@refill
X
X@item $@{@var{name}:=@var{word}@}
XIf @var{name} is unset or is null then set it to @var{word}; the value
Xof the parameter is then substituted.@refill
X
X@item $@{@var{name}:?@var{word}@}
XIf @var{name} is set and is non-null, then substitute its value;
Xotherwise, print @var{word} and exit from the shell. If @var{word} is
Xomitted, then a standard message is printed.@refill
X
X@item $@{@var{name}:+@var{word}@}
XIf @var{name} is set and is non-null then substitute @var{word};
Xotherwise substitute nothing.@refill
X
X@item $@{@var{name}#@var{pattern}@}
X@itemx $@{@var{name}##@var{pattern}@}
XIf the @var{pattern} matches the beginning of the value of @var{name},
Xthen substitute the value of @var{name} with the matched portion
Xdeleted; otherwise, just substitute the value of @var{name}. In the
Xfirst form, the smallest matching pattern is preferred; in the second
Xform, the largest matching pattern is preferred.@refill
X
X@item $@{@var{name}%@var{pattern}@}
X@itemx $@{@var{name}%%@var{pattern}@}
XIf the @var{pattern} matches the end of the value of @var{name}, then
Xsubstitute the value of @var{name} with the matched portion deleted;
Xotherwise, just substitute the value of @var{name}. In the first form,
Xthe smallest matching pattern is preferred; in the second form, the
Xlargest matching pattern is preferred.@refill
X
X@item $@{#@var{spec}@}
XIf @var{spec} is one of the above substitutions, substitute the length
Xin characters of the result instead of the result itself. If @var{spec}
Xis an array expression, substitute the number of elements of the
Xresult.@refill
X
X@cindex rc, array expansion style
X@cindex array expansion, rc style
X@pindex RC_EXPAND_PARAM, use of
X@item $@{^@var{spec}@}
XToggle the value of the @code{RC_EXPAND_PARAM} option for the evaluation
Xof @var{spec}. When this option is set, array expansions of the form
X@samp{foo$@{xx@}bar}, where the parameter @samp{xx} is set to @samp{(a b
Xc)}, are substituted with @samp{fooabar foobbar foocbar} instead of the
Xdefault @samp{fooa b cbar}.@refill
X
X@cindex word splitting, sh style
X@cindex sh, word splitting style
X@pindex SH_WORD_SPLIT, use of
X@vindex IFS, use of
X@item $@{=@var{spec}@}
XToggle the value of the @code{SH_WORD_SPLIT} option for the evaluation
Xof @var{spec}. When this option is set, parameter values are split into
Xseparate words using @code{IFS} as a delimiter before substitution.
XThis is done by default in most other shells.@refill
X@end table
X
X@noindent
XIf the colon is omitted from one of the above expressions containing a
Xcolon, then the shell only checks whether @var{name} is set or not, not
Xwhether it is null.@refill
X
X@node Command Substitution, Arithmetic Expansion, Parameter Expansion, Expansion
X@section Command Substitution
X@cindex command substitution
X@cindex substitution, command
X
X@vindex IFS, use of
X@noindent
XA command enclosed in parentheses preceded by a dollar sign, like so:
X@code{$(@dots{})} or quoted with grave accents: @code{`@dots{}`} is replaced
Xwith its standard output. If the substitution is not enclosed in double
Xquotes, the output is broken into words using the @code{IFS} parameter.
XThe substitution @code{$(cat foo)} may be replaced by the equivalent but
Xfaster @code{$(<foo)}.@refill
X
X@node Arithmetic Expansion, Brace Expansion, Command Substitution, Expansion
X@section Arithmetic Expansion
X@cindex arithmetic expansion
X@cindex expansion, arithmetic
X
X@noindent
XA string of the form @code{$[@var{exp}]} is substituted with the value
Xof the arithmetic expression @var{exp}. @var{exp} is treated as if it
Xwere within single quotes. @xref{Arithmetic Evaluation}.@refill
X
X@node Brace Expansion, Filename Generation, Arithmetic Expansion, Expansion
X@section Brace Expansion
X@cindex brace expansion
X@cindex expansion, brace
X
X@noindent
XA string of the form @samp{foo@{xx,yy,zz@}bar} is expanded to the
Xindividual words @samp{fooxxbar}, @*@samp{fooyybar}, and @samp{foozzbar}.
XLeft-to-right order is preserved. This construct may be nested.
XMalformed brace expansion expressions, including expressions without a
Xcomma, are left unchanged by the shell.@refill
X
X@noindent
XAn expression of the form @code{@{x-y@}}, where @code{x} and @code{y}
Xare single characters, is expanded to every character between @code{x}
Xand @code{y}, inclusive.@refill
X
X@node Filename Generation, , Brace Expansion, Expansion
X@section Filename Generation
X@cindex filename generation
X
X@cindex globbing
X@pindex NO_GLOB, use of
X@pindex EXTENDED_GLOB, use of
X@pindex NULL_GLOB, use of
X@pindex NO_NOMATCH, use of
X@pindex GLOB_DOTS, use of
X@noindent
XIf a word contains an unquoted instance of one of the characters
X@code{*}, @code{|}, @code{<}, @code{[}, or @code{?}, it is regarded as a
Xpattern for filename generation, unless the @code{NO_GLOB} option is
Xset. If the @code{EXTENDED_GLOB} option is set, the @code{^} and
X@code{#} characters also denote a pattern; otherwise they are not
Xtreated specially by the shell. The word is replaced with a list of
Xsorted filenames that match the pattern. If no matching pattern is
Xfound, the shell gives an error message, unless the @code{NULL_GLOB}
Xoption is set, in which case the word is deleted; or unless the
X@code{NO_NOMATCH} option is set, in which case the word is left
Xunchanged. In filename generation, the character @code{/} must be
Xmatched explicitly; also, a @code{.} must be matched explicitly at the
Xbeginning of a pattern or after a @code{/}, unless the @code{GLOB_DOTS}
Xoption is set. No filename generation pattern matches the files
X@file{.} or @file{..}. In other instances of pattern matching, the
X@code{/} and @code{.} are not treated specially.@refill
X
X@table @code
X@item *
Xmatches any string, including the null string.
X@item ?
Xmatches any character.
X@item [@dots{}]
Xmatches any of the enclosed characters.
X@item [^@dots{}]
Xmatches any character except the enclosed characters.
X@item <x-y>
Xmatches any number in the range @code{x} to @code{y}, inclusive. If
X@code{x} is omitted, the number must be less than or equal to @code{y}.
XIf @code{y} is omitted, the number must be greater than or equal to
X@code{x}. A pattern of the form @code{<->} or simply @code{<>} matches
Xany number.@refill
X@item ^x
Xmatches anything except the pattern @code{x}.
X@item x|y
Xmatches either @code{x} or @code{y}.
X@item x#
Xmatches zero or more occurrences of the pattern @code{x}.
X@item x##
Xmatches one or more occurrences of the pattern @code{x}.
X@end table
X
X@noindent
XParentheses may be used for grouping. Note that the @code{|} character
Xmust be within parentheses, so that the lexical analyzer does not think
Xit is a pipe character. Also note that @code{/} has a higher precedence
Xthan @code{^}; that is:@refill
X
X@code{ls ^foo/bar}
X
X@noindent
Xwill search directories in @file{.} except @file{./foo} for a file named
X@file{bar}.@refill
X
X@noindent
XA pathname component of the form @code{(@var{foo}/)#} matches a path
Xconsisting of zero or more directories matching the pattern @var{foo}.
XAs a shorthand, @code{**/} is equivalent to @code{(*/)#}. Thus:@refill
X
X@code{ls (*/)#bar}
X
X@noindent
Xor
X
X@code{ls **/bar}
X
X@noindent
Xdoes a recursive directory search for files named @file{bar}.
X
X@cindex exclusion, globbing
X@cindex globbing, excluding patterns
X@noindent
XIf used for filename generation, a pattern may contain an exclusion
Xspecifier. Such patterns are of the form @var{pat1}~@var{pat2}.
XThis pattern will generate all files matching @var{pat1}, but which do
Xnot match @var{pat2}. For example, @samp{*.c~lex.c} will match all
Xfiles ending in @file{.c}, except the file @file{lex.c}.@refill
X
X@cindex qualifiers, globbing
X@cindex globbing, qualifiers
X@noindent
XPatterns used for filename generation may also end in a list of
Xqualifiers enclosed in parentheses. The qualifiers specify which
Xfilenames that otherwise match the given pattern will be inserted in the
Xargument list. A qualifier may be any one of the following:
X
X@table @code
X@item /
Xdirectories
X@item .
Xplain files
X@item @@
Xsymbolic links
X@item =
Xsockets
X@item p
Xnamed pipes (FIFOs)
X@item *
Xexecutable plain files (0100)
X@item %
Xdevice files (character or block special)
X@item r
Xreadable files (0400)
X@item w
Xwritable files (0200)
X@item x
Xexecutable files (0100)
X@item R
Xworld-readable files (0004)
X@item W
Xworld-writable files (0002)
X@item X
Xworld-executable files (0001)
X@item s
Xsetuid files (04000)
X@item S
Xsetgid files (02000)
X@item d@var{dev}
Xfiles on the device @var{dev}
X@item l@var{ct}
Xfiles having a link count of @var{ct}
X@item U
Xfiles owned by the effective user id
X@item G
Xfiles owned by the effective group id
X@item u@var{num}
Xfiles owned by user id @var{num}
X@item g@var{num}
Xfiles owned by group id @var{num}
X@item a[+-]@var{n}
Xfiles accessed within last @var{n} days (@code{-}), more than @var{n}
Xdays ago (@code{+}), or exactly @var{n} days ago.@refill
X@item m[+-]@var{n}
Xfiles modified within last @var{n} days (@code{-}), more than @var{n}
Xdays ago (@code{+}), or exactly @var{n} days ago.@refill
X@item c[+-]@var{n}
Xfiles whose inode changed within last @var{n} days (@code{-}), more than
X@var{n} days ago (@code{+}), or exactly @var{n} days ago.@refill
X@item L[+-]@var{bytes}
Xfiles less than @var{n} bytes (@code{-}), more than @var{n} bytes
X(@code{+}), or exactly @var{n} bytes in length.@refill
X@item ^
Xnegates all qualifiers following it
X@item M
X@pindex MARK_DIRS, setting in pattern
Xsets the @code{MARK_DIRS} option for the current pattern
X@item N
X@pindex NULL_GLOB, setting in pattern
Xsets the @code{NULL_GLOB} option for the current pattern
X@item D
X@pindex GLOB_DOTS, setting in pattern
Xsets the @code{GLOB_DOTS} option for the current pattern
X@end table
X
X@noindent
XThus:
X
X@code{ls *(%W)}
X
X@noindent
Xlists all world-writable device files in the current directory,
Xand@refill
X
X@code{ls /tmp/foo*(u0^@@)}
X
X@noindent
Xlists all root-owned files beginning with the string @samp{foo} in
X@file{/tmp}, ignoring symlinks, and@refill
X
X@code{ls *.*~(lex|parse).[ch](^D^l1)}
X
X@noindent
Xlists all files having a link count of one whose names contain a dot
X(but not those starting with a dot, since @code{GLOB_DOTS} is explicitly
Xswitched off) except for @file{lex.c}, @file{lex.h}, @file{parse.c}, and
X@file{parse.h}. A @code{/} at the end of a pattern is equivalent to
X@code{(/)}.@refill
X
X@node Redirection, Command Execution, Expansion, Top
X@chapter Redirection
X@cindex redirection
X
X@cindex file descriptors
X@cindex descriptors, file
X@noindent
XBefore a command is executed, its input and output may be redirected.
XThe following may appear anywhere in a simple-command or may precede or
Xfollow a complex command. Substitution occurs before @var{word} is used
Xexcept as noted below. If the result of substitution on @var{word}
Xproduces more than one filename, redirection occurs for each separate
Xfilename in turn.@refill
X
X@table @code
X@item < @var{word}
XOpen file @var{word} as standard input.
X
X@item > @var{word}
X@pindex NO_CLOBBER, use of
XOpen file @var{word} as standard output. If the file does not exist
Xthen it is created. If the file exists, and the @code{NO_CLOBBER}
Xoption is set, this causes an error; otherwise, it is truncated to zero
Xlength.@refill
X
X@item >! @var{word}
XSame as @code{>}, except that the file is truncated to zero length if it
Xexists, even if @code{NO_CLOBBER} is set.@refill
X
X@item >> @var{word}
XOpen file @var{word} as standard output. If the file exists then output
Xis appended to it. If the file does not exist, and the
X@code{NO_CLOBBER} option is set, this causes an error; otherwise, the
Xfile is created.@refill
X
X@item >>! @var{word}
XSame as @code{>>}, except that the file is created if it does not exist,
Xeven if @code{NO_CLOBBER} is set.@refill
X
X@item <<[-] @var{word}
XThe shell input is read up to a line that is the same as @var{word}, or
Xto an end-of-file. No parameter substitution, command substitution or
Xfilename generation is performed on @var{word}. The resulting document,
Xcalled a @dfn{here-document}, becomes the standard input. If any
Xcharacter of @var{word} is quoted with single or double quotes
Xor a @code{\}, no interpretation is placed
Xupon the characters of the document. Otherwise, parameter and command
Xsubstitution occurs, @code{\} followed by a newline is removed, and
X@code{\} must be used to quote the characters @code{\}, @code{$},
X@code{`}, and the first character of @var{word}. If @code{<<-} is used,
Xthen all leading tabs are stripped from @var{word} and from the
Xdocument.@refill
X
X@item <<< @var{word}
XOpen a file containing @var{word}, after expansion, as standard input.
X
X@item <& @var{digit}
XThe standard input is duplicated from file descriptor @var{digit} (see
X@code{dup(2)}). Similarly for standard output using
X@code{>&@var{digit}}.@refill
X
X@item >& @var{word}
XSame as @code{> @var{word} 2>&1}.
X
X@item >>& @var{word}
XSame as @code{>> @var{word} 2>&1}.
X
X@item <&-
XClose the standard input.
X
X@item >&-
XClose the standard output.
X
X@item <&p
XThe input from the coprocess is moved to the standard input.
X
X@item >&p
XThe output to the coprocess is moved to the standard output.
X@end table
X
X@noindent
XIf one of the above is preceded by a digit, then the file descriptor
Xreferred to is that specified by the digit (instead of the default 0 or
X1). The order in which redirections are specified is significant. The
Xshell evaluates each redirection in terms of the (@var{file descriptor},
X@var{file}) association at the time of evaluation. For example:@refill
X
X@code{@dots{} 1>@var{fname} 1>&1}
X
X@noindent
Xfirst associates file descriptor 1 with file @var{fname}. It then
Xassociates file descriptor 2 with the file associated with file
Xdescriptor 1 (that is, @var{fname}). If the order of redirections were
Xreversed, file descriptor 2 would be associated with the terminal
X(assuming file descriptor 1 had been) and then file descriptor 1 would
Xbe associated with file @var{fname}.@refill
X
X@noindent
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 @code{tee(1)}. Thus:
X
X@code{date >foo >bar}
X
X@noindent
Xwrites the date to two files, named @file{foo} and @file{bar}. Note
Xthat a pipe is an implicit indirection; thus
X
X@code{date >foo | cat}
X
X@noindent
Xwrites the date to the file @file{foo}, and also pipes it to @code{cat}.
X
X@noindent
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 specified, similar
Xto @code{cat(1)}. Thus
X
X@code{sort <foo <fubar}
X
X@noindent
Xor even
X
X@code{sort <f@{oo,ubar@}}
X
X@noindent
Xis equivalent to @samp{cat foo fubar | sort}. Note that a pipe is an
Ximplicit indirection; thus@refill
X
X@code{cat bar | sort <foo}
X
X@noindent
Xis equivalent to @samp{cat bar foo | sort} (note the order of the inputs).
X
X@noindent
XIf a simple command consists of one or more redirection operators and
Xzero or more parameter assignments, but no command name, the command
X@code{cat} is assumed. Thus
X
X@code{< file}
X
X@noindent
Xprints the contents of @code{file}.
X
X@noindent
XIf a command is followed by @code{&} and job control is not active, then
Xthe default standard input for the command is the empty file
X@file{/dev/null}. Otherwise, the environment for the execution of a
Xcommand contains the file descriptors of the invoking shell as modified
Xby input/output specifications.@refill
X
X@node Command Execution, Functions, Redirection, Top
X@chapter Command Execution
X@cindex command execution
X@cindex execution, of commands
X
X@noindent
XIf a command name contains no slashes, the shell attempts to locate it.
XIf there exists a shell function by that name, the function is invoked
Xas described below (@pxref{Functions}). If there exists a shell builtin
Xby that name, the builtin is invoked.
X
X@vindex path, use of
X@noindent
XOtherwise, the shell searches each element of @code{path} for a directory
Xcontaining an executable file by that name. If the search is
Xunsuccessful, the shell prints an error message and returns a nonzero
Xexit status.
X
X@noindent
XIf execution fails because the file is not in executable format, and the
Xfile is not a directory, it is assumed to be a shell script.
X@code{/bin/sh} is spawned to execute it. If the program is a file
Xbeginning with @code{#!}, the remainder of the first line specifies an
Xinterpreter for the program. The shell will execute the specified
Xinterpreter on operating systems that do not handle this executable
Xformat in the kernel.@refill
X
X@node Functions, Jobs & Signals, Command Execution, Top
X@chapter Functions
X@cindex functions
X
X@findex function
X@noindent
XThe @code{function} reserved word is used to define shell functions.
XShell functions are read in and stored internally. Alias names are
Xresolved when the function is read. Functions are executed like
Xcommands with the arguments passed as positional parameters.@refill
X
X@noindent
XFunctions execute in the same process as the caller and share all files
Xand present working directory with the caller. A trap on @code{EXIT}
Xset inside a function is executed after the function completes in the
Xenvironment of the caller.@refill
X
X@findex return, use of
X@noindent
XThe @code{return} builtin is used to return from function calls.
X
X@findex functions, use of
X@findex unfunction, use of
X@noindent
XFunction identifiers can be listed with the @code{functions} builtin.
XFunctions can be undefined with the @code{unfunction} builtin.@refill
X
X@noindent
XThe following functions, if defined, have special meaning to the shell:
X
X@table @code
X@findex chpwd
X@item chpwd
XExecuted whenever the current working directory is changed.
X
X@findex precmd
X@item precmd
XExecuted before each prompt.
X
X@vindex PERIOD
X@findex periodic
X@item periodic
XIf the parameter @code{PERIOD} is set, this function is executed every
X@code{PERIOD} seconds, just before a prompt.@refill
X
X@findex TRAPERR
X@findex TRAPDEBUG
X@findex TRAPEXIT
X@cindex signals, trapping
X@cindex trapping signals
X@item TRAP@var{xxx}
XIf defined and non-null, this function will be executed whenever the
Xshell catches a signal @code{SIG@var{xxx}}, where @var{xxx} is a signal
Xname as specified for the @code{kill} builtin
X(@pxref{Shell Builtin Commands}).
XIn addition, @code{TRAPERR} is executed whenever a command
Xhas a non-zero exit status, @code{TRAPDEBUG} is executed after each
Xcommand, and @code{TRAPEXIT} is executed when the shell exits, or when
Xthe current function exits if defined inside a function. If a function
Xof this form is defined and null, the shell and processes spawned by it
Xwill ignore @code{SIG@var{xxx}}.@refill
X@end table
X
X@node Jobs & Signals, History, Functions, Top
X@chapter Jobs & Signals
X@cindex jobs
X
X@findex jobs, use of
X@pindex MONITOR, use of
X@noindent
XIf the @code{MONITOR} option is set, an interactive shell associates a
X@dfn{job} with each pipeline. It keeps a table of current jobs,
Xprinted by the @code{jobs} command, and assigns them small integer
Xnumbers. When a job is started asynchronously with @code{&}, the shell
Xprints a line which looks like:@refill
X
X@code{[1] 1234}
X
X@noindent
Xindicating that the job which was started asynchronously was job number
X1 and had one (top-level) process, whose process id was 1234.
X
X@kindex CTRL-Z
X@cindex jobs, suspending
X@cindex suspending jobs
X@findex fg, use of
X@findex bg, use of
X@noindent
XIf you are running a job and wish to do something else you may hit the
Xkey @ctrl{Z} (control-Z) which sends a @code{STOP} signal to the current
Xjob. The shell will then normally indicate that the job has been
X@dfn{suspended}, and print another prompt. You can then manipulate the
Xstate of this job, putting it in the background with the @code{bg}
Xcommand, or run some other commands and then eventually bring the job
Xback into the foreground with the foreground command @code{fg}. A
X@ctrl{Z} takes effect immediately and is like an interrupt in that
Xpending output and unread input are discarded when it is typed.@refill
X
X@cindex jobs, background, IO
X@cindex background jobs, IO
X@noindent
XA job being run in the background will suspend if it tries to read from
Xthe terminal. Background jobs are normally allowed to produce output,
Xbut this can be disabled by giving the command @code{stty tostop}. If
Xyou set this tty option, then background jobs will suspend when they try
Xto produce output like they do when they try to read input.@refill
X
X@cindex jobs, referring to
X@cindex referring to jobs
X@noindent
XThere are several ways to refer to jobs in the shell. A job can be
Xreferred to by the process id of any process of the job or by one of the
Xfollowing:
X
X@table @code
X@item %@var{number}
XThe job with the given number.
X@item %@var{string}
XAny job whose command line begins with @var{string}.
X@item %?@var{string}
XAny job whose command line contains @var{string}.
X@item %%
XCurrent job.
X@item %+
XEquivalent to @code{%%}.
X@item %-
XPrevious job.
X@end table
X
X@findex notify, use of
X@noindent
XThe shell learns immediately whenever a process changes state. It
Xnormally informs you whenever a job becomes blocked so that no further
Xprogress is possible. If @code{notify} is not set, it waits until just
Xbefore it prints a prompt before it informs you.@refill
X
X@noindent
XWhen the monitor mode is on, each background job that completes triggers
Xany trap set for @code{CHLD}.
X
X@findex disown, use of
X@cindex jobs, disowning
X@cindex disowning jobs
X@noindent
XWhen you try to leave the shell while jobs are running or suspended, you
Xwill be warned that @samp{You have suspended (running) jobs}. You may
Xuse the @code{jobs} command to see what they are. If you do this or
Ximmediately try to exit again, the shell will not warn you a second
Xtime; the suspended jobs will be terminated, and the running jobs will
Xbe sent a @code{SIGHUP} signal. To avoid having the shell terminate the
Xrunning jobs, either use the @code{nohup(1)} command or the
X@code{disown} builtin (@pxref{Shell Builtin Commands}).@refill
X
X@cindex signals
X@noindent
XThe @code{INT} and @code{QUIT} signals for an invoked command are
Xignored if the command is followed by @code{&} and the job @code{monitor}
Xoption is not active. Otherwise, signals have the values inherited by
Xthe shell from its parent (but @xref{Functions}, for the
X@code{TRAP@var{xxx}} special functions).@refill
X
X@node History, Arithmetic Evaluation, Jobs & Signals, Top
X@chapter History
X@cindex history
X
X@vindex HISTSIZE, use of
X@noindent
XHistory substitution allows you to use words from previous command lines
Xin 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 is
Xcontrolled by the @code{HISTSIZE} variable. The most recent command is
Xretained in any case. A history substitution begins with a @code{!} and
Xmay occur anywhere on the command line; history substitutions do not
Xnest. The @code{!} can be escaped with @code{\} to suppress its special
Xmeaning. Single or double quotes will @emph{not} work for this.@refill
X
X@noindent
XInput lines containing history substitutions are echoed on the terminal
Xafter being expanded, but before any other substitutions take place or
Xthe command gets executed.
X
X@menu
X* Event Designators::
X* Word Designators::
X* Modifiers::
X@end menu
X
X@node Event Designators, Word Designators, , History
X@section Event Designators
X@cindex history event designators
X@cindex event designators, history
X
X@noindent
XAn event designator is a reference to a command line entry in the
Xhistory list.
X
X@table @code
X@item !
XStart a history substitution, except when followed by a blank, newline,
X@code{=}, or @code{(}.
X@item !!
XRefer to the previous command. By itself, this substitution repeats the
Xprevious command.
X@item !n
XRefer to command line @var{n}.
X@item !-n
XRefer to the current command line minus @var{n}.
X@item !str
XRefer to the most recent command starting with @var{str}.
X@item !?@var{str}[?]
XRefer to the most recent command containing @var{str}.
X@item !#
XRefer to the current command line typed in so far.
X@item !@{@dots{}@}
XInsulate a history reference from adjacent characters (if necessary).
X@end table
X
X@node Word Designators, Modifiers, Event Designators, History
X@section Word Designators
X@cindex history word designators
X@cindex word designators, history
X
X@noindent
XA @code{:} separates the event specification from the word designator.
XIt can be omitted if the word designator begins with a @code{,},
X@code{$}, @code{*}, @code{-} or @code{%}. If the word is to be selected
Xfrom the previous command, the second @code{!} character can be omitted
Xfrom the event specification. For instance, @code{!!:1} and @code{!:1}
Xboth refer to the first word of the previous command, while @code{!!$}
Xand @code{!$} both refer to the last word in the previous command. Word
Xdesignators include:@refill
X
X@table @code
X@item 0
XThe first input word (command).
X@item @var{n}
XThe @var{n}'th argument.
X@item ^
XThe first argument, that is, @code{1}.
X@item $
XThe last argument.
X@item %
XThe word matched by (the most recent) @code{?}s search.
X@item @var{x}-@var{y}
XA range of words; @code{-@var{y}} abbreviates @code{0-@var{y}}.
X@item *
XAll the arguments, or a null value if there is just one word in the
Xevent.
X@item @var{x}*
XAbbreviates @code{@var{x}-$}.
X@item @var{x}
XLike @code{@var{x}*} but omitting word @code{$}.
X@end table
X
X@node Modifiers, , Word Designators, History
X@section Modifiers
X@cindex modifiers, history
X@cindex history modifiers
X
X@noindent
XAfter the optional word designator, you can add a sequence of one or
Xmore of the following modifiers, each preceded by a @code{:}. These
Xmodifiers also work on the result of filename and parameter
Xexpansion.@refill
X
X@table @code
X@item h
XRemove a trailing pathname component, leaving the head.
X@item r
XRemove a trailing suffix of the form @code{.@var{xxx}}, leaving the
Xbasename.@refill
X@item e
XRemove all but the suffix.
X@item t
XRemove all leading pathname components, leaving the tail.
X@item &
XRepeat the previous substitution.
X@item g
XApply the change to the first occurrence of a match in each word, by
Xprefixing the above (for example, @code{g&}).
X@item p
XPrint the new command but do not execute it.
X@item q
XQuote the substituted words, escaping further substitutions.
X@item x
XLike @code{q}, but break into words at each blank.
X@item l
XConvert the words to all lowercase.
X@item u
XConvert the words to all uppercase.
X@item s/@var{l}/@var{r}[/]
XSubstitute @var{r} for @var{l}.
X@end table
X
X@noindent
XUnless preceded by a @code{g}, the substitution is done only for the
Xfirst string that matches @var{l}.
X
X@noindent
XThe left-hand side of substitutions are not regular expressions, but
Xcharacter strings. Any character can be used as the delimiter in place
Xof @code{/}. A backslash quotes the delimiter character. The character
X@code{&}, in the right-hand side, is replaced by the text from the
Xleft-hand side. The @code{&} can be quoted with a backslash. A null
X@var{l} uses the previous string either from a @var{l} or from a
Xcontextual scan string @var{s} from @code{!?@var{s}}. You can omit the
Xrightmost delimiter if a newline immediately follows @var{r}; the
Xrightmost @code{?} in a context scan can similarly be omitted.@refill
X
X@noindent
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
X@noindent
XThe character sequence @samp{^foo^bar} repeats the last command,
Xreplacing the string @samp{foo} with the string @samp{bar}.@refill
X
X@cindex history, disabling
X@cindex disabling history
X@noindent
XIf the shell encounters the character sequence @code{!"} in the input,
Xthe history mechanism is temporarily disabled until the current list is
Xfully parsed. The @code{!"} is removed from the input, and any
Xsubsequent @code{!} characters have no special significance.@refill
X
X@findex fc, use of
X@noindent
XA less convenient but more comprehensible form of command history
Xsupport is provided by the @code{fc} builtin
X(@pxref{Shell Builtin Commands}).
X
X@node Arithmetic Evaluation, Conditional Expressions, History, Top
X@chapter Arithmetic Evaluation
X@cindex arithmetic evaluation
X@cindex evaluation, arithmetic
X
X@noindent
XAn ability to perform integer arithmetic is provided with the builtin
X@code{let}. Evaluations are performed using @emph{long} arithmetic.
XConstants are of the form @code{[@var{base}#]@var{n}} where @var{base}
Xis a decimal number between two and thirty-six representing the
Xarithmetic base and @var{n} is a number in that base. If @var{base} is
Xomitted then base 10 is used.@refill
X
X@cindex arithmetic operators
X@cindex operators, arithmetic
X@noindent
XAn arithmetic expression uses nearly the same syntax, precedence, and
END_OF_FILE
if test 49503 -ne `wc -c <'doc/zsh.texi.01'`; then
echo shar: \"'doc/zsh.texi.01'\" unpacked with wrong size!
fi
# end of 'doc/zsh.texi.01'
fi
if test -f 'help/TRAP' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/TRAP'\"
else
echo shar: Extracting \"'help/TRAP'\" \(640 characters\)
sed "s/^X//" >'help/TRAP' <<'END_OF_FILE'
X TRAPxxx
X If defined and non-null, this function will be executed
X whenever the shell catches a signal SIGxxx, where xxx
X is a signal name as specified for the kill builtin (see
X below). In addition, TRAPERR is executed whenever a
X command has a non-zero exit status, TRAPDEBUG is exe-
X cuted after each command, and TRAPEXIT is executed when
X the shell exits, or when the current function exits if
X defined inside a function. If a function of this form
X is defined and null, the shell and processes spawned by
X it will ignore SIGxxx.
END_OF_FILE
if test 640 -ne `wc -c <'help/TRAP'`; then
echo shar: \"'help/TRAP'\" unpacked with wrong size!
fi
# end of 'help/TRAP'
fi
if test -f 'help/fc' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/fc'\"
else
echo shar: Extracting \"'help/fc'\" \(1743 characters\)
sed "s/^X//" >'help/fc' <<'END_OF_FILE'
X fc [ -e ename ] [ -nlrdD ] [ old=new ... ] [ first [ last ] ]
X fc -ARW [ filename ]
X Select a range of commands from first to last from the
X history list. The arguments first and last may be
X specified as a number or as a string. A negative
X number is used as an offset to the current history
X event number. A string specifies the most recent event
X beginning with the given string. All substitutions
X old=new, if any, are then performed on the commands.
X If the -l flag is given, the resulting commands are
X listed on standard output. Otherwise the editor pro-
X gram ename is invoked on a file containing these his-
X tory events. If ename is not given, the value of the
X parameter FCEDIT is used. If ename is "-", no editor
X is invoked. When editing is complete, the edited
X command(s) is executed. If first is not specified, it
X will be set to -1 (the most recent event), or to -16 if
X the -l flag is given. If last is not specified, it
X will be set to first, or to -1 if the -l flag is given.
X The flag -r reverses the order of the commands and the
X flag -n suppresses command numbers when listing. Also
X when listing, -d prints datestamps for each command,
X and -D prints real execution times.
X
X fc -R reads the history from the given file, fc -W
X writes the history out to the given file, and fc -A
X appends the history out to the given file.
X history [ -nr ] [ first [ last ] ]
X Same as fc -l.
X r Equivalent to fc -e -.
END_OF_FILE
if test 1743 -ne `wc -c <'help/fc'`; then
echo shar: \"'help/fc'\" unpacked with wrong size!
fi
# end of 'help/fc'
fi
echo shar: End of archive 5 \(of 22\).
cp /dev/null ark5isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:22:01 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 56
Archive-name: zsh/part06

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: help/read man/man1/zsh.1.02 src/signals.h.sample
# Wrapped by mattson@odin on Sat Feb 6 14:41:52 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 6 (of 22)."'
if test -f 'help/read' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/read'\"
else
echo shar: Extracting \"'help/read'\" \(1012 characters\)
sed "s/^X//" >'help/read' <<'END_OF_FILE'
X read [ -rzp ] [ -un ] [ name?prompt ] [ name ... ]
X Read one line and break it into fields using the char-
X acters in IFS as separators. In raw mode, -r, a \ at
X the end of a line does not signify line continuation.
X If the -z flag is set, read from the editor buffer
X stack. The first field is assigned to the first name,
X the second field to the second name, etc., with left-
X over fields assigned to the last name. If name is
X omitted then REPLY is used. If -un is specified, then
X input is read from file descriptor n; if -p is speci-
X fied, then input is read from the coprocess. The exit
X status is 0 unless end-of-file is encountered. If the
X first argument contains a ?, the remainder of this word
X is used as a prompt on standard error when the shell is
X interactive. The exit status is 0 unless an end-of-
X file is encountered.
END_OF_FILE
if test 1012 -ne `wc -c <'help/read'`; then
echo shar: \"'help/read'\" unpacked with wrong size!
fi
# end of 'help/read'
fi
if test -f 'man/man1/zsh.1.02' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'man/man1/zsh.1.02'\"
else
echo shar: Extracting \"'man/man1/zsh.1.02'\" \(49353 characters\)
sed "s/^X//" >'man/man1/zsh.1.02' <<'END_OF_FILE'


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-line-or-search\fP


XMove up a line in the buffer, or if already at the top line,

Xsearch backward in the history for a line beginning with the
Xfirst word in the buffer.
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%# ". If the escape sequence takes an optional
Xinteger, it should appear between the '%' and the next character of the


Xsequence. The 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.
XAn integer may follow the '%' 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 '.'.
XAn integer may follow the '%' 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.B %v
XThe value of the first element of the $psvar array parameter. Following
Xthe '%' with an integer gives that element of the array.
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 psvar (PSVAR)


XAn array (colon-separated list) whose first nine values can be used in

X\fBPROMPT\fP strings. Setting \fBpsvar\fP also sets \fBPSVAR\fP, and
Xvice versa.
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. If it contains the single word "notme", then all
Xevents are reported as with "all" except $USERNAME.
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\fBAPPEND_HISTORY\fP
XIf this is set, zsh sessions will append their history list to
Xthe history file, rather than overwrite it. Thus, multiple parallel
Xzsh sessions will all have their history lists added to the
Xhistory file, in the order they are killed.
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_REMOVE_SLASH\fP
XWhen the last character resulting from a completion is a slash and the next
Xcharacter typed is a word delimiter, remove the slash.
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\fBEXTENDED_HISTORY\fP
XSave beginning and ending timestamps to the history file.
XThe format of these timestamps is
X\fI:<beginning time>:<ending time>:<command>.\fP
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)
XSource only the /etc/zshenv file.
XDo not source the .zshenv, /etc/zprofile, .zprofile,
X/etc/zshrc, .zshrc, /etc/zlogin, .zlogin, or .zlogout 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 \-\fBh\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, named directories 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 ] [ \-\fBnlrdDfE\fP ] [ \fIold\fP=\fInew\fP ... ] [ \fIfirst\fP [ \fIlast\fP ] ]
X.TP
X\fBfc\fP \-\fBARWI\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
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 timestamps for each command, and
X\-\fBf\fP prints full time-date stamps. Adding the \-\fBE\fP flag
Xcauses the dates to be printed as `dd.mm.yyyy'.
XWith the \-\fBD\fP flag, \fBfc\fP prints elapsed 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\fBfc\fP \-\fBAI\fP ( \-\fBWI\fP ) appends ( writes ) only those
Xevents that are new since last incremental append ( write ) to
Xthe history 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
END_OF_FILE
if test 49353 -ne `wc -c <'man/man1/zsh.1.02'`; then
echo shar: \"'man/man1/zsh.1.02'\" unpacked with wrong size!
fi
# end of 'man/man1/zsh.1.02'
fi
if test -f 'src/signals.h.sample' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/signals.h.sample'\"
else
echo shar: Extracting \"'src/signals.h.sample'\" \(1429 characters\)
sed "s/^X//" >'src/signals.h.sample' <<'END_OF_FILE'
XYour signals.h file should look something like this. If it doesn't,
Xperhaps your csh or ed is different.
X
X/* this file is created automatically by buildzsh */
X/* if all this is wrong, blame csh ;-) */
X
X#define SIGCOUNT 31
X
X#ifdef GLOBALS
X
Xchar *sigmsg[SIGCOUNT+2] = {
X "done",
X "hangup",
X "interrupt",
X "quit",
X "illegal instruction",
X "trace trap",
X "abort",
X "EMT instruction",
X "floating point exception",
X "killed",
X "bus error",
X "segmentation fault",
X "bad system call",
X "broken pipe",
X "SIGALRM",
X "terminated",
X "SIGURG",
X#ifdef USE_SUSPENDED
X "suspended (signal)",
X#else
X "stopped (signal)",
X#endif
X#ifdef USE_SUSPENDED
X "suspended",
X#else
X "stopped",
X#endif
X "continued",
X "SIGCHLD",
X#ifdef USE_SUSPENDED
X "suspended (tty input)",
X#else
X "stopped (tty input)",
X#endif
X#ifdef USE_SUSPENDED
X "suspended (tty output)",
X#else
X "stopped (tty output)",
X#endif
X "SIGIO",
X "cpu limit exceeded",
X "filesize limit exceeded",
X "virtual time alarm",
X "SIGPROF",
X "SIGWINCH",
X "SIGLOST",
X "SIGUSR1",
X "SIGUSR2",
X NULL
X};
X
Xchar *sigs[SIGCOUNT+4] = {
X "EXIT",
X "HUP",
X "INT",
X "QUIT",
X "ILL",
X "TRAP",
X "ABRT",
X "EMT",
X "FPE",
X "KILL",
X "BUS",
X "SEGV",
X "SYS",
X "PIPE",
X "ALRM",
X "TERM",
X "URG",
X "STOP",
X "TSTP",
X "CONT",
X "CHLD",
X "TTIN",
X "TTOU",
X "IO",
X "XCPU",
X "XFSZ",
X "VTALRM",
X "PROF",
X "WINCH",
X "LOST",
X "USR1",
X "USR2",
X "ERR",
X "DEBUG",
X NULL
X};
X
X#else
X
Xextern char *sigs[SIGCOUNT+4],*sigmsg[SIGCOUNT+2];
X
X#endif
END_OF_FILE
if test 1429 -ne `wc -c <'src/signals.h.sample'`; then
echo shar: \"'src/signals.h.sample'\" unpacked with wrong size!
fi
# end of 'src/signals.h.sample'
fi
echo shar: End of archive 6 \(of 22\).
cp /dev/null ark6isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:22:30 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 57
Archive-name: zsh/part07

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: help/trap man/man1/zsh.1.01 src/ztype.h
# Wrapped by mattson@odin on Sat Feb 6 14:41:52 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 7 (of 22)."'
if test -f 'help/trap' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/trap'\"
else
echo shar: Extracting \"'help/trap'\" \(946 characters\)
sed "s/^X//" >'help/trap' <<'END_OF_FILE'
X trap [ arg ] [ sig ] ...
X arg is a command to be read and executed when the shell
X receives sig. Each sig can be given as a number or as
X the name of a signal. If arg is -, then all traps sig
X are reset to their default values. If arg is the null
X string, then this signal is ignored by the shell and by
X the commands it invokes. If sig is ERR then arg will
X be executed after each command. If sig is 0 or EXIT
X and the trap statement is executed inside the body of a
X function, then the command arg is executed after the
X function completes. If sig is 0 or EXIT and the trap
X statement is not executed inside the body of a func-
X tion, then the command arg is executed when the shell
X terminates. The trap command with no arguments prints
X a list of commands associated with each signal.
END_OF_FILE
if test 946 -ne `wc -c <'help/trap'`; then
echo shar: \"'help/trap'\" unpacked with wrong size!
fi
# end of 'help/trap'
fi
if test -f 'man/man1/zsh.1.01' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'man/man1/zsh.1.01'\"
else
echo shar: Extracting \"'man/man1/zsh.1.01'\" \(49329 characters\)
sed "s/^X//" >'man/man1/zsh.1.01' <<'END_OF_FILE'
X.\"
X.TH ZSH 1 "5 February 1993" "zsh version 2.3.1"
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 string 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 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 if \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 or 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\fBa\fI[-|+]n\fR
Xfiles accessed within last n days (-), more than n days ago (+), or
Xn days ago.\fP
X.TP
X\fBm\fI[-|+]n\fR
Xfiles modified within last n days (-), more than n days ago (+), or
Xn days ago.\fP
X.TP
X\fBc\fI[-|+]n\fR
Xfiles whose inode changed within last n days (-), more than n days ago (+), or
Xn days ago.\fP
X.TP
X\fBL\fI[+|-]n\fR
Xfiles less than n bytes (-), more than n bytes (+), or
Xexactly n bytes in length.
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 or a \e,
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 the 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 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 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 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)


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-line-or-search\fP
XMove down a line in the buffer, or if already at the bottom line,
Xsearch forward in the history for a line beginning with the first
Xword in the buffer.
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)
END_OF_FILE
if test 49329 -ne `wc -c <'man/man1/zsh.1.01'`; then
echo shar: \"'man/man1/zsh.1.01'\" unpacked with wrong size!
fi
# end of 'man/man1/zsh.1.01'
fi
if test -f 'src/ztype.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/ztype.h'\"
else
echo shar: Extracting \"'src/ztype.h'\" \(1486 characters\)
sed "s/^X//" >'src/ztype.h' <<'END_OF_FILE'
X/*
X *
X * ztype.h - character classification macros


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#define IDIGIT 1
X#define IALNUM 2
X#define IBLANK 4
X#define INBLANK 8
X#define ITOK 16
X#define ISEP 32
X#define IALPHA 64
X#define IIDENT 128
X#define IUSER 256
X#define ICNTRL 512
X#define IWORD 1024
X#define ISPECIAL 2048
X#define _icom(X,Y) (typtab[(int) (unsigned char) (X)] & Y)
X#define idigit(X) _icom(X,IDIGIT)
X#define ialnum(X) _icom(X,IALNUM)
X#define iblank(X) _icom(X,IBLANK) /* blank, not including \n */
X#define inblank(X) _icom(X,INBLANK) /* blank or \n */
X#define itok(X) _icom(X,ITOK)
X#define isep(X) _icom(X,ISEP)
X#define ialpha(X) _icom(X,IALPHA)
X#define iident(X) _icom(X,IIDENT)
X#define iuser(X) _icom(X,IUSER) /* username char */
X#define icntrl(X) _icom(X,ICNTRL)
X#define iword(X) _icom(X,IWORD)
X#define ispecial(X) _icom(X,ISPECIAL)
X
XEXTERN short int typtab[256];
X
END_OF_FILE
if test 1486 -ne `wc -c <'src/ztype.h'`; then
echo shar: \"'src/ztype.h'\" unpacked with wrong size!
fi
# end of 'src/ztype.h'
fi
echo shar: End of archive 7 \(of 22\).
cp /dev/null ark7isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:23:07 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 58
Archive-name: zsh/part08

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: src/builtin.c.01 src/config.h.sample
# Wrapped by mattson@odin on Sat Feb 6 14:41:52 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 8 (of 22)."'
if test -f 'src/builtin.c.01' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/builtin.c.01'\"
else
echo shar: Extracting \"'src/builtin.c.01'\" \(49195 characters\)
sed "s/^X//" >'src/builtin.c.01' <<'END_OF_FILE'
X/*
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
X#define NULLBINCMD ((int (*) DCLPROTO((char *,char **,char *,int))) 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",NULLBINCMD,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,"nlreIRWAdDfE",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,"nrdDfE","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,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZaefghjklmnosuvwxy",NULL},
X {"setopt",bin_setopt,0,-1,BINF_PLUSOPTS,0,"0123456789BCDEFGHIJKLMNOPQRSTUVWXYZaefghjklmnosuvwxy",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,"0123456789BCDEFGHIJKLMNOPQRSTUWXYZabefghjklmnosuvwxy",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,NULLBINCMD,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, isset(opp->id) ? "on" : "off");
X } else
X for (opp = optns; opp->name; opp++)
X if (isset(opp->id))
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 breaks = loops;
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 (curjob != -1 && !(jobtab[curjob].stat & STAT_INUSE))
X {
X curjob = prevjob; setprevjob();
X if (curjob != -1 && !(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 if (unset(NORCS) && interact) {
X if (isset(APPENDHISTORY)) {
X savehistfile(getsparam("HISTFILE"),0,3);
X readhistfile(getsparam("HISTFILE"),0);
X }
X savehistfile(getsparam("HISTFILE"),0,0);
X if (islogin)
X sourcehome(".zlogout");
X }
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[(int)opp->id] = OPT_SET;
X else if (ops[(int)opp->id] == 2-isun)
X opts[(int)opp->id] = OPT_UNSET;
X while (*args) {
X c = optlookup(*args++);
X if (c != -1) {
X if (c == INTERACTIVE)
X zerrnam(nam,"can't change option: %s",args[-1],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
Xstatic hnamcmp DCLPROTO((struct hashnode **a,struct hashnode **b));
Xstatic int hnamcmp(a,b)
Xstruct hashnode **a;struct hashnode **b;
X{
X return forstrcmp(&((*a)->nam), &((*b)->nam));
X}
X
Xvoid listhtable(ht,func) /**/
XHashtab ht;HFunc func;
X{
Xint t0;
Xstruct hashnode *hn;
X
X#ifndef HASHORDER
X
Xint nhash; struct hashnode **hnsorttab, **htp;
X
X for (nhash = 0, t0 = ht->hsize-1; t0 >= 0; t0--)
X for (hn = ht->nodes[t0]; hn; hn = hn->next)
X nhash++;
X
X hnsorttab = (struct hashnode **)zalloc (nhash * sizeof(struct hashnode *));
X for (htp = hnsorttab, t0 = ht->hsize-1; t0 >= 0; t0--)
X for (hn = ht->nodes[t0]; hn; hn = hn->next)
X *htp++ = hn;
X
X qsort((vptr)&hnsorttab[0],nhash,sizeof(struct hashnode *),
X (int (*) DCLPROTO((const void *, const void *)))hnamcmp);
X
X for (htp = hnsorttab; nhash; nhash--, htp++)
X func((*htp)->nam, (char *) (*htp));
X
X free (hnsorttab);
X
X#else
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#endif HASHORDER
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;
Xint informed;
X
X for (; *argv; argv++) {
X informed = 0;
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 informed = 1;
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 informed = 1;
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 informed = 1;
X }
X }
X if (!informed && v) {
X printf("%s not found\n",*argv);
X retval = 1;
X break;
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 free(cnam);
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, *dir;
X
X if (func == BIN_CD && isset(AUTOPUSHD))
X func = BIN_PUSHD;
X dir = dest = cd_get_dest(nam,argv,ops,func);
X if (!dest)
X return 1;
X dest = cd_do_chdir(nam,dest);
X if (dest != dir)
X free(dir);
X if (!dest)
X return 1;
X cd_new_pwd(func,dest);
X free(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 || empty(dirstack)))
X dest = ztrdup(home);
X else
X dest = ztrdup(getnode(dirstack));
X else if (!argv[1]) {
X Lknode n;
X int dd;
X char *end;
X
X if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '-' : '+')) {
X dd = zstrtol(argv[0]+1,&end,10)-1;
X if (dd < 0 || *end != '\0') {
X zerrnam(nam,"%s: bad directory specification",argv[0],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 = zstrtol(argv[0]+1,&end,10);
X if (*end != '\0') {
X zerrnam(nam,"%s: bad directory specification",argv[0],0);
X return NULL;
X }
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 = ztrdup(oldpwd));
X else dest = ztrdup(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 = zalloc(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 ztrdup(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{
Xchar 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(buf) == -1) ? NULL : ztrdup(buf2);
X if (!dotsct) {
X if (chdir(buf) == -1) return NULL;
X if (*buf2) sprintf(buf,"%s/%s",(!strcmp("/",pwd)) ? "" : pwd,buf2);
X else strcpy(buf,pwd);
X return ztrdup(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 ztrdup(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 while (*s == '/' && s[1] == '.' && s[2] == '.') {
X *d++ = '/'; *d++ = '.'; *d++ = '.';
X s += 3;
X }
X#endif
X#ifdef apollo
X if (*s == '/') *d++ = *s++; /*added RBC 18/05/92 */
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 if (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;
Xchar *new_pwd;
X
X if (isset(CHASELINKS))
X new_pwd = findpwd(s);
X else
X new_pwd = ztrdup(s);
X if (!strcmp(new_pwd, pwd)) {
X free(new_pwd);
X#ifdef ALWAYS_DO_CD_PROCESSING
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#endif
X return;
X }
X free(oldpwd);
X oldpwd = pwd;
X pwd = new_pwd;
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 char *nodedata;
X for (n = firstnode(dirstack); n; incnode(n)) {
X nodedata = getdata(n);
X if (!strcmp(oldpwd,nodedata) || !strcmp(pwd,nodedata)) {
X free(remnode(dirstack,n)); break;
X }
X }
X }
X pushnode(dirstack,ztrdup(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 = 1; 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 retval = 1;
X } else if (kill(atoi(*argv),sig) == -1) {
X zerrnam("kill","kill failed: %e",NULL,errno);
X retval = 1;
X }
X }
X return retval;
X}
X
Xstatic char *recs[] = {
X "cputime","filesize","datasize","stacksize","coredumpsize",
X#ifdef RLIMIT_RSS
X#ifdef RLIMIT_MEMLOCK
X "memoryuse",
X#else
X "resident",
X#endif /* RLIMIT_MEMLOCK */
X#endif /* RLIMIT_RSS */
X#ifdef RLIMIT_MEMLOCK
X "memorylocked",
X#endif
X#ifdef RLIMIT_NPROC
X "maxproc",
X#endif
X#ifdef RLIMIT_OFILE
X "openfiles",
X#endif
X#ifdef RLIMIT_NOFILE
X "descriptors",
X#endif
X#ifdef RLIMIT_VMEM
X "memorysize"
X#endif
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_NPROC
X else if (lim == RLIMIT_NPROC)
X val = zstrtol(s,&s,10);
X#endif
X#ifdef RLIMIT_OFILE
X else if (lim == RLIMIT_OFILE)
X val = zstrtol(s,&s,10);
X#endif
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_NPROC
X else if (t0 == RLIMIT_NPROC)
X printf("%d\n",(int) val);
X#endif
X#ifdef RLIMIT_OFILE
X else if (t0 == RLIMIT_OFILE)
X printf("%d\n",(int) val);
X#endif
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 (r) {
X r = last;
X last = first;
X first = r;
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 if (d >= 2) {
X if (d >= 4) {
X fprintf(f,"%d.%d.%d ",
X ltm->tm_mday,ltm->tm_mon+1,
X ltm->tm_year+1900);
X } else {
X fprintf(f,"%d/%d/%d ",
X ltm->tm_mon+1,
X ltm->tm_mday,
X ltm->tm_year+1900);
X }
X }
X fprintf(f,"%02d:%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 else if (first > last) first--;
X else 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,delayrem,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 delayrem = !strcmp(nam,"r")
X && argv[0]
X &&(argv[1] || !strchr(argv[0],'='));
X if (!delayrem && !(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,
X (ops['I'] ? 2 : 0));
X return 0;
X }
X if (ops['A']) {
X savehistfile(*argv ? *argv : getsparam("HISTFILE"),1,
X (ops['I'] ? 3 : 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 (delayrem) remhist();
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'],
X ops['d'] + ops['f'] * 2 + ops['E'] * 4,
X first,last,asgf);
X else {
X FILE *out;
X char *fil = gettemp();
X
X retval = 1;
X out = fopen(fil,"w");
X if (!out)
X zerrnam("fc","can't open temp file: %e",NULL,errno);
X else {
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 ent->flags = 0;
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,0),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 = 0,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);
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) && bptr != buf) || c == '\n') break;
X if (isep(c)) continue;
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 *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 if (isep(c) && bptr == buf) continue;
X *bptr++ = c;
X if (bptr == buf+bsiz) {
X buf = realloc(buf,bsiz *= 2);
X bptr = buf+(bsiz/2);
X }
X }
X while(bptr > buf && isep(bptr[-1])) bptr--;
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{
END_OF_FILE
if test 49195 -ne `wc -c <'src/builtin.c.01'`; then
echo shar: \"'src/builtin.c.01'\" unpacked with wrong size!
fi
# end of 'src/builtin.c.01'
fi
if test -f 'src/config.h.sample' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/config.h.sample'\"
else
echo shar: Extracting \"'src/config.h.sample'\" \(2966 characters\)
sed "s/^X//" >'src/config.h.sample' <<'END_OF_FILE'


X/* this file is created automatically by buildzsh */
X

X/* define this if you are sysvish */
X/* #define SYSV */
X
X#define TERMIOS
X/* #define TTY_NEEDS_DRAINING */
X/* #define CLOBBERS_TYPEAHEAD */
X
X#define HAS_DIRENT
X
X#define HAS_UNISTD
X
X#define HAS_STDLIB
X
X#define HAS_STRING
X
X#define HAS_MEMORY
X
X#define HAS_LOCALE
X
X/*#define HAS_UTMPX*/
X
X#define UTMP_HOST
X
X/*#define HAS_TIME*/
X
X/*#define HAS_WAIT*/
X
X/* define this if you have WAITPID */
X#define WAITPID
X
X/* define this if you have SELECT */
X#define HAS_SELECT
X
X/* define this if you have <sys/select.h> */
X/* #define HAS_SYS_SELECT */
X
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
X/* #define NO_FIFOS */
X
X/* define this if you have strftime() */
X#define HAS_STRFTIME
X
X#define HAS_TCSETPGRP
X
X#define HAS_TCCRAP
X
X#define HAS_SETPGID
X
X/* #define HAS_SIGRELSE */
X
X/* define this if you have RFS */
X/* #define HAS_RFS */
X
X/* define this if you have a working getrusage and wait3 */
X#define HAS_RUSAGE
X/* define this if you use NIS for your passwd map */
X#define HAS_NIS_PASSWD
X
X/* define this if your signal handlers return void */
X#define SIGVOID
X#ifdef sgi
X#undef SIGVOID
X#endif
X
X/* define this if signal handlers need to be reset each time */
X/* #define RESETHANDNEEDED */
X
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 */
X#define HOSTTYPE "sun4"
X
X/* the default editor for the fc builtin */
X#define DEFFCEDIT "vi"
X
X/* the path of wtmp */
X#define WTMP_FILE "/var/adm/wtmp"
X
X/* the path of utmp */
X#define UTMP_FILE "/etc/utmp"
X
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 absolutely first whenever zsh is run; if undefined,
X don't source anything */
X#define GLOBALZSHENV "/etc/zshenv"
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#define _BBN_POSIX_SUPPORT /* this could be nX, 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
END_OF_FILE
if test 2966 -ne `wc -c <'src/config.h.sample'`; then
echo shar: \"'src/config.h.sample'\" unpacked with wrong size!
fi
# end of 'src/config.h.sample'
fi
echo shar: End of archive 8 \(of 22\).
cp /dev/null ark8isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:23:27 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 59
Archive-name: zsh/part09

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: doc/zsh.texi.03 scripts/c2z
# Wrapped by mattson@odin on Sat Feb 6 14:41:53 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 9 (of 22)."'
if test -f 'doc/zsh.texi.03' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'doc/zsh.texi.03'\"
else
echo shar: Extracting \"'doc/zsh.texi.03'\" \(48882 characters\)
sed "s/^X//" >'doc/zsh.texi.03' <<'END_OF_FILE'


XAll parameters subsequently defined are automatically exported.

X@cindex history, appending to file
X@pindex APPEND_HISTORY
X@item APPEND_HISTORY
XIf this is set, zsh sessions will append their history list to the
Xhistory file, rather than overwrite it. Thus, multiple parallel zsh
Xsessions will all have their history lists added to the history file, in
Xthe order they are killed. @xref{Shell Builtin Commands}, for the
X@code{fc} command.@refill
X@cindex cd, automatic
X@pindex AUTO_CD
X@item AUTO_CD (-J)
XIf a command is not in the hash table, and there exists an executable
Xdirectory by that name, perform the @code{cd} command to that directory.
X@cindex completion, listing choices
X@pindex AUTO_LIST
X@item AUTO_LIST (-9)


XAutomatically list choices on an ambiguous completion.

X@cindex completion, menu, on TAB
X@pindex AUTO_MENU
X@item AUTO_MENU
XAutomatically use menu completion if the @key{TAB} key is pressed
Xrepeatedly.@refill
X@cindex cd, behaving like pushd
X@cindex pushd, making cd behave like
X@pindex AUTO_PUSHD
X@item AUTO_PUSHD (-N)
XMake @code{cd} act like @code{pushd}.
X@cindex slash, removing trailing
X@pindex AUTO_REMOVE_SLASH
X@item AUTO_REMOVE_SLASH


XWhen the last character resulting from a completion is a slash and the next
Xcharacter typed is a word delimiter, remove the slash.

X@cindex jobs, resuming automatically
X@cindex resuming jobs automatically
X@pindex AUTO_RESUME
X@item AUTO_RESUME (-W)
XTreat single word simple commands without redirection as candidates for
Xresumption of an existing job.
X@cindex jobs, background priority
X@cindex background jobs, priority of
X@pindex BGNICE
X@item BGNICE (-6)
XRun all background jobs at a lower priority. This option is set by
Xdefault.
X@cindex brace expansion, extending
X@cindex expansion, brace, extended
X@pindex BRACECCL
X@item BRACECCL
XAllow brace expansions of the form @code{@{a-zA-Z@}}, etc.
X@cindex cd, to parameter
X@pindex CDABLEVARS
X@item CDABLEVARS (-T)
XIf the argument to a @code{cd} command is not a directory, but a
Xparameter exists by the same name whose value begins with a @code{/},
Xtry to change to the directory specified by the parameter's
Xvalue.@refill
X@cindex links, symbolic
X@cindex symbolic links
X@pindex CHASELINKS
X@item CHASELINKS (-w)


XResolve symbolic links to their true values.

X@cindex correction, spelling
X@cindex spelling correction
X@pindex CORRECT
X@item CORRECT (-0)
XTry to correct the spelling of commands.
X@pindex CORRECT_ALL
X@item CORRECT_ALL (-O)


XTry to correct the spelling of all arguments in a line.

X@cindex csh, loop style
X@cindex loop style, csh
X@pindex CSH_JUNKIE_LOOPS
X@item CSH_JUNKIE_LOOPS
XAllow loop bodies to take the form @samp{@var{list}; end} instead of
X@samp{do @var{list}; done}.
X@cindex csh, quoting style
X@cindex quoting style, csh
X@pindex CSH_JUNKIE_QUOTES
X@item CSH_JUNKIE_QUOTES
XComplain if a quoted expression runs off the end of a line; prevent
Xquoted expressions from containing unescaped newlines.
X@cindex csh, null globbing style
X@cindex null globbing, csh style
X@cindex globbing, null, csh style
X@pindex CSH_NULL_GLOB
X@item CSH_NULL_GLOB
XIf a pattern for filename generation has no matches, delete the pattern
Xfrom the argument list; do not report an error unless all the patterns
Xin a command have no matches. Overrides @code{NULL_GLOB}.
X@cindex exit status, trapping
X@pindex ERREXIT
X@item ERREXIT (-e)
XIf a command has a non-zero exit status, execute the @code{ERR} trap, if
Xset, and exit.
X@cindex globbing, extended
X@pindex EXTENDED_GLOB
X@item EXTENDED_GLOB
XTreat the @code{#} and @code{^} characters as part of patterns for
Xfilename generation, etc.@refill
X@cindex history, timestamping
X@pindex EXTENDED_HISTORY
X@item EXTENDED_HISTORY
XSave beginning and ending timestamps to the history file. The format of
Xthese timestamps is @code{:@var{beginning time}:@var{ending
Xtime}:@var{command}}.@refill
X@pindex GLOB_COMPLETE
X@item GLOB_COMPLETE
XLike @code{MENU_COMPLETE}, except that the current word is expanded
Xusing normal shell expansion instead of completion. If no matches are
Xfound, a @code{*} is added to the end of the word, and expansion is
Xattempted again.@refill
X@cindex globbing, of . files
X@pindex GLOB_DOTS
X@item GLOB_DOTS (-4)
XDo not require a leading @code{.} in a filename to be matched
Xexplicitly.@refill
X@cindex hashing, of commands
X@cindex command hashing
X@pindex HASH_CMDS
X@item HASH_CMDS
XPlace the location of each command in the hash table the first time it
Xis executed. If this option is unset, no path hashing will be done at
Xall.
X@cindex hashing, of directories
X@cindex directories, hashing
X@pindex HASH_DIRS
X@item HASH_DIRS
XWhenever a command is executed, hash the directory containing it, as
Xwell as all directories that occur earlier in the path. Has no effect
Xif @code{HASH_CMDS} is unset.
X@pindex HASH_LIST_ALL
X@item HASH_LIST_ALL
XWhenever a command completion is attempted, make sure the entire command
Xpath is hashed first. This makes the first completion slower.
X@cindex history, ignoring duplicates
X@pindex HIST_IGNORE_DUPS
X@item HIST_IGNORE_DUPS (-h)
XDo not enter command lines into the history list if they are duplicates
Xof the previous event.
X@cindex history, ignoring spaces
X@pindex HIST_IGNORE_SPACE
X@item HIST_IGNORE_SPACE (-g)
XDo not enter command lines into the history list if they begin with a
Xblank.
X@cindex history, storing as literal
X@pindex HIST_LIT
X@item HIST_LIT (-j)
XUse literal (unparsed) versions of the history lines in the editor.
X@pindex HIST_NO_STORE
X@item HIST_NO_STORE
XRemove the @code{history} (@code{fc} @code{-l}) command from the history
Xwhen invoked.
X@cindex history, verifying substitution
X@pindex HIST_VERIFY
X@item HIST_VERIFY
XWhenever the user enters a line with history substitution, don't execute
Xthe line directly; instead, perform history substitution and reload the
Xline into the editing buffer.
X@cindex brace expansion, disabling
X@cindex expansion, brace, disabling
X@cindex disabling brace expansion
X@pindex IGNORE_BRACES
X@item IGNORE_BRACES (-I)


XDo not perform brace expansion.

X@cindex EOF, ignoring
X@pindex IGNOR_EEOF
X@item IGNORE_EOF (-7)
XDo not exit on end-of-file. Require the use of @code{exit} or
X@code{logout} instead.@refill
X@pindex INTERACTIVE
X@item INTERACTIVE (-i)


XThis is an interactive shell.

X@cindex comments, in interactive shells
X@pindex INTERACTIVE_COMMENTS
X@item INTERACTIVE_COMMENTS (-k)


XAllow comments even in interactive shells.

X@cindex ksh, option printing style
X@cindex option printing, ksh style
X@pindex KSH_OPTION_PRINT
X@item KSH_OPTION_PRINT


XAlters the way options settings are printed.

X@cindex files, marking type of
X@cindex marking file types
X@pindex LIST_TYPES
X@item LIST_TYPES (-X)
XWhen listing files that are possible completions, show the type of each
Xfile with a trailing identifying mark.
X@pindex LOGIN
X@item LOGIN (-l)


XThis is a login shell.

X@cindex jobs, list format
X@cindex list format, of jobs
X@pindex LONG_LIST_JOBS
X@item LONG_LIST_JOBS (-R)


XList jobs in the long format by default.

X@cindex mail, warning of arrival
X@pindex MAIL_WARNING
X@item MAIL_WARNING (-U)
XPrint a warning message if a mail file has been accessed since the shell
Xlast checked.
X@cindex directories, marking
X@cindex marking directories
X@pindex MARK_DIRS
X@item MARK_DIRS (-8)
XAppend a trailing @code{/} to all directory names resulting from filename
Xgeneration (globbing).@refill
X@cindex completion, menu
X@pindex MENU_COMPLETE
X@item MENU_COMPLETE (-Y)
XOn an ambiguous completion, instead of listing possibilities, insert the
Xfirst match. Then when completion is requested again, remove the first
Xmatch and insert the second match, etc. When there are no more matches,
Xgo back to the first one again. @code{reverse-menu-complete} may be
Xused to loop through the list in the other direction.@refill
X@cindex beep, menu completion
X@pindex MENU_COMPLETE_BEEP
X@item MENU_COMPLETE_BEEP


XBeep on an ambiguous menu completion.

X@cindex job control, allowing
X@pindex MONITOR
X@item MONITOR (-m)


XAllow job control. Set by default in interactive shells.

X@cindex globbing, malformed pattern
X@pindex NO_BAD_PATTERN
X@item NO_BAD_PATTERN (-2)
XIf a pattern for filename generation is badly formed, leave it unchanged
Xin the argument list instead of printing an error.
X@cindex history, disabling substitution
X@cindex disabling history substitution
X@pindex NO_BANG_HIST
X@item NO_BANG_HIST (-K)
XDo not perform textual history substitution. Do not treat the @code{!}
Xcharacter specially.
X@cindex beep, disabling
X@cindex disabling the beep
X@pindex NO_BEEP
X@item NO_BEEP (-B)
XDo not beep.
X@cindex file clobbering, preventing
X@cindex clobbering, of files
X@pindex NO_CLOBBER
X@item NO_CLOBBER (-1)
XPrevents @code{>} redirection from truncating existing files. @code{>!}
Xmay be used to truncate a file instead. Also prevents @code{>>} from
Xcreating files. @code{>>!} may be used instead.@refill
X@cindex filename substitution, =
X@pindex NO_EQUALS
X@item NO_EQUALS
XDon't perform @code{=} filename substitution.
X@cindex command execution, preventing
X@pindex NO_EXEC
X@item NO_EXEC (-n)


XRead commands and check them for syntax errors, but do not execute them.

X@cindex globbing, disabling
X@cindex disabling globbing
X@pindex NO_GLOB
X@item NO_GLOB (-F)
XDisable filename generation.
X@cindex history, beeping
X@cindex beep, history
X@pindex NO_HIST_BEEP
X@item NO_HIST_BEEP
XDon't beep when an attempt is made to access a history entry which isn't
Xthere.
X@cindex jobs, nohup
X@pindex NO_HUP
X@item NO_HUP
XDon't send the @code{HUP} signal to running jobs when the shell exits.
X@cindex completion, beep on ambiguous
X@cindex beep, ambiguous completion
X@pindex NO_LIST_BEEP
X@item NO_LIST_BEEP


XDon't beep on an ambiguous completion.

X@cindex globbing, no matches
X@pindex NO_NOMATCH
X@item NO_NOMATCH (-3)
XIf a pattern for filename generation has no matches, leave it unchanged
Xin the argument list instead of printing an error.
X@cindex prompt, without CR
X@pindex NO_PROMPT_CR
X@item NO_PROMPT_CR (-V)
XDon't print a carriage return just before printing a prompt in the line
Xeditor.
X@cindex startup files, sourcing
X@pindex NO_RCS
X@item NO_RCS (-f)
XSource only the @file{/etc/zshenv} file.
XDo not source the @file{.zshenv}, @file{/etc/zprofile}, @file{.zprofile},
X@file{/etc/zshrc}, @file{.zshrc}, @file{/etc/zlogin}, @file{.zlogin}, or
X@file{.zlogout} files.@refill
X@pindex NO_SHORT_LOOPS
X@item NO_SHORT_LOOPS
XDisallow the short forms of @code{for}, @code{select}, @code{if}, and
X@code{function} constructs.@refill
X@cindex background jobs, notification
X@cindex notification of background jobs
X@pindex NOTIFY
X@item NOTIFY (-5)
XReport the status of background jobs immediately, rather than waiting
Xuntil just before printing a prompt.
X@cindex parameters, error on substituting unset
X@cindex unset parameters, error on substituting
X@pindex NO_UNSET
X@item NO_UNSET (-u)


XTreat unset parameters as an error when substituting.

X@cindex globbing, no matches
X@pindex NULL_GLOB
X@item NULL_GLOB (-G)
XIf a pattern for filename generation has no matches, delete the pattern
Xfrom the argument list instead of reporting an error. Overrides
X@code{NO_NOMATCH}.@refill
X@cindex sorting, numerically
X@pindex NUMERIC_GLOBSORT
X@item NUMERIC_GLOBSORT
XIf numeric filenames are matched by a filename generation pattern, sort
Xthe filenames numerically rather than lexicographically.
X@cindex editor, overstrike mode
X@cindex overstrike mode, of editor
X@pindex OVERSTRIKE
X@item OVERSTRIKE


XStart up the line editor in overstrike mode.

X@cindex path search, extended
X@pindex PATH_DIRS
X@item PATH_DIRS (-Q)
XPerform a path search even on command names with slashes in them. Thus
Xif @*@samp{/usr/local/bin} is in the user's path, and he types
X@samp{X11/xinit}, the command @samp{/usr/local/bin/X11/xinit} will be
Xexecuted (assuming it exists).@refill
X@cindex exit status, printing
X@pindex PRINT_EXIT_VALUE
X@item PRINT_EXIT_VALUE (-C)


XPrint the exit value of programs with non-zero exit status.

X@cindex directory stack, ignoring dups
X@pindex PUSHD_IGNORE_DUPS
X@item PUSHD_IGNORE_DUPS


XDon't push multiple copies of the same directory onto the directory

Xstack.
X@cindex popd, controlling syntax
X@pindex PUSHD_MINUS
X@item PUSHD_MINUS
X@xref{Shell Builtin Commands}, for the @code{popd} command.
X@cindex directory stack, silencing
X@pindex PUSHD_SILENT
X@item PUSHD_SILENT (-E)
XDo not print the directory stack after @code{pushd} or @code{popd}.
X@cindex pushd, to home
X@pindex PUSHD_TO_HOME
X@item PUSHD_TO_HOME (-D)
XHave @code{pushd} with no arguments act like @code{pushd $HOME}.
X@pindex RC_EXPAND_PARAM
X@item RC_EXPAND_PARAM (-P)
X@xref{Parameter Expansion}.
X@cindex rc, quoting style
X@cindex quoting style, rc
X@pindex RC_QUOTES
X@item RC_QUOTES
XAllow the character sequence @code{''} to signify a single quote within
Xsingly quoted strings.
X@cindex completion, exact matches
X@pindex RECEXACT
X@item RECEXACT (-S)
XIn completion, recognize exact matches even if they are ambiguous.
X@cindex rm *, querying before
X@cindex querying before rm *
X@pindex RMSTARSILENT
X@item RMSTARSILENT (-H)
XDo not query the user before executing @code{rm *} or @code{rm path/*}.
X@pindex SHINSTDIN
X@item SHINSTDIN (-s)


XRead commands from the standard input.

X@cindex sh, word splitting style
X@cindex word splitting, sh style

X@pindex SH_WORD_SPLIT
X@item SH_WORD_SPLIT (-y)
X@xref{Parameter Expansion}.
X@cindex editor, single line mode
X@pindex SINGLE_LINE_ZLE
X@item SINGLE_LINE_ZLE (-M)


XUse single-line command line editing instead of multi-line.

X@cindex sun keyboard, annoying
X@cindex annoying keyboard, sun
X@pindex SUN_KEYBOARD_HACK
X@item SUN_KEYBOARD_HACK (-L)
XIf a line ends with a backquote, and there are an odd number of
Xbackquotes on the line, ignore the trailing backquote. This is useful
Xon some keyboards where the return key is too small, and the backquote
Xkey lies annoyingly close to it.
X@cindex tracing, of input lines
X@pindex VERBOSE
X@item VERBOSE (-v)


XPrint shell input lines as they are read.

X@cindex tracing, of commands
X@pindex XTRACE
X@item XTRACE (-x)


XPrint commands and their arguments as they are executed.

X@cindex editor, disabling
X@cindex disabling the editor
X@pindex ZLE
X@item ZLE (-Z)


XUse the zsh line editor.

X@end table
X
X@node Shell Builtin Commands, Invocation, Options, Top
X@chapter Shell Builtin Commands
X@cindex builtin commands
X
X@table @code
X@findex .
X@item . @var{file} [ @var{arg} @dots{} ]
XRead and execute commands from @var{file} in the current shell
Xenvironment. If @var{file} does not contain a slash, the shell looks in
Xthe components of @code{path} to find the directory containing
X@var{file}. If any arguments @var{arg} are given, they become the
Xpositional parameters; the old positional parameters are restored when
Xthe @var{file} is done executing. The exit status is the exit status of
Xthe last command executed.@refill
X
X@cindex parameters, expanding
X@cindex expanding parameters
X@item : [ @var{arg} @dots{} ]


XThis command only expands parameters. A zero exit code is returned.
X

X@cindex alias
X@findex alias
X@item alias [ @code{-g} ] [ @var{name}[=@var{value}]] @dots{}


XWith no arguments, print the list of aliases in the form

X@code{@var{name}=@var{value}} on the standard output. For each
X@var{name} with a corresponding @var{value}, define an alias with that
Xvalue. A trailing space in @var{value} causes the next word to be
Xchecked for alias substitution. If the @code{-g} flag is present,
Xdefine a global alias; global aliases are expanded even if they do not
Xoccur in command position. For each @var{name} with no @var{value},
Xprint the value of @var{name}, if any. The exit status is nonzero if a
X@var{name} (with no @var{value}) given for which no alias has been
Xdefined.@refill
X
X@cindex functions, autoloading
X@cindex autoloading functions
X@findex autoload
X@item autoload [ @var{name} @dots{} ]
XFor each of the @var{name}s (which are names of functions), create a
Xfunction marked undefined. The @code{fpath} variable will be searched
Xto find the actual function definition when the function is first
Xreferenced.@refill
X
X@findex bg
X@item bg [ @var{job} @dots{} ]
X@itemx @var{job} @dots{} @code{&}
XPut each specified @var{job} in the background, or the current job if
Xnone is specified.
X
X@cindex rebinding the keys
X@cindex keys, rebinding
X@findex bindkey
X@item bindkey -mevd
X@itemx bindkey @code{-r} @var{in-string} @dots{}
X@itemx bindkey [ @code{-a} ] @var{in-string} [ @var{command} ] @dots{}
X@itemx bindkey @code{-s} [ @code{-a} ] @var{in-string} @var{out-string} @dots{}
XIf one of the @code{-e}, @code{-v}, or @code{-d} options is given, reset
Xthe keymaps for emacs mode, vi mode, or the default mode, respectively;
Xif the @code{-m} option is also given, allow the use of a meta key. If
Xthe @code{-r} option is given, remove any binding for each
X@var{in-string}. If the @code{-s} option is not specified, bind each
X@var{in-string} to a specified @var{command}. If no @var{command} is
Xspecified, print the binding of @var{in-string} if it is bound, or
Xreturn a nonzero exit code if it is not bound. If the @code{-s} option
Xis specified, bind each @var{in-string} to each specified
X@var{out-string}. When @var{in-string} is typed, @var{out-string} will
Xbe pushed back and treated as input to the line editor. If the
X@code{-a} option is specified, bind the @var{in-string}s in the
Xalternative keymap instead of the standard one. The alternative keymap
Xis used in vi command mode.@refill
X
X@noindent
XFor either @var{in-string} or @var{out-string}, control characters may
Xbe specified in the form @code{^X}, and the backslash may be used to
Xintroduce one of the following escape sequences:@refill
X
X@table @code
X@item \a
Xbell character
X@item \n
Xlinefeed (newline)
X@item \b
Xbackspace
X@item \t
Xhorizontal tab
X@item \v
Xvertical tab
X@item \f
Xform feed
X@item \r
Xcarriage return
X@item \e
Xescape
X@item \nnn
Xcharacter code in octal
X@item \M-xxx


Xcharacter or escape sequence with meta bit set

X@end table
X
XIn all other cases, @code{\} escapes the following character. Delete is
Xwritten as @code{^?}.@refill
X
X@cindex loops, exitting
X@cindex exitting loops
X@findex break
X@item break [ @var{n} ]
XExit from an enclosing @code{for}, @code{while}, @code{until},
X@code{select}, or @code{repeat} loop. If @var{n} is specified, then
Xbreak @var{n} levels instead of just one.@refill
X
X@findex builtin
X@item builtin @var{name} [ @var{args} ] @dots{}
XExecutes the builtin @var{name}, with the given @var{args}.
X
X@findex bye
X@item bye
XSame as @code{exit}.
X
X@cindex directories, changing
X@findex cd
X@item cd [ @var{arg} ]
X@itemx cd @var{old} @var{new}
X@itemx cd +-n
XChange the current directory. In the first form, change the current
Xdirectory to @var{arg}, or to the value of @code{HOME} if @var{arg} is
Xnot specified. If @var{arg} is @code{-}, change to the value of
X@code{OLDPWD}, the previous directory. If a directory named @var{arg}
Xis not found in the current directory and @var{arg} does not begin with
Xa slash, search each component of the shell parameter @code{cdpath}. If
Xthe option @code{CDABLEVARS} is set, and a parameter named @var{arg}
Xexists whose value begins with a slash, treat its value as the
Xdirectory.@refill
X
X@noindent
XThe second form of @code{cd} substitutes the string @var{new} for the
Xstring @var{old} in the name of the current directory, and tries to
Xchange to this new directory.@refill
X
X@noindent
XThe third form of @code{cd} is equivalent to @code{popd}.
X
X@findex chdir
X@item chdir
XSame as @code{cd}.
X
X@cindex completion, controlling
X@findex compctl
X@item compctl [ -cfhovbCD ] [ -k @var{name} ] [ @var{arg} @dots{} ]
XControl the editor's completion behavior when one of @var{arg} is the
Xcurrent command. With the @code{-D} flag, control default completion
Xbehavior for commands not assigned any special behavior; with @code{-C},
Xcontrol completion when there is no current command. The remaining
Xoptions specify the type of command arguments to look for during
Xcompletion. For example, @samp{compctl -hf rlogin} is equivalent to
X@samp{hostcmds=(rlogin)}.@refill
X
X@table @code
X@item -c
XExpect command names.
X@item -f
XExpect filenames, named directories, and filesystem paths.
X@item -h
XExpect hostnames taken from the @code{$hosts} variable.
X@item -o
XExpect option names.
X@item -v
XExpect variable names.
X@item -b
XExpect key binding names.
X@item -k @var{name}
XExpect names taken from the elements of @code{$name}.
X@end table
X
X@cindex loops, continuing
X@cindex continuing loops
X@findex continue
X@item continue [ @var{num} ]
XResume the next iteration of the enclosing @code{for}, @code{while},
X@code{until}, @code{select}, or @code{repeat} loop. If @var{n} is
Xspecified, break out of @var{n}-1 loops and resume at the @var{n}th
Xenclosing loop.@refill
X
X@findex declare
X@item declare [ @var{arg} @dots{} ]
XSame as @code{typeset}.
X
X@cindex directory stack, printing
X@findex dirs
X@item dirs [ @code{-v} ] [ @var{arg} @dots{} ]
XWith no arguments, print the contents of the directory stack. If the
X@code{-v} option is given, number the directories in the stack when
Xprinting. Directories are added to this stack with the @code{pushd}
Xcommand, and removed with the @code{cd} or @code{popd} commands. If
Xarguments are specified, load them onto the directory stack, replacing
Xanything that was there, and push the current directory onto the
Xstack.@refill
X
X@cindex disabling commands
X@cindex commands, disabling
X@findex disable
X@item disable @var{arg} @dots{}
XDisable the builtin @var{arg} temporarily. This allows you to use an
Xexternal command with the same name as a shell builtin. Actually the
Xsame as @code{unhash}. Builtins can be enabled with the @code{enable}
Xcommand.@refill
X
X@findex disown
X@item disown @var{job} @dots{}
XRemove the specified jobs from the job table; the shell will no longer
Xreport their status, and will not complain if you try to exit an
Xinteractive shell with them running or stopped.
X
X@findex echo
X@item echo [ @code{-n} ] [ @var{arg} @dots{} ]
XWrite each @var{arg} on the standard output, with a space separating
Xeach one. If the @code{-n} flag is not present, print a newline at the
Xend. @code{echo} recognizes the following escape sequences:@refill
X
X@table @code
X@item \b
Xbackspace
X@item \c


Xdon't print an ending newline

X@item \e
Xescape
X@item \f
Xform feed
X@item \n
Xnewline
X@item \r
Xcarriage return
X@item \t
Xhorizontal tab
X@item \v
Xvertical tab
X@item \\
Xbackslash
X@item \xxx
Xcharacter code in octal
X@end table
X
X@cindex termcap string, printing
X@findex echotc
X@item echotc @var{cap} [ @var{arg} @dots{} ]
XOutput the termcap string corresponding to the capability @var{cap},
Xwith optional arguments.@refill
X
X@findex enable
X@item enable @var{arg} @dots{}
XEnable the specified builtin commands, presumably disabled earlier with
X@code{disable}.
X
X@cindex evaluating arguments as commands
X@findex eval
X@item eval [ @var{arg} @dots{} ]


XRead the arguments as input to the shell and execute the resulting
Xcommand(s) in the current shell process.
X

X@pindex IGNORE_EOF, use of
X@findex exit
X@item exit [ @var{n} ]
XExit the shell with the exit code specified by @var{n}; if none is
Xspecified, use the exit code from the last command executed. An
X@code{EOF} condition will also cause the shell to exit, unless the
X@code{IGNORE_EOF} option is set.@refill
X
X@findex export
X@item export [ @var{name}[=@var{value}] @dots{} ]
XThe specified @var{name}s are marked for automatic export to the
Xenvironment of subsequently executed commands.@refill
X
X@findex false
X@item false


XDo nothing and return an exit code of 1.
X

X@cindex history, editting
X@cindex editting the history
X@findex fc
X@item fc [ -e @var{ename} ] [ -nlrdDfE ] [ @var{old}=@var{new} @dots{} ] [ @var{first} [ @var{last} ]]
X@itemx fc -ARWI [ @var{filename} ]
XSelect a range of commands from @var{first} to @var{last} from the
Xhistory list. The arguments @var{first} and @var{last} may be specified
Xas a number or as a string. A negative number is used as an offset to
Xthe current history event number. A string specifies the most recent
Xevent beginning with the given string. All substitutions
X@var{old}=@var{new}, if any, are then performed on the commands. If the
X@code{-l} flag is given, the resulting commands are listed on standard
Xoutput. Otherwise the editor program @var{ename} is invoked on a file
Xcontaining these history events. If @var{ename} is not given, the value
Xof the parameter @code{FCEDIT} is used. If @var{ename} is @code{-}, no
Xeditor is invoked. When editing is complete, the edited command(s) is
Xexecuted. If @var{first} is not specified, it will be set to -1 (the
Xmost recent event), or to -16 if the @code{-l} flag is given. If
X@var{last} is not specified, it will be set to @var{first}, or to -1 if
Xthe @code{-l} flag is given. The flag @code{-r} reverses the order of
Xthe commands and the flag @code{-n} suppresses command numbers when
Xlisting. Also when listing, @code{-d} prints timestamps for each
Xcommand, @code{-f} prints full time and date stamps, and @code{-D}
Xprints elapsed times. Adding the @code{-E} flag causes the dates
Xto be printed in the European format (@var{dd.mm.yyyy}). With the
X@code{-D} flag, @code{fc} prints elapsed times.@refill
X
X@cindex history, file
X@cindex file, history
X@noindent
X@code{fc -R} reads the history from the given file, @code{fc -W} writes
Xthe history out to the given file, and @code{fc -A} appends the history
Xto the given file. @code{fc -AI} (@code{-WI}) appends (writes) only
Xthose events that are new since the last incremental append (write) to
Xthe history file.
X
X@findex fg
X@item fg [ @var{job} @dots{} ]
X@itemx @var{job} @dots{}
XBring the specified @var{job}s to the foreground. If no @var{job} is
Xspecified, use the current job.@refill
X
X@findex functions
X@item functions [ +-tu ] [ @var{name} @dots{} ]
XEquivalent to @code{typeset -f}.
X
X@cindex line, reading
X@cindex reading a line
X@findex getln
X@item getln @var{name} @dots{}
XRead the top value from the buffer stack and put it in the shell
Xparameter @var{name}. Equivalent to @code{read -zr}.
X
X@cindex options, processing
X@findex getopts
X@item getopts @var{optstring} @var{name} [ @var{arg} @dots{} ]
XChecks @code{arg} for legal options. If @var{arg} is omitted, use the
Xpositional parameters. A valid option argument begins with a @code{+}
Xor a @code{-}. An argument not beginning with a @code{+} or a @code{-},
Xor the argument @code{--}, ends the options. @var{optstring} contains
Xthe letters that @code{getopts} recognizes. If a letter is followed by
Xa @code{:}, that option is expected to have an argument. The options
Xcan be separated from the argument by blanks.@refill
X
X@vindex OPTIND, use of
X@vindex OPTARG, use of
X@noindent
XEach time it is invoked, @code{getopts} places the option letter it
Xfinds in the shell parameter @var{name}, prepended with a @code{+} when
X@var{arg} begins with a @code{+}. The index of the next @var{arg} is
Xstored in @code{OPTIND}. The option argument, if any, is stored in
X@code{OPTARG}.@refill
X
X@noindent
XA leading @code{:} in @var{optstring} causes @code{getopts} to store the
Xletter of the invalid option in @code{OPTARG}, and to set @var{name} to
X@code{?} for an unknown option and to @code{:} when a required option is
Xmissing. Otherwise, @code{getopts} prints an error message. The exit
Xstatus is nonzero when there are no more options.@refill
X
X@findex hash
X@item hash @var{name} @var{path}
XPuts @var{name} in the command hash table, associating it with the
Xpathname @var{path}. Whenever @var{name} is used as a command argument,
Xthe shell will try to execute the file given by @var{path}.@refill
X
X@findex history
X@item history [ -nr ] [ @var{first} [ @var{last} ]]
XSame as @code{fc -l}.
X
X@findex integer
X@item integer
XSame as @code{typeset -i}.
X
X@findex jobs
X@item jobs [ -lp ] [ @var{job} @dots{} ]
XLists information about each given job, or all jobs if @var{job} is
Xomitted. The @code{-l} flag lists process ids, and the @code{-p} flag
Xlists process groups.@refill
X
X@cindex jobs, killing
X@cindex killing jobs
X@findex kill
X@item kill [ -@var{sig} ] @var{job} @dots{}
X@itemx kill @code{-l}
XSends either @code{SIGTERM} or the specified signal to the given jobs or
Xprocesses. Signals are given by number or by names (with the prefix
X@code{SIG} removed). If the signal being sent is not @code{KILL} or
X@code{CONT}, then the job will be sent a @code{CONT} signal if it is
Xstopped. The argument @var{job} can be the process id of a job not in
Xthe job list. In the second form, @code{kill} @code{-l}, the signal
Xnames are listed.@refill
X
X@findex let
X@item let @var{arg} @dots{}
XEvaluate each @var{arg} as an arithmetic expression.
X@c
X@c Why does the next line cause Info-validate to say "invalid reference"?
X@c
X@xref{Arithmetic Evaluation}, for a description of arithmetic
Xexpressions. The exit status is 0 if the value of the last expression
Xis nonzero, and 1 otherwise.@refill
X
X@cindex resource limits
X@cindex limits, resource
X@findex limit
X@item limit [ -h ] [ @var{resource} [ @var{limit} ]] @dots{}
X@itemx limit @code{-s}
XLimit the resource consumption of children of the current shell. If
X@var{limit} is not specified, print the current limit placed on
X@var{resource}; otherwise set the limit to the specified value. If the
X@code{-h} flag is given, use hard limits instead of soft limits. If no
X@var{resource} is given, print all limits.@refill
X
X@var{resource} is one of:
X
X@table @code
X@item cputime
XMaximum CPU seconds per process.
X@item filesize
XLargest single file allowed.
X@item datasize
XMaximum data size (including stack) for each process.
X@item stacksize
XMaximum stack size for each process.
X@item coredumpsize
XMaximum size of a core dump.
X@item resident
XMaximum resident set size.
X@item descriptors
XMaximum value for a file descriptor.
X@end table
X
X@var{limit} is a number, with an optional scaling factor, as follows:
X
X@table @code
X@item @var{n}h
Xhours.
X@item @var{n}k
Xkilobytes. This is the default for all but cputime.
X@item @var{n}m
Xmegabytes or minutes.
X@item @var{mm}:@code{ss}
Xminutes and seconds.
X@end table
X
X@findex local
X@item local
XSame as @code{typeset}.
X
X@cindex users, watching
X@cindex watching users
X@vindex watch, use of
X@findex log
X@item log
XList all users currently logged in who are affected by the current
Xsetting of the @code{watch} parameter.
X
X@findex logout
X@item logout
XExit the shell, if this is a login shell.
X
X@pindex PUSHD_MINUS, use of
X@findex popd
X@item popd [ +-@var{n} ]
XRemoves entries from the directory stack. With no arguments, removes
Xthe top directory from the stack, and performs a @code{cd} to the new
Xtop directory. With an argument of the form @code{+@var{n}}, remove the
X@var{n}th entry counting from the left of the list shown by the
X@code{dirs} command, starting with zero, and change to that directory.
XWith an argument of the form @code{-@var{n}}, remove the @var{n}th entry
Xcounting from the right. If the @code{PUSHD_MINUS} option is set, the
Xmeanings of @code{+} and @code{-} in this context are swapped.@refill
X
X@findex print
X@item print [ -RnrslzpNDP ] [ -u@var{n} ] [ @var{arg} @dots{} ]
XWith no flags or with flag @code{-}, the arguments are printed on the
Xstandard output as described by @code{echo}.@refill
X
X@table @code
X@item -R, -r
Xignore the escape conventions of @code{echo}. The @code{-R} option
Xwill print all subsequent arguments and options.@refill
X@item -s
Xplace the results in the history list instead of on the standard
Xoutput.@refill
X@item -n
Xdo not add a newline to the output.
X@item -l
Xprint the arguments separated by newlines instead of spaces.
X@item -N
Xprint the arguments separated and terminated by nulls.
X@item -u@var{n}
Xprint the arguments to file descriptor @var{n}.
X@item -p
Xprint the arguments to the input of the coprocess.
X@item -z
Xpush the arguments onto the editing buffer stack, separated by spaces;
Xno escape sequences are recognized.@refill
X@item -D
Xtreat the arguments as directory names, replacing prefixes with @code{~}
Xexpressions, as appropriate.
X@item -P
Xrecognize the same escape sequences as in the @code{PROMPT} parameter.
X@end table
X
X@findex pushd
X@pindex PUSHD_TO_HOME, use of
X@pindex CDABLEVARS, use of
X@pindex PUSHD_SILENT, use of
X@item pushd [ @var{arg} ]
X@itemx pushd @var{old} @var{new}
X@itemx pushd +-@var{n}
XChange the current directory, and push the old current directory onto
Xthe directory stack. In the first form, change the current directory to
X@var{arg}. If @var{arg} is not specified, change to the second
Xdirectory on the stack (that is, exchange the top two entries), or
Xchange to the value of @code{HOME} if the @code{PUSHD_TO_HOME} option is
Xset or if there is only one entry on the stack. If @var{arg} is
X@code{-}, change to the value of @code{OLDPWD}, the previous directory.
XIf a directory named @var{arg} is not found in the current directory and
X@var{arg} does not contain a slash, search each component of the shell
Xparameter @code{cdpath}. If the option @code{CDABLEVARS} is set, and a
Xparameter named @var{arg} exists whose value begins with a slash, treat
Xits value as the directory. If the option @code{PUSHD_SILENT} is not
Xset, the directory stack will be printed after a @code{pushd} is
Xperformed.@refill
X
X@noindent
XThe second form of @code{pushd} substitutes the string @var{new} for the
Xstring @var{old} in the name of the current directory, and tries to
Xchange to this new directory.@refill
X
X@noindent
XThe third form of @code{pushd} is equivalent to @code{popd}.
X
X@findex pwd
X@item pwd
XEquivalent to @code{print -R $PWD}.
X
X@findex r
X@item r
XEquivalent to @code{fc -e -}.
X
X@vindex IFS
X@findex read
X@item read [ -rzp ] [ -u@var{n} ] [ @var{name}?@var{prompt} ] [ @var{name} @dots{} ]
XRead one line and break it into fields using the characters in
X@code{IFS} as separators. In raw mode, @code{-r}, a @code{\} at the end
Xof a line does not signify line continuation. If the @code{-z} flag is
Xset, read from the editor buffer stack. The first field is assigned to
Xthe first @var{name}, the second field to the second @var{name}, etc,
Xwith leftover fields assigned to the last @var{name}. If @var{name} is
Xomitted then @code{REPLY} is used. If @code{-u@var{n}} is specified,
Xthen input is read from file descriptor @var{n}; if @code{-p} is
Xspecified, then input is read from the coprocess. The exit status is 0
Xunless end-of-file is encountered. If the first argument contains a
X@code{?}, the remainder of this word is used as a @var{prompt} on
Xstandard error when the shell is interactive. The exit status is 0
Xunless an end-of-file is encountered.@refill
X
X@cindex parameters, marking readonly
X@findex readonly
X@item readonly [ @var{name}[=@var{value}]] @dots{}
XThe given @var{names} are marked readonly; these names cannot be changed
Xby subsequent assignment.@refill
X
X@findex rehash
X@item rehash [ @code{-f} ]
XThrow out the command hash table and start over. If the @code{-f}
Xoption is set, rescan the command path immediately, instead of
Xrebuilding the hash table incrementally.@refill
X
X@cindex functions, returning from
X@findex return
X@item return [ @var{n} ]
XCauses a shell function or @code{.} script to return to the invoking
Xscript with the return status specified by @var{n}. If @var{n} is
Xomitted then the return status is that of the last command
Xexecuted.@refill
X
X@cindex timed execution
X@cindex execution, timed
X@findex sched
X@item sched [+]@var{hh}:@var{mm} @var{command} @dots{}
X@itemx sched [ -@var{item} ]
XMake an entry in the scheduled list of commands to execute. The time
Xmay be specified in either absolute or relative time. With no
Xarguments, prints the list of scheduled commands. With the argument
X@code{-@var{item}}, removes the given item from the list.@refill
X
X@cindex parameters, positional
X@cindex parameters, array
X@cindex array parameter, declaring
X@findex set
X@item set [ +-@var{options} ] [ +-o @var{option name} ] @dots{} [ -A @var{name} ] [ @var{arg} ] @dots{}
XSet the options for the shell and/or set the positional parameters, or
Xdeclare an array. @xref{Options}, for the meaning of the flags. Flags
Xmay be specified by name using the @code{-o} option. If the @code{-A}
Xflag is specified, @var{name} is set to an array containing the given
X@var{arg}s. Otherwise the positional parameters are set. If no
Xarguments are given, then the names and values of all parameters are
Xprinted on the standard output. If the only argument is @code{+}, the
Xnames of all parameters are printed.@refill
X
X@cindex options, setting
X@findex setopt
X@item setopt [ +-@var{options} ] [ @var{name} @dots{} ]
XSet the options for the shell. All options specified either with flags
Xor by name are set. If no arguments are supplied, the names of all
Xoptions currently set are printed. In option names, case is
Xinsignificant, and all underscore characters are ignored.
X
X@cindex parameters, positional
X@findex shift
X@item shift [ @var{n} ]
XThe positional parameters from @code{$@var{n}+1} @dots{} are renamed
X@code{$1}, where @var{n} is an arithmetic expression that defaults to
X1.@refill
X
X@findex source
X@item source
XSame as @samp{.}.
X
X@cindex shell, suspending
X@findex suspend
X@item suspend [ -f ]
XSuspend the execution of the shell (send it a @code{SIGTSTP}) until it
Xreceives a @code{SIGCONT}. If the @code{-f} option is not given,
Xcomplain if this is a login shell.@refill
X
X@findex test
X@item test @var{arg} @dots{}
X@itemx [ @var{arg} @dots{} ]
XLike the system version of @code{test}. Added for compatibility; use
Xconditional expressions instead.@refill
X
X@cindex shell, timing
X@cindex timing the shell
X@findex times
X@item times
XPrint the accumulated user and system times for the shell and for
Xprocesses run from the shell.
X


X@cindex signals, trapping
X@cindex trapping signals

X@findex trap
X@item trap [ @var{arg} ] [ @var{sig} ] @dots{}
X@var{arg} is a command to be read and executed when the shell receives
X@var{sig}. Each @var{sig} can be given as a number or as the name of a
Xsignal. If @var{arg} is @code{-}, then all traps @var{sig} are reset to
Xtheir default values. If @var{arg} is the null string, then this signal
Xis ignored by the shell and by the commands it invokes. If @var{sig} is
X@code{ERR} then @var{arg} will be executed after each command. If
X@var{sig} is @code{0} or @code{EXIT} and the @code{trap} statement is
Xexecuted inside the body of a function, then the command @var{arg} is
Xexecuted after the function completes. If @var{sig} is @code{0} or
X@code{EXIT} and the @code{trap} statement is not executed inside the
Xbody of a function, then the command @var{arg} is executed when the
Xshell terminates. The @code{trap} command with no arguments prints a
Xlist of commands associated with each signal.@refill
X
X@findex true
X@item true
XDo nothing and return an exit code of 0.
X
X@cindex tty, freezing
X@findex ttyctl
X@item ttyctl -fu
XThe @code{-f} option freezes the tty, and @code{-u} unfreezes it. When
Xthe tty is frozen, no changes made to the tty settings by external
Xprograms will be honored by the shell; the shell will simply reset the
Xsettings to their previous values as soon as each command exits. Thus,
X@code{stty} and similar programs have no effect when the tty is
Xfrozen.@refill
X
X@findex type
X@item type
XSame as @code{whence} @code{-v}.
X
X@cindex parameters, setting
X@findex typeset
X@item typeset [ +-LRZfilrtux [@var{n}]] [ @var{name}[=@var{value}]] @dots{}
XSet attributes and values for shell parameters. When invoked inside a
Xfunction, if @var{name} is not already defined, a new parameter is
Xcreated which will be unset when the function completes. The following
Xattributes are valid:@refill
X
X@table @code
X@item -L
XLeft justify and remove leading blanks from @var{value}. If @var{n} is
Xnonzero, it defines the width of the field; otherwise it is determined
Xby the width of the value of the first assignment. When the parameter
Xis printed, it is filled on the right with blanks or truncated if
Xnecessary to fit the field. Leading zeros are removed if the @code{-Z}
Xflag is also set.@refill
X@item -R
XRight justify and fill with leading blanks. If @var{n} is nonzero if
Xdefines the width of the field; otherwise it is determined by the width
Xof the value of the first assignment. When the parameter is printed,
Xthe field is left filled with blanks or truncated from the end.@refill
X@item -Z
XRight justify and fill with leading zeros if the first non-blank
Xcharacter is a digit and the @code{-L} flag has not been set. If
X@var{n} is nonzero it defines the width of the field; otherwise it is
Xdetermined by the width of the value of the first assignment.@refill
X@item -f
XThe names refer to functions rather than parameters. No assignments can
Xbe made, and the only other valid flags are @code{-t} and @code{-u}.
XThe flag @code{-t} turns on execution tracing for this function. The
Xflag @code{-u} causes this function to be marked for autoloading. The
X@code{fpath} parameter will be searched to find the function definition
Xwhen the function is first referenced.@refill
X@item -i
XUse an internal integer representation. If @code{i} is nonzero it
Xdefines the output arithmetic base, otherwise it is determined by the
Xfirst assignment.@refill
X@item -l
XConvert to lower case.
X@item -r
XThe given @var{name}s are marked readonly.
X@item -t
XTags the named parameters. Tags have no special meaning to the
Xshell.@refill
X@item -u
XConvert to upper case.
X@item -x
XMark for automatic export to the environment of subsequently executed
Xcommands.@refill
X@end table
X
X@noindent
XUsing @code{+} rather than @code{-} causes these flags to be turned off.
XIf no arguments are given but flags are specified, a list of named
Xparameters which have these flags set is printed. Using @code{+}
Xinstead of @code{-} keeps their values from being printed. If no
Xarguments or options are given, the names and attributes of all
Xparameters are printed.@refill
X
X@cindex resource limits
X@cindex limits, resource
X@findex ulimit
X@item ulimit [ -HSacdfmnt ] [ @var{limit} ]
XSet or display a resource limit. The value of limit can be a number in
Xthe unit specified below or the value @code{unlimited}. The @code{H}
Xand @code{S} flags specify whether the hard limit or the soft limit for
Xthe given resource is set.@refill


X
X@table @code
X@item -a

XLists all of the current resource limits.
X@item -c
XThe number of 512-byte blocks on the size of core dumps.
X@item -d
XThe number of K-bytes on the size of the data segment.
X@item -f
XThe number of 512-byte blocks on the size of files written.
X@item -m
XThe number of K-bytes on the size of physical memory.
X@item -n
XThe number of file descriptors.
X@item -s
XThe number of K-bytes on the size of the stack.
X@item -t
XThe number of CPU seconds to be used.
X@end table
X
X@cindex umask
X@findex umask
X@item umask [ @var{mask} ]
XThe umask is set to @var{mask}. @var{mask} can be either an octal
Xnumber or a symbolic value as described in @code{chmod(1)}. If
X@var{mask} is omitted, the current value is printed.@refill
X
X@cindex aliases, removing
X@findex unalias
X@item unalias @var{name} @dots{}
XThe alias definition, if any, for each @var{name} is removed.
X
X@cindex functions, removing
X@findex unfunction
X@item unfunction @var{name} @dots{}
XThe function definition, if any, for each @var{name} is removed.
X
X@findex unhash
X@item unhash @var{name} @dots{}
XThe entry in the command hash table, if any, for each @var{name} is
Xremoved.@refill
X
X@cindex limits, resource
X@cindex resource limits
X@findex unlimit
X@item unlimit [ -h ] @var{resource} @dots{}
XThe resource limit for each @var{resource} is set to the hard limit. If
Xthe @code{-h} flag is given and the shell is running as root, the hard
Xresource limit for each @var{resource} is removed.@refill
X
X@cindex parameters, unsetting
X@findex unset
X@item unset @var{name} @dots{}
XEach named parameter is unset.
X
X@cindex options, unsetting
X@findex unsetopt
X@item unsetopt [ +-@var{options} ] [ @var{name} @dots{} ]
XUnset the options for the shell. All options specified either with
Xflags or by name are unset.@refill
X
X@cindex parameters, editting
X@cindex editting parameters
X@findex vared
X@item vared @var{name}
XThe value of the parameter @var{name} is loaded into the edit buffer,
Xand the line editor is invoked. When the editor exits, @var{name} is
Xset to the string value returned by the editor.@refill
X
X@cindex jobs, waiting for
X@cindex waiting for jobs
X@findex wait
X@item wait [ @var{job} @dots{} ]
XWait for the specified jobs or processes. If @var{job} is not given
Xthen all currently active child processes are waited for. Each
X@var{job} can be either a job specification or the process-id of a job
Xin the job table. The exit status from this command is that of the job
Xwaited for.@refill
X
X@findex whence
X@item whence [ -acpv ] @var{name} @dots{}
XFor each name, indicate how it would be interpreted if used as a command
Xname. The @code{-v} flag produces a more verbose report. The @code{-p}
Xflag does a path search for @var{name} even if it is a shell function,
Xalias, or reserved word. The @code{-c} flag prints the results in a
Xcsh-like format. The @code{-a} flag does a search for all occurences of
X@var{name} throughout the command path.@refill
X
X@findex which
X@item which
XSame as @code{whence -c}.
X@end table
X
X@node Invocation, Wrapping Up, Shell Builtin Commands, Top
X@chapter Invocation
X@cindex invocation
X
X@code{zsh [ +-@var{options} ] [ +-o @var{option} ] @dots{} [ -c @var{string} ] [ @var{arg} @dots{} ]}
X
X@pindex NO_RCS, use of
X@cindex files, startup
X@cindex startup files
X@noindent
XCommands are first read from @file{/etc/zshenv}. Then, if the
X@code{NO_RCS} option is unset, commands are read from
X@file{$ZDOTDIR/.zshenv} (if @code{ZDOTDIR} is unset, @code{HOME} is used
Xinstead). If the first character of argument zero passed to the shell is
X@code{-}, or if the @code{-l} flag is present, then
Xthe shell is assumed to be a login shell, and commands are read from
X@file{/etc/zprofile} and then @file{$ZDOTDIR/.zprofile}.
XThen, if the shell is interactive and the @code{NO_RCS} option is unset,
Xcommands are read from @file{/etc/zshrc} and then @file{$ZDOTDIR/.zshrc}.
XFinally, if the shell is a login shell, @file{/etc/zlogin} and
X@file{$ZDOTDIR/.zlogin} are read.@refill
X
XIf the @code{NO_RCS} option is set within @file{/etc/zshenv}, then only
X@file{/etc/zprofile}, @file{/etc/zshrc}, and @file{/etc/zlogin} are read,
Xand the @code{$ZDOTDIR} files are skipped. If the @code{-f} flag is present,
Xonly @file{/etc/zshenv} is read, and all other initialization files are
Xskipped.
X
XIf the @code{-s} flag is not present and an argument is given,
Xthe first argument is taken to be the pathname of a script to execute.
XThe remaining arguments are assigned to the positional parameters. The
Xfollowing flags are interpreted by the shell when invoked:@refill
X
X@cindex flags, shell
X@cindex shell flags
X@table @code
X@item -c @var{string}
XRead commands from @var{string}.
X@item -s
XRead command from the standard input.
X@item -i
XIf this flag is present or the shell input and output are attached to a
Xterminal, this shell is interactive.
X@end table
X
X@node Wrapping Up, Concept Index, Invocation, Top
X@chapter Wrapping Up
X
X@menu


X* See Also::
X* Files Used::
X* Availability::
X* Undocumented Features::
X@end menu
X

X@node See Also, Files Used, , Wrapping Up
X@section See Also
X
X@noindent
Xsh(1), csh(1), tcsh(1), itcsh(1), rc(1), bash(1), ash(1), ksh(1),
Xclam(1), strftime(3).
X
X@node Files Used, Availability, See Also, Wrapping Up
X@section Files Used
X@cindex files used
X
X@noindent
X$ZDOTDIR/.zshenv@*
X@noindent
X$ZDOTDIR/.zprofile@*
X@noindent
X$ZDOTDIR/.zshrc@*
X@noindent
X$ZDOTDIR/.zlogin@*
X@noindent
X$ZDOTDIR/.zlogout@*
X@noindent
X/tmp/zsh*@*
X@noindent
X/etc/zshenv@*
X@noindent
X/etc/zprofile@*
X@noindent
X/etc/zshrc@*
X@noindent
X/etc/zlogin
X
X@node Availability, Undocumented Features, Files Used, Wrapping Up
X@section Availability
X@cindex availability
X
X@noindent
XThe latest official release of zsh is available via anonymous ftp from
X@code{cs.ucsd.edu} (132.239.51.3), in the directory
X@code{pub/zsh}. The beta release of zsh 2.4 is available from
X@code{carlo.phys.uva.nl} (145.18.220.25), in the directory
X@code{pub/bas/zsh}. This man page is current to zsh 2.3.1.@refill
X
X@node Undocumented Features, , Availability, Wrapping Up
X@section Undocumented Features
X@cindex undocumented features
X
X@noindent
XKnown only to the recipients of the zsh mailing list,
X@code{zsh-list@@cs.uow.edu.au}. If you run into problems, please send
Xyour questions and patches to the mailing list. To join the list, send
Xemail to @code{zsh-request@@cs.uow.edu.au}.@refill
X
X
X@node Concept Index, Variables Index, Wrapping Up, Top
X@unnumbered Concept Index
X
X@printindex cp
X
X@node Variables Index, Options Index, Concept Index, Top
X@unnumbered Variables Index
X
X@printindex vr
X
X@node Options Index, Functions Index, Variables Index, Top
X@unnumbered Options Index
X
X@printindex pg
X
X@node Functions Index, Editor Functions Index, Options Index, Top
X@unnumbered Functions Index
X
X@printindex fn
X
X@node Editor Functions Index, Keystroke Index, Functions Index, Top
X@unnumbered Editor Functions Index
X
X@printindex tp
X
X@node Keystroke Index, , Editor Functions Index, Top
X@unnumbered Keystroke Index
X
X@printindex ky
X
X
X@contents
X@bye
END_OF_FILE
if test 48882 -ne `wc -c <'doc/zsh.texi.03'`; then
echo shar: \"'doc/zsh.texi.03'\" unpacked with wrong size!
fi
# end of 'doc/zsh.texi.03'
fi
if test -f 'scripts/c2z' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'scripts/c2z'\"
else
echo shar: Extracting \"'scripts/c2z'\" \(3299 characters\)
sed "s/^X//" >'scripts/c2z' <<'END_OF_FILE'
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
END_OF_FILE
if test 3299 -ne `wc -c <'scripts/c2z'`; then
echo shar: \"'scripts/c2z'\" unpacked with wrong size!
fi
chmod +x 'scripts/c2z'
# end of 'scripts/c2z'
fi
echo shar: End of archive 9 \(of 22\).
cp /dev/null ark9isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:23:57 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 60
Archive-name: zsh/part10

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: help/chdir src/exec.c src/zle_refresh.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:53 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 10 (of 22)."'
if test -f 'help/chdir' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/chdir'\"
else
echo shar: Extracting \"'help/chdir'\" \(934 characters\)
sed "s/^X//" >'help/chdir' <<'END_OF_FILE'
X cd [ arg ]
X cd old new
X cd +-n
X Change the current directory. In the first form,
X change the current directory to arg, or to the value of
X HOME if arg is not specified. If arg is -, change to
X the value of OLDPWD, the previous directory. If a
X directory named arg is not found in the current direc-
X tory and arg does not begin with a slash, search each
X component of the shell parameter cdpath. If the option
X CDABLEVARS is set, and a parameter named arg exists
X whose value begins with a slash, treat its value as the
X directory.
X
X The second form of cd substitutes the string new for
X the string old in the name of the current directory,
X and tries to change to this new directory.
X
X The third form of cd is equivalent to popd.
X
X chdir
X Same as cd.
END_OF_FILE
if test 934 -ne `wc -c <'help/chdir'`; then
echo shar: \"'help/chdir'\" unpacked with wrong size!
fi
# end of 'help/chdir'
fi
if test -f 'src/exec.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/exec.c'\"
else
echo shar: Extracting \"'src/exec.c'\" \(37664 characters\)
sed "s/^X//" >'src/exec.c' <<'END_OF_FILE'
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
X#define execerr() { if (forked) _exit(1); \
X closemnodes(mfds); lastval = 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{
Xstatic Lklist exargs;
Xchar **argv,*arg0,**pp;
Xchar *z,*s,buf[MAXCMDLEN],buf2[MAXCMDLEN];
Xint ee,eno = 0;
X
X if (empty(args)) {
X zerr("no command",NULL,0);
X _exit(1);
X }
X if (!exargs && (s = zgetenv("STTY"))) {
X exargs = args;
X args = (Lklist) 0;
X zyztem("stty",s);
X args = exargs;
X exargs = (Lklist) 0;
X }
X arg0 = peekfirst(args);
X cn = (Cmdnam) gethnode(arg0,cmdnamtab);
X if (cn && cn->type == DISABLED)
X cn = NULL;
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 /* errflag = 0; */
X execlist(list->right);


X }
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 && (empty(vl) || !nextnode(firstnode(vl)))) {
X Param pm;
X char *val;
X
X if (empty(vl))
X val = ztrdup("");
X else {
X untokenize(peekfirst(vl));
X val = ztrdup(ugetnode(vl));
X }
X pm = setsparam(v->name,ztrdup(val));
X if (export && !(pm->flags & PMFLAG_x))
X addenv(v->name,val);
X free(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;
Xint save[10],t0;
Xstruct redir *fn;
Xstruct multio *mfds[10];
Xint fil,forked = 0,iscursh,nullexec = 0;
Xchar *text;
X
X args = cmd->args;
X cn = NULL;
X for (t0 = 0; t0 != 10; t0++) {
X save[t0] = -1;
X mfds[t0] = NULL;
X }
X if ((type = cmd->type) == SIMPLE && empty(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 if (errflag)
X lastval = 1;
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 && empty(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 !(cmd->flags & CFLAG_NOGLOB)) {
X Lknode node, next;
X
X for (node = nextnode(firstnode(args)); node && !errflag; node = next) {
X char *s = getdata(node);
X int l = strlen(s);
X
X next = nextnode(node);
X if (s[0] == Star && !s[1]) {
X if (!checkrmall(pwd)) uremnode(args,node);
X } else if (l > 2 && s[l-2] == '/' && s[l-1] == Star) {
X char t = s[l-2];
X s[l-2] = 0;
X if (!checkrmall(s)) uremnode(args,node);
X s[l-2] = t;
X }
X }
X if (!nextnode(firstnode(args))) errflag = 1;
X }
X if (jobbing) { /* get the text associated with this command */
X 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) && empty(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 fixfds(save);
X execerr();
X }
X addfd(forked,save,mfds,fn->fd1,fn->fd2,0);
X } else if (fn->type == OUTPIPE) {
X if (fn->fd2 == -1) {
X fixfds(save);
X execerr();
X }
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) {
X fixfds(save);
X execerr();
X }
X if (fn->type == HERESTR) {
X fil = getherestr(fn);
X if (fil == -1) {
X fixfds(save);
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 fixfds(save);
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 closemn(mfds,fn->fd1);
X fil = dup(fn->fd2);
X if (fil == -1) {
X char fdstr[4];
X fixfds(save);
X sprintf(fdstr,"%d",fn->fd2);
X zerr("%s: %e",fdstr,errno);
X execerr();
X }
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 fixfds(save);
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 for (t0 = 0; t0 != 10; t0++)
X if (save[t0] != -1)
X close(save[t0]);
X return;
X }
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 (!cn) {
X lastval = 1;
X return;
X }
X if (cmd->vars) {
X addvars(cmd->vars,0);
X if (errflag) {
X lastval = 1;
X return;
X }
X }
X fixcline(args);
X if (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 (errflag) {
X lastval = 1;
X return;
X }
X }
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 old_errno = errno;
Xint t0;
X
X for (t0 = 0; t0 != 10; t0++)
X if (save[t0] != -1)
X redup(save[t0],t0);
X errno = old_errno;
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] != 2)
X signal(SIGINT, SIG_DFL);
X }
X if (sigtrapped[SIGQUIT] != 2)
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 (INULL(*s))
X {
X *s = Nularg;
X qt = 1;
X }
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,sizeof(pbuf)))
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];
Xint pid;
Xint status;
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 ((cmdoutpid = pid = phork()) > 0)
X {
X Lklist retval;
X
X popheap();
X close(pipes[1]);
X#ifdef WAITPID
X retval = readoutput(pipes[0],qt);
X waitpid(pid,&status,0);
X#else
X blockchld();
X retval = readoutput(pipes[0],qt);
X if (kill(pid, 0) >= 0)
X {
X unblockchld();
X chldsuspend();
X }
X else
X unblockchld();
X#endif
X lastval = cmdoutval;
X cmdoutval = 0;
X return retval;
X }
X else if (pid == -1)
X {
X popheap();
X close(pipes[0]);
X close(pipes[1]);
X errflag = 1;
X cmdoutpid = 0;
X return NULL;
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(lastval);
X zerr("exit returned in child!!",NULL,0);
X kill(getpid(),SIGKILL);
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 if (qt) {
X *ptr++ = Nularg;
X cnt++;
X }
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;
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;
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 (void) creat(nam,0666);
X exiting = 1;
X execlist(list);
X close(1);
X _exit(lastval);
X zerr("exit returned in child!!",NULL,0);
X kill(getpid(),SIGKILL);
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(1);
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(lastval); 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(lastval); 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;
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(lastval); 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 entersubsh(1);
X redup(pipes[0],0);
X closem();
X exiting = 1;
X execlist(list);
X _exit(lastval); 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];
X#ifdef apollo
Xchar *buf2 = buf0+2; /* changed +1 to +2 RBC 17.11.91 */
X#else
Xchar *buf2 = buf0+1;
X#endif
Xstruct stat sbuf;
Xstruct direct *de;
XDIR *dir;
Xino_t ino, rootino = ~0;
Xdev_t dev, rootdev = ~0;
X
X holdintr();
X buf2[0] = '\0';
X buf0[0] = '/';
X#ifdef apollo
X buf0[1] = '/'; /* added RBC 17.11.91 */
X#endif
X if (stat(buf0,&sbuf) >= 0)
X {
X rootino = sbuf.st_ino;
X rootdev = sbuf.st_dev;
X }
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 (ino == rootino && dev == rootdev))
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 {
X settrap(t0,cmd->u.list);
X permalloc();
X }
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 breaks = 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 (isset(CDABLEVARS) && (t = getsparam(s)) && *t == '/') return cancd2(t);
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}
END_OF_FILE
if test 37664 -ne `wc -c <'src/exec.c'`; then
echo shar: \"'src/exec.c'\" unpacked with wrong size!
fi
# end of 'src/exec.c'
fi
if test -f 'src/zle_refresh.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle_refresh.c'\"
else
echo shar: Extracting \"'src/zle_refresh.c'\" \(12060 characters\)
sed "s/^X//" >'src/zle_refresh.c' <<'END_OF_FILE'
X/*
X *
X * zle_refresh.c - screen update


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#define ZLE
X#include "zsh.h"
X
Xchar **obuf = NULL,**nbuf = NULL;
Xint olnct,nlnct;
Xint winw,winh,winpos;
X
Xint vcs,vln,vmaxln;
X
Xvoid resetvideo() /**/
X{
Xint ln;
Xstatic int lwinw = -1,lwinh = -1;
X
X setterm();
X winw = columns-1;
X if (isset(SINGLELINEZLE) || !termok)
X winh = 1;
X else
X winh = (lines < 2) ? 24 : lines;
X winpos = vln = vmaxln = 0;
X if (lwinw != winw || lwinh != winh)
X {
X if (nbuf)
X {
X for (ln = 0; ln != lwinh; ln++)
X {
X free(nbuf[ln]);
X free(obuf[ln]);
X }
X free(nbuf);
X free(obuf);
X }
X nbuf = (char **) zalloc((winh+1)*sizeof(char *));
X obuf = (char **) zalloc((winh+1)*sizeof(char *));
X for (ln = 0; ln != winh+1; ln++)
X {
X nbuf[ln] = zalloc(winw+1);
X obuf[ln] = zalloc(winw+1);
X }
X lwinw = winw;
X lwinh = winh;
X }
X for (ln = 0; ln != winh+1; ln++)
X {
X *nbuf[ln] = '\0';
X *obuf[ln] = '\0';
X }
X if (!pptlen)
X nbuf[0][0] = obuf[0][0] = '\0';
X else
X {
X for (ln = 0; ln != pptlen-1; ln++)
X nbuf[0][ln] = obuf[0][ln] = ' ';
X nbuf[0][ln] = obuf[0][ln] = '>';
X nbuf[0][pptlen] = obuf[0][pptlen] = '\0';
X }
X vcs = pptlen;
X olnct = nlnct = 1;
X}
X
Xint scrollwindow() /**/
X{
Xint t0,hwinh = winh/2;
X
X for (t0 = 0; t0 != winh-hwinh; t0++)
X {
X char *s;
X
X s = nbuf[t0];
X nbuf[t0] = nbuf[t0+hwinh];
X nbuf[t0+hwinh] = s;
X }
X for (t0 = 0; t0 != pptlen-1; t0++)
X nbuf[0][t0] = ' ';
X strcpy(nbuf[0]+t0,"> ...");
X return winh-hwinh;
X}
X
X/* this is the messy part. */
X/* this define belongs where it's used!!! */
X
X#define nextline { *s = (unsigned char)'\0'; \
X if (winh == ln+1) if (nvln != -1) break; else ln = scrollwindow()-1; \
X s = (unsigned char *)nbuf[++ln]; sen = s+winw; \
X }
X
Xvoid refresh() /**/
X{
Xunsigned char *s,*t,*sen,*scs = line+cs; char **qbuf;
Xint ln = 0,nvcs = 0,nvln = -1,t0;
X
X cost = 0;
X if (resetneeded)
X {
X resetvideo();
X resetneeded = 0;
X if (isset(SINGLELINEZLE) || !termok)
X vcs = 0;
X else
X printf("%s",pmpt);
X }
X zleactive = 1;
X if (isset(SINGLELINEZLE) || !termok)
X {
X singlerefresh();
X return;
X }
X
X/* first, we generate the video line buffers so we know what to
X put on the screen.
X
X s = ptr into the video buffer.
X t = ptr into the real buffer.
X sen = end of the video buffer (eol)
X*/
X
X s = (unsigned char *)(nbuf[ln = 0]+pptlen);
X t = line;
X sen = (unsigned char *)(*nbuf+winw);
X for (; *t; t++)
X {
X if (icntrl((char)*t))
X if (*t == '\n')
X {
X if (t == scs)
X {
X nvcs = (char *)s-nbuf[nvln = ln];
X scs = (unsigned char *)NULL;
X }
X nextline
X }
X else if ((char)*t == '\t')
X {
X int t1 = (char *)s-nbuf[ln];
X
X if ((t1|7)+1 >= winw) nextline
X else
X do
X *s++ = ' ';
X while ((++t1) & 7);
X }
X else
X {
X if (s == sen) nextline
X *s++ = '^';
X if (s == sen) nextline
X *s++ = (*t == 127) ? '?' : (*t | '@');
X }
X else
X {
X if (s == sen) nextline
X *s++ = *t;
X }
X/* if the cursor is here, remember it */
X
X if (t == scs)
X nvcs = s-(unsigned char *)nbuf[nvln = ln]-1;
X }
X if (scs == t)
X nvcs = s-(unsigned char *)nbuf[nvln = ln];
X *s = '\0';
X nlnct = ln+1;
X if (statusline)
X strcpy(nbuf[(nlnct == winh) ? winh-1 : nlnct++],statusline);
X
X/* do RPROMPT */
X
X if (pmpt2 && ln == 0 && strlen(nbuf[0])+strlen(pmpt2) < winw)
X {
X for (t0 = strlen(nbuf[0]); t0 != winw; t0++)
X nbuf[0][t0] = ' ';
X strcpy(nbuf[0]+winw-strlen(pmpt2),pmpt2);
X }
X for (ln = 0; ln < nlnct; ln++)
X {
X
X/* if old line and new line are different,
X see if we can insert/delete a line */
X
X if (ln < olnct && strncmp(nbuf[ln],obuf[ln],16))
X {
X if (tccan(TCDELLINE) && !strncmp(nbuf[ln],obuf[ln+1],16)
X && obuf[ln+1][0] && ln != olnct)
X {
X int t0;
X
X moveto(ln,0);
X tcout(TCDELLINE);
X for (t0 = ln; t0 != olnct; t0++)
X strcpy(obuf[t0],obuf[t0+1]);
X olnct--;
X }
X
X/* don't try to insert a line if olnct < vmaxln (vmaxln is the number
X of lines that have been displayed by this routine) so that we don't
X go off the end of the screen. */
X
X else if (tccan(TCINSLINE) && !strncmp(nbuf[ln+1],obuf[ln],16) &&
X olnct < vmaxln && nbuf[ln+1][0] && ln != olnct)
X {
X int t0;
X
X moveto(ln,0);
X tcout(TCINSLINE);
X for (t0 = olnct; t0 != ln; t0--)
X strcpy(obuf[t0],obuf[t0-1]);
X *obuf[ln] = '\0';
X olnct++;
X }
X }
X refreshline(ln);
X }
X
X/* if old buffer had extra lines, do a clear-end-of-display if we can,
X otherwise, just fill new buffer with blank lines and refresh them */
X
X if (olnct > nlnct)
X {
X for (ln = nlnct; ln < olnct; ln++)
X nbuf[ln][0] = '\0';
X if (tccan(TCCLEAREOD))
X {
X moveto(nlnct,0);
X tcout(TCCLEAREOD);
X }
X else
X for (ln = nlnct; ln < olnct; ln++)
X refreshline(ln);
X }
X
X/* move to the new cursor position */
X
X moveto(nvln,nvcs);
X qbuf = nbuf;
X nbuf = obuf;
X obuf = qbuf;
X olnct = nlnct;
X if (nlnct > vmaxln)
X vmaxln = nlnct;
X fflush(stdout);
X}
X
X#define tcinscost(X) (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS])
X#define tcdelcost(X) (tccan(TCMULTDEL) ? tclen[TCMULTDEL] : (X)*tclen[TCDEL])
X#define tc_delchars(X) tcmultout(TCDEL,TCMULTDEL,(X))
X#define tc_inschars(X) tcmultout(TCINS,TCMULTINS,(X))
X#define tc_upcurs(X) tcmultout(TCUP,TCMULTUP,(X))
X#define tc_leftcurs(X) tcmultout(TCLEFT,TCMULTLEFT,(X))
X
Xvoid refreshline(ln) /**/
Xint ln;
X{
Xchar *nl = nbuf[ln],*ol = obuf[ln];
Xchar *p1;
Xchar junk,*truncptr = &junk;
Xint ccs = 0;
X
X if (ln >= olnct)
X *ol = '\0';
X for (;;)
X {
X while (*nl && *nl == *ol)
X {
X nl++,ol++,ccs++;
X }
X if (!*nl && !*ol)
X { *truncptr = '\0'; return; }
X
X/* if this is the end of the new buffer but the old buffer has stuff
X here, clear to end of line if we can, otherwise fill the new buffer
X with blanks and continue. */
X
X if (!*nl)
X {
X if (tccan(TCCLEAREOL) && strlen(ol) > tclen[TCCLEAREOL])
X {
X moveto(ln,ccs);
X tcout(TCCLEAREOL);
X *ol = '\0';
X *truncptr = '\0';
X return;
X }
X else
X {
X int x = strlen(ol);
X char *p = nl;
X
X truncptr = p;
X while (x--)
X *p++ = ' ';
X *p = '\0';
X continue;
X }
X }
X
X/* if this is the end of the old buffer, just dump the rest of the
X new buffer. */
X
X if (!*ol)
X {
X while (*nl == ' ')
X nl++,ccs++;
X if (*nl)
X {
X moveto(ln,ccs);
X fwrite(nl,strlen(nl),1,stdout);
X cost += strlen(nl);
X vcs += strlen(nl);
X }
X *truncptr = 0;
X return;
X }
X moveto(ln,ccs);
X
X/* try to insert/delete characters */
X
X if (ol[1] != nl[1] && tccan(TCDEL))
X {
X int ct = 0;
X
X for (p1 = ol; *p1; p1++,ct++)
X if (tcdelcost(ct) < streqct(p1,nl))
X {
X tc_delchars(ct);
X ol = p1;
X break;
X }
X if (*p1)
X continue;
X }
X
X if (ol[1] != nl[1] && tccan(TCINS))
X {
X int ct = 0;
X
X for (p1 = nl; *p1; p1++,ct++)
X if (tcinscost(ct) < streqct(p1,ol)+ct)
X {
X#if 0
X/* make sure we aren't inserting characters off the end of the screen;
X if we are, jump to the end and truncate the line, if we can do
X it quickly (gee, clever idea, Paul!) */
X if (ct+ccs+strlen(ol) >= winw-1)
X {
X if (!tccan(TCMULTRIGHT) || ccs > winw-tclen[TCMULTRIGHT])
X continue;
X moveto(ln,winw-1-ct);
X if (!tccan(TCCLEAREOL) || ct < tclen[TCCLEAREOL])
X {
X int x = ct;
X
X while (vcs++,x--)
X putchar(' ');
X }
X else
X tcout(TCCLEAREOL);
X moveto(ln,ccs);
X }
X#endif
X if (ct+ccs+strlen(ol) < winw-1)
X {
X tc_inschars(ct = p1-nl);
X ccs = (vcs += p1-nl);
X cost += ct;
X fwrite(nl,ct,1,stdout);
X nl += ct;
X break;
X }
X }
X if (*p1)
X continue;
X }
X
X/* if we can't do anything fancy, just write the new character and
X keep going. */
X
X putchar(*nl);
X cost++;
X nl++,ol++,ccs = ++vcs;
X }
X}
X
Xvoid moveto(ln,cl) /**/
Xint ln;int cl;
X{
X
X/* move up */
X
X if (ln < vln)
X {
X tc_upcurs(vln-ln);
X vln = ln;
X }
X
X/* move down; if we might go off the end of the screen, use newlines
X instead of TCDOWN */
X
X while (ln > vln)
X if (cl < (vcs/2) || ln >= vmaxln || !tccan(TCLEFT))
X {
X putchar('\r');
X putchar('\n');
X cost+=2;
X vln++;
X vcs = 0;
X }
X else
X {
X tc_downcurs(ln-vln);
X vln = ln;
X }
X if (cl < (vcs/2) || !tccan(TCLEFT))
X {
X putchar('\r');
X cost++;
X vcs = 0;
X }
X if (vcs < cl)
X tc_rightcurs(cl-vcs);
X else if (vcs > cl)
X tc_leftcurs(vcs-cl);
X vcs = cl;
X}
X
Xvoid tcmultout(cap,multcap,ct) /**/
Xint cap;int multcap;int ct;
X{
X if (tccan(multcap) && (!tccan(cap) || tclen[multcap] < tclen[cap]*ct))
X tcoutarg(multcap,ct);
X else while (ct--)
X tcout(cap);
X}
X
Xvoid tc_rightcurs(ct) /**/
Xint ct;
X{
X
X/* do a multright if it's cheaper or if we're walking over the prompt. */
X
X if (tccan(TCMULTRIGHT) &&
X (ct > tclen[TCMULTRIGHT] || (vln == 0 && vcs < pptlen)))
X tcoutarg(TCMULTRIGHT,ct);
X
X/* if we're walking over the prompt and we can do a bunch of cursor rights,
X do them, even though they're more expensive. (We can't redraw the
X prompt very easily in general.) */
X
X else if (vln == 0 && vcs < pptlen && tccan(TCRIGHT))
X while (ct--)
X tcout(TCRIGHT);
X
X/* otherwise write the contents of the video buffer. */
X
X else
X fwrite(nbuf[vln]+vcs,ct,1,stdout);
X}
X
Xvoid tc_downcurs(ct) /**/
Xint ct;
X{
X if (tccan(TCMULTDOWN) &&
X (!tccan(TCDOWN) || tclen[TCMULTDOWN] < tclen[TCDOWN]*ct))
X tcoutarg(TCMULTDOWN,ct);
X else if (tccan(TCDOWN))
X while (ct--)
X tcout(TCDOWN);
X else
X {
X while (ct--)
X putchar('\n');
X vcs = 0;
X }
X}
X
X/* I'm NOT going to worry about padding unless anyone complains. */
X
Xvoid tcout(cap) /**/
Xint cap;
X{
X tputs(tcstr[cap],1,putraw);
X}
X
Xvoid tcoutarg(cap,arg) /**/
Xint cap;int arg;
X{
X tputs(tgoto(tcstr[cap],arg,arg),1,putraw);
X}
X
Xvoid clearscreen() /**/
X{
X tcout(TCCLEARSCREEN);
X resetneeded = 1;
X}
X
Xvoid redisplay() /**/
X{
X trashzle();
X}
X
Xvoid trashzle() /**/
X{
X if (zleactive)
X {
X refresh();
X moveto(nlnct,0);
X printf("%s",postedit);
X fflush(stdout);
X unsetterm();
X resetneeded = 1;
X }
X}
X
Xvoid singlerefresh() /**/
X{
Xchar *vbuf,*vp,**qbuf,*op;
Xint t0,vsiz,nvcs = 0;
X
X for (vsiz = 1+pptlen, t0 = 0; t0 != ll; t0++,vsiz++)
X if (line[t0] == '\t')
X vsiz += 7;
X else if (icntrl(line[t0]))
X vsiz++;
X vbuf = zalloc(vsiz);
X strcpy(vbuf,pmpt);
X vp = vbuf+pptlen;
X for (t0 = 0; t0 != ll; t0++)
X {
X if (line[t0] == '\t')
X do
X *vp++ = ' ';
X while ((vp-vbuf) & 7);
X else if (line[t0] == '\n')
X {
X *vp++ = '\\';
X *vp++ = 'n';
X }
X else if (line[t0] == 0x7f)
X {
X *vp++ = '^';
X *vp++ = '?';
X }
X else if (icntrl(line[t0]))
X {
X *vp++ = '^';
X *vp++ = line[t0] | '@';
X }
X else
X *vp++ = line[t0];
X if (t0 == cs)
X nvcs = vp-vbuf-1;
X }
X if (t0 == cs)
X nvcs = vp-vbuf;
X *vp = '\0';
X if ((winpos && nvcs < winpos+1) || (nvcs > winpos+winw-1))
X {
X if ((winpos = nvcs-(winw/2)) < 0)
X winpos = 0;
X }
X if (winpos)
X vbuf[winpos] = '<';
X if (strlen(vbuf+winpos) > winw)
X {
X vbuf[winpos+winw-1] = '>';
X vbuf[winpos+winw] = '\0';
X }
X strcpy(nbuf[0],vbuf+winpos);
X free(vbuf);
X nvcs -= winpos;
X for (t0 = 0,vp = *nbuf,op = *obuf; *vp; t0++,vp++)
X {
X if (*vp != *op && !(*vp == ' ' && !*op))
X {
X singmoveto(t0);
X putchar(*vp);
X vcs++;
X }
X if (*op)
X op++;
X }
X if (*op)
X {
X singmoveto(t0);
X for (; *op; op++)
X {
X putchar(' ');
X vcs++;
X }
X }
X singmoveto(nvcs);
X qbuf = nbuf;
X nbuf = obuf;
X obuf = qbuf;
X fflush(stdout);
X}
X
Xvoid singmoveto(pos) /**/
Xint pos;
X{
X while (pos < vcs)
X {
X vcs--;
X putchar('\b');
X }
X while (pos > vcs)
X {
X putchar(nbuf[0][vcs]);
X vcs++;
X }
X}
X
Xint streqct(s,t) /**/


Xchar *s;char *t;
X{

Xint ct = 0;
X
X while (*s && *s == *t) s++,t++,ct++;


X return ct;
X}
X

END_OF_FILE
if test 12060 -ne `wc -c <'src/zle_refresh.c'`; then
echo shar: \"'src/zle_refresh.c'\" unpacked with wrong size!
fi
# end of 'src/zle_refresh.c'
fi
echo shar: End of archive 10 \(of 22\).
cp /dev/null ark10isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:24:21 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 61
Archive-name: zsh/part11

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: src/jobs.c src/zsh.h
# Wrapped by mattson@odin on Sat Feb 6 14:41:53 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 11 (of 22)."'
if test -f 'src/jobs.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/jobs.c'\"
else
echo shar: Extracting \"'src/jobs.c'\" \(17010 characters\)
sed "s/^X//" >'src/jobs.c' <<'END_OF_FILE'
X/*
X *
X * jobs.c - job control


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/* empty job structure for quick clearing of jobtab entries */
X
Xstatic struct job zero = {
X 0L, 0, (char *)NULL, (struct process *) NULL, (Lklist) NULL
X};
X
X#ifdef INTHANDTYPE
X#define RETURN return 0
X#else
X#define RETURN return
X#endif
X
X/* the signal handler */
X
XHANDTYPE handler(sig) /**/
Xint sig;
X{
Xlong pid;
Xint statusp;
XJob jn;
Xstruct process *pn;
X#ifdef HAS_RUSAGE
Xstruct rusage ru;
X#else
Xlong chlds,chldu;
X#endif
X
X#ifdef RESETHANDNEEDED
X signal(sig,handler);
X#endif
X if (sig == SIGHUP)
X {
X if (sigtrapped[SIGHUP])
X dotrap(SIGHUP);
X else
X {
X stopmsg = 1;
X zexit(SIGHUP);
X }
X }
X if (sig == SIGINT)
X {
X if (sigtrapped[SIGINT])
X dotrap(SIGINT);
X else
X {
X breaks = loops;


X errflag = 1;
X }

X RETURN;
X }
X#ifdef SIGWINCH
X if (sig == SIGWINCH)
X adjustwinsize();
X#endif
X if (sig != SIGCHLD)
X {
X dotrap(sig);
X if (sig == SIGALRM)
X {
X if (!sigtrapped[SIGALRM])
X {
X zerr("timeout",NULL,0);
X exit(1);
X }
X else if (tmout)
X {
X alarm(tmout);
X }
X }
X RETURN;
X }


X for (;;)
X {

X#ifdef HAS_RUSAGE
X pid = wait3((vptr) &statusp,WNOHANG|WUNTRACED,&ru);
X#else
X#ifndef WNOHANG
X pid = wait(&statusp);
X#else
X#ifdef WAITPID
X pid = waitpid(-1,(vptr) &statusp,WNOHANG|WUNTRACED);
X#else
X pid = wait3((vptr) &statusp,WNOHANG|WUNTRACED,NULL);
X#endif
X#endif
X chlds = shtms.tms_cstime;
X chldu = shtms.tms_cutime;
X times(&shtms);
X#endif


X if (pid == -1)

X {
X if (errno != ECHILD)
X zerr("wait failed: %e",NULL,errno);
X RETURN;
X }
X if (!pid)
X RETURN;
X if (pid == cmdoutpid) {
X cmdoutpid = 0;
X if (WIFSIGNALED(statusp))
X {
X cmdoutval = (0200 | WTERMSIG(statusp));
X if (WTERMSIG(statusp) == SIGINT)
X (void) kill(getpid(),SIGINT);
X else if (sigtrapped[WTERMSIG(statusp)])
X dotrap(WTERMSIG(statusp));
X }
X else
X cmdoutval = WEXITSTATUS(statusp);
X RETURN;
X }
X findproc(pid,&jn,&pn); /* find the process of this pid */
X if (jn)
X {
X pn->statusp = statusp;
X#ifdef HAS_RUSAGE
X pn->ti.ru = ru;
X#else
X pn->ti.st = shtms.tms_cstime-chlds;
X pn->ti.ut = shtms.tms_cutime-chldu;
X#endif
X pn->endtime = time(NULL);
X updatestatus(jn);
X }
X#if 0
X else if (WIFSTOPPED(statusp))
X kill(pid,SIGKILL); /* kill stopped untraced children */
X#endif
X }
X}
X
X/* change job table entry from stopped to running */
X
Xvoid makerunning(jn) /**/
XJob jn;
X{
Xstruct process *pn;
X
X jn->stat &= ~STAT_STOPPED;
X for (pn = jn->procs; pn; pn = pn->next)
X if (WIFSTOPPED(pn->statusp))
X pn->statusp = SP_RUNNING;
X}
X
X/* update status of job, possibly printing it */
X
Xvoid updatestatus(jn) /**/
XJob jn;
X{
Xstruct process *pn;
Xint notrunning = 1,alldone = 1,val = 0,job = jn-jobtab,somestopped = 0;
X
X for (pn = jn->procs; pn; pn = pn->next)
X {
X if (pn->statusp == SP_RUNNING)
X notrunning = 0;
X if (pn->statusp == SP_RUNNING || WIFSTOPPED(pn->statusp))
X alldone = 0;
X if (WIFSTOPPED(pn->statusp))
X somestopped = 1;
X if (!pn->next && jn)
X val = (WIFSIGNALED(pn->statusp)) ?
X 0200 | WTERMSIG(pn->statusp) : WEXITSTATUS(pn->statusp);
X }
X if (!notrunning)
X return;
X if (somestopped && (jn->stat & STAT_STOPPED))
X return;
X jn->stat |= (alldone) ? STAT_CHANGED|STAT_DONE :
X STAT_CHANGED|STAT_STOPPED;
X if (alldone && job == thisjob)
X {
X if (!ttyfrozen && !val) {
X gettyinfo(&shttyinfo);
X if (interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE))
X sanetty(&shttyinfo);
X#ifdef TIOCSWINSZ
X if (!(columns = shttyinfo.winsize.ws_col))
X columns = 80;
X lines = shttyinfo.winsize.ws_row;
X#endif
X } else
X settyinfo(&shttyinfo);


X lastval = val;
X }

X if ((jn->stat & (STAT_DONE|STAT_STOPPED)) == STAT_STOPPED) {
X prevjob = curjob;
X curjob = job;
X }
X if ((isset(NOTIFY) || job == thisjob) && jn->stat & STAT_LOCKED) {
X printjob(jn,!!isset(LONGLISTJOBS));
X if (zleactive) refresh();
X }
X if (sigtrapped[SIGCHLD] && job != thisjob)
X dotrap(SIGCHLD);
X}
X
X/* find process and job associated with pid */
X
Xvoid findproc(pid,jptr,pptr) /**/
Xint pid;Job *jptr;struct process **pptr;
X{
Xstruct process *pn;
Xint jn;
X
X for (jn = 1; jn != MAXJOB; jn++)
X for (pn = jobtab[jn].procs; pn; pn = pn->next)
X if (pn->pid == pid)
X {
X *pptr = pn;
X *jptr = jobtab+jn;
X return;
X }
X *pptr = NULL;
X *jptr = NULL;
X}
X
X/*
X lng = 0 means jobs
X lng = 1 means jobs -l
X lng = 2 means jobs -p
X*/
X
Xvoid printjob(jn,lng) /**/
XJob jn;int lng;
X{
Xint job = jn-jobtab,len = 9,sig,sflag = 0,llen;
Xint conted = 0,lineleng = getlineleng(),skip = 0,doputnl = 0;
Xstruct process *pn;
X
X if (lng < 0)
X {
X conted = 1;
X lng = 0;
X }
X
X /* find length of longest signame, check to see if we
X really need to print this job */
X
X for (pn = jn->procs; pn; pn = pn->next)
X {
X if (pn->statusp != SP_RUNNING)
X if (WIFSIGNALED(pn->statusp))
X {
X sig = WTERMSIG(pn->statusp);
X llen = strlen(sigmsg[sig]);
X if (WCOREDUMP(pn->statusp))
X llen += 14;
X if (llen > len)
X len = llen;
X if (sig != SIGINT && sig != SIGPIPE)
X sflag = 1;
X else if (sig == SIGINT)
X errflag = 1;
X if (job == thisjob && sig == SIGINT)
X doputnl = 1;
X }
X else if (WIFSTOPPED(pn->statusp))
X {
X sig = WSTOPSIG(pn->statusp);
X if (strlen(sigmsg[sig]) > len)
X len = strlen(sigmsg[sig]);
X if (job == thisjob && sig == SIGTSTP)
X doputnl = 1;
X }
X else if (isset(PRINTEXITVALUE) && isset(SHINSTDIN) &&
X WEXITSTATUS(pn->statusp))
X sflag = 1;
X }
X
X /* print if necessary */
X
X if (interact && jobbing && ((jn->stat & STAT_STOPPED) || sflag ||
X job != thisjob))
X {
X int len2,fline = 1;
X struct process *qn;
X
X trashzle();
X if (doputnl)
X putc('\n',stderr);
X for (pn = jn->procs; pn;)
X {
X len2 = ((job == thisjob) ? 5 : 10)+len; /* 2 spaces */
X if (lng)
X qn = pn->next;
X else for (qn = pn->next; qn; qn = qn->next)
X {
X if (qn->statusp != pn->statusp)
X break;
X if (strlen(qn->text)+len2+((qn->next) ? 3 : 0) > lineleng)
X break;
X len2 += strlen(qn->text)+2;
X }
X if (job != thisjob)
X if (fline)
X fprintf(stderr,"[%d] %c ",jn-jobtab,(job == curjob) ? '+' :
X (job == prevjob) ? '-' : ' ');
X else
X fprintf(stderr,(job > 9) ? " " : " ");
X else
X fprintf(stderr,"zsh: ");
X if (lng)
X if (lng == 1)
X fprintf(stderr,"%d ",pn->pid);
X else
X {
X int x = jn->gleader;
X
X fprintf(stderr,"%d ",x);
X do skip++; while (x /= 10);
X skip++;
X lng = 0;
X }
X else
X fprintf(stderr,"%*s",skip,"");
X if (pn->statusp == SP_RUNNING)
X if (!conted)
X fprintf(stderr,"running%*s",len-7+2,"");
X else
X fprintf(stderr,"continued%*s",len-9+2,"");
X else if (WIFEXITED(pn->statusp))
X if (WEXITSTATUS(pn->statusp))
X fprintf(stderr,"exit %-4d%*s",WEXITSTATUS(pn->statusp),
X len-9+2,"");
X else
X fprintf(stderr,"done%*s",len-4+2,"");
X else if (WIFSTOPPED(pn->statusp))
X fprintf(stderr,"%-*s",len+2,sigmsg[WSTOPSIG(pn->statusp)]);
X else if (WCOREDUMP(pn->statusp))
X fprintf(stderr,"%s (core dumped)%*s",
X sigmsg[WTERMSIG(pn->statusp)],
X len-14+2-strlen(sigmsg[WTERMSIG(pn->statusp)]),"");
X else
X fprintf(stderr,"%-*s",len+2,sigmsg[WTERMSIG(pn->statusp)]);
X for (; pn != qn; pn = pn->next)
X fprintf(stderr,(pn->next) ? "%s | " : "%s",pn->text);
X putc('\n',stderr);
X fline = 0;
X }
X }
X else if (doputnl && interact)
X putc('\n',stderr);
X fflush(stderr);
X
X /* print "(pwd now: foo)" messages */
X
X if (interact && job==thisjob && strcmp(jn->pwd,pwd))
X {
X printf("(pwd now: ");
X printdir(pwd);


X printf(")\n");

X fflush(stdout);
X }
X
X /* delete job if done */
X
X if (jn->stat & STAT_DONE)
X {
X struct process *nx;
X char *s;
X
X if ((jn->stat & STAT_TIMED) || (reporttime != -1 && report(jn))) {
X dumptime(jn);
X }
X for (pn = jn->procs; pn; pn = nx)
X {
X nx = pn->next;
X free(pn);
X }
X free(jn->pwd);
X if (jn->filelist)
X {
X while (s = getnode(jn->filelist))
X {
X unlink(s);
X free(s);
X }
X free(jn->filelist);
X }
X *jn = zero;
X if (job == curjob)


X {
X curjob = prevjob;

X prevjob = job;
X }
X if (job == prevjob)
X setprevjob();
X }
X else
X jn->stat &= ~STAT_CHANGED;
X}
X
X/* set the previous job to something reasonable */
X
Xvoid setprevjob() /**/
X{
Xint t0;
X
X for (t0 = MAXJOB-1; t0; t0--)
X if ((jobtab[t0].stat & STAT_INUSE) && (jobtab[t0].stat & STAT_STOPPED) &&
X t0 != curjob && t0 != thisjob)
X break;
X if (!t0)
X for (t0 = MAXJOB-1; t0; t0--)
X if ((jobtab[t0].stat & STAT_INUSE) && t0 != curjob && t0 != thisjob)
X break;
X prevjob = (t0) ? t0 : -1;
X}
X
X/* initialize a job table entry */
X
Xvoid initjob() /**/
X{
X jobtab[thisjob].pwd = ztrdup(pwd);
X jobtab[thisjob].stat = STAT_INUSE;
X jobtab[thisjob].gleader = 0;
X}
X
X/* add a process to the current job */
X
Xstruct process *addproc(pid,text) /**/
Xlong pid;char *text;
X{
Xstruct process *process;
X
X if (!jobtab[thisjob].gleader) jobtab[thisjob].gleader = pid;
X process = zcalloc(sizeof *process);
X process->pid = pid;
X if (text) strcpy(process->text,text);
X else *process->text = '\0';
X process->next = NULL;
X process->statusp = SP_RUNNING;
X process->bgtime = time(NULL);
X if (jobtab[thisjob].procs) {
X struct process *n;
X for (n = jobtab[thisjob].procs; n->next; n = n->next);
X process->next = NULL;
X n->next = process;
X } else jobtab[thisjob].procs = process;
X return process;
X}
X
X/* determine if it's all right to exec a command without
X forking in last component of subshells; it's not ok if we have files
X to delete */
X
Xint execok() /**/
X{
XJob jn;
X
X if (!exiting)
X return 0;
X for (jn = jobtab+1; jn != jobtab+MAXJOB; jn++)
X if (jn->stat && jn->filelist)
X return 0;
X return 1;
X
X}
X
Xvoid waitforpid(pid) /**/
Xlong pid;
X{
X while (!errflag && (kill(pid,0) >= 0 || errno != ESRCH)) chldsuspend();
X}
X
X/* wait for a job to finish */
X
Xvoid waitjob(job) /**/
Xint job;
X{
XJob jn;
X
X if (jobtab[job].procs) /* if any forks were done */
X {
X jobtab[job].stat |= STAT_LOCKED;
X if (jobtab[job].stat & STAT_CHANGED)
X printjob(jobtab+job,!!isset(LONGLISTJOBS));
X while (jobtab[job].stat &&
X !(jobtab[job].stat & (STAT_DONE|STAT_STOPPED)))
X chldsuspend();
X }
X else /* else do what printjob() usually does */


X {
X char *s;
X

X jn = jobtab+job;
X free(jn->pwd);
X if (jn->filelist)
X {
X while (s = getnode(jn->filelist))
X {
X unlink(s);
X free(s);
X }
X free(jn->filelist);
X }
X *jn = zero;
X }
X}
X
X/* wait for running job to finish */
X
Xvoid waitjobs() /**/
X{
X waitjob(thisjob);
X thisjob = -1;
X}
X
X/* clear job table when entering subshells */
X
Xvoid clearjobtab() /**/
X{
Xint t0;
X
X for (t0 = 1; t0 != MAXJOB; t0++) {
X if (jobtab[thisjob].pwd)
X free(jobtab[thisjob].pwd);
X jobtab[thisjob] = zero;
X }
X}
X
X/* get a free entry in the job table to use */
X
Xint getfreejob() /**/
X{
Xint t0;
X
X for (t0 = 1; t0 != MAXJOB; t0++)
X if (!jobtab[t0].stat) {
X jobtab[t0].stat |= STAT_INUSE;
X return t0;
X }
X zerr("job table full or recursion limit exceeded",NULL,0);


X return -1;
X}
X

X/* print pids for & */
X
Xvoid spawnjob() /**/
X{
Xstruct process *pn;
X
X if (!subsh)
X {
X if (curjob == -1 || !(jobtab[curjob].stat & STAT_STOPPED))
X {
X curjob = thisjob;
X setprevjob();
X }
X else if (prevjob == -1 || !(jobtab[prevjob].stat & STAT_STOPPED))
X prevjob = thisjob;
X if (interact && jobbing && jobtab[thisjob].procs)
X {
X fprintf(stderr,"[%d]",thisjob);
X for (pn = jobtab[thisjob].procs; pn; pn = pn->next)
X fprintf(stderr," %d",pn->pid);
X fprintf(stderr,"\n");
X fflush(stderr);
X }
X }
X if (!jobtab[thisjob].procs)
X {
X char *s;
X struct job *jn;
X
X jn = jobtab+thisjob;
X free(jn->pwd);
X if (jn->filelist)
X {
X while (s = getnode(jn->filelist))
X {
X unlink(s);
X free(s);
X }
X free(jn->filelist);
X }
X *jn = zero;
X }
X else
X jobtab[thisjob].stat |= STAT_LOCKED;
X thisjob = -1;
X}
X
Xvoid fixsigs() /**/
X{
X unblockchld();
X}
X
Xint report(j) /**/
XJob j;
X{
X if (!j->procs) return 0;
X#ifdef HAS_RUSAGE
X return (j->procs->ti.ru.ru_utime.tv_sec+j->procs->ti.ru.ru_stime.tv_sec)
X >= reporttime;
X#else
X return (j->procs->ti.ut+j->procs->ti.st)/HZ >= reporttime;
X#endif
X}
X
Xvoid printtime(real,ti,desc) /**/
Xtime_t real;struct timeinfo *ti;char *desc;
X{
Xchar *s;
X#ifdef HAS_RUSAGE
X#ifdef sun
Xlong ticks = 1;
Xint pk = getpagesize()/1024;
X#else
Xlong sec;
X#endif
Xstruct rusage *ru = &ti->ru;
X#endif
X
X if (!desc) desc = "";
X#ifdef HAS_RUSAGE
X#ifdef sun
X ticks = (ru->ru_utime.tv_sec+ru->ru_stime.tv_sec)*HZ+
X (ru->ru_utime.tv_usec+ru->ru_stime.tv_usec)*HZ/1000000;
X if (!ticks) ticks = 1;
X#else
X sec = ru->ru_utime.tv_sec + ru->ru_stime.tv_sec;
X if (!sec) sec = 1;
X#endif
X#endif
X for (s = timefmt; *s; s++)
X if (*s == '%')
X switch(s++,*s)
X {
X case 'E': fprintf(stderr,"%lds",real); break;
X#ifndef HAS_RUSAGE
X case 'U': fprintf(stderr,"%ld.%03lds",
X ti->ut/HZ,ti->ut*1000/HZ%1000); break;
X case 'S': fprintf(stderr,"%ld.%03lds",
X ti->st/HZ,ti->st*1000/HZ%1000); break;
X case 'P':
X if (real)
X fprintf(stderr,"%d%%",
X (int) (100*((ti->ut+ti->st)/HZ))/real);
X break;
X#else
X case 'U': fprintf(stderr,"%ld.%03lds",
X ru->ru_utime.tv_sec,ru->ru_utime.tv_usec/1000); break;
X case 'S': fprintf(stderr,"%ld.%03lds",
X ru->ru_stime.tv_sec,ru->ru_stime.tv_usec/1000); break;
X case 'P':
X if (real)
X fprintf(stderr,"%d%%",
X (int) (100*(ru->ru_utime.tv_sec+ru->ru_stime.tv_sec))
X / real);
X break;
X case 'W': fprintf(stderr,"%ld",ru->ru_nswap); break;
X#ifdef sun
X case 'K': case 'D':
X fprintf(stderr,"%ld",ru->ru_idrss/ticks*pk); break;
X case 'M': fprintf(stderr,"%ld",ru->ru_maxrss*pk); break;
X#else
X case 'X': fprintf(stderr,"%ld",ru->ru_ixrss/sec); break;
X case 'D': fprintf(stderr,"%ld",
X (ru->ru_idrss+ru->ru_isrss)/sec); break;
X case 'K': fprintf(stderr,"%ld",
X (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss)/sec); break;
X case 'M': fprintf(stderr,"%ld",ru->ru_maxrss/1024); break;
X#endif
X case 'F': fprintf(stderr,"%ld",ru->ru_majflt); break;
X case 'R': fprintf(stderr,"%ld",ru->ru_minflt); break;
X case 'I': fprintf(stderr,"%ld",ru->ru_inblock); break;
X case 'O': fprintf(stderr,"%ld",ru->ru_oublock); break;
X case 'r': fprintf(stderr,"%ld",ru->ru_msgrcv); break;
X case 's': fprintf(stderr,"%ld",ru->ru_msgsnd); break;
X case 'k': fprintf(stderr,"%ld",ru->ru_nsignals); break;
X case 'w': fprintf(stderr,"%ld",ru->ru_nvcsw); break;
X case 'c': fprintf(stderr,"%ld",ru->ru_nivcsw); break;
X#endif
X case 'J': fprintf(stderr,"%s",desc); break;
X default: fprintf(stderr,"%%%c",*s); break;
X }
X else
X putc(*s,stderr);
X putc('\n',stderr);
X fflush(stderr);
X}
X
Xvoid dumptime(jn) /**/
XJob jn;
X{
Xstruct process *pn;
X
X if (!jn->procs)
X return;
X for (pn = jn->procs; pn; pn = pn->next)
X printtime(pn->endtime-pn->bgtime,&pn->ti,pn->text);
X}
X
Xvoid shelltime() /**/
X{
Xstruct timeinfo ti;
X#ifdef HAS_RUSAGE
Xstruct rusage ru;
X
X getrusage(RUSAGE_SELF,&ru);
X memcpy(&ti.ru,&ru,sizeof(ru));
X printtime(time(NULL)-shtimer,&ti,"shell");
X
X getrusage(RUSAGE_CHILDREN,&ru);
X memcpy(&ti.ru,&ru,sizeof(ru));
X printtime(time(NULL)-shtimer,&ti,"children");
X#else
Xstruct tms buf;
X
X times(&buf);
X ti.ut = buf.tms_utime;
X ti.st = buf.tms_stime;
X printtime(time(NULL)-shtimer,&ti,"shell");
X ti.ut = buf.tms_cutime;
X ti.st = buf.tms_cstime;
X printtime(time(NULL)-shtimer,&ti,"children");
X#endif
X}
X
X/* SIGHUP any jobs left running */
X
Xvoid killrunjobs() /**/
X{
Xint t0,killed = 0;
X
X if (isset(NOHUP)) return;
X for (t0 = 1; t0 != MAXJOB; t0++)
X if (t0 != thisjob && (jobtab[t0].stat & STAT_LOCKED) &&
X !(jobtab[t0].stat & STAT_STOPPED)) {
X if (killpg(jobtab[t0].gleader,SIGHUP) != -1) killed++;
X }
X if (killed) zerr("warning: %d jobs SIGHUPed",NULL,killed);
X}
X
X/* check to see if user has jobs running/stopped */
X
Xvoid checkjobs() /**/
X{
Xint t0;
X
X scanjobs();
X for (t0 = 1; t0 != MAXJOB; t0++)
X if (t0 != thisjob && jobtab[t0].stat & STAT_LOCKED)
X break;
X if (t0 != MAXJOB) {
X if (jobtab[t0].stat & STAT_STOPPED) {
X#ifdef USE_SUSPENDED
X zerr("you have suspended jobs.",NULL,0);
X#else
X zerr("you have stopped jobs.",NULL,0);
X#endif
X } else
X zerr("you have running jobs.",NULL,0);
X stopmsg = 1;
X }
X}
X
X/* send a signal to a job (simply involves kill if monitoring is on) */
X
Xint killjb(jn,sig) /**/
XJob jn;int sig;
X{
Xstruct process *pn;
Xint err = 0;
X
X if (jobbing)
X return(killpg(jn->gleader,sig));
X for (pn = jn->procs; pn; pn = pn->next)
X if ((err = kill(pn->pid,sig)) == -1 && errno != ESRCH)
X return -1;
X return err;
X}
END_OF_FILE
if test 17010 -ne `wc -c <'src/jobs.c'`; then
echo shar: \"'src/jobs.c'\" unpacked with wrong size!
fi
# end of 'src/jobs.c'
fi
if test -f 'src/zsh.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zsh.h'\"
else
echo shar: Extracting \"'src/zsh.h'\" \(34760 characters\)
sed "s/^X//" >'src/zsh.h' <<'END_OF_FILE'
X/*
X *
X * zsh.h - standard header file


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 "config.h"
X
X#include <stdio.h>
X#include <ctype.h>
X
X#ifdef HAS_STRING
X#include <string.h>
X#else
X#include <strings.h>
X#endif
X
X#ifdef HAS_MEMORY
X#include <memory.h>
X#endif
X
X#ifdef HAS_LOCALE
X#include <locale.h>
X#endif
X
X#ifdef HAS_STDLIB
X#include <stdlib.h>
X#endif
X
X#ifdef SYSV
X#ifndef SYSVR4
X#include <sys/bsdtypes.h>
X#define _POSIX_SOURCE
X#include <sys/limits.h>
X#include <sys/sioctl.h>
X#define MAXPATHLEN PATH_MAX
X#define lstat stat
X#endif
Xextern int gethostname();
X#define sigmask(m) m
X#else
X#include <sys/types.h> /* this is the key to the whole thing */
X#endif
X
X#ifdef _IBMR2
X#undef _BSD /* union wait SUCKS! */
X#include <sys/wait.h>
X#define _BSD
X#else
X#ifdef HAS_WAIT
X#include <wait.h>
X#else
X#include <sys/wait.h>
X#endif
X#endif
X
X#ifdef HAS_TIME
X#include <time.h>
X#else
X#include <sys/time.h>
X#endif
X
X#ifdef SYSV
X#include <fcntl.h>
X#else
X#include <sys/file.h>
X#endif
X
X#if !defined(SYSV) || defined(SYSVR4)
X#include <sys/resource.h>
X#endif
X
X#include <signal.h>
X
X#ifdef TERMIO
X#define VDISABLEVAL -1
X#define TIO 1
X#include <sys/termio.h>
X#else
X#ifdef TERMIOS
X#define VDISABLEVAL 0
X#define TIO 1
X#include <termios.h>
X#else
X#include <sgtty.h>
X#endif
X#endif
X
X#if defined(SYSV) && !defined(SYSVR4)
X#define readlink(s,t,z) (-1)
X#undef TIOCGWINSZ
X#endif
X
X#include <sys/param.h>
X#include <sys/times.h>
X
X#ifdef HAS_DIRENT
X#include <dirent.h>
X#define direct dirent
X#else
X#include <sys/dir.h>
X#endif
X
X#ifdef SYSV
X#undef _POSIX_SOURCE
X#endif
X
X#ifdef __hp9000s800
X#include <sys/bsdtty.h>
X#endif
X
X#if !defined(sun) && !defined(SYSVR4)
X#include <sys/ioctl.h>
X#else
X#include <sys/filio.h>
X#endif
X
X#ifdef __STDC__
X#define DCLPROTO(X) X
X#ifdef HAS_UNISTD
X#include <unistd.h>
X#endif
X#include <fcntl.h>
X#include <sys/stat.h>
X#undef NULL
X#define NULL ((void *)0)
X#else /* K&R C */
X#define DCLPROTO(X) ()
X#define const
X#include <sys/stat.h>
X#ifndef NULL
X#define NULL 0
X#endif
X#endif
X
X#ifdef HAS_UTMPX
X#include <utmpx.h>
X# define utmp utmpx
X# define ut_time ut_xtime
X# undef UTMP_FILE
X# define UTMP_FILE UTMPX_FILE
X# undef WTMP_FILE
X# define WTMP_FILE WTMPX_FILE
X#else
X#include <utmp.h>
X#endif
X
X#if !defined(UTMP_FILE) && defined(_PATH_UTMP)
X#define UTMP_FILE _PATH_UTMP
X#endif
X#if !defined(WTMP_FILE) && defined(_PATH_WTMP)
X#define WTMP_FILE _PATH_WTMP
X#endif
X
X#define DEFWORDCHARS "*?_-.[]~=/&;!#$%^(){}<>"
X#define DEFTIMEFMT "%E real %U user %S system %P %J"
X#ifdef UTMP_HOST
X#define DEFWATCHFMT "%n has %a %l from %m."
X#else
X#define DEFWATCHFMT "%n has %a %l."
X#endif
X
X#ifdef GLOBALS
X#define EXTERN
X#else
X#define EXTERN extern
X#endif
X
X#ifdef HAS_STRING
X#define killpg(pgrp,sig) kill(-(pgrp),sig)
X#endif
X
X/* SYSV or POSIX compatible BSD */
X#if defined(SYSV) || ( defined(BSD) && BSD >= 199103 )
X#define getpgrp(X) getpgrp()
X#endif
X
X#ifndef F_OK
X#define F_OK 00
X#define R_OK 04
X#define W_OK 02
X#define X_OK 01
X#endif
X
X#include "zle.h"
X
X/* size of job list */
X
X#define MAXJOB 80
X
X/* memory allocation routines - changed with permalloc()/heapalloc() */
X
Xvptr (*alloc)DCLPROTO((int));
Xvptr (*ncalloc)DCLPROTO((int));
X
X#define addhnode(A,B,C,D) Addhnode(A,B,C,D,1)
X#define addhperm(A,B,C,D) Addhnode(A,B,C,D,0)
X
X/* character tokens */
X
X#define ALPOP ((char) 0x81)
X#define HISTSPACE ((char) 0x83)
X#define Pound ((char) 0x84)
X#define String ((char) 0x85)
X#define Hat ((char) 0x86)
X#define Star ((char) 0x87)
X#define Inpar ((char) 0x88)
X#define Outpar ((char) 0x89)
X#define Qstring ((char) 0x8a)
X#define Equals ((char) 0x8b)
X#define Bar ((char) 0x8c)
X#define Inbrace ((char) 0x8d)
X#define Outbrace ((char) 0x8e)
X#define Inbrack ((char) 0x8f)
X#define Outbrack ((char) 0x90)
X#define Tick ((char) 0x91)
X#define Inang ((char) 0x92)
X#define Outang ((char) 0x93)
X#define Quest ((char) 0x94)
X#define Tilde ((char) 0x95)
X#define Qtick ((char) 0x96)
X#define Comma ((char) 0x97)
X#define Snull ((char) 0x98)
X#define Dnull ((char) 0x99)
X#define Bnull ((char) 0x9a)
X#define Nularg ((char) 0x9b)
X
X#define INULL(x) (((x) & 0x98) == 0x98)
X
X/* Character tokens are sometimes casted to (unsigned char)'s. Unfortunately,
X SVR4's deceiving compiler botches non-terminal, same size, signed to unsigned
X promotions; i.e. (int) (unsigned char) ((char) -1) evaluates to -1,
X not 255 as it should!
X
X We circumvent the troubles of such shameful delinquency by casting to a
X larger unsigned type then back down to unsigned char.
X -- Marc Boucher <ma...@cam.org>
X <dan...@ug.eds.com> 25-Jan-1993 Dec Alpha OSF compilers have the same property
X*/
X
X#if (defined(SYSVR4) || defined (__osf__)) && !defined(__GNUC__)
X#define STOUC(X) ((unsigned char)(unsigned short)(X))
X#else
X#define STOUC(X) ((unsigned char)(X))
X#endif
X
X/*
X * The source was full of implicit casts between signed and unsigned
X * character pointers. To get a clean compile, I've made these casts
X * explicit, but the potential for error is still there. If your machine
X * needs special treatment, just define your own macros here.
X * --jim <jmat...@ucsd.edu>
X */
X
X#define STOUCP(X) ((unsigned char *)(X))
X#define UTOSCP(X) ((char *)(X))
X
X/* chars that need to be quoted if meant literally */
X
X#define SPECCHARS "#$^*()$=|{}[]`<>?~;&!\n\t \\\'\""
X
X/* ALPOP in the form of a string */
X
X#define ALPOPS " \201"
X#define HISTMARK "\201"
X
X#define SEPER 1
X#define NEWLIN 2
X#define LEXERR 3
X#define SEMI 4
X#define DSEMI 5
X#define AMPER 6
X#define INPAR 7
X#define INBRACE 8
X#define OUTPAR 9
X#define DBAR 10
X#define DAMPER 11
X#define BANG 12
X#define OUTBRACE 13
X#define OUTANG 14
X#define OUTANGBANG 15
X#define DOUTANG 16
X#define DOUTANGBANG 17
X#define INANG 18
X#define DINANG 19
X#define DINANGDASH 20
X#define INANGAMP 21
X#define OUTANGAMP 22
X#define OUTANGAMPBANG 23
X#define DOUTANGAMP 24
X#define DOUTANGAMPBANG 25
X#define TRINANG 26
X#define BAR 27
X#define BARAMP 28
X#define DINBRACK 29
X#define DOUTBRACK 30
X#define STRING 31
X#define ENVSTRING 32
X#define ENVARRAY 33
X#define ENDINPUT 34
X#define INOUTPAR 35
X#define DO 36
X#define DONE 37
X#define ESAC 38
X#define THEN 39
X#define ELIF 40
X#define ELSE 41
X#define FI 42
X#define FOR 43
X#define CASE 44
X#define IF 45
X#define WHILE 46
X#define FUNC 47
X#define REPEAT 48
X#define TIME 49
X#define UNTIL 50
X#define EXEC 51
X#define COMMAND 52
X#define SELECT 53
X#define COPROC 54
X#define NOGLOB 55
X#define DASH 56
X#define NOCORRECT 57
X#define FOREACH 58
X#define ZEND 59
X
X#define WRITE 0
X#define WRITENOW 1
X#define APP 2
X#define APPNOW 3
X#define MERGEOUT 4
X#define MERGEOUTNOW 5
X#define ERRAPP 6
X#define ERRAPPNOW 7
X#define READ 8
X#define HEREDOC 9
X#define HEREDOCDASH 10
X#define HERESTR 11
X#define MERGE 12
X#define CLOSE 13
X#define INPIPE 14
X#define OUTPIPE 15
X#define NONE 16
X
X#ifdef GLOBALS
Xint redirtab[TRINANG-OUTANG+1] = {
X WRITE,
X WRITENOW,
X APP,
X APPNOW,
X READ,
X HEREDOC,
X HEREDOCDASH,
X MERGE,
X MERGEOUT,
X MERGEOUTNOW,
X ERRAPP,
X ERRAPPNOW,
X HERESTR,
X};
X#else
Xextern int redirtab[TRINANG-OUTANG+1];
X#endif
X
X#ifdef GLOBALS
Xchar nulstring[] = { Nularg, '\0' };
Xint nulstrlen = sizeof(nulstring) - 1;
X#else
Xextern char nulstring[];
Xextern int nulstrlen;
X#endif
X
X#define IS_READFD(X) ((X)>=READ && (X)<=MERGE)
X#define IS_REDIROP(X) ((X)>=OUTANG && (X)<=TRINANG)
X#define IS_ERROR_REDIR(X) ((X)>=MERGEOUT && (X)<=ERRAPPNOW)
X#define UN_ERROR_REDIR(X) ((X)-MERGEOUT+WRITE)
X
X#define FD_WORD -1
X#define FD_COPROC -2
X#define FD_CLOSE -3
X
Xextern char **environ;
X
Xtypedef struct hashtab *Hashtab;
Xtypedef struct hashnode *Hashnode;
Xtypedef struct schedcmd *Schedcmd;
Xtypedef struct alias *Alias;
Xtypedef struct process *Process;
Xtypedef struct job *Job;
Xtypedef struct value *Value;
Xtypedef struct arrind *Arrind;
Xtypedef struct varasg *Varasg;
Xtypedef struct param *Param;
Xtypedef struct cmdnam *Cmdnam;
Xtypedef struct cond *Cond;
Xtypedef struct cmd *Cmd;
Xtypedef struct pline *Pline;
Xtypedef struct sublist *Sublist;
Xtypedef struct list *List;
Xtypedef struct lklist *Lklist;
Xtypedef struct lknode *Lknode;
Xtypedef struct comp *Comp;
Xtypedef struct redir *Redir;
Xtypedef struct complist *Complist;
Xtypedef struct heap *Heap;
Xtypedef struct histent *Histent;
Xtypedef struct compctl *Compctl;
Xtypedef void (*FFunc)DCLPROTO((vptr));
Xtypedef vptr (*VFunc)DCLPROTO((vptr));
Xtypedef void (*HFunc)DCLPROTO((char *,char *));
X
X/* linked list abstract data type */
X
Xstruct lknode;
Xstruct lklist;
X
Xstruct lknode {
X Lknode next,last;
X vptr dat;
X };
Xstruct lklist {
X Lknode first,last;
X };
X
X#define addnode(X,Y) insnode(X,(X)->last,Y)
X#define full(X) ((X)->first != NULL)
X#define empty(X) ((X)->first == NULL)
X#define firstnode(X) ((X)->first)
X#define getaddrdata(X) (&((X)->dat))
X#define getdata(X) ((X)->dat)
X#define setdata(X,Y) ((X)->dat = (Y))
X#define lastnode(X) ((X)->last)
X#define nextnode(X) ((X)->next)
X#define prevnode(X) ((X)->last)
X#define peekfirst(X) ((X)->first->dat)
X#define pushnode(X,Y) insnode(X,(Lknode) X,Y)
X#define incnode(X) (X = nextnode(X))
X#define gethistent(X) (histentarr+((X)%histentct))
X
X/* node structure for syntax trees */
X
X/* struct list, struct sublist, struct pline, etc. all fit the form
X of this structure and are used interchangably
X*/
X
Xstruct node {
X int data[4]; /* arbitrary integer data */
X vptr ptrs[4]; /* arbitrary pointer data */
X int types[4]; /* what ptrs[] are pointing to */
X int type; /* node type */
X };
X
X#define N_LIST 0
X#define N_SUBLIST 1
X#define N_PLINE 2
X#define N_CMD 3
X#define N_REDIR 4
X#define N_COND 5
X#define N_FOR 6
X#define N_CASE 7
X#define N_IF 8
X#define N_WHILE 9
X#define N_VARASG 10
X#define N_COUNT 11
X
X/* values for types[4] */
X
X#define NT_EMPTY 0
X#define NT_NODE 1
X#define NT_STR 2
X#define NT_LIST 4
X#define NT_MALLOC 8
X
X/* tree element for lists */
X
Xstruct list {
X int type;
X int ifil[3]; /* to fit struct node */
X Sublist left;
X List right;
X };
X
X#define SYNC 0 /* ; */
X#define ASYNC 1 /* & */
X#define TIMED 2
X
X/* tree element for sublists */
X
Xstruct sublist {
X int type;
X int flags; /* see PFLAGs below */
X int ifil[2];
X Pline left;
X Sublist right;
X };
X
X#define ORNEXT 10 /* || */
X#define ANDNEXT 11 /* && */
X
X#define PFLAG_NOT 1 /* ! ... */
X#define PFLAG_COPROC 32 /* coproc ... */
X
X/* tree element for pipes */
X
Xstruct pline {
X int type;
X int ifil[3];
X Cmd left;
X Pline right;
X };
X
X#define END 0 /* pnode *right is null */
X#define PIPE 1 /* pnode *right is the rest of the pipeline */
X
X/* tree element for commands */
X
Xstruct cmd {
X int type;
X int flags; /* see CFLAGs below */
X int ifil[2];
X Lklist args; /* command & argmument List (char *'s) */
X union {
X List list; /* for SUBSH/CURSH/SHFUNC */
X struct forcmd *forcmd;
X struct casecmd *casecmd;
X struct ifcmd *ifcmd;
X struct whilecmd *whilecmd;
X Sublist pline;
X Cond cond;
X } u;
X Lklist redir; /* i/o redirections (struct redir *'s) */
X Lklist vars; /* param assignments (struct varasg *'s) */
X };
X
X#define SIMPLE 0
X#define SUBSH 1
X#define CURSH 2
X#define ZCTIME 3
X#define FUNCDEF 4
X#define CFOR 5
X#define CWHILE 6
X#define CREPEAT 7
X#define CIF 8
X#define CCASE 9
X#define CSELECT 10
X#define COND 11
X
X#define CFLAG_EXEC 1 /* exec ... */
X#define CFLAG_COMMAND 2 /* command ... */
X#define CFLAG_NOGLOB 4 /* noglob ... */
X#define CFLAG_DASH 8 /* - ... */
X
X/* tree element for redirection lists */
X
Xstruct redir {
X int type,fd1,fd2,ifil;
X char *name;
X };
X
X/* tree element for conditionals */
X
Xstruct cond {
X int type; /* can be cond_type, or a single letter (-a, -b, ...) */
X int ifil[3];
X vptr left,right,vfil[2];
X int types[4],typ; /* from struct node. DO NOT REMOVE */
X };
X
X#define COND_NOT 0
X#define COND_AND 1
X#define COND_OR 2
X#define COND_STREQ 3
X#define COND_STRNEQ 4
X#define COND_STRLT 5
X#define COND_STRGTR 6
X#define COND_NT 7
X#define COND_OT 8
X#define COND_EF 9
X#define COND_EQ 10
X#define COND_NE 11
X#define COND_LT 12
X#define COND_GT 13
X#define COND_LE 14
X#define COND_GE 15
X
Xstruct forcmd { /* for/select */
X /* Cmd->args contains list of words to loop thru */
X int inflag; /* if there is an in ... clause */
X int ifil[3];
X char *name; /* parameter to assign values to */
X List list; /* list to look through for each name */
X };
Xstruct casecmd {
X /* Cmd->args contains word to test */
X int ifil[4];
X struct casecmd *next;
X char *pat;
X List list; /* list to execute */
X };
X
X/*
X
X a command like "if foo then bar elif baz then fubar else fooble"
X generates a tree like:
X
X struct ifcmd a = { next = &b, ifl = "foo", thenl = "bar" }
X struct ifcmd b = { next = &c, ifl = "baz", thenl = "fubar" }
X struct ifcmd c = { next = NULL, ifl = NULL, thenl = "fooble" }
X
X*/
X
Xstruct ifcmd {
X int ifil[4];
X struct ifcmd *next;
X List ifl;
X List thenl;
X };
X
Xstruct whilecmd {
X int cond; /* 0 for while, 1 for until */
X int ifil[3];
X List cont; /* condition */
X List loop; /* list to execute until condition met */
X };
X
X/* structure used for multiple i/o redirection */
X/* one for each fd open */
X
Xstruct multio {
X int ct; /* # of redirections on this fd */
X int rflag; /* 0 if open for reading, 1 if open for writing */
X int pipe; /* fd of pipe if ct > 1 */
X int fds[NOFILE]; /* list of src/dests redirected to/from this fd */
X };
X
X/* node used in command path hash table (cmdnamtab) */
X
Xstruct cmdnam
X{


X struct hashnode *next; int canfree; char *nam; /* hash data */

X int type,flags;
X union {
X char *nam; /* full pathname if type != BUILTIN */
X int binnum; /* func to exec if type == BUILTIN */
X List list; /* list to exec if type == SHFUNC */
X } u;
X char **pcomp; /* location in path for EXCMD's */
X };
X
X#define EXCMD 0
X#define BUILTIN 2
X#define SHFUNC 3
X#define DISABLED 4
X#define ISEXCMD(X) ((X)==EXCMD)
X
X/* node used in parameter hash table (paramtab) */
X
Xstruct param {


X struct hashnode *next; int canfree; char *nam; /* hash data */

X union {
X char **arr; /* value if declared array */
X char *str; /* value if declared string (scalar) */
X long val; /* value if declared integer */
X } u;
X union { /* functions to call to set value */
X void (*cfn)DCLPROTO((Param,char *));
X void (*ifn)DCLPROTO((Param,long));
X void (*afn)DCLPROTO((Param,char **));
X } sets;
X union { /* functions to call to get value */
X char *(*cfn)DCLPROTO((Param));
X long (*ifn)DCLPROTO((Param));
X char **(*afn)DCLPROTO((Param));
X } gets;


X int ct; /* output base or field width */
X int flags;
X vptr data; /* used by getfns */
X char *env; /* location in environment, if exported */
X char *ename; /* name of corresponding environment var */
X };
X

X#define PMFLAG_s 0 /* scalar */
X#define PMFLAG_L 1 /* left justify and remove leading blanks */
X#define PMFLAG_R 2 /* right justify and fill with leading blanks */
X#define PMFLAG_Z 4 /* right justify and fill with leading zeros */
X#define PMFLAG_i 8 /* integer */
X#define PMFLAG_l 16 /* all lower case */
X#define PMFLAG_u 32 /* all upper case */
X#define PMFLAG_r 64 /* readonly */
X#define PMFLAG_t 128 /* tagged */
X#define PMFLAG_x 256 /* exported */
X#define PMFLAG_A 512 /* array */
X#define PMFLAG_SPECIAL 1024
X#define PMTYPE (PMFLAG_i|PMFLAG_A)
X#define pmtype(X) ((X)->flags & PMTYPE)
X
X/* variable assignment tree element */
X
Xstruct varasg {
X int type; /* nonzero means array */
X int ifil[3];
X char *name;
X char *str; /* should've been a union here. oh well */
X Lklist arr;
X };
X
X/* lvalue for variable assignment/expansion */
X
Xstruct value {
X int isarr;
X struct param *pm; /* parameter node */
X int a; /* first element of array slice, or -1 */
X int b; /* last element of array slice, or -1 */
X };
X
Xstruct fdpair {
X int fd1,fd2;
X };
X
X/* tty state structure */
X
Xstruct ttyinfo {
X#ifdef TERMIOS
X struct termios tio;
X#else
X#ifdef TERMIO
X struct termio tio;
X#else
X struct sgttyb sgttyb;
X int lmodes;
X struct tchars tchars;
X struct ltchars ltchars;
X#endif
X#endif
X#ifdef TIOCGWINSZ
X struct winsize winsize;
X#endif
X };
X
XEXTERN struct ttyinfo savedttyinfo;
X
X/* entry in job table */
X
Xstruct job {
X long gleader; /* process group leader of this job */
X int stat;
X char *pwd; /* current working dir of shell when
X this job was spawned */
X struct process *procs; /* list of processes */
X Lklist filelist; /* list of files to delete when done */
X };
X
X#define STAT_CHANGED 1 /* status changed and not reported */
X#define STAT_STOPPED 2 /* all procs stopped or exited */
X#define STAT_TIMED 4 /* job is being timed */
X#define STAT_DONE 8
X#define STAT_LOCKED 16 /* shell is finished creating this job,
X may be deleted from job table */
X#define STAT_INUSE 64 /* this job entry is in use */
X
X#define SP_RUNNING -1 /* fake statusp for running jobs */
X
X#ifndef RUSAGE_CHILDREN
X#undef HAS_RUSAGE
X#endif
X
Xstruct timeinfo {
X#ifdef HAS_RUSAGE
X struct rusage ru;
X#else
X long ut, st;
X#endif
X};
X
X/* node in job process lists */
X
X#define JOBTEXTSIZE 80
X
Xstruct process {
X struct process *next;
X long pid;
X char text[JOBTEXTSIZE]; /* text to print when 'jobs' is run */
X int statusp; /* return code from wait3() */
X struct timeinfo ti;
X time_t bgtime; /* time job was spawned */
X time_t endtime; /* time job exited */
X };
X
X/* node in alias hash table */
X
Xstruct alias {


X struct hashnode *next; int canfree; char *nam; /* hash data */

X char *text; /* expansion of alias */
X int cmd; /* one for regular aliases,
X zero for global aliases,
X negative for reserved words */
X int inuse; /* alias is being expanded */
X };
X
X/* node in sched list */
X
Xstruct schedcmd {
X struct schedcmd *next;
X char *cmd; /* command to run */
X time_t time; /* when to run it */
X };
X
X#define MAXAL 20 /* maximum number of aliases expanded at once */
X
X/* hash table node */
X
Xstruct hashnode {
X struct hashnode *next;
X int canfree; /* nam is free()able */


X char *nam;
X };
X

X/* hash table */
X
Xstruct hashtab {
X int hsize; /* size of nodes[] */
X int ct; /* # of elements */
X struct hashnode **nodes; /* array of size hsize */
X };
X
X/* history entry */
X
Xstruct histent {
X char *lex; /* lexical history line */
X char *lit; /* literal history line */
X time_t stim; /* command started time (datestamp) */
X time_t ftim; /* command finished time */
X int flags; /* Misc flags */
X };
X
X#define HIST_OLD 0x00000001 /* Command is already written to disk*/
X
X/* completion control */
X
Xstruct compctl {


X struct hashnode *next; int canfree; char *nam; /* hash data */

X int mask;
X char *keyvar;
X };
X
X#define CC_FILES 1
X#define CC_COMMPATH 2
X#define CC_HOSTS 4
X#define CC_OPTIONS 8
X#define CC_VARS 16
X#define CC_BINDINGS 32
X#define CC_USRKEYS 64
X
Xextern char *sys_errlist[];
Xextern int errno;
X
X/* values in opts[] array */
X
X#define OPT_INVALID 1 /* opt is invalid, like -$ */
X#define OPT_UNSET 0
X#define OPT_SET 2
X
X/* the options */
X
Xstruct option {
X char *name;
X char id; /* corresponding letter */
X };
X
X#define CORRECT '0'
X#define NOCLOBBER '1'
X#define NOBADPATTERN '2'
X#define NONOMATCH '3'
X#define GLOBDOTS '4'
X#define NOTIFY '5'
X#define BGNICE '6'
X#define IGNOREEOF '7'
X#define MARKDIRS '8'
X#define AUTOLIST '9'
X#define NOBEEP 'B'
X#define PRINTEXITVALUE 'C'
X#define PUSHDTOHOME 'D'
X#define PUSHDSILENT 'E'
X#define NOGLOBOPT 'F'
X#define NULLGLOB 'G'
X#define RMSTARSILENT 'H'
X#define IGNOREBRACES 'I'
X#define AUTOCD 'J'
X#define NOBANGHIST 'K'
X#define SUNKEYBOARDHACK 'L'
X#define SINGLELINEZLE 'M'
X#define AUTOPUSHD 'N'
X#define CORRECTALL 'O'
X#define RCEXPANDPARAM 'P'
X#define PATHDIRS 'Q'
X#define LONGLISTJOBS 'R'
X#define RECEXACT 'S'
X#define CDABLEVARS 'T'
X#define MAILWARNING 'U'
X#define NOPROMPTCR 'V'
X#define AUTORESUME 'W'
X#define LISTTYPES 'X'
X#define MENUCOMPLETE 'Y'
X#define USEZLE 'Z'
X#define ALLEXPORT 'a'
X#define ERREXIT 'e'
X#define NORCS 'f'
X#define HISTIGNORESPACE 'g'
X#define HISTIGNOREDUPS 'h'
X#define INTERACTIVE 'i'
X#define HISTLIT 'j'
X#define INTERACTIVECOMMENTS 'k'
X#define LOGINSHELL 'l'
X#define MONITOR 'm'
X#define NOEXEC 'n'
X#define SHINSTDIN 's'
X#define NOUNSET 'u'
X#define VERBOSE 'v'
X#define CHASELINKS 'w'
X#define XTRACE 'x'
X#define SHWORDSPLIT 'y'
X#define MENUCOMPLETEBEEP '\2'
X#define HISTNOSTORE '\3'
X#define EXTENDEDGLOB '\5'
X#define GLOBCOMPLETE '\6'
X#define CSHJUNKIEQUOTES '\7'
X#define PUSHDMINUS '\10'
X#define CSHJUNKIELOOPS '\11'
X#define RCQUOTES '\12'
X#define KSHOPTIONPRINT '\13'
X#define NOSHORTLOOPS '\14'
X#define LASTMENU '\15'
X#define AUTOMENU '\16'
X#define HISTVERIFY '\17'
X#define NOLISTBEEP '\20'
X#define NOHUP '\21'
X#define NOEQUALS '\22'
X#define CSHNULLGLOB '\23'
X#define HASHCMDS '\24'
X#define HASHDIRS '\25'
X#define NUMERICGLOBSORT '\26'
X#define BRACECCL '\27'
X#define HASHLISTALL '\30'
X#define OVERSTRIKE '\31'
X#define NOHISTBEEP '\32'
X#define PUSHDIGNOREDUPS '\33'
X#define AUTOREMOVESLASH '\34'
X#define EXTENDEDHISTORY '\35'
X#define APPENDHISTORY '\36'
X
X#ifndef GLOBALS
Xextern struct option optns[];
X#else
Xstruct option optns[] = {
X {"correct",CORRECT},
X {"noclobber",NOCLOBBER},
X {"nobadpattern",NOBADPATTERN},
X {"nonomatch",NONOMATCH},
X {"globdots",GLOBDOTS},
X {"notify",NOTIFY},
X {"bgnice",BGNICE},
X {"ignoreeof",IGNOREEOF},
X {"markdirs",MARKDIRS},
X {"autolist",AUTOLIST},
X {"nobeep",NOBEEP},
X {"printexitvalue",PRINTEXITVALUE},
X {"pushdtohome",PUSHDTOHOME},
X {"pushdsilent",PUSHDSILENT},
X {"noglob",NOGLOBOPT},
X {"nullglob",NULLGLOB},
X {"rmstarsilent",RMSTARSILENT},
X {"ignorebraces",IGNOREBRACES},
X {"braceccl",BRACECCL},
X {"autocd",AUTOCD},
X {"nobanghist",NOBANGHIST},
X {"sunkeyboardhack",SUNKEYBOARDHACK},
X {"singlelinezle",SINGLELINEZLE},
X {"autopushd",AUTOPUSHD},
X {"correctall",CORRECTALL},
X {"rcexpandparam",RCEXPANDPARAM},
X {"pathdirs",PATHDIRS},
X {"longlistjobs",LONGLISTJOBS},
X {"recexact",RECEXACT},
X {"cdablevars",CDABLEVARS},
X {"mailwarning",MAILWARNING},
X {"nopromptcr",NOPROMPTCR},
X {"autoresume",AUTORESUME},
X {"listtypes",LISTTYPES},
X {"menucomplete",MENUCOMPLETE},
X {"zle",USEZLE},
X {"allexport",ALLEXPORT},
X {"errexit",ERREXIT},
X {"norcs",NORCS},
X {"histignorespace",HISTIGNORESPACE},
X {"histignoredups",HISTIGNOREDUPS},
X {"interactive",INTERACTIVE},
X {"histlit",HISTLIT},
X {"interactivecomments",INTERACTIVECOMMENTS},
X {"login",LOGINSHELL},
X {"monitor",MONITOR},
X {"noexec",NOEXEC},
X {"shinstdin",SHINSTDIN},
X {"nounset",NOUNSET},
X {"verbose",VERBOSE},
X {"chaselinks",CHASELINKS},
X {"xtrace",XTRACE},
X {"shwordsplit",SHWORDSPLIT},
X {"menucompletebeep",MENUCOMPLETEBEEP},
X {"histnostore",HISTNOSTORE},
X {"extendedglob",EXTENDEDGLOB},
X {"globcomplete",GLOBCOMPLETE},
X {"cshjunkiequotes",CSHJUNKIEQUOTES},
X {"pushdminus",PUSHDMINUS},
X {"cshjunkieloops",CSHJUNKIELOOPS},
X {"rcquotes",RCQUOTES},
X {"noshortloops",NOSHORTLOOPS},
X {"lastmenu",LASTMENU},
X {"automenu",AUTOMENU},
X {"histverify",HISTVERIFY},
X {"nolistbeep",NOLISTBEEP},
X {"nohup",NOHUP},
X {"noequals",NOEQUALS},
X {"kshoptionprint",KSHOPTIONPRINT},
X {"cshnullglob",CSHNULLGLOB},
X {"hashcmds",HASHCMDS},
X {"hashdirs",HASHDIRS},
X {"numericglobsort",NUMERICGLOBSORT},
X {"hashlistall",HASHLISTALL},
X {"overstrike",OVERSTRIKE},
X {"nohistbeep",NOHISTBEEP},
X {"pushdignoredups",PUSHDIGNOREDUPS},
X {"autoremoveslash",AUTOREMOVESLASH},
X {"extendedhistory",EXTENDEDHISTORY},
X {"appendhistory",APPENDHISTORY},
X {NULL,0}
X};
X#endif
X
X#define ALSTAT_MORE 1 /* last alias ended with ' ' */
X#define ALSTAT_JUNK 2 /* don't put word in history List */
X
X#undef isset
X#define isset(X) (opts[(int)X] == OPT_SET)
X#define unset(X) (opts[(int)X] == OPT_UNSET)
X#define interact (isset(INTERACTIVE))
X#define jobbing (isset(MONITOR))
X#define jobbingv opts[MONITOR]
X#define nointr() signal(SIGINT,SIG_IGN)
X#define islogin (isset(LOGINSHELL))
X
X#ifndef SYSVR4
X#ifndef _IBMR2
X#undef WIFSTOPPED
X#undef WIFSIGNALED
X#undef WIFEXITED
X#undef WEXITSTATUS
X#undef WTERMSIG
X#undef WSTOPSIG
X#undef WCOREDUMP
X
X#define WIFSTOPPED(X) (((X)&0377)==0177)
X#define WIFSIGNALED(X) (((X)&0377)!=0&&((X)&0377)!=0177)
X#define WIFEXITED(X) (((X)&0377)==0)
X#define WEXITSTATUS(X) (((X)>>8)&0377)
X#define WTERMSIG(X) ((X)&0177)
X#define WSTOPSIG(X) (((X)>>8)&0377)
X#endif
X#define WCOREDUMP(X) ((X)&0200)
X#endif
X
X#ifndef S_ISBLK
X#define _IFMT 0170000
X#define _IFDIR 0040000
X#define _IFCHR 0020000
X#define _IFBLK 0060000
X#define _IFREG 0100000
X#define _IFIFO 0010000
X#define S_ISBLK(m) (((m)&_IFMT) == _IFBLK)
X#define S_ISCHR(m) (((m)&_IFMT) == _IFCHR)
X#define S_ISDIR(m) (((m)&_IFMT) == _IFDIR)
X#define S_ISFIFO(m) (((m)&_IFMT) == _IFIFO)
X#define S_ISREG(m) (((m)&_IFMT) == _IFREG)
X#endif
X
X#ifndef _IFMT
X#define _IFMT 0170000
X#endif
X
X#ifndef S_ISSOCK
X#define _IFSOCK 0140000
X#define S_ISSOCK(m) (((m)&_IFMT) == _IFSOCK)
X#endif
X
X#ifndef S_ISLNK
X#define _IFLNK 0120000
X#define S_ISLNK(m) (((m)&_IFMT) == _IFLNK)
X#endif
X
X#if S_IFIFO == S_IFSOCK
X#undef S_IFIFO
X#endif
X
X#ifndef S_IFIFO
X#define NO_FIFOS
X#endif
X
X/* buffered shell input for non-interactive shells */
X
XEXTERN FILE *bshin;
X
X/* NULL-terminated arrays containing path, cdpath, etc. */
X
XEXTERN char **path,**cdpath,**fpath,**watch,**mailpath;
XEXTERN char **manpath,**tildedirs,**fignore;
XEXTERN char **hosts,**psvar;
X
X/* named directories */
X
XEXTERN char **userdirs,**usernames;
X
X/* size of userdirs[], # of userdirs */
X
XEXTERN int userdirsz,userdirct;
X
XEXTERN char *mailfile;
X
XEXTERN char *yytext;
X
X/* error/break flag */
X
XEXTERN int errflag;
X
XEXTERN char *tokstr;
XEXTERN int tok, tokfd;
X
X/* lexical analyzer error flag */
X
XEXTERN int lexstop;
X
X/* suppress error messages */
X
XEXTERN int noerrs;
X
X/* current history event number */
X
XEXTERN int curhist;
X
X/* if != 0, this is the first line of the command */
X
XEXTERN int isfirstln;
X
X/* if != 0, this is the first char of the command (not including
X white space */
X
XEXTERN int isfirstch;
X
X/* number of history entries */
X
XEXTERN int histentct;
X
X/* array of history entries */
X
XEXTERN Histent histentarr;
X
X/* capacity of history lists */
X
XEXTERN int histsiz,lithistsiz;
X
X/* if = 1, we have performed history substitution on the current line
X if = 2, we have used the 'p' modifier */
X
XEXTERN int histdone;
X
X/* default event (usually curhist-1, that is, "!!") */
X
XEXTERN int defev;
X
X/* != 0 if we are about to read a command word */
X
XEXTERN int incmdpos;
X
X/* != 0 if we are in the middle of a [[ ... ]] */
X
XEXTERN int incond;
X
X/* != 0 if we are after a redirection (for ctxtlex only) */
X
XEXTERN int inredir;
X
X/* != 0 if we are about to read a case pattern */
X
XEXTERN int incasepat;
X
X/* != 0 if we just read FUNCTION */
X
XEXTERN int infunc;
X
X/* != 0 if we just read a newline */
X
XEXTERN int isnewlin;
X
X/* the lists of history events */
X
XEXTERN Lklist histlist,lithistlist;
X
X/* the directory stack */
X
XEXTERN Lklist dirstack;
X
X/* the zle buffer stack */
X
XEXTERN Lklist bufstack;
X
X/* the input queue (stack?)
X
X inbuf = start of buffer
X inbufptr = location in buffer (= inbuf for a FULL buffer)
X (= inbuf+inbufsz for an EMPTY buffer)
X inbufct = # of chars in buffer (inbufptr+inbufct == inbuf+inbufsz)
X inbufsz = max size of buffer
X*/
X
XEXTERN char *inbuf,*inbufptr;
XEXTERN int inbufct,inbufsz;
X
XEXTERN char *ifs; /* $IFS */
X
XEXTERN char *oldpwd; /* $OLDPWD */
X
XEXTERN char *underscore; /* $_ */
X
X/* != 0 if this is a subshell */
X
XEXTERN int subsh;
X
X/* # of break levels */
X
XEXTERN int breaks;
X
X/* != 0 if we have a return pending */
X
XEXTERN int retflag;
X
X/* how far we've hashed the PATH so far */
X
XEXTERN char **pathchecked;
X
X/* # of nested loops we are in */
X
XEXTERN int loops;
X
X/* # of continue levels */
X
XEXTERN int contflag;
X
X/* the job we are working on */
X
XEXTERN int thisjob;
X
X/* the current job (+) */
X
XEXTERN int curjob;
X
X/* the previous job (-) */
X
XEXTERN int prevjob;
X
X/* hash table containing the aliases and reserved words */
X
XEXTERN Hashtab aliastab;
X
X/* hash table containing the parameters */
X
XEXTERN Hashtab paramtab;
X
X/* hash table containing the builtins/shfuncs/hashed commands */
X
XEXTERN Hashtab cmdnamtab;
X
X/* hash table containing the zle multi-character bindings */
X
XEXTERN Hashtab xbindtab;
X
X/* hash table for completion info for commands */
X
XEXTERN Hashtab compctltab;
X
X/* default completion infos */
X
XEXTERN struct compctl cc_compos, cc_default;
X
X/* the job table */
X
XEXTERN struct job jobtab[MAXJOB];
X
X/* shell timings */
X
X#ifndef HAS_RUSAGE
XEXTERN struct tms shtms;
X#endif
X
X/* the list of sched jobs pending */
X
XEXTERN struct schedcmd *schedcmds;
X
X/* the last l for s/l/r/ history substitution */
X
XEXTERN char *hsubl;
X
X/* the last r for s/l/r/ history substitution */
X
XEXTERN char *hsubr;
X
XEXTERN char *username; /* $USERNAME */
XEXTERN char *logname; /* $LOGNAME */
XEXTERN long lastval; /* $? */
XEXTERN long baud; /* $BAUD */
XEXTERN long columns; /* $COLUMNS */
XEXTERN long lines; /* $LINES */
XEXTERN long reporttime; /* $REPORTTIME */
X
X/* input fd from the coprocess */
X
XEXTERN int coprocin;
X
X/* output fd from the coprocess */
X
XEXTERN int coprocout;
X
XEXTERN long mailcheck; /* $MAILCHECK */
XEXTERN long logcheck; /* $LOGCHECK */
X
X/* the last time we checked mail */
X
XEXTERN time_t lastmailcheck;
X
X/* the last time we checked the people in the WATCH variable */
X
XEXTERN time_t lastwatch;
X
X/* the last time we did the periodic() shell function */
X
XEXTERN time_t lastperiod;
X
X/* $SECONDS = time(NULL) - shtimer */
X
XEXTERN time_t shtimer;
X
XEXTERN long mypid; /* $$ */
XEXTERN long lastpid; /* $! */
XEXTERN long ppid; /* $PPID */
X
X/* the process group of the shell */
X
XEXTERN long mypgrp;
X
XEXTERN char *pwd; /* $PWD */
XEXTERN char *optarg; /* $OPTARG */
XEXTERN long zoptind; /* $OPTIND */
XEXTERN char *prompt; /* $PROMPT */
XEXTERN char *rprompt; /* $RPROMPT */
XEXTERN char *prompt2; /* etc. */
XEXTERN char *prompt3;
XEXTERN char *prompt4;
XEXTERN char *sprompt;
XEXTERN char *timefmt;
XEXTERN char *watchfmt;
XEXTERN char *wordchars;
XEXTERN char *fceditparam;
XEXTERN char *tmpprefix;
XEXTERN char *rstring, *Rstring;
XEXTERN char *postedit;
X
XEXTERN char *argzero; /* $0 */
X
XEXTERN char *hackzero;
X
X/* the hostname */
X
XEXTERN char *hostnam;
X
XEXTERN char *home; /* $HOME */
XEXTERN char **pparams; /* $argv */
X
X/* the default command for null commands */
X
XEXTERN char *nullcmd;
XEXTERN char *readnullcmd;
X
X/* the List of local variables we have to destroy */
X
XEXTERN Lklist locallist;
X
X/* the shell input fd */
X
XEXTERN int SHIN;
X
X/* the shell tty fd */
X
XEXTERN int SHTTY;
X
X/* the stack of aliases we are expanding */
X
XEXTERN struct alias *alstack[MAXAL];
X
X/* the alias stack pointer; also, the number of aliases currently
X being expanded */
X
XEXTERN int alstackind;
X
X/* != 0 means we are reading input from a string */
X
XEXTERN int strin;
X
X/* period between periodic() commands, in seconds */
X
XEXTERN long period;
X
X/* != 0 means history substitution is turned off */
X
XEXTERN int stophist;
X
XEXTERN int lithist;
X
X/* this line began with a space, so junk it if HISTIGNORESPACE is on */
X
XEXTERN int spaceflag;
X
X/* don't do spelling correction */
X
XEXTERN int nocorrect;
X
X/* != 0 means we have removed the current event from the history List */
X
XEXTERN int histremmed;
X
X/* the options; e.g. if opts['a'] == OPT_SET, -a is turned on */
X
XEXTERN int opts[128];
X
XEXTERN long lineno; /* LINENO */
XEXTERN long listmax; /* LISTMAX */
XEXTERN long savehist; /* SAVEHIST */
XEXTERN long shlvl; /* SHLVL */
XEXTERN long tmout; /* TMOUT */
XEXTERN long dirstacksize; /* DIRSTACKSIZE */
X
X/* != 0 means we have called execlist() and then intend to exit(),
X so don't fork if not necessary */
X
XEXTERN int exiting;
X
XEXTERN int lastbase; /* last input base we used */
X
X/* the limits for child processes */
X
X#ifdef RLIM_INFINITY
XEXTERN struct rlimit limits[RLIM_NLIMITS];
X#endif
X
X/* the current word in the history List */
X
XEXTERN char *hlastw;
X
X/* pointer into the history line */
X
XEXTERN char *hptr;
X
X/* the current history line */
X
XEXTERN char *chline;
X
X/* the termcap buffer */
X
XEXTERN char termbuf[1024];
X
X/* $TERM */
X
XEXTERN char *term;
X
X/* != 0 if this $TERM setup is usable */
X
XEXTERN int termok;
X
X/* flag for CSHNULLGLOB */
X
XEXTERN int badcshglob;
X
X/* max size of histline */
X
XEXTERN int hlinesz;
X
X/* the alias expansion status - if == ALSTAT_MORE, we just finished
X expanding an alias ending with a space */
X
XEXTERN int alstat;
X
X/* we have printed a 'you have stopped (running) jobs.' message */
X
XEXTERN int stopmsg;
X
X/* the default tty state */
X
XEXTERN struct ttyinfo shttyinfo;
X
X/* $TTY */
X
XEXTERN char *ttystrname;
X
X/* 1 if ttyctl -f has been executed */
X
XEXTERN int ttyfrozen;
X
X/* list of memory heaps */
X
XEXTERN Lklist heaplist;
X
X/* != 0 if we are allocating in the heaplist */
X
XEXTERN int useheap;
X
X/* pid of process undergoing 'process substitution' */
X
XEXTERN int cmdoutpid;
X
X/* exit status of process undergoing 'process substitution' */
X
XEXTERN int cmdoutval;
X
X#include "signals.h"
X
X#ifdef GLOBALS
X
X/* signal names */
Xchar **sigptr = sigs;
X
X/* tokens */
Xchar *ztokens = "#$^*()$=|{}[]`<>?~`,'\"\\";
X
X#else
Xextern char *ztokens,**sigptr;
X#endif
X
X#define SIGERR (SIGCOUNT+1)
X#define SIGDEBUG (SIGCOUNT+2)
X#define VSIGCOUNT (SIGCOUNT+3)
X#define SIGEXIT 0
X
X/* signals that are trapped = 1, signals ignored =2 */
X
XEXTERN int sigtrapped[VSIGCOUNT];
X
X/* trap functions for each signal */
X
XEXTERN List sigfuncs[VSIGCOUNT];
X
X/* $HISTCHARS */
X
XEXTERN unsigned char bangchar,hatchar,hashchar;
X
XEXTERN int eofseen;
X
X/* we are parsing a line sent to use by the editor */
X
XEXTERN int zleparse;
X
XEXTERN int wordbeg;
X
XEXTERN int parbegin;
X
X/* interesting termcap strings */
X
X#define TCCLEARSCREEN 0
X#define TCLEFT 1
X#define TCMULTLEFT 2
X#define TCRIGHT 3
X#define TCMULTRIGHT 4
X#define TCUP 5
X#define TCMULTUP 6
X#define TCDOWN 7
X#define TCMULTDOWN 8
X#define TCDEL 9
X#define TCMULTDEL 10
X#define TCINS 11
X#define TCMULTINS 12
X#define TCCLEAREOD 13
X#define TCCLEAREOL 14
X#define TCINSLINE 15
X#define TCDELLINE 16
X#define TC_COUNT 17
X
X/* lengths of each string */
X
XEXTERN int tclen[TC_COUNT];
X
XEXTERN char *tcstr[TC_COUNT];
X
X#ifdef GLOBALS
X
X/* names of the strings we want */
X
Xchar *tccapnams[TC_COUNT] = {
X "cl","le","LE","nd","RI","up","UP","do",
X "DO","dc","DC","ic","IC","cd","ce","al","dl"
X };
X
X#else
Xextern char *tccapnams[TC_COUNT];
X#endif
X
X#define tccan(X) (!!tclen[X])
X
X#define HISTFLAG_DONE 1
X#define HISTFLAG_NOEXEC 2
X#define HISTFLAG_RECALL 4
X
X#include "ztype.h"
X#include "funcs.h"
X
X#ifdef HAS_SETPGID
X#define setpgrp setpgid
X#endif
X
X#define _INCLUDE_POSIX_SOURCE
X#define _INCLUDE_XOPEN_SOURCE
X#define _INCLUDE_HPUX_SOURCE
X
X#ifdef SV_BSDSIG
X#define SV_INTERRUPT SV_BSDSIG
X#endif
X
X#ifdef HAS_SIGRELSE
X#define blockchld() sighold(SIGCHLD)
X#define unblockchld() sigrelse(SIGCHLD)
X#define chldsuspend() sigpause(SIGCHLD)
X#else
X#define blockchld() sigblock(sigmask(SIGCHLD))
X#define unblockchld() sigsetmask(0)
X#define chldsuspend() sigpause(0)
X#endif
END_OF_FILE
if test 34760 -ne `wc -c <'src/zsh.h'`; then
echo shar: \"'src/zsh.h'\" unpacked with wrong size!
fi
# end of 'src/zsh.h'
fi
echo shar: End of archive 11 \(of 22\).
cp /dev/null ark11isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:24:58 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 62
Archive-name: zsh/part12

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: help/zle src/utils.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:53 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 12 (of 22)."'
if test -f 'help/zle' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/zle'\"
else
echo shar: Extracting \"'help/zle'\" \(19344 characters\)
sed "s/^X//" >'help/zle' <<'END_OF_FILE'
X bindkey -mevd
X bindkey -r in-string ...
X bindkey [ -a ] in-string [ command ] ...
X bindkey -s [ -a ] in-string out-string ...
X If one of the -e, -v, or -d options is given, reset the
X keymaps for emacs mode, vi mode, or the default mode,
X respectively; if the -m option is also given, allow the
X use of a meta key. If the -r option is given, remove
X any binding for each in-string. If the -s option is
X not specified, bind each in-string to a specified com-
X mand. If no command is specified, print the binding of
X in-string if it is bound, or return a nonzero exit code
X if it is not bound. If the -s option is specified,
X bind each in-string to each specified out-string. When
X in-string is typed, out-string will be pushed back and
X treated as input to the line editor. If the -a option
X is specified, bind the in-strings in the alternative
X keymap instead of the standard one. The alternative
X keymap is used in vi command mode.
X
X For either in-string or out-string, control characters
X may be specified in the form ^X, and the backslash may
X be used to introduce one of the following escape
X sequences:
X \a bell character
X \n linefeed (newline)
X \b backspace
X \t horizontal tab
X \v vertical tab
X \f form feed
X \r carriage return
X \e escape
X \nnn character code in octal
X \M-xxx
X character or escape sequence with meta bit
X set
X
X In all other cases, \ escapes the following character.
X Delete is written as `^?'.
X
X vi-backward-blank-word (unbound) (B)
X Move backward one word, where a word is defined as a
X series of non-blank characters.
X
X backward-char (^B ESC-[D) ()


X Move backward one character.
X

X vi-backward-char () (h)
X Move backward one character, without changing lines.
X
X backward-word (ESC-B ESC-b) (unbound)
X Move to the beginning of the previous word.
X
X emacs-backward-word
X Move to the beginning of the previous word.
X
X vi-backward-word (unbound) (b)
X Move to the beginning of the previous word, vi-style.
X
X beginning-of-line (^A) (0)
X Move to the beginning of the line. If already at the
X beginning of the line, move to the beginning of the
X previous line, if any.
X
X vi-beginning-of-line
X Move to the beginning of the line, without changing
X lines.
X
X end-of-line (^E)
X Move to the end of the line. If already at the end of
X the line, move to the end of the next line, if any.
X
X vi-end-of-line (unbound) ($)
X Move to the end of the line.
X
X vi-forward-blank-word (unbound) (W)
X Move forward one word, where a word is defined as a
X series of non-blank characters.
X
X vi-forward-blank-word-end (unbound) (E)
X Move to the end of the current word, or, if at the end
X of the current word, to the end of the next word, where
X a word is defined as a series of non-blank characters.
X
X forward-char (^F ESC-[C)


X Move forward one character.
X

X vi-forward-char (unbound) (space l)
X Move forward one character.
X
X vi-find-next-char (^X^F) (f)
X Read a character from the keyboard, and move to the
X next occurrence of it in the line.
X
X vi-find-next-char-skip (unbound) (t)
X Read a character from the keyboard, and move to the
X position just before the next occurrence of it in the
X line.
X
X vi-find-prev-char (unbound) (F)
X Read a character from the keyboard, and move to the
X previous occurrence of it in the line.
X
X vi-find-prev-char-skip (unbound) (T)
X Read a character from the keyboard, and move to the
X position just after the previous occurrence of it in
X the line.
X
X vi-first-non-blank (unbound) (^)
X Move to the first non-blank character in the line.
X
X vi-forward-word (unbound) (w)
X Move forward one word, vi-style.
X
X forward-word (ESC-F ESC-f) (unbound)
X Move to the beginning of the next word. The editor's
X idea of a word is specified with the WORDCHARS parame-
X ter.
X
X emacs-forward-word
X Move to the end of the next word.
X
X vi-forward-word-end (unbound) (e)
X Move to the end of the next word.
X
X vi-goto-column (ESC-|) (|)
X Move to the column specified by the numeric argument.
X
X vi-goto-mark (unbound) (`)
X Move to the specified mark.
X
X vi-goto-mark-line (unbound) (')
X Move to beginning of the line containing the specified
X mark.
X
X vi-repeat-find (unbound) (;)
X Repeat the last vi-find command.
X
X vi-rev-repeat-find (unbound) (,)
X Repeat the last vi-find command in the opposite direc-
X tion.
X
X beginning-of-buffer-or-history (ESC-<)
X Move to the beginning of the buffer, or if already
X there, move to the first event in the history list.
X
X beginning-of-line-hist
X Move to the beginning of the line. If already at the
X beginning of the buffer, move to the previous history
X line.
X
X beginning-of-history
X Move to the first event in the history list.
X
X down-line-or-history (^N ESC-[B) (+ j)
X Move down a line in the buffer, or if already at the
X bottom line, move to the next event in the history
X list.
X
X down-history (unbound) (^N)
X Move to the next event in the history list.
X
X end-of-buffer-or-history (ESC->)
X Move to the end of the buffer, or if already there,
X move to the last event in the history list.
X
X end-of-line-hist
X Move to the end of the line. If already at the end of
X the buffer, move to the next history line.
X
X end-of-history
X Move to the last event in the history list.
X
X vi-fetch-history (unbound) (G)
X Fetch the history line specified by the numeric argu-
X ment.
X
X history-incremental-search-backward (^R ^Xr)
X Search backward incrementally for a specified string.
X The string may begin with `^' to anchor the search to
X the beginning of the line.
X
X history-incremental-search-forward (^Xs)
X Search forward incrementally for a specified string.
X The string may begin with `^' to anchor the search to
X the beginning of the line.
X
X history-search-backward (ESC-P ESC-p) (K)
X Search backward in the history for a line beginning
X with the first word in the buffer.
X
X vi-history-search-backward (unbound) (/)
X Search backward in the history for a specified string.
X The string may begin with `^' to anchor the search to
X the beginning of the line.
X
X history-search-forward (ESC-N ESC-n) (J)
X Search forward in the history for a line beginning with
X the first word in the buffer.
X
X vi-history-search-forward (unbound) (?)
X Search forward in the history for a specified string.
X The string may begin with `^' to anchor the search to
X the beginning of the line.
X
X infer-next-history (^X^N)
X Search in the history list for a line matching the
X current one and fetch the event following it.
X
X insert-last-word (ESC-_ ESC-.)
X Insert the last word from the previous history event at
X the cursor position.
X
X vi-repeat-search (unbound) (n)
X Repeat the last vi history search.
X
X vi-rev-repeat-search (unbound) (N)
X Repeat the last vi history search, but in reverse.
X
X toggle-literal-history (ESC-R ESC-r)
X Toggle between literal and lexical history. The
X default is lexical history unless the HISTLIT option is
X set.
X
X up-line-or-history (^P ESC-[A) (- k)
X Move up a line in the buffer, or if already at the top
X line, move to the previous event in the history list.
X
X up-history (unbound) (^P)
X Move to the previous event in the history list.
X
X vi-add-eol (unbound) (A)
X Move to the end of the line and enter insert mode.
X
X vi-add-next (unbound) (a)
X Move forward one character and enter insert mode.
X
X backward-delete-char (^H ^?) (^?)
X Delete the character behind the cursor.
X
X vi-backward-delete-char (unbound) (X)
X Delete the character behind the cursor, without chang-
X ing lines.
X
X backward-delete-word
X Delete the word behind the cursor.
X
X backward-kill-line
X Kill from the beginning of the line to the cursor posi-
X tion.
X
X backward-kill-word (^W ESC-^H ESC-^?)
X Kill the word behind the cursor.
X
X vi-backward-kill-word (unbound) (^W)
X Kill the word behind the cursor.
X
X capitalize-word (ESC-C ESC-c)
X Capitalize the current word and move past it.
X
X vi-change (unbound) (c)
X Read a movement command from the keyboard, and kill
X from the cursor position to the endpoint of the move-
X ment. Then enter insert mode. If the command is vi-
X change, kill the current line.
X
X vi-change-eol (unbound) (C)
X Kill to the end of the line and enter insert mode.
X
X vi-change-whole-line (unbound) (S s)
X Kill the current line and enter insert mode.
X
X copy-region-as-kill (ESC-W ESC-w)
X Copy the area from the cursor to the mark to the kill
X buffer.
X
X copy-prev-word (ESC-^_)
X Duplicate the word behind the cursor.
X
X vi-delete (unbound) (d)
X Read a movement command from the keyboard, and kill
X from the cursor position to the endpoint of the move-
X ment. If the command is vi-delete, kill the current
X line.
X
X delete-char (unbound) (x)
X Delete the character under the cursor.
X
X vi-delete-char (unbound) (x)
X Delete the character under the cursor.
X
X delete-word (ESC-D ESC-d)


X Delete the current word.
X

X down-case-word (ESC-L ESC-l)
X Convert the current word to all lowercase and move past
X it.
X
X kill-word
X Kill the current word.
X
X gosmacs-transpose-chars
X Exchange the two characters behind the cursor.
X
X vi-indent (unbound) (>)
X Indent a number of lines.
X
X vi-insert (unbound) (i)
X Enter insert mode.
X
X vi-insert-bol (unbound) (I)
X Move to the beginning of the line and enter insert
X mode.
X
X vi-join (^X^J)
X Join the current line with the next one.
X
X kill-line (^K) (D)
X Kill from the cursor to the end of the line.
X
X kill-region
X Kill from the cursor to the mark.
X
X kill-buffer (^X^U) (^U)
X Kill the entire buffer.
X
X kill-whole-line (^U) (unbound)
X Kill the current line.
X
X vi-match-bracket (^X^B) (%)
X Move to the bracket character (one of {}, (), or [])
X that matches the one under the cursor.
X
X vi-open-line-above (unbound) (O)
X Open a line above the cursor and enter insert mode.
X
X vi-open-line-below (unbound) (o)
X Open a line below the cursor and enter insert mode.
X
X vi-oper-swap-case
X Read a movement command from the keyboard, and swap the
X case of all characters from the cursor position to the
X endpoint of the movement. If the movement command is
X vi-oper-swap-case, swap the case of all characters on
X the current line.
X
X overwrite-mode (^X^O)
X Toggle between overwrite mode and insert mode.
X
X vi-put-after (unbound) (p)
X Insert the contents of the kill buffer after the cur-
X sor.
X
X quoted-insert (^V)
X Insert the next character typed into the buffer
X literally.
X
X quote-line (ESC-')
X Quote the current line; that is, put a ' character at
X the beginning and the end, and convert all ' characters
X to '\''.
X
X quote-region (ESC-")
X Quote the region from the cursor to the mark.
X
X vi-replace (unbound) (R)
X Enter overwrite mode.
X
X vi-repeat-change (unbound) (.)
X Repeat the last vi mode text modification.
X
X vi-replace-chars (unbound) (r)
X Replace the character under the cursor with a character


X read from the keyboard.
X

X self-insert (printable characters)
X Put a character in the buffer at the cursor position.
X
X self-insert-unmeta (ESC-^I ESC-^J ESC-^M)
X Put a character in the buffer after stripping the meta
X bit and converting ^M to ^J.
X
X vi-substitute (unbound) (s)
X Substitute the next character(s).
X
X vi-swap-case (unbound) (~)
X Swap the case of the character under the cursor and
X move past it.
X
X transpose-chars (^T)
X Exchange the two characters to the left of the cursor
X if at end of line, else exchange the character under
X the cursor with the character to the left.
X
X transpose-words (ESC-T ESC-t)
X Exchange the current word with the one before it.
X
X vi-unindent (unbound) (<)
X Unindent a number of lines.
X
X up-case-word (ESC-U ESC-u)
X Convert the current word to all caps and move past it.
X
X yank (^Y) (P)
X Insert the contents of the kill buffer at the cursor
X position.
X
X yank-pop (ESC-y) (unbound)
X Remove the text just yanked, rotate the kill-ring, and
X yank the new top. Only works following yank or yank-
X pop.
X
X vi-yank (unbound) (y)
X Read a movement command from the keyboard, and copy the
X region from the cursor position to the endpoint of the
X movement into the kill buffer. If the command is vi-
X yank, copy the current line.
X
X vi-yank-eol (unbound) (Y)
X Copy the region from the cursor position to the end of
X the line into the kill buffer.
X
X digit-argument (ESC-0..ESC-9) (0-9)
X Start a new numeric argument, or add to the current
X one.
X
X universal-argument
X Multiply the argument of the next command by 4.
X
X accept-and-menu-complete
X In a menu completion, insert the current completion
X into the buffer, and advance to the next possible com-
X pletion.
X
X complete-word (unbound) (\)
X Attempt completion on the current word.
X
X delete-char-or-list (^D)
X Delete the character under the cursor. If the cursor
X is at the end of the line, list possible completions
X for the current word.
X
X execute-named-cmd (ESC-x)
X Read the name of a editor command and execute it.
X
X execute-last-named-cmd (ESC-z)
X Redo the last function executed with execute-named-cmd.
X
X expand-cmd-path
X Expand the current command to its full pathname.
X
X expand-or-complete (TAB) (TAB ^X)
X Attempt shell expansion on the current word. If that
X fails, attempt completion.
X
X expand-history (ESC-space ESC-!)
X Perform history expansion on the edit buffer.
X
X expand-word (^X*)
X Attempt shell expansion on the current word.
X
X list-choices (ESC-^D) (^D =)
X List possible completions for the current word.
X
X list-expand (^Xg ^XG) (^G)
X List the expansion of the current word.
X
X magic-space
X Perform history expansion and insert a space into the
X buffer. This is intended to be bound to space.
X
X menu-complete
X Like complete-word, except that menu completion is
X used. See the MENU_COMPLETE option below.
X
X menu-expand-or-complete
X Like expand-or-complete, except that menu completion is
X used.
X
X reverse-menu-complete
X See the MENU_COMPLETE option below.
X
X accept-and-hold (ESC-A ESC-a)
X Push the contents of the buffer on the buffer stack and
X execute it.
X
X accept-and-infer-next-history
X Execute the contents of the buffer. Then search the
X history list for a line matching the current one and
X push the event following onto the buffer stack.
X
X accept-line (^J ^M)
X Execute the contents of the buffer.
X
X accept-line-and-down-history (^O)
X Execute the current line, and push the next history
X event on the the buffer stack.
X
X vi-cmd-mode (^X^V) (^[)
X Enter command mode; that is, use the alternate keymap.
X Yes, this is bound by default in emacs mode.
X
X vi-caps-lock-panic (unbound) (H K)
X Hang until any lowercase key is pressed. This is for
X vi users without the mental capacity to keep track of
X their caps lock key (like the author).
X
X clear-screen (^L ESC-^L)
X Clear the screen and redraw the prompt.
X
X exchange-point-and-mark (^X^X)
X Exchange the cursor position with the position of the
X mark.
X
X get-line (ESC-G ESC-g)
X Pop the top line off the buffer stack and insert it at
X the cursor position.
X
X pound-insert (unbound) (#)
X If there is no # character at the beginning of the
X current line, add one. If there is one, remove it. In
X either case, accept the current line. The
X INTERACTIVE_COMMENTS option must be set for this to
X have any usefulness.
X
X push-line (^Q ESC-Q ESC-q)
X Push the current buffer onto the buffer stack and clear
X the buffer. Next time the editor starts up, the buffer
X will be popped off the top of the buffer stack and
X loaded into the editing buffer.
X
X redisplay (unbound) (^R)
X Redisplays the edit buffer.
X
X run-help (ESC-H ESC-h)
X Push the buffer onto the buffer stack, and execute the
X command "run-help cmd", where cmd is the current com-
X mand. run-help is normally aliased to man.
X
X send-break (^C)
X Abort the parsing of the current line.
X
X vi-set-buffer (unbound) (")
X Specify a buffer to be used in the following command.
X
X vi-set-mark (unbound) (m)
X Set the specified mark at the cursor position.
X
X set-mark-command (^@)
X Set the mark at the cursor position.
X
X spell-word (ESC-$ ESC-S ESC-s)
X Attempt spelling correction on the current word.
X
X undefined-key
X Beep.
X
X undo (^_ ^X^U) (u)
X Incrementally undo the last text modification.
X
X which-command (ESC-?)
X Push the buffer onto the buffer stack, and execute the
X command "which-command cmd", where cmd is the current
X command. which-command is normally aliased to whence.
END_OF_FILE
if test 19344 -ne `wc -c <'help/zle'`; then
echo shar: \"'help/zle'\" unpacked with wrong size!
fi
# end of 'help/zle'
fi
if test -f 'src/utils.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/utils.c'\"
else
echo shar: Extracting \"'src/utils.c'\" \(32015 characters\)
sed "s/^X//" >'src/utils.c' <<'END_OF_FILE'
X/*
X *
X * utils.c - miscellaneous utilities


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 <pwd.h>
X#include <errno.h>
X#include <fcntl.h>
X
X/* source a file */
X
Xint source(s) /**/
Xchar *s;
X{
Xint fd,cj = thisjob;
Xint oldlineno = lineno,oldshst;
XFILE *obshin = bshin;
X
X fd = SHIN;
X lineno = 0;
X oldshst = opts[SHINSTDIN];
X opts[SHINSTDIN] = OPT_UNSET;
X if ((SHIN = movefd(open(s,O_RDONLY))) == -1)
X {
X SHIN = fd;
X thisjob = cj;
X opts[SHINSTDIN] = oldshst;
X return 1;
X }
X bshin = fdopen(SHIN,"r");
X loop(0);
X fclose(bshin);
X bshin = obshin;
X opts[SHINSTDIN] = oldshst;
X SHIN = fd;
X thisjob = cj;
X errflag = 0;
X retflag = 0;
X lineno = oldlineno;


X return 0;
X}
X

X/* try to source a file in the home directory */
X
Xvoid sourcehome(s) /**/
Xchar *s;
X{
Xchar buf[MAXPATHLEN];
Xchar *h;
X
X if (!(h = getsparam("ZDOTDIR")))
X h = home;
X sprintf(buf,"%s/%s",h,s);
X (void) source(buf);
X}
X
X/* print an error */
X
Xvoid zerrnam(cmd,fmt,str,num) /**/
Xchar *cmd; char *fmt; char *str;int num;
X{
X if (cmd)
X {
X if (errflag || noerrs)
X return;
X errflag = 1;
X trashzle();
X if (isset(SHINSTDIN))
X fprintf(stderr,"%s: ",cmd);
X else
X fprintf(stderr,"%s: %s: ",argzero,cmd);
X }
X while (*fmt)
X if (*fmt == '%')
X {
X fmt++;
X switch(*fmt++)
X {
X case 's':
X while (*str)
X niceputc(*str++,stderr);
X break;
X case 'l':
X while (num--)
X niceputc(*str++,stderr);
X break;
X case 'd':
X fprintf(stderr,"%d",num);
X break;
X case '%':
X putc('%',stderr);
X break;
X case 'c':
X niceputc(num,stderr);
X break;
X case 'e':
X if (num == EINTR)
X {
X fputs("interrupt\n",stderr);
X errflag = 1;
X return;
X }
X if (num == EIO)
X fputs(sys_errlist[num],stderr);
X else
X {
X fputc(tulower(sys_errlist[num][0]),stderr);
X fputs(sys_errlist[num]+1,stderr);


X }
X break;
X }
X }

X else
X putc(*fmt++,stderr);
X if (unset(SHINSTDIN) && lineno)
X fprintf(stderr," [%ld]\n",lineno);
X else


X putc('\n',stderr);
X fflush(stderr);
X}
X

Xvoid zerr(fmt,str,num) /**/
Xchar *fmt; char *str;int num;
X{
X if (errflag || noerrs)
X return;
X errflag = 1;
X trashzle();
X fprintf(stderr,"%s: ",(isset(SHINSTDIN)) ? "zsh" : argzero);
X zerrnam(NULL,fmt,str,num);
X}
X
Xvoid niceputc(c,f) /**/
Xint c;FILE *f;
X{
X if (itok(c))
X {
X if (c >= Pound && c <= Comma)
X putc(ztokens[c-Pound],f);
X return;
X }
X c &= 0xff;
X if (isprint(c))
X putc(c,f);
X else if (c == '\n')
X {


X putc('\\',f);
X putc('n',f);

X }
X else
X {
X putc('^',f);
X putc(c|'@',f);
X }
X}
X
X/* enable ^C interrupts */
X
Xvoid intr() /**/
X{
X#ifdef SV_INTERRUPT
Xstatic struct sigvec vec = { handler,sigmask(SIGINT),SV_INTERRUPT };
X
X if (interact)
X sigvec(SIGINT,&vec,NULL);
X#else
X if (interact)
X signal(SIGINT,handler);
X#endif
X}
X
Xvoid noholdintr() /**/
X{
X intr();
X}
X
Xvoid holdintr() /**/
X{
X#ifdef SV_INTERRUPT
Xstatic struct sigvec vec = { handler,sigmask(SIGINT),0 };
X
X if (interact) sigvec(SIGINT,&vec,NULL);
X#else
X if (interact) signal(SIGINT,SIG_IGN);
X#endif
X}
X
X/* get a symlink-free pathname for s relative to PWD */
X
Xchar *findpwd(s) /**/
Xchar *s;
X{
Xchar *t;
X


X if (*s == '/')

X return xsymlink(s);
X s = tricat((pwd[1]) ? pwd : "","/",s);
X t = xsymlink(s);
X free(s);


X return t;
X}
X

Xstatic char xbuf[MAXPATHLEN];
X
X#if 0
Xchar *fixpwd(s) /**/
Xchar *s;
X{
Xstruct stat sbuf,tbuf;
Xchar *t;
X
X strcpy(xbuf,"");


X if (*s == '/')

X t = ztrdup(s);
X else
X t = tricat((pwd[1]) ? pwd : "","/",s);
X (void) xsymlinks(t+1,0);
X free(t);
X if (!*xbuf)
X strcpy(xbuf,"/");
X if (stat(xbuf,&sbuf) == 0 && stat(".",&tbuf) == 0)
X if (!(sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino))
X chdir(xbuf);
X return ztrdup(xbuf);
X}
X#endif
X
Xint ispwd(s) /**/
Xchar *s;
X{
Xstruct stat sbuf,tbuf;
X
X if (stat(s,&sbuf) == 0 && stat(".",&tbuf) == 0)
X if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
X return 1;


X return 0;
X}
X

X/* expand symlinks in s, and remove other weird things */
X
Xchar *xsymlink(s) /**/
Xchar *s;
X{
X if (unset(CHASELINKS))
X return ztrdup(s);


X if (*s != '/')

X return NULL;
X strcpy(xbuf,"");
X if (xsymlinks(s+1,1))
X return ztrdup(s);
X if (!*xbuf)
X return ztrdup("/");
X return ztrdup(xbuf);
X}
X
Xchar **slashsplit(s) /**/
Xchar *s;
X{
Xchar *t,**r,**q;
Xint t0;
X
X if (!*s)
X return (char **) zcalloc(sizeof(char **));
X for (t = s, t0 = 0; *t; t++)
X if (*t == '/')
X t0++;
X q = r = (char **) zalloc(sizeof(char **)*(t0+2));
X while (t = strchr(s,'/'))


X {
X *t = '\0';

X *q++ = ztrdup(s);
X *t = '/';
X while (*t == '/')
X t++;
X if (!*t)
X {
X *q = NULL;
X return r;
X }
X s = t;
X }
X *q++ = ztrdup(s);
X *q = NULL;
X return r;
X}
X
Xint islink(s) /**/
Xchar *s;
X{
X return readlink(s,NULL,0) == 0;
X}
X
X/* expands symlinks and .. or . expressions */
X/* if flag = 0, only expand .. and . expressions */
X
Xint xsymlinks(s,flag) /**/
Xchar *s;int flag;
X{
Xchar **pp,**opp;
Xchar xbuf2[MAXPATHLEN],xbuf3[MAXPATHLEN];
Xint t0;
X
X opp = pp = slashsplit(s);


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

X if (!strcmp(*pp,"."))
X {
X free(*pp);
X continue;
X }
X if (!strcmp(*pp,".."))
X {
X char *p;
X
X free(*pp);
X if (!strcmp(xbuf,"/"))
X continue;
X p = xbuf+strlen(xbuf);
X while (*--p != '/');


X *p = '\0';
X continue;
X }

X if (unset(CHASELINKS))
X {
X strcat(xbuf,"/");
X strcat(xbuf,*pp);
X free(*pp);
X continue;
X }
X sprintf(xbuf2,"%s/%s",xbuf,*pp);
X t0 = readlink(xbuf2,xbuf3,MAXPATHLEN);
X if (t0 == -1 || !flag)
X {
X strcat(xbuf,"/");
X strcat(xbuf,*pp);
X free(*pp);
X }
X else
X {
X xbuf3[t0] = '\0'; /* STUPID */
X if (*xbuf3 == '/')
X {
X strcpy(xbuf,"");
X if (xsymlinks(xbuf3+1,flag))
X return 1;
X }
X else
X if (xsymlinks(xbuf3,flag))
X return 1;
X free(*pp);
X }
X }
X free(opp);


X return 0;
X}
X

X/* print a directory */
X
Xvoid fprintdir(s, f) /**/
Xchar *s; FILE *f;
X{
Xint t0;
X
X t0 = finddir(s);
X if (t0 == -1)
X {
X fputs(s,f);
X }
X else
X {
X putc('~', f);
X fputs(usernames[t0],f);
X fputs(s+strlen(userdirs[t0]),f);
X }
X}
X
Xvoid printdir(s) /**/
Xchar *s;
X{
X fprintdir(s, stdout);
X}
X
Xvoid printdircr(s) /**/
Xchar *s;
X{
X fprintdir(s, stdout);


X putchar('\n');
X}

X
X/* see if a path has a named directory as its prefix */
X/* Modified by Carl Edman, ced...@golem.ps.uci.edu.
X Exhaustive search is more expensive, but binary search just doesn't
X handle all the cases for directory prefixes very well.
X Caching improves performance */
X
Xint finddir(s) /**/
Xchar *s;
X{
Xint t0,t1 = -1;
Xint bestlen = -1,len,bestnlen = -1,nlen;
Xint hash;
Xstatic int cdir = -1,cval = -1;
X
X if (!s) /* Invalidate directory cache table */
X {
X cval = -1;
X return -1;
X }
X if (!userdirsz) return -1;
X
X hash = hasher(s);
X
X if (cval != -1 && cval == hash) return cdir;
X
X for(t0 = 0; t0 < userdirsz; t0++)
X if (userdirs[t0] && !dircmp(userdirs[t0],s))
X {
X len = strlen(userdirs[t0]);
X nlen = strlen(usernames[t0]);
X if ((len > bestlen) || ((len == bestlen) && (nlen < bestnlen)))
X {
X t1 = t0;
X bestlen = len;
X bestnlen = nlen;
X }
X }
X cval = hash;
X cdir = t1;
X return t1;
X}
X
X/* add a named directory */
X
Xvoid adduserdir(s,t) /**/


Xchar *s;char *t;
X{

Xint t0,t1;
X
X if (!interact || ((t0 = finddir(t)) != -1 && !strcmp(s,usernames[t0])))
X return;
X if (!strcmp(t,"/"))
X return;
X if ((t0 = finddir(t)) != -1 && !strcmp(s,usernames[t0]))
X return;
X finddir(0); /* Invalidate directory cache table */
X if (userdirsz == userdirct)
X {
X userdirsz *= 2;
X userdirs = (char **) realloc((char *) userdirs,
X sizeof(char **)*userdirsz);
X usernames = (char **) realloc((char *) usernames,
X sizeof(char **)*userdirsz);
X for (t0 = userdirct; t0 != userdirsz; t0++)
X userdirs[t0] = usernames[t0] = NULL;
X }
X for (t0 = 0; t0 != userdirct; t0++)
X if (strcmp(userdirs[t0],t) > 0)
X break;
X for (t1 = userdirct-1; t1 >= t0; t1--)
X {
X userdirs[t1+1] = userdirs[t1];
X usernames[t1+1] = usernames[t1];
X }
X userdirs[t0] = ztrdup(t);
X usernames[t0] = ztrdup(s);
X userdirct++;
X}
X
Xint dircmp(s,t) /**/


Xchar *s;char *t;
X{

X for (; *s && *t; s++,t++)
X if (*s != *t)
X return *s-*t;
X if (!*s && (!*t || *t == '/'))
X return 0;
X return *s-*t;
X}
X
Xint ddifftime(t1,t2) /**/
Xtime_t t1;time_t t2;
X{
X return ((long) t2-(long) t1);
X}
X
X/* see if jobs need printing */
X
Xvoid scanjobs() /**/
X{
Xint t0;
X


X for (t0 = 1; t0 != MAXJOB; t0++)

X if (jobtab[t0].stat & STAT_CHANGED)
X printjob(jobtab+t0,0);
X}
X
X/* do pre-prompt stuff */
X
Xvoid preprompt() /**/
X{
Xint diff;
XList list;
Xstruct schedcmd *sch,*schl;
X
X if (unset(NOTIFY))
X scanjobs();


X if (errflag)
X return;

X if (list = getshfunc("precmd")) doshfuncnoval(list,NULL,0);


X if (errflag)
X return;

X if (period && (time(NULL) > lastperiod+period) &&
X (list = getshfunc("periodic"))) {
X doshfuncnoval(list,NULL,0);
X lastperiod = time(NULL);
X }


X if (errflag)
X return;

X if (watch)
X {
X diff = (int) ddifftime(lastwatch,time(NULL));
X if (diff > logcheck)
X {
X dowatch();
X lastwatch = time(NULL);
X }
X }


X if (errflag)
X return;

X diff = (int) ddifftime(lastmailcheck,time(NULL));
X if (diff > mailcheck)
X {
X if (mailpath && *mailpath)
X checkmailpath(mailpath);
X else if (mailfile)
X {
X char *x[2];
X
X x[0] = mailfile;
X x[1] = NULL;
X checkmailpath(x);
X }
X lastmailcheck = time(NULL);
X }
X for (schl = (struct schedcmd *) &schedcmds, sch = schedcmds; sch;
X sch = (schl = sch)->next)
X {
X if (sch->time < time(NULL))
X {
X execstring(sch->cmd);


X schl->next = sch->next;
X free(sch->cmd);

X free(sch);
X }
X if (errflag)


X return;
X }
X}
X

Xint arrlen(s) /**/
Xchar **s;
X{
Xint t0;
X
X for (t0 = 0; *s; s++,t0++);


X return t0;
X}
X

Xvoid checkmailpath(s) /**/
Xchar **s;
X{
Xstruct stat st;
Xchar *v,*u,c;
X
X while (*s)
X {
X for (v = *s; *v && *v != '?'; v++);
X c = *v;
X *v = '\0';
X if (c != '?')
X u = NULL;
X else
X u = v+1;
X if (stat(*s,&st) == -1)
X {
X if (errno != ENOENT)
X zerr("%e: %s",*s,errno);
X }
X else if (S_ISDIR(st.st_mode))
X {
X Lklist l;
X DIR *lock = opendir(*s);
X char buf[MAXPATHLEN*2],**arr,**ap;
X struct direct *de;
X int ct = 1;
X
X if (lock)
X {
X pushheap();
X heapalloc();
X l = newlist();
X readdir(lock); readdir(lock);
X while (de = readdir(lock))
X {
X if (errflag)
X break;
X if (u)
X sprintf(buf,"%s/%s?%s",*s,de->d_name,u);
X else
X sprintf(buf,"%s/%s",*s,de->d_name);
X addnode(l,strdup(buf));
X ct++;
X }
X closedir(lock);
X ap = arr = (char **) alloc(ct*sizeof(char *));
X while (*ap++ = ugetnode(l));
X checkmailpath(arr);
X popheap();
X }
X }
X else
X {
X if (st.st_size && st.st_atime <= st.st_mtime &&
X st.st_mtime > lastmailcheck)
X if (!u)
X {
X fprintf(stderr,"You have new mail.\n");
X fflush(stderr);
X }
X else
X {
X char *z = u;
X
X while (*z)
X if (*z == '$' && z[1] == '_')
X {
X fprintf(stderr,"%s",*s);
X z += 2;
X }
X else
X fputc(*z++,stderr);
X fputc('\n',stderr);
X fflush(stderr);
X }
X if (isset(MAILWARNING) && st.st_atime > st.st_mtime &&
X st.st_atime > lastmailcheck && st.st_size)
X {
X fprintf(stderr,"The mail in %s has been read.\n",*s);
X fflush(stderr);
X }
X }
X *v = c;
X s++;
X }
X}
X
Xvoid saveoldfuncs(x,y) /**/
Xchar *x;Cmdnam y;
X{
XCmdnam cc;
X
X if (y->type == SHFUNC || y->type == DISABLED)
X {
X cc = (Cmdnam) zcalloc(sizeof *cc);
X *cc = *y;
X y->u.list = NULL;
X addhnode(ztrdup(x),cc,cmdnamtab,freecmdnam);
X }
X}
X
X/* create command hashtable */
X
Xvoid newcmdnamtab() /**/
X{
XHashtab oldcnt;
X
X oldcnt = cmdnamtab;
X permalloc();
X cmdnamtab = newhtable(101);
X addbuiltins();
X if (oldcnt) {
X listhtable(oldcnt,(HFunc) saveoldfuncs);
X freehtab(oldcnt,freecmdnam);
X }
X lastalloc();
X pathchecked = path;
X}
X
Xvoid freecmdnam(a) /**/
Xvptr a;
X{
Xstruct cmdnam *c = (struct cmdnam *) a;
X
X if (c->type == SHFUNC) {
X if (c->u.list)
X freestruct(c->u.list);
X } else if (c->type != BUILTIN && c->type != DISABLED)
X free(c->u.nam);
X free(c);
X}
X
Xvoid freecompctl(a) /**/
Xvptr a;
X{
XCompctl cc = (Compctl) a;
X
X free(cc);
X}
X
Xvoid freestr(a) /**/
Xvptr a;
X{
X free(a);
X}
X
Xvoid freeanode(a) /**/
Xvptr a;
X{
Xstruct alias *c = (struct alias *) a;
X
X free(c->text);
X free(c);
X}
X
Xvoid freepm(a) /**/
Xvptr a;
X{
Xstruct param *pm = (Param) a;
X
X free(pm);
X}
X
Xvoid restoretty() /**/
X{
X settyinfo(&shttyinfo);
X}
X
Xvoid gettyinfo(ti) /**/
Xstruct ttyinfo *ti;
X{


X if (SHTTY != -1)
X {

X#ifdef TERMIOS
X#ifdef HAS_TCCRAP
X if (tcgetattr(SHTTY,&ti->tio) == -1)
X#else
X if (ioctl(SHTTY,TCGETS,&ti->tio) == -1)
X#endif
X zerr("bad tcgets: %e",NULL,errno);
X#else
X#ifdef TERMIO
X ioctl(SHTTY,TCGETA,&ti->tio);
X#else
X ioctl(SHTTY,TIOCGETP,&ti->sgttyb);
X ioctl(SHTTY,TIOCLGET,&ti->lmodes);
X ioctl(SHTTY,TIOCGETC,&ti->tchars);
X ioctl(SHTTY,TIOCGLTC,&ti->ltchars);
X#endif
X#endif
X#ifdef TIOCGWINSZ
X if (ioctl(SHTTY,TIOCGWINSZ,&ti->winsize) == -1)
X /* zerr("bad tiocgwinsz: %e",NULL,errno)*/;
X#endif
X }
X}
X
Xvoid settyinfo(ti) /**/
Xstruct ttyinfo *ti;
X{


X if (SHTTY != -1)
X {

X#ifdef TERMIOS
X#ifdef HAS_TCCRAP
X#ifndef TCSADRAIN
X#define TCSADRAIN 1 /* XXX Princeton's include files are screwed up */
X#endif
X if (tcsetattr(SHTTY, TCSADRAIN, &ti->tio) == -1)
X#else
X if (ioctl(SHTTY,TCSETS,&ti->tio) == -1)
X#endif
X /* zerr("settyinfo: %e",NULL,errno)*/;
X#else
X#ifdef TERMIO
X ioctl(SHTTY,TCSETA,&ti->tio);
X#else
X ioctl(SHTTY,TIOCSETN,&ti->sgttyb);
X ioctl(SHTTY,TIOCLSET,&ti->lmodes);
X ioctl(SHTTY,TIOCSETC,&ti->tchars);
X ioctl(SHTTY,TIOCSLTC,&ti->ltchars);
X#endif
X#endif
X#ifdef TIOCGWINSZ
X signal(SIGWINCH,SIG_IGN);
X if (ioctl(SHTTY,TIOCSWINSZ,&ti->winsize) == -1)
X /* zerr("settyinfo: %e",NULL,errno)*/;
X signal(SIGWINCH,handler);
X#endif
X }
X}
X
X#define SANEKEY(X) \
X if (ti->X == -1 && savedttyinfo.X != -1) ti->X = savedttyinfo.X;
X
Xvoid sanetty(ti) /**/
Xstruct ttyinfo *ti;
X{
Xint t0;
X
X#ifdef TIO
X ti->tio.c_lflag |= ICANON|ECHO;
X#ifdef FLUSHO
X ti->tio.c_lflag &= ~FLUSHO;
X#endif


X for (t0 = 0; t0 !=

X#ifdef NCCS
X NCCS
X#else
X NCC
X#endif
X ; t0++)
X if (ti->tio.c_cc[t0] == VDISABLEVAL &&
X savedttyinfo.tio.c_cc[t0] != VDISABLEVAL)
X ti->tio.c_cc[t0] = savedttyinfo.tio.c_cc[t0];
X#else
X ti->sgttyb.sg_flags = (ti->sgttyb.sg_flags & ~CBREAK) | ECHO;
X ti->lmodes &= ~LFLUSHO;
X SANEKEY(tchars.t_quitc);
X SANEKEY(tchars.t_startc);
X SANEKEY(tchars.t_stopc);
X SANEKEY(ltchars.t_suspc);
X SANEKEY(ltchars.t_dsuspc);
X SANEKEY(ltchars.t_lnextc);
X SANEKEY(ltchars.t_flushc);
X#endif
X}
X
Xvoid adjustwinsize() /**/
X{
X#ifdef TIOCGWINSZ
X ioctl(SHTTY,TIOCGWINSZ,&shttyinfo.winsize);
X if (!(columns = shttyinfo.winsize.ws_col)) columns = 80;
X lines = shttyinfo.winsize.ws_row;
X setintenv("COLUMNS",columns);
X setintenv("LINES",lines);
X if (zleactive) refresh();
X#endif
X}
X
Xint zyztem(s,t) /**/


Xchar *s;char *t;
X{

Xint cj = thisjob;
X

X s = tricat(s," ",t);
X execstring(s); /* Depends on recursion condom in execute() */
X free(s);
X thisjob = cj;
X return lastval;
X}
X
X#ifndef WAITPID
X
X/* fork a process and wait for it to complete without confusing
X the SIGCHLD handler */
X
Xint waitfork() /**/
X{
Xint pipes[2];
Xchar x;
X
X pipe(pipes);
X if (!fork())


X {
X close(pipes[0]);

X signal(SIGCHLD,SIG_DFL);
X if (!fork())
X return 0;
X wait(NULL);
X _exit(0);


X }
X close(pipes[1]);

X read(pipes[0],&x,1);
X close(pipes[0]);


X return 1;
X}
X

X#endif
X
X/* move a fd to a place >= 10 */
X
Xint movefd(fd) /**/
Xint fd;
X{
Xint fe;
X
X if (fd == -1)
X return fd;
X#ifdef F_DUPFD
X fe = fcntl(fd,F_DUPFD,10);
X#else
X if ((fe = dup(fd)) < 10)
X fe = movefd(fe);
X#endif
X close(fd);
X return fe;
X}
X
X/* move fd x to y */
X
Xvoid redup(x,y) /**/
Xint x;int y;
X{
X if (x != y)
X {
X dup2(x,y);
X close(x);
X }
X}
X
Xvoid settrap(t0,l) /**/
Xint t0;List l;
X{
XCmd c;
X
X if (l)
X {
X c = l->left->left->left;
X if (c->type == SIMPLE && empty(c->args) && empty(c->redir)
X && empty(c->vars) && !c->flags)
X l = NULL;
X }
X if (t0 == -1)
X return;
X if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
X || t0 == SIGPIPE))
X {
X zerr("can't trap SIG%s in interactive shells",sigs[t0-1],0);
X return;
X }
X if (!l)
X {
X sigtrapped[t0] = 2;
X if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD &&
X#ifdef SIGWINCH
X t0 != SIGWINCH &&
X#endif
X t0 != SIGHUP) signal(t0,SIG_IGN);
X }
X else
X {
X if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD &&
X#ifdef SIGWINCH
X t0 != SIGWINCH &&
X#endif
X t0 != SIGHUP) signal(t0,handler);
X sigtrapped[t0] = 1;
X permalloc();
X sigfuncs[t0] = (List) dupstruct(l);
X heapalloc();
X }
X}
X
Xvoid unsettrap(t0) /**/
Xint t0;
X{
X if (t0 == -1)
X return;
X if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
X || t0 == SIGPIPE)) {
X return;
X }
X sigtrapped[t0] = 0;
X if (t0 == SIGINT) intr();
X else if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD &&
X#ifdef SIGWINCH
X t0 != SIGWINCH &&
X#endif
X t0 != SIGHUP) signal(t0,SIG_DFL);
X if (sigfuncs[t0]) freestruct(sigfuncs[t0]);
X}
X
Xvoid dotrap(sig) /**/
Xint sig;
X{
Xint sav,savval;
X
X sav = sigtrapped[sig];
X savval = lastval;
X if (sav == 2)
X return;
X sigtrapped[sig] = 2;
X if (sigfuncs[sig]) {
X lexsave();
X doshfuncnoval(sigfuncs[sig],NULL,0);
X lexrestore();
X }
X if (sigtrapped[sig])
X sigtrapped[sig] = sav;
X lastval = savval;
X}
X
X/* copy len chars from t into s, and null terminate */
X
Xvoid ztrncpy(s,t,len) /**/
Xchar *s;char *t;int len;
X{
X while (len--) *s++ = *t++;


X *s = '\0';
X}

X
X/* copy t into *s and update s */
X
Xvoid strucpy(s,t) /**/
Xchar **s;char *t;
X{
Xchar *u = *s;
X
X while (*u++ = *t++);
X *s = u-1;
X}
X
Xvoid struncpy(s,t,n) /**/
Xchar **s;char *t;int n;
X{
Xchar *u = *s;
X
X while (n--)
X *u++ = *t++;
X *s = u;
X *u = '\0';
X}
X
Xint checkrmall(s) /**/
Xchar *s;
X{
X fflush(stdin);


X if (*s == '/')

X fprintf(stderr,"zsh: sure you want to delete all the files in %s? ",s);
X else
X fprintf(stderr,"zsh: sure you want to delete all the files in %s/%s? ",
X (pwd[1]) ? pwd : "",s);
X fflush(stderr);
X feep();
X return (getquery() == 'y');
X}
X
Xint getquery() /**/
X{
Xchar c;
Xlong val;
X
X setcbreak();
X#ifdef FIONREAD
X ioctl(SHTTY,FIONREAD,&val);
X if (val) { unsetcbreak(); write(2,"n\n",2); return 'n'; }
X#endif
X if (read(SHTTY,&c,1) == 1)
X if (c == 'y' || c == 'Y' || c == '\t') c = 'y';
X unsetcbreak();
X if (c != '\n')
X write(2,"\n",1);
X return (int) c;
X}
X
Xstatic int d;
Xstatic char *guess,*best;
X
Xvoid spscannodis(s,cn) /**/
Xchar *s;char *cn;
X{
X if (((Cmdnam) cn)->type != DISABLED)
X spscan(s,NULL);
X}
X
Xvoid spscan(s,junk) /**/
Xchar *s;char *junk;
X{
Xint nd;
X
X nd = spdist(s,guess,strlen(guess)/4+1);
X if (nd <= d) {
X best = s;
X d = nd;
X }
X}
X
X/* spellcheck a word */
X/* fix s and s2 ; if s2 is non-null, fix the history list too */
X
Xvoid spckword(s,s2,tptr,cmd,ask) /**/
Xchar **s;char **s2;char **tptr;int cmd;int ask;
X{
Xchar *t,*u;
Xchar firstchar;
Xint x;
Xint pram = 0;
X
X if (**s == '-' || **s == '%')
X return;
X if (!strcmp(*s,"in"))
X return;
X if (!(*s)[0] || !(*s)[1]) return;
X if (gethnode(*s,cmdnamtab) || gethnode(*s,aliastab)) return;
X t = *s;
X if (*t == Tilde || *t == Equals || *t == String) t++;
X for (; *t; t++) if (itok(*t)) return;
X best = NULL;
X for (t = *s; *t; t++) if (*t == '/') break;
X if (**s == String) {
X if (*t) return;
X pram = 1;
X guess = *s+1;
X d = 100;
X listhtable(paramtab,spscan);
X } else {
X if ((u = spname(guess = *s)) != *s)
X best = u;
X if (!*t && !cmd) {
X if (access(*s,F_OK) == 0) return;
X if (hashcmd(*s,pathchecked)) return;
X guess = *s;
X d = 100;
X listhtable(aliastab,spscan);
X listhtable(cmdnamtab,spscan);
X }


X }
X if (errflag) return;

X if (best && strlen(best) > 1 && strcmp(best,guess)) {
X if (ask) {
X char *pp;
X int junk;
X
X rstring = best; Rstring = guess;
X firstchar = *guess;
X if (*guess == Tilde) *guess = '~';
X else if (*guess == String) *guess = '$';
X else if (*guess == Equals) *guess = '=';
X pp = putprompt(sprompt,&junk,1);
X *guess = firstchar;
X fprintf(stderr,"%s",pp);
X fflush(stderr);
X feep();
X x = getquery();
X } else
X x = 'y';
X if (x == 'y') {
X if (!pram) {
X *s = strdup(best);
X } else {
X *s = alloc(strlen(best)+2);
X strcpy(*s+1,best);
X **s = String;
X }
X if (s2) {
X if (*tptr && !strcmp(hlastw,*s2) && hlastw < hptr) {
X char *z;
X hptr = hlastw;
X if (pram) hwaddc('$');
X for (z = best; *z; z++) hwaddc(*z);
X hwaddc(HISTSPACE);
X *tptr = hptr-1;
X **tptr = '\0';
X }
X *s2 = strdup(best);
X }
X } else if (x == 'a') {
X histdone |= HISTFLAG_NOEXEC;
X } else if (x == 'e') {
X histdone |= HISTFLAG_NOEXEC|HISTFLAG_RECALL;
X }
X }
X}
X
Xint ztrftime(buf,bufsize,fmt,tm) /**/
Xchar *buf;int bufsize;char *fmt;struct tm *tm;
X{
Xstatic char *astr[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
Xstatic char *estr[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
X "Aug","Sep","Oct","Nov","Dec"};
Xstatic char *lstr[] = {"12"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9",
X "10","11"};
Xchar tmp[3];
X#ifdef HAS_STRFTIME
Xchar *origbuf = buf;
X#endif
X
X tmp[0] = '%'; tmp[2] = '\0';
X while (*fmt)
X if (*fmt == '%')
X {
X fmt++;
X switch(*fmt++)
X {
X case 'a':
X strucpy(&buf,astr[tm->tm_wday]);
X break;
X case 'b':
X strucpy(&buf,estr[tm->tm_mon]);
X break;
X case 'd':
X *buf++ = '0'+tm->tm_mday/10;
X *buf++ = '0'+tm->tm_mday%10;
X break;
X case 'e':
X if (tm->tm_mday > 9)
X *buf++ = '0'+tm->tm_mday/10;
X *buf++ = '0'+tm->tm_mday%10;
X break;
X case 'k':
X if (tm->tm_hour > 9)
X *buf++ = '0'+tm->tm_hour/10;
X *buf++ = '0'+tm->tm_hour%10;
X break;
X case 'l':
X strucpy(&buf,lstr[tm->tm_hour%12]);
X break;
X case 'm':
X *buf++ = '0'+(tm->tm_mon+1)/10;
X *buf++ = '0'+(tm->tm_mon+1)%10;
X break;
X case 'M':
X *buf++ = '0'+tm->tm_min/10;
X *buf++ = '0'+tm->tm_min%10;
X break;
X case 'p':
X *buf++ = (tm->tm_hour > 11) ? 'p' : 'a';
X *buf++ = 'm';
X break;
X case 'S':
X *buf++ = '0'+tm->tm_sec/10;
X *buf++ = '0'+tm->tm_sec%10;
X break;
X case 'y':
X *buf++ = '0'+tm->tm_year/10;
X *buf++ = '0'+tm->tm_year%10;
X break;
X default:
X#ifdef HAS_STRFTIME
X *buf = '\0';
X tmp[1] = fmt[-1];
X strftime(buf,bufsize-strlen(origbuf),tmp,tm);
X buf += strlen(buf);
X#else
X *buf++ = '%';
X *buf++ = fmt[-1];
X#endif
X break;
X }
X }
X else
X *buf++ = *fmt++;
X *buf = '\0';


X return 0;
X}
X

Xchar *join(arr,delim) /**/
Xchar **arr;int delim;
X{
Xint len = 0;
Xchar **s,*ret,*ptr;
Xstatic char *lastmem = NULL;
X
X for (s = arr; *s; s++)
X len += strlen(*s)+1;
X if (!len) return "";
X if (lastmem) free(lastmem);
X lastmem = ptr = ret = zalloc(len);
X for (s = arr; *s; s++) {
X strucpy(&ptr,*s);
X *ptr++ = delim;
X }


X ptr[-1] = '\0';

X return ret;
X}
X
Xchar *spacejoin(s) /**/
Xchar **s;
X{
X return join(s,*ifs);
X}
X
Xchar *colonjoin(s) /**/
Xchar **s;
X{
X return join(s,':');
X}
X
Xchar **colonsplit(s) /**/
Xchar *s;
X{
Xint ct;
Xchar *t,**ret,**ptr;
X
X for (t = s, ct = 0; *t; t++) if (*t == ':') ct++;
X ptr = ret = (char **) zalloc(sizeof(char **)*(ct+2));
X t = s;
X do {
X for (s = t; *t && *t != ':'; t++);
X *ptr = zalloc((t-s)+1);
X ztrncpy(*ptr++,s,t-s);
X }
X while (*t++);
X *ptr = NULL;
X return ret;
X}
X
Xchar **spacesplit(s) /**/
Xchar *s;
X{
Xint ct;
Xchar *t,**ret,**ptr;
X
X for (t = s, ct = 0; *t; t++)
X if (isep(*t)) ct++;
X ptr = ret = (char **) zalloc(sizeof(char **)*(ct+2));
X t = s;
X do {
X for (s = t; *t && !isep(*t); t++);
X *ptr = zalloc((t-s)+1);
X ztrncpy(*ptr++,s,t-s);
X } while (*t++);
X *ptr = NULL;
X return ret;
X}
X
XList getshfunc(nam) /**/
Xchar *nam;
X{
XCmdnam x = (Cmdnam) gethnode(nam,cmdnamtab);
X
X return (x && x->type == SHFUNC) ? x->u.list : NULL;
X}
X
X/* allocate a tree element */
X
Xvptr allocnode(type) /**/
Xint type;
X{
Xint t0;
Xstruct node *n = (struct node *) alloc(sizeof *n);
Xstatic int typetab[N_COUNT][4] = {
X {NT_NODE,NT_NODE,0,0},
X {NT_NODE,NT_NODE,0,0},
X {NT_NODE,NT_NODE,0,0},
X {NT_STR|NT_LIST,NT_NODE,NT_NODE|NT_LIST,NT_NODE|NT_LIST},
X {NT_STR,0,0,0},
X {NT_NODE,NT_NODE,0,0},
X {NT_STR,NT_NODE,0,0},
X {NT_NODE,NT_STR,NT_NODE,0},
X {NT_NODE,NT_NODE,NT_NODE,0},
X {NT_NODE,NT_NODE,0,0},
X {NT_STR,NT_STR,NT_STR|NT_LIST,0}
X };
X
X n->type = type;
X for (t0 = 0; t0 != 4; t0++)
X n->types[t0] = typetab[type][t0];
X return (vptr) n;
X}
X
X/* duplicate a syntax tree */
X
Xvptr dupstruct(a) /**/
Xvptr a;
X{
Xstruct node *n = a,*m;
Xint t0;
X
X if (!a) return NULL;
X m = alloc(sizeof *m);
X *m = *n;
X for (t0 = 0; t0 != 4; t0++)
X if (m->ptrs[t0])
X switch(m->types[t0])
X {
X case NT_NODE: m->ptrs[t0] = dupstruct(m->ptrs[t0]); break;
X case NT_STR: m->ptrs[t0] =
X (useheap) ? strdup(m->ptrs[t0]) : ztrdup(m->ptrs[t0]); break;
X case NT_LIST|NT_NODE:
X m->ptrs[t0] = duplist(m->ptrs[t0],dupstruct); break;
X case NT_LIST|NT_STR:
X m->ptrs[t0] = duplist(m->ptrs[t0],(VFunc)
X ((useheap) ? strdup : ztrdup));
X break;
X }
X return (vptr) m;
X}
X
X/* free a syntax tree */
X
Xvoid freestruct(a) /**/
Xvptr a;
X{
Xstruct node *n = (struct node *) a;
Xint t0;
X
X for (t0 = 0; t0 != 4; t0++)
X if (n->ptrs[t0])
X switch(n->types[t0])
X {
X case NT_NODE: freestruct(n->ptrs[t0]); break;
X case NT_STR: free(n->ptrs[t0]); break;
X case NT_LIST|NT_STR: freetable(n->ptrs[t0],freestr); break;
X case NT_LIST|NT_NODE: freetable(n->ptrs[t0],freestruct); break;
X }
X free(n);
X}
X
XLklist duplist(l,func) /**/
XLklist l;VFunc func;
X{
XLklist ret;
XLknode node;
X
X ret = newlist();
X for (node = firstnode(l); node; incnode(node))
X addnode(ret,func(getdata(node)));


X return ret;
X}
X

Xchar **mkarray(s) /**/
Xchar *s;
X{
Xchar **t = (char **) zalloc((s) ? (2*sizeof s) : (sizeof s));
X
X if (*t = s) t[1] = NULL;


X return t;
X}
X

Xvoid feep() /**/
X{
X if (unset(NOBEEP))
X write(2,"\07",1);
X}
X
Xvoid freearray(s) /**/
Xchar **s;
X{
Xchar **t = s;
X
X while (*s)
X free(*s++);
X free(t);
X}
X
Xint equalsplit(s,t) /**/


Xchar *s;char **t;
X{

X for (; *s && *s != '='; s++);
X if (*s == '=')
X {
X *s++ = '\0';
X *t = s;
X return 1;
X }
X return 0;
X}
X
X/* see if the right side of a list is trivial */
X
Xvoid simplifyright(l) /**/
XList l;
X{
XCmd c;
X
X if (!l->right)
X return;
X if (l->right->right || l->right->left->right ||
X l->right->left->flags || l->right->left->left->right ||
X l->left->flags)
X return;
X c = l->left->left->left;
X if (c->type != SIMPLE || full(c->args) || full(c->redir)
X || full(c->vars))
X return;
X l->right = NULL;
X return;
X}
X
X/* initialize the ztypes table */
X
Xvoid inittyptab() /**/
X{
Xint t0;
Xchar *s;
X
X for (t0 = 0; t0 != 256; t0++)
X typtab[t0] = 0;
X for (t0 = 0; t0 != 32; t0++)
X typtab[t0] = typtab[t0+128] = ICNTRL;
X typtab[127] = ICNTRL;
X for (t0 = '0'; t0 <= '9'; t0++)
X typtab[t0] = IDIGIT|IALNUM|IWORD|IIDENT|IUSER;
X for (t0 = 'a'; t0 <= 'z'; t0++)
X typtab[t0] = typtab[t0-'a'+'A'] = IALPHA|IALNUM|IIDENT|IUSER|IWORD;
X for (t0 = 0240; t0 != 0400; t0++)
X typtab[t0] = IALPHA|IALNUM|IIDENT|IUSER|IWORD;
X typtab['_'] = IIDENT|IUSER;
X typtab['-'] = IUSER;
X typtab[' '] |= IBLANK|INBLANK;
X typtab['\t'] |= IBLANK|INBLANK;
X typtab['\n'] |= INBLANK;
X for (t0 = (int) STOUC(ALPOP); t0 <= (int) STOUC(Nularg);
X t0++)
X typtab[t0] |= ITOK;
X for (s = ifs; *s; s++)
X typtab[(int) (unsigned char) *s] |= ISEP;
X for (s = wordchars; *s; s++)
X typtab[(int) (unsigned char) *s] |= IWORD;
X for (s = SPECCHARS; *s; s++)
X typtab[(int) (unsigned char) *s] |= ISPECIAL;
X}
X
Xchar **arrdup(s) /**/
Xchar **s;
X{
Xchar **x,**y;
X
X y = x = (char **) ncalloc(sizeof(char *)*(arrlen(s)+1));
X while (*x++ = strdup(*s++));
X return y;
X}
X
X/* next few functions stolen (with changes) from Kernighan & Pike */
X/* "The UNIX Programming Environment" (w/o permission) */
X
Xchar *spname (oldname) /**/
Xchar *oldname;
X{
X char *p,guess[MAXPATHLEN+1],best[MAXPATHLEN+1];
X static char newname[MAXPATHLEN+1];
X char *new = newname, *old;
X
X if (itok(*oldname)) {
X singsub(&oldname);
X if (!oldname) return NULL;
X }
X if (access(oldname,F_OK) == 0) return NULL;
X old = oldname;
X for (;;) {
X while (*old == '/') *new++ = *old++;
X *new = '\0';
X if (*old == '\0') return newname;
X p = guess;
X for (; *old != '/' && *old != '\0'; old++)
X if (p < guess+MAXPATHLEN) *p++ = *old;
X *p = '\0';
X if (mindist(newname,guess,best) >= 3) return NULL;
X for (p = best; *new = *p++; ) new++;
X }
X}
X
Xint mindist(dir,guess,best) /**/
Xchar *dir;char *guess;char *best;
X{
X int d,nd;
X DIR *dd;
X struct direct *de;
X char buf[MAXPATHLEN];
X
X if (dir[0] == '\0')
X dir = ".";
X d = 100;
X sprintf(buf,"%s/%s",dir,guess);
X if (access(buf,F_OK) == 0) { strcpy(best,guess); return 0; }
X if (!(dd = opendir(dir))) return d;
X while (de = readdir(dd)) {
X nd = spdist(de->d_name,guess,strlen(guess)/4+1);
X if (nd <= d) {
X strcpy(best,de->d_name);
X d = nd;
X if (d == 0) break;
X }
X }
X closedir(dd);
X return d;
X}
X
Xint spdist(s,t,thresh) /**/
Xchar *s;char *t;int thresh;
X{
Xchar *p,*q;
Xchar *keymap =
X"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
X\t1234567890-=\t\
X\tqwertyuiop[]\t\
X\tasdfghjkl;'\n\t\
X\tzxcvbnm,./\t\t\t\
X\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
X\t!@#$%^&*()_+\t\
X\tQWERTYUIOP{}\t\
X\tASDFGHJKL:\"\n\t\
X\tZXCVBNM<>?\n\n\t\
X\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
X
X if (!strcmp(s,t))
X return 0;
X /* any number of upper/lower mistakes allowed (dist = 1) */
X for (p = s, q = t; *p && tulower(*p) == tulower(*q); p++,q++);
X if (!*p && !*q)
X return 1;
X if (!thresh)
X return 200;
X for (p = s, q = t; *p && *q; p++,q++)
X if (*p == *q) continue; /* don't consider "aa" transposed, ash */
X else if (p[1] == q[0] && q[1] == p[0]) /* transpositions */
X return spdist(p+2,q+2,thresh-1)+1;
X else if (p[1] == q[0]) /* missing letter */
X return spdist(p+1,q+0,thresh-1)+2;
X else if (p[0] == q[1]) /* missing letter */
X return spdist(p+0,q+1,thresh-1)+2;
X else if (*p != *q)
X break;
X if ((!*p && strlen(q) == 1) || (!*q && strlen(p) == 1))
X return 2;
X for (p = s, q = t; *p && *q; p++,q++)
X if (p[0] != q[0] && p[1] == q[1])
X {
X int t0;
X char *z;
X
X /* mistyped letter */
X
X if (!(z = strchr(keymap,p[0])) || *z == '\n' || *z == '\t')
X return spdist(p+1,q+1,thresh-1)+1;
X t0 = z-keymap;
X if (*q == keymap[t0-15] || *q == keymap[t0-14] ||
X *q == keymap[t0-13] ||
X *q == keymap[t0-1] || *q == keymap[t0+1] ||
X *q == keymap[t0+13] || *q == keymap[t0+14] ||
X *q == keymap[t0+15])
X return spdist(p+1,q+1,thresh-1)+2;
X return 200;
X }
X else if (*p != *q)
X break;
X return 200;
X}
X
Xchar *zgetenv(s) /**/
Xchar *s;
X{
Xchar **av,*p,*q;
X
X for (av = environ; *av; av++)
X {
X for (p = *av, q = s; *p && *p != '=' && *q && *p == *q; p++,q++);
X if (*p == '=' && !*q)
X return p+1;


X }
X return NULL;
X}
X

Xint tulower(c) /**/
Xint c;
X{
X c &= 0xff;
X return (isupper(c) ? tolower(c) : c);
X}
X
Xint tuupper(c) /**/
Xint c;
X{
X c &= 0xff;
X return (islower(c) ? toupper(c) : c);
X}
X
X#ifdef SYSV
X#include <sys/utsname.h>
X
Xint gethostname(nameptr, maxlength)
Xchar *nameptr;
Xint maxlength;
X{
Xstruct utsname name;
Xint result;
X
X result = uname(&name);
X if (result >= 0) {
X strncpy(nameptr,name.nodename,maxlength);
X return 0;
X } else return -1;
X}
X#endif
X
X/* set cbreak mode, or the equivalent */
X
Xvoid setcbreak() /**/
X{
Xstruct ttyinfo ti;
X
X ti = shttyinfo;
X#ifdef TIO
X ti.tio.c_lflag &= ~ICANON;
X ti.tio.c_cc[VMIN] = 1;
X ti.tio.c_cc[VTIME] = 0;
X#else
X ti.sgttyb.sg_flags |= CBREAK;
X#endif
X settyinfo(&ti);
X}
X
Xint getlineleng() /**/
X{
Xint z;
X
X#ifdef TIOCSWINSZ
X z = shttyinfo.winsize.ws_col;
X return (z) ? z : 80;
X#else
X return 80;
X#endif
X}
X
Xvoid unsetcbreak() /**/
X{
X settyinfo(&shttyinfo);
X}
X
X/* give the tty to some process */
X
Xvoid attachtty(pgrp) /**/
Xlong pgrp;
X{
Xstatic int ep = 0;
X
X if (jobbing) {
X#ifdef HAS_TCSETPGRP
X if (SHTTY != -1 && tcsetpgrp(SHTTY,pgrp) == -1 && !ep)
X#else
X int arg = pgrp;
X if (SHTTY != -1 && ioctl(SHTTY,TIOCSPGRP,&arg) == -1 && !ep)
X#endif
X {
X zerr("can't set tty pgrp: %e",NULL,errno);
X fflush(stderr);


X opts[MONITOR] = OPT_UNSET;

X ep =1;


X errflag = 0;
X }

X }
X}
X
X/* get the tty pgrp */
X
Xlong gettygrp() /**/
X{
Xint arg;
X
X if (SHTTY == -1) return -1;
X#ifdef HAS_TCSETPGRP
X arg = tcgetpgrp(SHTTY);
X#else
X ioctl(SHTTY,TIOCGPGRP,&arg);
X#endif
X return arg;
X}
END_OF_FILE
if test 32015 -ne `wc -c <'src/utils.c'`; then
echo shar: \"'src/utils.c'\" unpacked with wrong size!
fi
# end of 'src/utils.c'
fi
echo shar: End of archive 12 \(of 22\).
cp /dev/null ark12isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:25:31 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 63
Archive-name: zsh/part13

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: FAQ help/pushd src/zle_tricky.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:54 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 13 (of 22)."'
if test -f 'FAQ' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'FAQ'\"
else
echo shar: Extracting \"'FAQ'\" \(21578 characters\)
sed "s/^X//" >'FAQ' <<'END_OF_FILE'
XArchive-Name: zsh.FAQ
XSubmitted-By: p...@s-a.amtp.liv.ac.uk (Peter Stephenson)
X
X$Id: FAQ,v 1.3 1993/02/04 10:17:55 pws Exp pws $
X
XThis document contains a list of frequently-asked (or otherwise
Xsignificant) questions concerning the Z-shell, a powerful command
Xinterpreter for many UNIX systems.
X
XIf you have never heard of `sh', `csh' or `ksh', then you are probably
Xbetter off to start by reading a general introduction to UNIX rather
Xthan this document.
X
XAnother useful source of information is the collection of FAQ articles
Xposted bi-weekly to the Usenet news groups comp.unix.questions,
Xcomp.unix.shells and news.answers with answers to general questions
Xabout UNIX. The fifth of the seven articles deals with shells,
Xincluding zsh, with a brief description of differences. (This article
Xalso talks about shell startup files which would otherwise rate a
Xmention here.)
X
XIf you just want to know how to get your hands on the latest version,
Xskip to question 4; if you want to know what to do with insoluble
Xproblems, go to 17.
X
XNotation: Quotes `like this' are ordinary textual quotation
Xmarks. Other uses of quotation marks are input to the shell.
X
XContents:
X1) What is it?
X2) On what machines will it run?
X3) What's the latest version?
X4) Where do I get it?
X5) How does zsh differ from sh, ksh, csh,...?
X6) Why do my csh aliases not work?
X7) How do I get the meta key to work on my xterm?
X8) Why does my terminal act funny in way x?
X9) Why does `$vble' where vble="foo bar" not do what I expect?
X10) How does base arithmetic work?
X11) How do I get a newline in my prompt?
X12) Why does `bindkey ^a command-name' do something funny?
X13) How do I reference command `foo' from within function `foo'?
X14) I don't have root access: how do I make zsh my login shell?
X15) What bugs are currently known and unfixed?
X16) Where do I report bugs, get more info / who's working on zsh?
X17) What's on the wish-list?
X
X
X1) What is it?
X
X Zsh is a UNIX command interpreter (shell) which of the standard shells
X most resembles the Korn shell (ksh), although it is not completely
X compatible. It includes enhancements of many types, notably in the
X command-line editor, options for customising its behaviour, filename
X globbing, features to make C-shell (csh) users feel more at home and
X extra features drawn from tcsh (another `custom' shell).
X
X It was written by Paul Falstad <p...@ttisms.com> when a student at
X Princeton; however, Paul doesn't maintain it any more and enquiries
X should be sent to the mailing list (see question 17). It is freely
X available to anyone under unrestrictive conditions.
X
X For more information, the files doc/intro.txt or doc/intro.troff
X included with the source distribution are highly recommended. The
X files intro.ps.Z and intro.txt.Z can also be FTP'd separately from the
X archive (see 4). A list of features is given in FEATURES, also with
X the source.
X
X
X2) On what machines will it run?
X
X Zsh was written for machines of the Berkeley UNIX family; most such
X machines (and all the most popular) will run it without major surgery.
X Modifications have been made so that it should work under SYSVR4-based
X operating systems such as Solaris 2.x. This best thing is to suck it
X and see. You may not have to change too much: if you do change
X anything, arrange for the shell script `buildzsh' to set the
X necessary #define's, etc., without human intervention.
X
X
X3) What's the latest version?
X
X The latest production version is 2.3.1, which has just been released.
X New patches occur frequently and are added to the archive (next
X question).
X
X
X4) Where do I get it?
X
X The current release is available for anonymous FTP from
X cs.ucsd.edu (132.239.51.3):pub/zsh/zsh2.3.1.tar.Z
X The archive maintainer currently is Jim Mattson <mat...@cs.UCSD.EDU>,
X who also reads the mailing list.
X
X Bas de Bakker (b...@phys.uva.nl) will shortly be taking over the archive
X and new patches are likely to be available from:
X carlo.phys.uva.nl (145.18.220.25):/pub/bas/zsh
X
X Richard Ohnemus will probably have a North American reflector at
X ftp.sterling.com.
X
X
X5) How does zsh differ from sh, ksh, csh,...?
X
X As mentioned, zsh is most similar to ksh, while many of the additions are
X to please csh users.
X
X i) ksh:
X Most features of ksh are implemented in zsh; problems can arise
X because the implementation is slightly different. Note also not all
X ksh's are the same either. I have based this on SunOS 4, which is
X essentially the 11/16/88 version of ksh.
X
X Differences from ksh which might prove significant for ksh
X programmers, some of which may be interpreted as bugs (there must be
X more) include:
X Shell word splitting: see question 14.
X Arrays are more csh-like than ksh-like:
X subscripts start at 1, not 0; array[0] refers to array[1];
X `$array' refers to the whole array, not $array[0];
X braces are unnecessary: $a[1] == ${a[1]}, etc.
X Path not searched for commands specified at invocation without -c.
X Management of histories in multiple shells may be different.
X Coprocesses are established by `coproc'; `|&' behaves like csh.
X PS1 does not do parameter substitution.
X Globbing does not allow ksh-style `pattern-lists'.
X The options emacs, gmacs, privileged, trackall, viraw are not supported.
X The `keyword' option does not exist and -k is instead interactivecomments.
X [ ] is a shell built-in, rather than a call to /bin/test.
X There is no built-in command newgrp: use a shell function.
X The order in which aliases and functions are defined is significant.
X Some built-ins (true, false, r, ...) were aliases in ksh.
X Aliases and functions cannot be exported.
X There are no tracked aliases.
X There is no ENV variable.
X No built-in commands cause automatic termination of a script.
X The -- flag to terminate option processing is not recognised
X as an argument to the shell (it is recognised by set).
X `jobs' has no `-n' flag.
X Treatment of backslashes within backquotes is different.
X Variable assignments with tilde expansions are special-cased.
X Editing:
X \ does not escape editing chars (use ^V).
X Not all ksh bindings are set (e.g. `<ESC>#').
X The following is particularly near the feature/bug borderline:
X To turn off signal traps, use `trap - <signo>', not `trap <signo>'.
X "$@" always indicates at least one argument (older sh's do this too).
X
X ii) csh:
X
X Although certain features aim to ease the withdrawal symptoms of Csh
X (ab)users, the syntax is in general rather different and you should
X certainly not try to run scripts without modification. The c2z script
X is provided with the source (in scripts/c2z) to help convert .cshrc
X and .login files; see also the next question concerning aliases.
X
X Csh-compatibility additions include:
X Logout, rehash, source, (un)limit built-in commands.
X *rc file for interactive shells.
X Directory stacks.
X Cshjunkie*, ignoreeof options.
X The nonomatch option.
X >&, |& etc. redirection.
X foreach ... loops.
X $PROMPT as well as $PS1, $status as well as $?, $#argv as well as $#, ....
X Escape sequences via % for prompts.
X Special array variables $PATH etc. are colon-separated, $path are arrays.
X !-type history (which may be turned off).
X Arrays have csh-like features (see i)).
X
X iii) tcsh:
X
X Certain features have been borrowed from tcsh, including $watch,
X run-help, $savehist, $histlit, periodic commands etc., extended
X prompts, sched and which/where built-ins. This list is not
X definitive: some features have gone in the other direction.
X
X iv) specific features:
X
X Things that zsh is particularly good at (no claim of exclusivity is made,
X especially as shells copy one another) include:
X Command line editing:
X multi-line commands,
X variable editing,
X command buffer stack,
X execution of unbound commands,
X menu completion,
X variable, host, editing function and option name completion,
X inline expansion of variables, history commands,
X path expansion (=foo).
X Globbing:
X recursive globbing (c.f find),
X file attribute qualifiers,
X full alternation and negation of patterns.
X Large number of options for tailoring.
X Adaptable messages for spelling, watch, time as well as prompt.
X Named directories.
X Comprehensive integer arithmetic.
X Manipulation of arrays.
X Spelling correction.
X
X
X6) Why do my csh aliases not work?
X
X First of all, check you are using the syntax
X alias newcmd='list of commands'
X and not
X alias newcmd 'list of commands'
X which won't work. (It tells you if `newcmd' and `list of commands' are
X already defined as aliases.)
X
X Otherwise, your aliases probably contain references to the command
X line of the form `\!*', etc. Zsh does not handle this behaviour as it
X has shell functions which provide a way of solving this problem more
X consistent with other forms of argument handling. For example, the
X csh alias
X alias cd 'cd \!*; echo $cwd'
X can be replaced by the zsh function,
X cd() { builtin cd $*; echo $PWD; }
X (the `builtin' tells zsh to use its own `cd', avoiding an infinite loop)
X or, perhaps better,
X cd() { builtin cd $*; print -D $PWD; }
X (which converts your home directory to a ~). In fact, this problem is
X better solved by defining the special function chpwd() (see the manual).
X
X Note also that the `;' at the end of the function is optional in zsh,
X but not in ksh or sh (for sh's where it exists).
X
X Here is Bart Schaefer's guide to converting csh aliases for zsh.
X
X 1. If the csh alias references "parameters" (\!:1 \!* etc.),
X then in zsh you need a function (referencing $1 $* etc.).
X Otherwise, you can use a zsh alias.
X
X 2. If you use a zsh function, you need to refer _at_least_ to
X $* in the body (inside the { }). Parameters don't magically
X appear inside the { } the way they get appended to an alias.
X
X 3. If the csh alias references its own name (alias rm "rm -i"),
X then in a zsh function you need the "command" keyword
X (function rm() { command rm -i $* }), but in a zsh alias
X you don't (alias rm="rm -i").
X
X 4. If you have aliases that refer to each other (alias ls "ls -C";
X alias lf "ls -F" ==> lf == ls -C -F) then you must either:
X a. convert all of them to zsh functions; or
X b. after converting, be sure your .zshrc defines all of your
X aliases before it defines any of your functions.
X
X Those first four are all you really need, but here are four more for
X heavy csh alias junkies:
X
X 5. Mapping from csh alias "parameter referencing" into zsh function
X (assuming shwordsplit is NOT set in zsh):
X csh zsh
X ===== ==========
X \!* $* (or $argv)
X \!^ $1 (or $argv[1])
X \!:1 $1
X \!:2 $2 (or $argv[2], etc.)
X \!$ $*[$#] (or $argv[$#], or $*[-1])
X \!:1-4 $*[1,4]
X \!:1- $*[1,$#-1] (or $*[1,-2])
X \!^- $*[1,$#-1]
X \!*:q "$@" ($*:q doesn't work (yet))
X \!*:x $=* ($*:x doesn't work (yet))
X
X 6. Remember that it is NOT a syntax error in a zsh function to
X refer to a position ($1, $2, etc.) greater than the number of
X parameters. (E.g., in a csh alias, a reference to \!:5 will
X cause an error if 4 or fewer arguments are given; in a zsh
X function, $5 is the empty string if there are 4 or fewer
X parameters.)
X
X 7. To begin a zsh alias with a - (dash, hyphen) character, use
X "alias --":
X csh zsh
X =============== ==================
X alias - "fg %-" alias -- -="fg %-"
X
X 8. Stay away from "alias -g" in zsh until you REALLY know what
X you're doing.
X
X
X7) How do I get the meta key to work on my xterm?
X
X As stated in the manual, zsh needs to be told about the meta key by
X using `bindkey -me' or `bindkey -mv' in your .zshrc or on the command
X line. You probably also need to tell the terminal driver to allow the
X `meta' bit of the character through; `stty pass8' is the usual
X incantation. Sample .zshrc entry:
X [[ $TERM = "xterm" ]] && stty pass8 && bindkey -me
X Make sure this comes *before* any bindkey entries in your .zshrc which
X redefine keys normally defined in the emacs/vi keymap.
X
X
X8) Why does my terminal act funny in way x?
X
X If you are using an OpenWindows cmdtool as your terminal, any
X escape sequences (such as those produced by cursor keys) will be
X swallowed up and never reach zsh. Either use shelltool or avoid
X commands with escape sequences. You can also disable scrolling from
X the cmdtool pane menu (which effectively turns it into a shelltool).
X If you still want scrolling, try using an xterm with the scrollbar
X activated.
X
X If that's not the problem, and you are using stty to change some tty
X settings, make sure you haven't asked zsh to freeze the tty settings:
X type
X ttyctl -u
X before any stty commands you use.
X
X If _that's_ not the problem, and you are having difficulties with
X external commands (not part of zsh), and you think some terminal
X setting is wrong (e.g. ignpar should be -ignpar: see the stty(1)
X manual page), try:
X ttyctl -u
X STTY='-ignpar' commandname
X (in this not-very-useful example). Note that zsh doesn't reset the
X terminal completely afterwards: just the modes it uses itself.
X
X
X9) Why does `$var' where var="foo bar" not do what I expect?
X
X In most Bourne-shell derivatives, multi-word variables such as
X var="foo bar"
X are split into words when passed to a command or used in a `for foo in $var'
X loop. By default, zsh does not have that behaviour: the variable remains
X intact. An option (shwordsplit) exists to provide compatibility.
X
X For example, defining the function args to show the number of its
X arguments:
X args() { echo $#; }
X and with our definition of vble,
X args $vble
X produces the output `1'. After
X setopt shwordsplit
X the same function produces the output `2', like sh and ksh.
X
X Unless you need strict sh/ksh compatibility, you should ask yourself
X whether you really want this behaviour, as it can produce unexpected
X effects for variables with entirely innocuous embedded spaces. The
X natural way to produce word-splitting behaviour in zsh is via arrays.
X For example,
X set -A array one two three twenty
X (or
X array=(one two three twenty)
X if you prefer), followed by
X args $array
X produces the output `4', regardless of the setting of shwordsplit.
X Arrays are also much more versatile than single strings.
X
X Note also the "$@" method of word splitting is always available in zsh
X functions and scripts (though strictly this does array splitting, not
X word splitting), also the substitution ${=foo} to toggle word
X splitting on variable `foo'.
X
X
X10) How does base arithmetic work?
X
X The syntax (e.g. using the `let' builtin is)
X let 'foo = [16]ff'
X or equivalently
X (( foo = [16]ff ))
X Then
X echo $foo
X gives the answer `255'. It is possible to declare variables explicitly
X to be integers, via
X typeset -i foo
X which has a different effect: namely the base used in the first
X assignment (hexadecimal in the example) is subsequently used whenever
X `foo' is displayed (although the internal representation is unchanged).
X To ensure foo is always displayed in decimal, declare it as
X typeset -i 10 foo
X which requests base 10 for output. You can change the output base of an
X existing variable in this fashion. Using the `$[ ... ]' method will
X always display in decimal.
X
X
X11) How do I get a newline in my prompt?
X
X You can place a literal newline in quotes, i.e.
X PROMPT="Hi Joe,
X what now?%# "
X If you have the bad taste to set the option cshjunkiequotes, which
X inhibits such behaviour, you will have to bracket this with
X `unsetopt cshjunkiequotes' and `setopt cshjunkiequotes', or put it in
X your .zshrc before the option is set.
X
X
X12) Why does `bindkey ^a command-name' do something funny?
X
X You probably have the extendedglob option set in which case ^ and #
X are metacharacters. ^a matches any file except one called a, so the
X line is interpreted as bindkey followed by a list of files. Quote the
X ^ with a backslash or put quotation marks around ^a.
X
X
X13) How do I reference command `foo' from within function `foo'?
X
X The command `command foo' does just that. You don't need this with
X aliases, but you do with functions. Note that the error message
X zsh: job table full or recursion limit exceeded
X is a good sign that you tried calling `foo' in function `foo' without
X using `command'.
X
X
X14) I don't have root access: how do I make zsh my login shell?
X
X Unfortunately, on many machines you can't use `chsh' to change your
X shell unless the name of the shell is contained in /etc/shells, so if
X you have your own copy of zsh you need some sleight-of-hand to use it
X when you log on. (Simply typing `zsh' is not really a solution since
X you still have your original login shell waiting for when you exit.)
X
X The basic idea is to use `exec <zsh-path>' to replace the current
X shell with zsh. Often you can do this in a login file such as
X .profile (if your shell is sh or ksh) or .login (if it's csh). Make
X sure you have some way of altering the file (e.g. via FTP) before you
X try this as `exec' is often rather unforgiving.
X
X In .profile, try something like
X [ -f $HOME/bin/zsh ] && exec $HOME/bin/zsh -l
X and in .login, try something like
X if ( -f ~/bin/zsh ) exec ~/bin/zsh -l
X (in each case the -l tells zsh it is a login shell).
X
X It's not a good idea to put this (even without the -l) into .cshrc, at
X least without some tests on what the csh is supposed to be doing, as
X that will cause _every_ instance of csh to turn into a zsh and will
X cause csh scripts (yes, some people write these) to fail. If you want
X to tell xterm to run zsh, change the SHELL environment variable to the
X full path of zsh.
X
X If you like your login shell to appear in the process list as '-zsh',
X you can link zsh to -zsh (e.g. by `ln -s ~/bin/zsh ~/bin/-zsh') and
X change the exec to `exec -zsh'. (Make sure -zsh is in your path.)
X This has the same effect as the `-l' option.
X
X
X15) What bugs are currently known and unfixed?
X
X Here are some of the more well-known ones, very roughly in decreasing
X order of significance. A fuller bug list is now maintained by Carlos
X Carvalho <car...@snfep1.if.usp.br>. Many of these can also be counted
X against differences from ksh in question 5). Bugs marked [2.4] are
X fixed in patches which should appear in early versions of the next
X release.
X
X Unsetting multiply-named functions via a name other than the first
X crashes the shell. [2.4]
X Functions are a bit half-hearted about local variables. [2.4]
X `return' in a trap simply returns from the trap. [2.4]
X `return' in a shell script should act as `exit'.
X Pipelines ending in a while/until/for loop are uninterruptible.
X Certain built-ins won't allow the `VAR=value command ...' assignment.
X The ones that do don't unset VAR after use.
X Killing a command substitution in a loop doesn't kill the loop. [2.4]
X Assigments in a typeset are overenthusiastic about tildes.
X `bindkey -a -[ed]' modifies the alternate keymap.
X `echo !-2:$ !$' substitutes !-2:$ twice.
X The :q modifier doesn't split words and -q and -x don't work for variables.
X `echo -n ^V^J!<return>' causes a shell crash [2.4]
X Command line editing in vi mode:
X `.' doesn't repeat `x' (repeats command before `x').
X `u' can go past original modification point.
X `.' doesn't repeat count for `s', `cw', `dw', `r' (and others?).
X If a command has both file and command completion enabled,
X completion of a word that is a directory finds only commands in
X the directory, not files and commands.
X $_ returns the last unexpanded word from the previous line (not command).
X Autocd won't use globbed filenames and sometimes refuses to work.
X `if (( 1 )) command' and `if (( 1 )) { ...' do not work
X (and related syntax problems).
X The rmstar feature doesn't handle shell variables properly.
X
X
X16) Where do I report bugs, get more info / who's working on zsh?
X
X Zsh is now maintained by a motley collection of enthusiasts who
X subscribe to the mailing list, so any suggestions, complaints,
X questions and matters for discussion should be addressed to:
X zsh-...@cs.uow.edu.au
X (if you want someone to mail you directly, say so). If you wish to
X subscribe to the mailing list, ask
X zsh-r...@cs.uow.edu.au
X which is in the hands of Peter Gray, who also reads the list. It is
X by no means restricted to source-code hackers.
X
X
X17) What's on the wish-list?
X
X `compctl' to be enhanced to shut up tcsh-users.
X Option for glob qualifiers to follow perl syntax.
X Selective expansion of history, variables, globs on <TAB>.
X Option to quote !-history lexically via '' but not "" (hard).
X Binding of external commands to zle functions (arg-passing mechanism??).
X Ksh compatibility could be improved if required.
X
X
XAcknowledgments:
X
XThanks to zsh-list, in particular Bart Schaefer, for suggestions
Xregarding this document; thanks to Jim Mattson for his hard work as
Xarchivist.
END_OF_FILE
if test 21578 -ne `wc -c <'FAQ'`; then
echo shar: \"'FAQ'\" unpacked with wrong size!
fi
# end of 'FAQ'
fi
if test -f 'help/pushd' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/pushd'\"
else
echo shar: Extracting \"'help/pushd'\" \(1305 characters\)
sed "s/^X//" >'help/pushd' <<'END_OF_FILE'
X pushd [ arg ]
X pushd old new
X pushd +-n
X Change the current directory, and push the old current
X directory onto the directory stack. In the first form,
X change the current directory to arg. If arg is not
X specified, change to the second directory on the stack
X (that is, exchange the top two entries), or change to
X the value of HOME if the PUSHD_TO_HOME option is set or
X if there is only one entry on the stack. If arg is -,
X change to the value of OLDPWD, the previous directory.
X If a directory named arg is not found in the current
X directory and arg does not contain a slash, search each


X component of the shell parameter cdpath. If the option
X CDABLEVARS is set, and a parameter named arg exists
X whose value begins with a slash, treat its value as the

X directory. If the option PUSHD_SILENT is not set, the
X directory stack will be printed after a pushd is per-
X formed.
X
X The second form of pushd substitutes the string new for


X the string old in the name of the current directory,
X and tries to change to this new directory.
X

X The third form of pushd is equivalent to popd.
END_OF_FILE
if test 1305 -ne `wc -c <'help/pushd'`; then
echo shar: \"'help/pushd'\" unpacked with wrong size!
fi
# end of 'help/pushd'
fi
if test -f 'src/zle_tricky.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle_tricky.c'\"
else
echo shar: Extracting \"'src/zle_tricky.c'\" \(28258 characters\)
sed "s/^X//" >'src/zle_tricky.c' <<'END_OF_FILE'
X/*
X *
X * zle_tricky.c - expansion and completion


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#define ZLE
X#include "zsh.h"
X#include <pwd.h>
X#ifdef HAS_NIS_PASSWD
X#include <rpc/rpc.h>
X#include <rpcsvc/ypclnt.h>
X#include <rpcsvc/yp_prot.h>
X
X#define PASSWD_FILE "/etc/passwd"
X#define PASSWD_MAP "passwd.byname"
X
Xtypedef struct {
X int len;
X char *s;
X } dopestring;
X#endif
X
Xstatic int we,wb,usemenu,useglob;
X
Xstatic int menub,menue,menuw;
Xstatic Lklist menulist;
Xstatic Lknode menunode;
X
X#define inststr(X) inststrlen((X),-1)
X
Xint usetab() /**/
X{
Xunsigned char *s = line+cs-1;
X
X for (; s >= line && *s != '\n'; s--)
X if (*s != '\t' && *s != ' ')
X return 0;
X return 1;
X}
X
X#define COMP_COMPLETE 0
X#define COMP_LIST_COMPLETE 1
X#define COMP_SPELL 2
X#define COMP_EXPAND 3
X#define COMP_EXPAND_COMPLETE 4
X#define COMP_LIST_EXPAND 5
X#define COMP_ISEXPAND(X) ((X) >= COMP_EXPAND)
X
Xvoid completeword() /**/
X{
X usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
X if (c == '\t' && usetab())
X selfinsert();
X else
X docomplete(COMP_COMPLETE);
X}
X
Xvoid menucompleteword() /**/
X{
X usemenu = 1; useglob = isset(GLOBCOMPLETE);
X if (c == '\t' && usetab())
X selfinsert();
X else
X docomplete(COMP_COMPLETE);
X}
X
Xvoid listchoices() /**/
X{
X usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
X docomplete(COMP_LIST_COMPLETE);
X}
X
Xvoid spellword() /**/
X{
X usemenu = useglob = 0;
X docomplete(COMP_SPELL);
X}
X
Xvoid deletecharorlist() /**/
X{
X usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
X if (cs != ll)
X deletechar();
X else
X docomplete(COMP_LIST_COMPLETE);
X}
X
Xvoid expandword() /**/
X{
X usemenu = useglob = 0;
X if (c == '\t' && usetab())
X selfinsert();
X else
X docomplete(COMP_EXPAND);
X}
X
Xvoid expandorcomplete() /**/
X{
X usemenu = isset(MENUCOMPLETE) || (useglob = isset(GLOBCOMPLETE));
X if (c == '\t' && usetab())
X selfinsert();
X else
X docomplete(COMP_EXPAND_COMPLETE);
X}
X
Xvoid menuexpandorcomplete() /**/
X{
X usemenu = 1; useglob = isset(GLOBCOMPLETE);
X if (c == '\t' && usetab())
X selfinsert();
X else
X docomplete(COMP_EXPAND_COMPLETE);
X}
X
Xvoid listexpand() /**/
X{
X usemenu = isset(MENUCOMPLETE); useglob = isset(GLOBCOMPLETE);
X docomplete(COMP_LIST_EXPAND);
X}
X
Xvoid reversemenucomplete() /**/
X{
X if (!menucmp)
X menucompleteword(); /* better than just feep'ing, pem */
X if (!menucmp) return;
X cs = menub;
X foredel(menue-menub);
X if (menunode == firstnode(menulist))
X menunode = lastnode(menulist);
X else
X menunode = prevnode(menunode);
X inststr(menunode->dat);
X menue = cs;
X}
X
X/*
X * Accepts the current completion and starts a new arg,
X * with the next completions. This gives you a way to accept
X * several selections from the list of matches.
X */
Xvoid acceptandmenucomplete() /**/
X{
Xint t0,t1;
X
X if (!menucmp) {
X feep();
X return;
X }
X spaceinline(1);
X line[cs++] = ' ';
X spaceinline(menub-menuw);
X t1 = cs;
X for (t0 = menuw; t0 != menub; t0++)
X line[cs++] = line[t0];
X menue = menub = cs;
X menuw = t1;
X menucompleteword();
X}
X
Xstatic char *lastmenu = NULL;
Xstatic int lastmenupos = -1;
Xstatic int lincmd,linredir,lastambig;
Xstatic char *cmdstr;
X
Xvoid docomplete(lst) /**/
Xint lst;
X{
Xchar *s;
X
X if (isset(AUTOMENU) && !menucmp && c == '\t' &&
X (lastcmd & ZLE_MENUCMP) && lastambig) usemenu = 1;
X if (menucmp) { do_menucmp(lst); return; }
X if (doexpandhist()) return;
X s = get_comp_string();
X if (s) {
X if (lst == COMP_EXPAND_COMPLETE) {
X char *q = s;
X
X if (*q == Tilde) q++;
X else if (*q == Equals) {
X q = s+1;
X if (gethnode(q,cmdnamtab) || hashcmd(q,pathchecked))
X lst = COMP_EXPAND;
X } else {
X for (; *q && *q != String; q++);
X if (*q == String && q[1] != Inpar) {
X if (getsparam(q+1)) lst = COMP_EXPAND;
X else lst = COMP_COMPLETE;
X }
X q = s;
X }
X if (lst == COMP_EXPAND_COMPLETE) {
X for (; *q; q++)
X if (itok(*q))
X break;
X if (!*q)
X lst = COMP_COMPLETE;
X }
X }
X if (lst == COMP_SPELL) {
X char **x = &s;
X char *q = s;
X for(; *q; q++) if (INULL(*q)) *q = Nularg;
X untokenize(s);
X cs = wb;
X foredel(we-wb);
X /* call the real spell checker, a...@aaii.oz.zu */
X spckword(x, NULL, NULL, !lincmd, 0);
X inststr(*x);
X } else if (COMP_ISEXPAND(lst))
X doexpansion(s,lst,lincmd);
X else {
X docompletion(s,lst,lincmd);
X }
X free(s);
X }
X popheap();
X lexrestore();
X}
X
Xvoid do_menucmp(lst) /**/
Xint lst;
X{
Xchar *s;
X
X if (isset(LASTMENU) && lastmenu) {
X if (COMP_ISEXPAND(lst) || cs != lastmenupos ||
X strcmp((char *) line, lastmenu) != 0) {
X free(lastmenu);
X lastmenu = NULL;
X lastmenupos = -1;
X freemenu();
X }
X }
X if (lst == COMP_LIST_COMPLETE) {
X listmatches(menulist, NULL);
X return;
X }
X cs = menub;
X foredel(menue-menub);
X incnode(menunode);
X if (!menunode)
X menunode = firstnode(menulist);
X s = menunode->dat;
X if (*s == '~' || *s == '=' || *s == '$') {
X spaceinline(1);
X line[cs++] = *s++;
X }
X inststr(s = menunode->dat);
X if (isset(LASTMENU)) {
X if (lastmenu) free(lastmenu);
X lastmenu = ztrdup(UTOSCP(line));
X lastmenupos = cs;
X }
X menue = cs;
X}
X
Xchar *get_comp_string() /**/
X{
Xint t0;
Xunsigned char *s = NULL,*linptr;
X
X linptr = line;
Xstart:
X lincmd = incmdpos;
X linredir = inredir;
X cmdstr = NULL;
X zleparse = 1;
X lexsave();
X hungets(" "); /* KLUDGE! */
X hungets(UTOSCP(linptr));
X strinbeg();
X pushheap();
X do {
X lincmd = incmdpos;
X linredir = inredir;
X ctxtlex();
X if (tok == ENDINPUT) break;
X if (lincmd && tok == STRING) cmdstr = strdup(tokstr);
X } while (tok != ENDINPUT && zleparse);
X t0 = tok;
X if (t0 == ENDINPUT) {
X s = (unsigned char *)ztrdup("");
X we = wb = cs;
X t0 = STRING;
X } else if (t0 == STRING) {
X s = (unsigned char *)ztrdup(tokstr);
X } else if (t0 == ENVSTRING) {
X for (s = (unsigned char *)tokstr; *s && *s != (unsigned char)'='; s++, wb++);
X if (*s) { s++; wb++; t0 = STRING; s = STOUCP(ztrdup(UTOSCP(s))); }
X lincmd = 1;


X }
X hflush();
X strinend();

X errflag = zleparse = 0;
X if (we > ll) we = ll;
X if (t0 == LEXERR && parbegin != -1) {
X linptr += ll+1-parbegin;
X popheap();
X lexrestore();
X goto start;
X }
X if (t0 != STRING) { feep(); return NULL; }
X return (char *)s;
X}
X
Xvoid doexpansion(s,lst,lincmd) /**/
Xchar *s;int lst;int lincmd;
X{
XLklist vl = newlist();
Xchar *ss;
X
X pushheap();
X addnode(vl,s);


X prefork(vl);
X if (errflag)

X goto end;


X postfork(vl,1);
X if (errflag)

X goto end;
X if (empty(vl) || !*(char *) peekfirst(vl)) {
X feep();
X goto end;
X }
X if (lst == COMP_LIST_EXPAND) {
X listmatches(vl,NULL);
X goto end;
X } else if (peekfirst(vl) == s) {
X if (lst == COMP_EXPAND_COMPLETE) {
X docompletion(s,COMP_COMPLETE,lincmd);
X } else
X feep();
X goto end;
X }
X cs = wb;
X foredel(we-wb);
X while (ss = ugetnode(vl)) {
X untokenize(ss);
X inststr(ss);
X#if 0
X if (full(vl)) {
X spaceinline(1);
X line[cs++] = ' ';
X }
X#endif
X spaceinline(1);
X line[cs++] = ' ';
X }
Xend:
X popheap();
X setterm();
X}
X
Xvoid gotword(s) /**/
Xchar *s;
X{
X we = ll+1-inbufct;
X if (cs <= we)
X {
X wb = ll-wordbeg;
X zleparse = 0;
X /* major hack ahead */
X if (wb && line[wb] == '!' && line[wb-1] == '\\')
X wb--;
X }
X}
X
Xvoid inststrlen(s,l) /**/


Xchar *s;int l;
X{

Xchar *t,*u,*v;
X
X t = halloc(strlen(s)*2+2);
X u = s;
X v = t;
X for (; *u; u++)
X {
X if (l != -1 && !l--)
X break;
X if (ispecial(*u))
X if (*u == '\n')
X {
X *v++ = '\'';
X *v++ = '\n';
X *v++ = '\'';
X continue;
X }
X else
X *v++ = '\\';
X *v++ = *u;
X }
X *v = '\0';
X spaceinline(strlen(t));
X strncpy((char *) line+cs,t,strlen(t));
X cs += strlen(t);
X}
X
Xstatic int ambig,haspath,exact;
Xstatic Lklist matches;
Xstatic char *pat,*exactstr;
Xstatic int typechar;
X
Xvoid addmatch(s) /**/
Xchar *s;
X{
X if (full(matches))
X {
X int y = pfxlen(peekfirst(matches),s);
X
X if (y < ambig)
X ambig = y;
X }
X else
X ambig = strlen(s);
X if (!strcmp(pat,s)) { exact = 1; exactstr = pat; }
X addnodeinorder(matches,strdup(s));
X}
X
X
Xvoid addcmdmatch(s,t) /**/


Xchar *s;char *t;
X{

X if (strpfx(pat,s)) addmatch(s);
X}
X
Xvoid addcmddirparam(s,t) /**/


Xchar *s;char *t;
X{

XParam pm = (Param) t;
X
X if (strpfx(pat,s) && pmtype(pm) == PMFLAG_s) {
X t = pm->gets.cfn(pm);
X if (t && *t == '/') addmatch(s);
X }
X}
X
Xvoid addcmdnodis(s,t) /**/


Xchar *s;char *t;
X{

X if (strpfx(pat,s) && ((Cmdnam) t)->type != DISABLED) addmatch(s);
X}
X
X#ifdef HAS_NIS_PASSWD
Xstatic int match_username(status, key, keylen, val, vallen, data)
Xint status;
Xchar *key, *val;
Xint keylen, vallen;
Xdopestring *data;
X{
X if (errflag || status != YP_TRUE) return 1;
X
X if (vallen > keylen && val[keylen] == ':')
X {
X val[keylen] = '\0';
X /* Can't call getpwnam() here; it breaks yp_all() */
X if(strncmp(val,data->s,data->len) == 0) addmatch(val);


X }
X return 0;
X}

X#endif
X
Xvoid maketildelist(s) /**/
Xchar *s;
X{
X#ifdef HAS_NIS_PASSWD
X char domain[YPMAXDOMAIN];
X struct ypall_callback cb;
X dopestring data;
X Lknode n;
X FILE *pwf;
X char buf[BUFSIZ], *p;
X int skipping;
X
X data.s = ++s;
X data.len = strlen(s);
X if(*s == '+' || *s == '-')
X {
X /* We don't want to match any NIS inclusions/exclusions */
X *s = '\0';
X return;
X }
X /* Get potential matches from NIS and cull those without local accounts */
X if (getdomainname(domain, YPMAXDOMAIN) == 0)
X {
X cb.foreach = match_username;
X cb.data = (char *) &data;
X yp_all(domain, PASSWD_MAP, &cb);
X for(n = firstnode(matches); n; incnode(n))
X if(getpwnam(getdata(n)) == NULL) uremnode(matches,n);
X }
X /* Don't forget the non-NIS matches from the flat passwd file */
X if ((pwf = fopen(PASSWD_FILE, "r")) != NULL)
X {
X skipping = 0;
X while (fgets(buf, BUFSIZ, pwf) != NULL)
X {
X if (strchr(buf, '\n') != NULL)
X {
X if (!skipping)
X {
X if (strncmp(buf,data.s,data.len) == 0 &&
X (p = strchr(buf, ':')) != NULL)
X {
X *p = '\0';
X addmatch(buf);
X }
X }
X else skipping = 0;
X }
X else skipping = 1;
X }
X fclose(pwf);
X }
X#else
X struct passwd *pwd;
X int len,i;
X
X if (!usernamescached)
X {
X setpwent();
X while((pwd=getpwent()) != NULL && !errflag)
X adduserdir(pwd->pw_name,pwd->pw_dir);
X endpwent();
X usernamescached=1;
X }
X
X s++;
X len = strlen(s);
X
X for(i=0;i<userdirsz;i++)
X {
X if(usernames[i] && userdirs[i] &&
X strncmp(usernames[i],s,len)==0) addmatch(usernames[i]);
X }
X#endif


X *s = 0;
X}

X
X/*
X * opendir that handles '~' and '=' and '$'.
X * orig. by a...@aaii.oz.au, mod. by pf
X */
XDIR *OPENDIR(s)
Xchar *s;
X{
X if (*s != '~' && *s != '=' && *s != '$')
X return(opendir(s));
X s = strdup(s);
X *s = (*s == '=') ? Equals : (*s == '~') ? Tilde : String;
X singsub(&s);
X return(opendir(s));
X}
Xchar *dirname(s)
Xchar *s;
X{
X if (*s == '~' || *s == '=' || *s == '$') {
X s = strdup(s);
X *s = (*s == '=') ? Equals : (*s == '~') ? Tilde : String;
X singsub(&s);
X }
X return(s);
X}
X
Xint Isdir(s) /**/
Xchar *s;
X{
Xstruct stat sbuf;
X
X if (!*s) return 0;
X if (stat(s,&sbuf) == -1) return 0;
X return S_ISDIR(sbuf.st_mode);
X}
X
X/* this will work whether s is tokenized or not */
Xint isdir(t,s) /**/
Xchar *t;char *s;


X{
Xchar buf[MAXPATHLEN];
X

X if (typechar != '$')
X sprintf(buf,"%s/%s",(s) ? s : ".",t);
X else
X sprintf(buf,"$%s",t);
X s = buf;
X if (*s != '~' && *s != '=' && *s != Tilde && *s != Equals &&
X *s != '$' && *s != String)
X return(Isdir(s));
X s = strdup(s);
X if (*s == '~' || *s == '=' || *s == '$')
X *s = (*s == '=') ? Equals : (*s == '~') ? Tilde : String;
X singsub(&s);
X return(Isdir(s));
X}
X
X#define SLASH_YES 0
X#define SLASH_NO 1
X#define SLASH_MAYBE 2
X
Xint slashflag;
Xint addedstar;
Xchar *pathprefix;
X
Xvoid docompletion(s,lst,incmd) /**/
Xchar *s;int lst;int incmd;
X{
Xchar *tokorigs = NULL;
Xchar *origs;
XCompctl cc;
Xchar *u;
Xchar *pfx = s;
X
X slashflag = SLASH_MAYBE;
X addedstar = 0;
X lastambig = 0;
X
X heapalloc();
X pushheap();
X if (useglob)
X tokorigs = strdup(s);
X untokenize(s);
X origs = strdup(s);
X matches = newlist();
X if (incmd)
X cc = &cc_compos;
X else if (linredir || !(cmdstr && (cc = gethnode(cmdstr,compctltab))))
X cc = &cc_default;
X exact = 0;
X if (cc->mask & CC_COMMPATH) gen_matches_reg(s,1,(cc->mask & CC_FILES));
X else if (cc->mask & CC_FILES) gen_matches_reg(s,0,1);
X else {
X haspath = 0;
X slashflag = SLASH_NO;
X }
X if (cc->mask & (CC_FILES|CC_COMMPATH)) {
X /* only do "globbed" completion if regular completion fails.
X pem, 7Oct91 */
X if ((empty(matches) || errflag) && useglob) {
X gen_matches_glob(tokorigs,incmd);
X /*
X * gen_matches_glob changes the insert line to be correct up
X * to the match, so the prefix string must be "". ash, 7Oct91
X */


X *s = 0;
X }

X }
X pat = s;
X if ((cc->mask & CC_HOSTS) && !haspath) {
X char **x;
X for (x = hosts; *x; x++) addcmdmatch(*x,NULL);
X
X/* we now try to do expansion if there is an @ symbol in the string */
X
X haspath = 0;
X for (u = s+strlen(s); u >= s; u--)
X if (*u == '@' ) break;
X if (u >= s) {
X typechar = *u;
X *u++ = '\0';
X haspath = 1;
X } else u = s;
X pat = u;
X if (typechar == '@' && haspath ) {
X char **x;
X slashflag = SLASH_NO;
X for (x = hosts; *x; x++) addcmdmatch(*x,NULL);
X }
X }
X pat = s;
X if ((cc->mask & CC_OPTIONS) && !haspath) {
X struct option *o;
X for (o = optns; o->name; o++) addcmdmatch(o->name,NULL);
X }
X if ((cc->mask & CC_VARS) && !haspath) listhtable(paramtab,addcmdmatch);
X if ((cc->mask & CC_BINDINGS) && !haspath) {
X int t0;
X for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
X if (*zlecmds[t0].name) addcmdmatch(zlecmds[t0].name,NULL);
X }
X if (cc->mask & CC_USRKEYS) {
X char **usr = get_user_var(cc->keyvar);
X if (usr) while (*usr) addcmdmatch(*usr++,NULL);
X }
X if (lst != COMP_LIST_COMPLETE) do_fignore(origs);
X if (empty(matches) || errflag) {
X feep();
X } else if (lst == COMP_LIST_COMPLETE) {
X listmatches(matches,
X unset(LISTTYPES) ? NULL :
X (haspath) ? pathprefix : "./");
X } else if (nextnode(firstnode(matches))) {
X do_ambiguous(pfx);
X } else {
X do_single(pfx);
X }
X ll = strlen((char *) line);
X setterm();
X popheap();
X permalloc();
X}
X
Xchar **get_user_var(nam) /**/
Xchar *nam;
X{
X return (nam) ? getaparam(nam) : NULL;
X}
X
Xvoid gen_matches_glob(s,incmd) /**/
Xchar *s;int incmd;
X{
Xchar *pt,*u;
Xint hasp = 0;
XDIR *d;
Xstruct direct *de;
X
X /*
X * Find the longest prefix string without any
X * chars special to glob - ash.
X */
X for (pt = s; *pt; pt++) {
X if (pt == s && (*pt == Tilde || *pt == Equals)) continue;
X if (ispecial(*pt) || itok(*pt)) break;
X }
X for (; pt > s && *pt != '/'; pt--) ;
X if (*pt == '/') {
X *pt = 0;
X u = pt + 1;
X wb += strlen(s);
X hasp = 1;
X } else u = s;
X if (!hasp && (*s == Tilde || *s == Equals)) {
X /* string contains only ~xx, so do tilde expansion */
X maketildelist(s);
X wb++;
X pathprefix = s;
X slashflag = SLASH_YES;
X } else if (incmd && !hasp) {
X slashflag = SLASH_NO;
X pat = s;
X listhtable(aliastab ,addcmdmatch);
X if (isset(HASHLISTALL)) fullhash();
X listhtable(cmdnamtab,addcmdnodis);
X if (isset(AUTOCD)) listhtable(paramtab ,addcmddirparam);
X if (d = opendir(".")) {
X char *q;
X
X readdir(d); readdir(d);
X while ((de = readdir(d)) && !errflag)
X if (strpfx(pat,q = de->d_name) &&
X (*q != '.' || *u == '.' || isset(GLOBDOTS)))
X addmatch(q);
X closedir(d);
X }
X } else {
X int commonprefix = 0;
X char *prefix;
X Lknode n;
X int nonomatch = isset(NONOMATCH);
X
X opts[NONOMATCH] = 1;
X if (hasp) {
X /* Find the longest common prefix string
X * after globbing the input. All expansions
X * '~foo/bar/*' will turn into something like
X * /tmp_mnt/hosts/somehost/home/foo/...
X * We will remove this common prefix from the matches.
X * ash, 7 May '91
X */
X pathprefix = s;
X addnode(matches,s);
X prefork(matches);
X if (!errflag) postfork(matches,1);
X if (!errflag) {
X prefix = peekfirst(matches);
X if (prefix) commonprefix = strlen(prefix) + 1;
X *pt = '/';
X }
X }
X if (s[strlen(s) - 1] == '/') {
X /* if strings ends in a '/' always add a '*' */
X s = dyncat(s,"x");
X s[strlen(s)-1] = Star;
X addedstar = 1;
X }
X matches = newlist();
X addnode(matches,s);
X prefork(matches);
X if (!errflag) postfork(matches,1);
X opts[NONOMATCH] = nonomatch;
X if (errflag || empty(matches) || !nextnode(firstnode(matches))) {
X /* if there were no matches (or only one)
X add a trailing * and try again */
X s = dyncat(s,"x");
X s[strlen(s)-1] = Star;
X addedstar = 1;
X matches = newlist();
X addnode(matches,s);
X prefork(matches);
X if (errflag) return;
X postfork(matches,1);


X if (errflag) return;
X }

X /* remove the common prefix from all the matches */
X if (commonprefix)
X for (n = firstnode(matches); n; incnode(n))
X n->dat = (char *) n->dat+commonprefix;
X s = pt;


X *s = 0;
X }

X}
X
Xvoid gen_matches_reg(s,incmd,regfiles) /**/
Xchar *s;int incmd;int regfiles;
X{
Xchar *u;
XDIR *d;
Xstruct direct *de;
X
X haspath = 0;
X for (u = s+strlen(s); u >= s; u--)
X if (*u == '/' || *u == '@' || *u == '$') break;
X if (u >= s) {
X typechar = *u;
X *u++ = '\0';
X haspath = 1;
X } else if (*s == '=') {
X typechar = '=';
X *s = '\0'; u = s+1;
X haspath = 1;
X } else u = s;
X pat = u;
X if (typechar == '$' && haspath) {
X /* slashflag = SLASH_NO; */
X listhtable(paramtab,addcmdmatch);
X } else if (typechar == '=' && haspath) {
X slashflag = SLASH_NO;
X if (isset(HASHLISTALL)) fullhash();
X listhtable(cmdnamtab,addcmdnodis);
X } else if (typechar == '@' && haspath) {
X char **x;
X slashflag = SLASH_NO;
X for (x = hosts; *x; x++) addcmdmatch(*x,NULL);
X } else if (*s == '~' && !haspath) {
X maketildelist(s);
X pathprefix = s;
X slashflag = SLASH_YES;
X } else if (incmd && !haspath) {
X slashflag = SLASH_NO;
X listhtable(aliastab ,addcmdmatch);
X if (isset(HASHLISTALL)) fullhash();
X listhtable(cmdnamtab,addcmdnodis);
X if (isset(AUTOCD) && isset(CDABLEVARS))
X listhtable(paramtab ,addcmddirparam);
X if (d = opendir(".")) {
X char *q;
X struct stat buf;
X
X readdir(d); readdir(d);
X if (regfiles) {
X while ((de = readdir(d)) && !errflag)
X if (strpfx(pat,q = de->d_name) &&
X (*q != '.' || *u == '.' || isset(GLOBDOTS))) addmatch(q);
X } else if (isset(AUTOCD)) {
X while ((de = readdir(d)) && !errflag)
X if (strpfx(pat,q = de->d_name) &&
X (*q != '.' || *u == '.' || isset(GLOBDOTS)) &&
X stat(q,&buf) >= 0 &&
X (buf.st_mode & S_IEXEC) == S_IEXEC) addmatch(q);
X } else {
X while ((de = readdir(d)) && !errflag)
X if (strpfx(pat,q = de->d_name) &&
X (*q != '.' || *u == '.' || isset(GLOBDOTS)) &&
X stat(q,&buf) >= 0 &&
X (buf.st_mode & (S_IFMT|S_IEXEC)) == (S_IFREG|S_IEXEC))
X addmatch(q);
X }
X closedir(d);
X }
X } else if (d = OPENDIR(pathprefix =
X ((haspath || *s == '~') ? ((*s) ? s : "/") : "."))) {
X char *q,buf2[MAXPATHLEN];
X struct stat buf;
X char dn[MAXPATHLEN];
X
X strcpy(dn,dirname(pathprefix));
X readdir(d); readdir(d);
X while ((de = readdir(d)) && !errflag)
X if (strpfx(pat,q = de->d_name) &&
X (*q != '.' || *u == '.' || isset(GLOBDOTS))) {
X if (incmd) {
X sprintf(buf2,"%s/%s",dn,q);
X if (stat(buf2,&buf) < 0 ||
X (buf.st_mode & S_IEXEC) == S_IEXEC) {
X addmatch(q);
X }
X } else {
X addmatch(q);
X }
X }
X closedir(d);
X }
X}
X
Xvoid do_fignore(origstr) /**/
Xchar *origstr;
X{
X if (full(matches) && nextnode(firstnode(matches))) {
X Lknode z,zn;
X
X ambig = 1000;
X for (z = firstnode(matches); z; z = zn) {
X char *q = getdata(z);
X int namlen = strlen(q);
X int slen = strlen(origstr);
X int slpt;
X char **pt = fignore;
X
X zn = nextnode(z);
X for (; *pt; pt++) {
X /* We try to be smart here and override the
X fignore variable if the user has explicity
X used the ignored prefix, pem, 7 May 1991 */
X slpt = strlen(*pt);
X if (!addedstar && slen > slpt &&
X strcmp(origstr+slen-slpt, *pt) == 0)
X continue;
X if (slpt < namlen && !strcmp(q+namlen-slpt,*pt)) {
X uremnode(matches,z);
X break;
X }
X }
X if (!*pt) {
X int y = pfxlen(peekfirst(matches),q);
X if (y < ambig) ambig = y;


X }
X }
X }
X}
X

Xvoid do_ambiguous(s) /**/
Xchar *s;
X{
X lastambig = 1;
X if (usemenu) { do_ambig_menu(s); return; }
X if (useglob) {
X feep();
X if (isset(AUTOLIST))
X listmatches(matches,
X unset(LISTTYPES) ? NULL : (haspath) ? pathprefix : "./");
X return;
X }
X cs = wb;
X foredel(we-wb);
X if (*s == '~' || *s == '=' || *s == '$') {
X spaceinline(1);
X line[cs++] = *s++;
X }
X if (haspath) {
X inststr(s);
X spaceinline(1);
X line[cs++] = typechar;
X }
X if (isset(RECEXACT) && exact) {
X lastambig = 0;
X if ((*pat == '~' || *pat == '=' || *pat == '$') && !haspath) {
X spaceinline(1);
X line[cs++] = *s++;
X }
X inststr(exactstr);
X spaceinline(1);
X switch (slashflag) {
X case SLASH_YES: line[cs++] = '/'; break;
X case SLASH_NO : line[cs++] = ' '; break;
X case SLASH_MAYBE: line[cs++] =
X isdir(exactstr,pathprefix) ? '/' : ' '; break;
X }
X return;
X }
X s = peekfirst(matches);
X if ((*s == '~' || *s == '=' || *s == '$') && !haspath) {
X spaceinline(1);
X line[cs++] = *s++;
X ambig--;
X }
X inststrlen(s,ambig);
X refresh();
X if (isset(AUTOLIST)) {
X if (unset(NOLISTBEEP)) feep();
X listmatches(matches,
X unset(LISTTYPES) ? NULL : (haspath) ? pathprefix : "./");
X } else feep();
X}
X
Xvoid do_single(s) /**/
Xchar *s;
X{
X cs = wb;
X foredel(we-wb);
X if (*s == '~' || *s == '=' || *s == '$') {
X spaceinline(1);
X line[cs++] = *s++;
X }
X if (haspath) {
X inststr(s);
X spaceinline(1);
X line[cs++] = typechar;
X }
X s = peekfirst(matches);
X if ((*s == '~' || *s == '=' || *s == '$') && !haspath) {
X spaceinline(1);
X line[cs++] = *s++;
X }
X inststr(s);
X spaceinline(1);
X switch (slashflag) {
X case SLASH_YES: line[cs++] = '/'; break;
X case SLASH_NO : line[cs++] = ' '; break;
X case SLASH_MAYBE: line[cs++] = isdir(s,pathprefix) ? '/' : ' '; break;
X }
X if (isset(AUTOREMOVESLASH) && line[cs-1] == '/') addedslash = 1;
X}
X
Xvoid do_ambig_menu(s) /**/
Xchar *s;
X{
X menucmp = 1;
X if (isset(MENUCOMPLETEBEEP)) feep();
X cs = wb;
X menuw = cs;
X foredel(we-wb);
X if (*s == '~' || *s == '=' || *s == '$') {
X spaceinline(1);
X line[cs++] = *s++;
X }
X if (haspath) {
X inststr(s);
X spaceinline(1);
X line[cs++] = typechar;
X }
X menub = cs;
X s = peekfirst(matches);
X if ((*s == '~' || *s == '=' || *s == '$') && !haspath) {
X spaceinline(1);
X line[cs++] = *s++;
X }
X inststr(s);
X menue = cs;
X permalloc();
X menulist = duplist(matches,(VFunc)ztrdup);
X heapalloc();
X menunode = firstnode(menulist);
X permalloc();
X if (isset(LASTMENU)) {
X if (lastmenu)
X free(lastmenu);
X lastmenu = ztrdup(UTOSCP(line));
X lastmenupos = cs;
X }
X}
X
Xint strpfx(s,t) /**/
Xchar *s;char *t;


X{
X while (*s && *s == *t) s++,t++;

X return !*s;
X}
X
Xint pfxlen(s,t) /**/


Xchar *s;char *t;
X{

Xint i = 0;
X
X while (*s && *s == *t) s++,t++,i++;
X return i;
X}
X
Xvoid listmatches(l,apps) /**/
XLklist l;char *apps;
X{
Xint longest = 1,fct,fw = 0,colsz,t0,t1,ct;
XLknode n;
Xchar **arr,**ap;
X
X trashzle();
X ct = countnodes(l);
X if (listmax && ct > listmax)
X {
X fprintf(stdout,"zsh: do you wish to see all %d possibilities? ",ct);
X fflush(stdout);
X if (getquery() != 'y')
X return;
X }
X ap = arr = alloc((countnodes(l)+1)*sizeof(char **));
X for (n = firstnode(l); n; incnode(n))
X *ap++ = getdata(n);
X *ap = NULL;
X for (ap = arr; *ap; ap++)
X if (strlen(*ap) > longest)
X longest = strlen(*ap);
X if (apps)
X {
X apps = strdup(apps);
X if (*apps == '~')
X *apps = Tilde;
X else if (*apps == '=')
X *apps = Equals;
X else if (*apps == '$')
X *apps = String;
X singsub(&apps);
X longest++;
X }
X qsort((vptr)arr,ct,sizeof(char *),
X (int (*) DCLPROTO((const void *, const void *)))forstrcmp);
X fct = (columns-1)/(longest+2);
X if (fct == 0)
X fct = 1;
X else
X fw = (columns-1)/fct;
X colsz = (ct+fct-1)/fct;
X for (t1 = 0; t1 != colsz; t1++)
X {
X ap = arr+t1;
X if (apps)
X {
X do
X {
X int t2 = strlen(*ap)+1;
X char pbuf[MAXPATHLEN];
X struct stat buf;
X
X printf("%s",*ap);
X sprintf(pbuf,"%s/%s",apps,*ap);
X if (lstat(pbuf,&buf)) putchar(' ');
X else switch (buf.st_mode & S_IFMT) /* screw POSIX */
X {
X case S_IFDIR: putchar('/'); break;
X#ifdef S_IFIFO
X case S_IFIFO: putchar('|'); break;
X#endif
X case S_IFCHR: putchar('%'); break;
X case S_IFBLK: putchar('#'); break;
X#ifdef S_IFLNK
X case S_IFLNK: putchar(
X (access(pbuf,F_OK) == -1) ? '&' : '@'); break;
X#endif
X#ifdef S_IFSOCK
X case S_IFSOCK: putchar('='); break;
X#endif
X default:
X if (buf.st_mode & 0111)
X putchar('*');
X else
X putchar(' ');
X break;
X }
X for (; t2 < fw; t2++) putchar(' ');
X for (t0 = colsz; t0 && *ap; t0--,ap++);
X }
X while (*ap);
X }
X else
X do
X {
X int t2 = strlen(*ap);
X
X printf("%s",*ap);
X for (; t2 < fw; t2++) putchar(' ');
X for (t0 = colsz; t0 && *ap; t0--,ap++);
X }
X while (*ap);


X putchar('\n');
X }

X resetneeded = 1;
X fflush(stdout);
X}
X
Xvoid selectlist(l) /**/
XLklist l;
X{
Xint longest = 1,fct,fw = 0,colsz,t0,t1,ct;
XLknode n;
Xchar **arr,**ap;
X
X trashzle();
X ct = countnodes(l);
X ap = arr = alloc((countnodes(l)+1)*sizeof(char **));
X for (n = firstnode(l); n; incnode(n))
X *ap++ = getdata(n);
X *ap = NULL;
X for (ap = arr; *ap; ap++)
X if (strlen(*ap) > longest)
X longest = strlen(*ap);
X t0 = ct;
X longest++;
X while (t0)
X t0 /= 10, longest++;
X fct = (columns-1)/(longest+3); /* to compensate for added ')' */
X if (fct == 0)
X fct = 1;
X else
X fw = (columns-1)/fct;
X colsz = (ct+fct-1)/fct;
X for (t1 = 0; t1 != colsz; t1++) {
X ap = arr+t1;
X do {
X int t2 = strlen(*ap)+2,t3;
X
X fprintf(stderr,"%d) %s",t3 = ap-arr+1,*ap);
X while (t3) t2++,t3 /= 10;
X for (; t2 < fw; t2++) fputc(' ',stderr);
X for (t0 = colsz; t0 && *ap; t0--,ap++);
X } while (*ap);


X fputc('\n',stderr);
X }

X
X/* Below is a simple attempt at doing it the Korn Way..
X ap = arr;
X t0 = 0;
X do
X {
X t0++;
X fprintf(stderr,"%d) %s\n",t0,*ap);
X ap++;
X }
X while (*ap);*/
X resetneeded = 1;
X fflush(stderr);
X}
X
Xint doexpandhist() /**/
X{
Xunsigned char *cc,*ce;
Xint t0,oldcs,oldll;
X
X for (cc = line, ce = line+ll; cc < ce; cc++)
X if (*cc == '\\' && cc[1])
X cc++;
X else if (*cc == bangchar ||
X (*cc == hatchar && *line == hatchar && cc != line))
X break;
X if (*cc == bangchar && cc[1] == '"') return 0;
X if (cc == ce) return 0;
X oldcs = cs;
X oldll = ll;
X zleparse = 1;
X lexsave();
X hungets(UTOSCP(line));
X strinbeg();
X pushheap();
X ll = cs = 0;
X for(;;)
X {
X t0 = hgetc();
X if (lexstop)
X break;
X spaceinline(1);
X line[cs++] = t0;
X }
X hflush();
X popheap();
X strinend();
X errflag = zleparse = 0;
X t0 = histdone;
X lexrestore();
X line[ll = cs] = '\0';
X if (ll == oldll) cs = oldcs;


X return t0;
X}
X

Xvoid magicspace() /**/
X{
X c = ' ';
X selfinsert();
X doexpandhist();
X}
X
Xvoid expandhistory() /**/
X{
X if (!doexpandhist())
X feep();
X}
X
Xstatic int cmdwb,cmdwe;
X
Xchar *getcurcmd() /**/
X{
Xint lincmd;
Xchar *s = NULL;
X
X zleparse = 1;
X lexsave();
X hungets(" "); /* KLUDGE! */
X hungets(UTOSCP(line));
X strinbeg();
X pushheap();
X do {
X lincmd = incmdpos;
X ctxtlex();
X if (tok == ENDINPUT) break;
X if (tok == STRING && lincmd) {
X if (s) free(s);
X s = ztrdup(tokstr);
X cmdwb = ll-wordbeg; cmdwe = ll+1-inbufct;
X }
X } while (tok != ENDINPUT && zleparse);
X hflush();
X popheap();
X strinend();
X errflag = zleparse = 0;
X lexrestore();


X return s;
X}
X

Xvoid processcmd() /**/
X{
Xchar *s,*t;
X
X s = getcurcmd();
X if (!s) { feep(); return; }
X t = zlecmds[bindk].name;
X mult = 1;
X pushline();
X sizeline(strlen(s)+strlen(t)+1);
X strcpy((char *) line,t);
X strcat((char *) line," ");
X cs = ll = strlen((char *) line);
X inststr(s);
X free(s);
X done = 1;
X}
X
Xvoid expandcmdpath() /**/
X{
Xint oldcs = cs;
Xchar *s,*str;
X
X s = getcurcmd();
X if (!s) { feep(); return; }
X str = findcmd(s);
X free(s);
X if (!str) { feep(); return; }
X cs = cmdwb;
X foredel(cmdwe-cmdwb);
X spaceinline(strlen(str));
X strncpy((char *) line+cs,str,strlen(str));
X cs = oldcs;
X if (cs >= cmdwe) cs += cmdwe-cmdwb+strlen(str);
X if (cs > ll) cs = ll;
X free(str);
X}
X
Xvoid freemenu() /**/
X{
X if (menucmp && (unset(LASTMENU) || lastmenu == NULL)) {
X menucmp = 0;
X freetable(menulist,freestr);
X }
X}
X
Xint inarray(s,a) /**/
Xchar *s; char **a;
X{
X for (; *a; a++) if (!strcmp(*a,s)) return 1;


X return 0;
X}
X

END_OF_FILE
if test 28258 -ne `wc -c <'src/zle_tricky.c'`; then
echo shar: \"'src/zle_tricky.c'\" unpacked with wrong size!
fi
# end of 'src/zle_tricky.c'
fi
echo shar: End of archive 13 \(of 22\).
cp /dev/null ark13isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:26:01 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 64
Archive-name: zsh/part14

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: help/case src/glob.c src/hist.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:54 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 14 (of 22)."'
if test -f 'help/case' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/case'\"
else
echo shar: Extracting \"'help/case'\" \(398 characters\)
sed "s/^X//" >'help/case' <<'END_OF_FILE'
X case word in [ pattern ) list ;; ] ... esac
X Execute the list associated with the first pattern
X that matches word, if any. The form of the pat-
X terns is the same as that used for filename gen-
X eration. See Filename Generation below.
X
X case word { [ pattern ) list ;; ] ... }
X Another form of case.
END_OF_FILE
if test 398 -ne `wc -c <'help/case'`; then
echo shar: \"'help/case'\" unpacked with wrong size!
fi
# end of 'help/case'
fi
if test -f 'src/glob.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/glob.c'\"
else
echo shar: Extracting \"'src/glob.c'\" \(26147 characters\)
sed "s/^X//" >'src/glob.c' <<'END_OF_FILE'
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#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#ifdef ULTRIX
Xtypedef struct stat *Statptr; /* This makes the Ultrix compiler happy. Go figure. */
X#endif
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 qualamc[QUALCT];
Xstatic int qualrange[QUALCT];
Xstatic int qualct;
Xstatic int range, amc;
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);
Xchar *str; /* the pattern */
Xint sl; /* length of the pattern */
XComplist q; /* pattern after parsing */
Xchar *ostr = getdata(*np); /* the pattern before the parser chops it up */
X
X heapalloc();
X str = strdup(ostr);
X lastalloc();
X sl = strlen(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 = 0;
X#ifdef ULTRIX
X int (*func) DCLPROTO((Statptr,long));
X#else
X int (*func) DCLPROTO((struct stat *,long));
X#endif
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 while (*s != Outpar)
X {
X#ifdef ULTRIX
X func = (int (*) DCLPROTO((Statptr,long))) 0;
X#else
X func = (int (*) DCLPROTO((struct stat *,long))) 0;
X#endif
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)STOUC(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)STOUC(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 case 'a': amc = 0; func = qualtime; goto getrange;
X case 'm': amc = 1; func = qualtime; goto getrange;
X case 'c': amc = 2; func = qualtime; goto getrange;
X case 'L': func = qualsize;
Xgetrange:
X if (range = *s == '+' ? 1 : *s == '-' ? -1 : 0) ++s;
X data = qgetnum(&s);
X 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 qualrange[qualct] = range;
X qualamc[qualct] = amc;
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#ifdef ULTRIX
X qualfuncs[qualct] = (int (*) DCLPROTO((Statptr,long))) 0;
X#else
X qualfuncs[qualct] = (int (*) DCLPROTO((struct stat *,long))) 0;
X#endif
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((vptr)&matchbuf[0],matchct,sizeof(char *),
X (int (*) DCLPROTO((const void *, const void *)))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,cmp;
X
X for (; *c == *d && *c; c++,d++);
X cmp = (int) (unsigned char) *c-(int) (unsigned char) *d;
X if (isset(NUMERICGLOBSORT)) {
X for (; c > *b && idigit(c[-1]); c--,d--);
X if(idigit(*c) && idigit(*d)) {
X x1 = atoi(c); x2 = atoi(d);
X if(x1 != x2) return x1-x2;
X }
X }
X return cmp;
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#ifdef ULTRIX
X int (**fptr)DCLPROTO((Statptr,long)) = qualfuncs;
X#else
X int (**fptr)DCLPROTO((struct stat *,long)) = qualfuncs;
X#endif
X int *sptr = qualsense;
X int *rptr = qualrange;
X int *aptr = qualamc;
X long *lptr = qualdata;
X
X if (statted || lstat(s,&buf) >= 0)
X while (*fptr) {
X range = *rptr++;
X amc = *aptr++;
X if (!(!!((*fptr++)(&buf,*lptr++)) ^ *sptr++))
X return;
X }
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 - STOUC(Pound)];
X if (itok(c2 = *p))
X c2 = ztokens[c2 - STOUC(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 (INULL(*s))
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
Xint qualsize(buf,size) /**/
Xstruct stat *buf;long size;
X{
X return(range < 0 ? buf->st_size < size :
X range > 0 ? buf->st_size > size :
X buf->st_size == size);
X}
X
Xint qualtime(buf,days) /**/
Xstruct stat *buf;long days;
X{
X time_t now, diff;
X
X time(&now);
X diff = now - (amc == 0 ? buf->st_atime : amc == 1 ? buf->st_mtime :
X buf->st_ctime);
X diff /= 86400l;
X return(range < 0 ? diff < days :
X range > 0 ? diff > days :
X diff == days);
X}
END_OF_FILE
if test 26147 -ne `wc -c <'src/glob.c'`; then
echo shar: \"'src/glob.c'\" unpacked with wrong size!
fi
# end of 'src/glob.c'
fi
if test -f 'src/hist.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/hist.c'\"
else
echo shar: Extracting \"'src/hist.c'\" \(24223 characters\)
sed "s/^X//" >'src/hist.c' <<'END_OF_FILE'
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 && chline && (!(errflag || lexstop) || c == HISTSPACE)) {
X if (c == '!' && unset(NOBANGHIST)) hwaddc('\\');
X *hptr++ = c;
X if (hptr-chline >= hlinesz) {
X int ll,flag = 0,oldsiz = hlinesz;
X
X ll = hptr-hlastw;
X if (curhistent->lex == chline) flag = 1;
X chline = hp_realloc(&hp_lex,chline,oldsiz,hlinesz = oldsiz+16);
X if (flag) curhistent->lex = chline;
X hptr = chline+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 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 ((unsigned) *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 }
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 = NULL,*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,0);
X else
X {
X int foo;
X
X pmpt = (unsigned char *)putprompt(prompt,&plen,0);
X pmpt2 = (unsigned char *)((rprompt) ? putprompt(rprompt,&foo,0) : 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 chline */
X
Xvoid hungetc(c) /**/
Xint c;
X{
X if (lexstop)
X return;
X if (hlastw) {
X if (hlastw == hptr)
X zerr("hungetc attempted at buffer start",NULL,0);
X else {
X hptr--;
X if (*hptr == '!' && unset(NOBANGHIST)) hptr--;
X }
X }
X hungetch(c);
X}
X
Xvoid hungetch(c) /**/
Xint c;
X{
X if (lexstop)
X return;
X if (inbufct == inbufsz)
X {
X hungets(" ");
X *inbufptr = c;
X }
X else
X {
X *--inbufptr = c;
X inbufct++;
X }
X}
X
X/* begin reading a string */
X
Xvoid strinbeg() /**/
X{
X strin = 1;
X hbegin();
X lexinit();
X}
X
X/* done reading a string */
X
Xvoid strinend() /**/
X{
X strin = 0;
X isfirstch = 1;
X histdone = 0;
X hend();
X}
X
X/* stuff a whole file into the input queue and print it */
X
Xint stuff(fn) /**/
Xchar *fn;
X{
XFILE *in;
Xchar *buf;
Xint len;
X
X if (!(in = fopen(fn,"r")))
X {
X zerr("can't open %s",fn,0);
X return 1;
X }
X fseek(in,0,2);
X len = ftell(in);
X fseek(in,0,0);
X buf = alloc(len+1);
X if (!(fread(buf,len,1,in)))
X {
X zerr("read error on %s",fn,0);
X fclose(in);
X free(buf);
X return 1;
X }
X fclose(in);
X buf[len] = '\0';
X fwrite(buf,len,1,stdout);
X hungets(buf);


X return 0;
X}
X

X/* flush input queue */
X
Xvoid hflush() /**/
X{
X inbufptr += inbufct;
X inbufct = 0;
X}
X
X/* initialize the history mechanism */
X
Xvoid hbegin() /**/
X{
X isfirstln = isfirstch = 1;
X histremmed = errflag = histdone = spaceflag = 0;
X stophist = !interact || isset(NOBANGHIST) || unset(SHINSTDIN);
X lithist = isset(HISTLIT);
X chline = hptr = hp_alloc(&hp_lex,hlinesz = 16);
X curhistent = gethistent(curhist);
X if (!curhistent->ftim) curhistent->ftim = time(NULL);
X if (interact && isset(SHINSTDIN) && !strin) {
X inittty();
X defev = curhist++;
X if (curhist-histsiz >= 0) gethistent(curhist-histsiz)->lex = NULL;
X if (curhist-lithistsiz >= 0) gethistent(curhist-lithistsiz)->lit = NULL;
X curhistent = gethistent(curhist);
X hp_purge(hp_lex,curhist-histsiz);
X hp_purge(hp_lit,curhist-lithistsiz);
X curhistent->lex = chline;
X *(curhistent->lit = hp_alloc(&hp_lit,1)) = '\0';
X } else
X histremmed = 1;
X}
X
Xvoid inittty() /**/
X{
X attachtty(mypgrp);
X}
X
X/* say we're done using the history mechanism */
X
Xint hend() /**/
X{
Xint flag,save = 1;
XHistent he;
X
X if (!chline)
X return 1;
X if (!interact || strin || unset(SHINSTDIN)) {
X hp_free(hp_lex,chline,hlinesz);
X return 1;
X }
X flag = histdone;
X histdone = 0;
X if (hptr < chline+2)
X save = 0;
X else {
X char *s,*t;
X
X s = curhistent->lit;
X if (*s && *(t = s+strlen(s)-1) == HISTSPACE) *t = '\0';
X hptr[-1] = '\0';
X if (hptr[-2] == '\n')
X if (chline[1]) {
X if (hptr[-3] == HISTSPACE) hptr[-3] = '\0';
X } else save = 0;
X he = gethistent(curhist-1);
X if (!strcmp(chline,"\n") ||
X (isset(HISTIGNOREDUPS) && he->lex && !strcmp(he->lex,chline)) ||
X (isset(HISTIGNORESPACE) && spaceflag))
X save = 0;
X }
X if (flag & (HISTFLAG_DONE|HISTFLAG_RECALL)) {
X char *ptr,*p;
X p = ptr = ztrdup(chline);
X for (;*p;p++) if (*p == HISTSPACE) *p = ' ';
X if ((flag & (HISTFLAG_DONE|HISTFLAG_RECALL)) == HISTFLAG_DONE) {
X fprintf(stderr,"%s\n",ptr);
X fflush(stderr);
X }
X if (flag & HISTFLAG_RECALL) {
X permalloc();
X pushnode(bufstack,ptr);
X lastalloc();
X save = 0;
X } else free(ptr);
X }
X curhistent->stim = time(NULL);
X curhistent->ftim = 0L;
X curhistent->flags = 0;
X if (!save) remhist();
X if (chline && !curhistent->lex) hp_free(hp_lex,chline,hlinesz);
X chline = NULL;
X return !(flag & HISTFLAG_NOEXEC || errflag);
X}
X
X/* remove the current line from the history List */
X
Xvoid remhist() /**/
X{
X if (!histremmed) { histremmed = 1; curhist--; }
X}
X
X/* begin a word */
X
Xvoid hwbegin() /**/
X{
X hlastw = hptr;
X}
X
X/* add a word to the history List */
X
Xchar *hwadd() /**/
X{
Xchar *ret = hlastw;
X
X if (hlastw && chline)
X {
X hwaddc(HISTSPACE);
X if (alstackind || strin)
X if (!(alstackind == 1 && !alstack[0]))


X hptr = hlastw;
X }

X if (alstat == ALSTAT_JUNK)
X alstat = 0;


X return ret;
X}
X

X/* get an argument specification */
X
Xint getargspec(argc,marg) /**/
Xint argc;int marg;
X{
Xint c,ret = -1;
X
X if ((c = hgetch()) == '0')
X return 0;
X if (idigit(c))
X {
X ret = 0;
X while (idigit(c))
X {
X ret = ret*10+c-'0';
X c = hgetch();
X }
X hungetch(c);
X }
X else if (c == '^')
X ret = 1;
X else if (c == '$')
X ret = argc;
X else if (c == '%')
X {
X if (marg == -1)
X {
X herrflush();
X zerr("%% with no previous word matched",NULL,0);
X return -2;
X }
X ret = marg;
X }
X else
X hungetch(c);


X return ret;
X}
X

X/* do ?foo? search */
X
Xint hconsearch(str,marg) /**/
Xchar *str;int *marg;
X{
Xint t0,t1 = 0;
Xchar *s,*hs;
X
X for (t0 = curhist-1; hs = quietgetevent(t0); t0--)
X if (s = ztrstr(hs,str)) {
X while (s != hs) if (*s-- == HISTSPACE) t1++;
X *marg = t1;
X return t0;
X }


X return -1;
X}
X

X/* do !foo search */
X
Xint hcomsearch(str) /**/
Xchar *str;
X{
Xint t0;
Xchar *hs;
X
X for (t0 = curhist-1; hs = quietgetevent(t0); t0--)
X if (!strncmp(hs,str,strlen(str))) return t0;


X return -1;
X}
X

X/* various utilities for : modifiers */
X
Xint remtpath(junkptr) /**/
Xchar **junkptr;
X{
Xchar *str = *junkptr,*cut;
X
X if (cut = strrchr(str,'/')) {
X if (str != cut) *cut = '\0';
X else str[1] = '\0';
X return 1;
X }


X return 0;
X}
X

Xint remtext(junkptr) /**/
Xchar **junkptr;
X{
Xchar *str = *junkptr,*cut;
X
X if ((cut = strrchr(str,'.')) && cut != str)
X {
X *cut = '\0';
X return 1;
X }


X return 0;
X}
X

Xint rembutext(junkptr) /**/
Xchar **junkptr;
X{
Xchar *str = *junkptr,*cut;
X
X if ((cut = strrchr(str,'.')) && cut != str)
X {
X *junkptr = strdup(cut+1); /* .xx or xx? */
X return 1;
X }


X return 0;
X}
X

Xint remlpaths(junkptr) /**/
Xchar **junkptr;
X{
Xchar *str = *junkptr,*cut;
X
X if (cut = strrchr(str,'/'))
X {
X *cut = '\0';
X *junkptr = strdup(cut+1);
X return 1;
X }


X return 0;
X}
X

Xint makeuppercase(junkptr) /**/
Xchar **junkptr;
X{
Xchar *str = *junkptr;
X
X for (; *str; str++)
X *str = tuupper(*str);


X return 1;
X}
X

Xint makelowercase(junkptr) /**/
Xchar **junkptr;
X{
Xchar *str = *junkptr;
X
X for (; *str; str++)
X *str = tulower(*str);


X return 1;
X}
X

Xvoid subst(strptr,in,out,gbal) /**/
Xchar **strptr;char *in;char *out;int gbal;
X{
Xchar *str = *strptr,*cut,*sptr;
Xint off;
X
X while (cut = (char *) ztrstr(str,in)) {
X *cut = '\0';
X sptr = convamps(out,in);
X off = cut-*strptr+strlen(sptr);
X cut += strlen(in);
X *strptr = tricat(*strptr,sptr,cut);
X if (gbal) {
X str = (char *) *strptr+off;
X continue;


X }
X break;
X }
X}
X

Xchar *convamps(out,in) /**/
Xchar *out;char *in;
X{
Xchar *ptr,*ret,*pp;
Xint slen,inlen = strlen(in);
X
X for (ptr = out, slen = 0; *ptr; ptr++,slen++)
X if (*ptr == '\\')
X ptr++;
X else if (*ptr == '&')
X slen += inlen-1;
X ret = pp = alloc(slen+1);
X for (ptr = out; *ptr; ptr++)
X if (*ptr == '\\')
X *pp++ = *++ptr;
X else if (*ptr == '&')
X {
X strcpy(pp,in);
X pp += inlen;
X }
X else
X *pp++ = *ptr;
X *pp = '\0';


X return ret;
X}
X

Xchar *makehstr(s) /**/
Xchar *s;
X{
Xchar *t;


X
X t = s = strdup(s);

X for (; *t; t++)

X if (*t == HISTSPACE)

X *t = ' ';


X return s;
X}
X

Xchar *quietgetevent(ev) /**/
Xint ev;
X{
XHistent ent;
X
X if (ev < firsthist()) return NULL;
X ent = gethistent(ev);
X return (lithist) ? ent->lit : ent->lex;
X}
X
Xchar *getevent(ev) /**/
Xint ev;
X{
Xchar *ret;
X
X ret = quietgetevent(ev);
X if (!ret) {
X herrflush();
X zerr("no such event: %d",NULL,ev);
X }


X return ret;
X}
X

Xint getargc(list) /**/
Xchar *list;
X{
Xint argc = 0;
X
X for (; *list; list++) if (*list == HISTSPACE) argc++;
X return argc;
X}
X
Xchar *getargs(elist,arg1,arg2) /**/
Xchar *elist;int arg1;int arg2;
X{
Xchar *ret = elist,*retn;
Xint acnt = arg2-arg1+1;
X
X while (arg1--)
X while (*ret && *ret++ != HISTSPACE);
X if (!*ret)
X {
X herrflush();
X zerr("no such word in event",NULL,0);
X return NULL;
X }
X retn = ret = strdup(ret);
X while (acnt > 0)
X {
X while (*ret && *ret != HISTSPACE)
X ret++;
X if (*ret == HISTSPACE)
X *ret = ' ';
X else
X break;
X acnt--;
X }
X if (acnt > 1 && !*ret)
X {
X herrflush();
X zerr("no such word in event",NULL,0);
X return NULL;
X }
X *ret = '\0';
X return retn;
X}
X
Xvoid upcase(x) /**/
Xchar **x;
X{
Xchar *pp = *(char **) x;
X


X for (; *pp; pp++)

X *pp = tuupper(*pp);
X}
X
Xvoid downcase(x) /**/
Xchar **x;
X{
Xchar *pp = *(char **) x;
X


X for (; *pp; pp++)

X *pp = tulower(*pp);
X}
X
Xint quote(tr) /**/
Xchar **tr;
X{
Xchar *ptr,*rptr,**str = (char **) tr;
Xint len = 3;
X
X for (ptr = *str; *ptr; ptr++,len++)
X if (*ptr == '\'') len += 3;
X ptr = *str;
X *str = rptr = alloc(len);
X *rptr++ = '\'';
X for (; *ptr; ptr++)
X if (*ptr == '\'') {
X *rptr++ = '\''; *rptr++ = '\\'; *rptr++ = '\''; *rptr++ = '\'';
X } else
X *rptr++ = *ptr;
X *rptr++ = '\'';
X *rptr++ = 0;


X str[1] = NULL;

X return 0;
X}
X

Xint quotebreak(tr) /**/
Xchar **tr;
X{
Xchar *ptr,*rptr,**str = (char **) tr;
Xint len = 3;
X
X for (ptr = *str; *ptr; ptr++,len++)
X if (*ptr == '\'')
X len += 3;
X else if (inblank(*ptr))
X len += 2;
X ptr = *str;
X *str = rptr = alloc(len);
X *rptr++ = '\'';
X for (; *ptr; )
X if (*ptr == '\'') {
X *rptr++ = '\''; *rptr++ = '\\'; *rptr++ = '\''; *rptr++ = '\'';
X ptr++;
X } else if (inblank(*ptr)) {
X *rptr++ = '\''; *rptr++ = *ptr++; *rptr++ = '\'';
X } else
X *rptr++ = *ptr++;
X *rptr++ = '\'';
X *rptr++ = '\0';


X return 0;
X}
X

Xvoid herrflush() /**/
X{
X if (strin)
X hflush();
X else while (lastc != '\n' && !lexstop)
X hgetch();
X}
X
X/* read an arbitrary amount of data into a buffer until stop is found */
X
Xchar *hdynread(stop) /**/
Xint stop;
X{
Xint bsiz = 256,ct = 0,c;
Xchar *buf = zalloc(bsiz),*ptr;
X
X ptr = buf;
X while ((c = hgetch()) != stop && c != '\n' && !lexstop)
X {
X if (c == '\\')
X c = hgetch();
X *ptr++ = c;
X if (++ct == bsiz)
X {


X buf = realloc(buf,bsiz *= 2);

X ptr = buf+ct;
X }
X }
X *ptr = 0;
X if (c == '\n')
X {
X hungetch('\n');
X zerr("delimiter expected",NULL,0);
X free(buf);
X return NULL;
X }


X return buf;
X}
X

Xchar *hdynread2(stop) /**/
Xint stop;
X{
Xint bsiz = 256,ct = 0,c;
Xchar *buf = zalloc(bsiz),*ptr;
X
X ptr = buf;
X while ((c = hgetch()) != stop && c != '\n' && !lexstop)
X {
X if (c == '\n')
X {
X hungetch(c);
X break;
X }
X if (c == '\\')
X c = hgetch();
X *ptr++ = c;
X if (++ct == bsiz)
X {


X buf = realloc(buf,bsiz *= 2);

X ptr = buf+ct;
X }
X }
X *ptr = 0;
X if (c == '\n')
X hungetch('\n');


X return buf;
X}
X

Xvoid inithist() /**/
X{
X hp_lit = zcalloc(sizeof *hp_lit);
X hp_lit->next = NULL;
X hp_lit->ptr = hp_lit->pool = zcalloc(HEAPSIZE);
X hp_lit->free = HEAPSIZE;
X hp_lex = zcalloc(sizeof *hp_lex);
X hp_lex->next = NULL;
X hp_lex->ptr = hp_lex->pool = zcalloc(HEAPSIZE);
X hp_lex->free = HEAPSIZE;
X histentct = (lithistsiz > histsiz) ? lithistsiz : histsiz;
X histentarr = zcalloc(histentct*sizeof *histentarr);
X}
X
Xvoid resizehistents() /**/
X{
Xint newentct,t0,t1,firstlit,firstlex;
XHistent newarr;
X
X newentct = (lithistsiz > histsiz) ? lithistsiz : histsiz;
X newarr = zcalloc(newentct*sizeof *newarr);
X firstlex = curhist-histsiz+1;
X firstlit = curhist-lithistsiz+1;
X t0 = firsthist();
X if (t0 < curhist-newentct) t0 = curhist-newentct;
X t1 = t0 % newentct;
X for (; t0 <= curhist; t0++) {
X newarr[t1] = *gethistent(t0);
X if (t0 < firstlex) newarr[t1].lex = NULL;
X if (t0 < firstlit) newarr[t1].lit = NULL;
X t1++; if (t1 == newentct) t1 = 0;
X }
X free(histentarr);
X histentarr = newarr;
X histentct = newentct;
X}
X
Xchar *hp_alloc(hp,siz) /**/
XHp *hp; int siz;
X{
Xchar *ret;
XHp h = *hp;
X
X if (h->free >= siz) {
X ret = h->ptr;
X h->ptr += siz;
X h->free -= siz;
X return ret;
X }
X#ifdef MEMDEBUG
X fprintf(stderr,"new heap (siz = %d, curhist = %d)\n",siz,curhist);
X#endif
X permalloc();
X h = zalloc(sizeof *h);
X h->next = *hp;
X h->free = (siz > HEAPSIZE) ? siz : HEAPSIZE;
X h->ptr = h->pool = zalloc(h->free);
X h->histno = curhist;
X *hp = h;
X heapalloc();
X return hp_alloc(hp,siz);
X}
X
Xchar *hp_realloc(hp,ptr,oldsiz,newsiz) /**/
XHp *hp; char *ptr; int oldsiz; int newsiz;
X{
XHp h = *hp;
Xint delta = newsiz-oldsiz;
Xchar *ret;
X
X if (h->ptr-oldsiz == ptr && h->free >= delta) {
X h->free -= delta;
X h->ptr += delta;
X return ptr;
X }
X#ifdef MEMDEBUG
X fprintf(stderr,"realloc copy\n");
X#endif
X memcpy(ret = hp_alloc(hp,newsiz),ptr,oldsiz);


X return ret;
X}
X

Xvoid hp_free(h,ptr,siz) /**/
XHp h; char *ptr; int siz;
X{
X if (h->ptr-siz == ptr) {
X h->free += siz;
X h->ptr -= siz;
X }
X}
X
Xchar *hp_concat(old,new) /**/
Xchar *old; char *new;
X{
Xint oldlen,newlen;
X
X oldlen = strlen(old); newlen = strlen(new);
X old = hp_realloc(&hp_lit,old,oldlen+1,oldlen+newlen+1);
X strcpy(old+oldlen,new);
X return old;
X}
X
Xvoid hp_purge(h,lim) /**/
XHp h; int lim;
X{
XHp hlast;
X
X if (!h->next) return;
X while (h->next) { hlast = h; h = h->next; }
X if (hlast->histno <= lim) {
X#ifdef MEMDEBUG
X fprintf(stderr,"purging %d\n",lim);
X#endif
X free(h->pool);
X free(h);
X hlast->next = NULL;
X }
X}
X
Xvoid readhistfile(s,err) /**/
Xchar *s;int err;
X{
Xchar buf[1024];
XFILE *in;
XHistent ent;
Xtime_t tim = time(NULL);
X
X if (!s) return;
X if (in = fopen(s,"r")) {
X while (fgets(buf,sizeof(buf),in)) {
X int l = strlen(buf);
X char *pt = buf;
X
X while (l && buf[l-1] == '\n') {
X buf[l-1] = '\0';
X if (l > 1 && buf[l-2] == '\\') {
X buf[l-2] = '\n';
X fgets(buf+l-1,sizeof(buf)-(l-1),in);
X l = strlen(buf);
X } else break;
X }
X for (;*pt;pt++) if (*pt == ' ') *pt = HISTSPACE;
X
X ent = gethistent(++curhist);
X pt = buf;
X if (*pt == ':') {
X pt++;
X ent->stim = atol(pt);
X for(;*pt != ':' && *pt; pt++)
X ;
X if (*pt) {
X pt++;
X ent->ftim = atol(pt);
X for(;*pt != ':' && *pt; pt++)
X ;
X if (*pt) pt++;
X } else {
X ent->ftim = tim;
X }
X if (ent->stim == 0) ent->stim = tim;
X if (ent->ftim == 0) ent->ftim = tim;
X } else {
X ent->ftim = ent->stim = tim;
X }
X ent->lex = hp_alloc(&hp_lex,strlen(pt)+1);
X strcpy(ent->lex,pt);
X ent->lit = hp_alloc(&hp_lit,strlen(pt)+1);
X strcpy(ent->lit,pt);
X ent->flags = HIST_OLD;
X }
X fclose(in);
X } else if (err)
X zerr("can't read history file",s,0);
X}
X
Xvoid savehistfile(s,err,app) /**/
Xchar *s;int err;int app;
X{
Xchar *t;
XFILE *out;
Xint ev,flag;
XHistent ent;
X
X if (!s || !interact || savehist == 0) return;
X ev = curhist-savehist+1;
X flag = (app & 1) ? O_APPEND : O_TRUNC;
X if (ev < firsthist()) ev = firsthist();
X if (out = fdopen(open(s,O_CREAT|O_WRONLY|flag,0600),"w")) {
X for (; ev <= curhist; ev++) {
X ent = gethistent(ev);
X if (app & 2) {
X if (ent->flags & HIST_OLD) continue;
X ent->flags |= HIST_OLD;
X }
X t = ((lithist) ? ent->lit : ent->lex);
X if (isset(EXTENDEDHISTORY)) {
X fprintf(out, ":%d:%d:", ent->stim,
X ent->ftim);
X }


X for (; *t; t++)

X if (*t == HISTSPACE) fputc(' ',out);
X else {
X if (*t == '\n') fputc('\\',out);
X fputc(*t,out);
X }
X fputc('\n',out);
X }
X fclose(out);
X } else if (err) zerr("can't write history file: %s",s,0);
X}
X
Xint firsthist() /**/
X{
Xint ev;
XHistent ent;
X
X ev = curhist-histentct+1;
X if (ev < 1) ev = 1;
X do {
X ent = gethistent(ev);
X if ((lithist) ? ent->lit : ent->lex) break;
X ev++;
X } while (ev < curhist);
X return ev;
X}
END_OF_FILE
if test 24223 -ne `wc -c <'src/hist.c'`; then
echo shar: \"'src/hist.c'\" unpacked with wrong size!
fi
# end of 'src/hist.c'
fi
echo shar: End of archive 14 \(of 22\).
cp /dev/null ark14isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:26:27 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 65
Archive-name: zsh/part15

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: help/bindkey help/unalias help/unsetopt src/parse.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:54 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 15 (of 22)."'
if test -f 'help/bindkey' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/bindkey'\"
else
echo shar: Extracting \"'help/bindkey'\" \(19763 characters\)
sed "s/^X//" >'help/bindkey' <<'END_OF_FILE'

X down-line-or-search


X Move down a line in the buffer, or if already at the

X bottom line, search forward in the history for a line
X beginning with the first word in the buffer.
X

X up-line-or-search


X Move up a line in the buffer, or if already at the top

X line, search backward in the history for a line begin-
X ning with the first word in the buffer.
X

if test 19763 -ne `wc -c <'help/bindkey'`; then
echo shar: \"'help/bindkey'\" unpacked with wrong size!
fi
# end of 'help/bindkey'
fi
if test -f 'help/unalias' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/unalias'\"
else
echo shar: Extracting \"'help/unalias'\" \(781 characters\)
sed "s/^X//" >'help/unalias' <<'END_OF_FILE'
X alias [ -g ] [ name[=value] ] ...
X With no arguments, print the list of aliases in the
X form name=value on the standard output. For each name
X with a corresponding value, define an alias with that
X value. A trailing space in value causes the next word
X to be checked for alias substitution. If the -g flag
X is present, define a global alias; global aliases are
X expanded even if they do not occur in command position.
X For each name with no value, print the value of name,
X if any. The exit status is nonzero if a name (with no
X value) given for which no alias has been defined.
X unalias name ...
X The alias definition, if any, for each name is removed.
END_OF_FILE
if test 781 -ne `wc -c <'help/unalias'`; then
echo shar: \"'help/unalias'\" unpacked with wrong size!
fi
# end of 'help/unalias'
fi
if test -f 'help/unsetopt' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/unsetopt'\"
else
echo shar: Extracting \"'help/unsetopt'\" \(11726 characters\)
sed "s/^X//" >'help/unsetopt' <<'END_OF_FILE'
X setopt [ +-options ] [ name ... ]
X Set the options for the shell. All options specified
X either with flags or by name are set. If no arguments
X are supplied, the names of all options currently set
X are printed. In option names, case is insignificant,
X and all underscore characters are ignored.
X unsetopt [ +-options ] [ name ... ]
X Unset the options for the shell. All options specified
X either with flags or by name are unset.
X
X The following options may be set upon invocation of the
X shell, or with the set or setopt builtins:
X ALLEXPORT (-a)
X All parameters subsequently defined are automati-
X cally exported.
X AUTO_CD (-J)
X If a command is not in the hash table, and there
X exists an executable directory by that name, per-
X form the cd command to that directory.
X AUTOLIST (-9)
X Automatically list choices on an ambiguous comple-
X tion.
X AUTOMENU
X Automatically use menu completion if the TAB key
X is pressed repeatedly.
X AUTO_PUSHD (-N)
X Make cd act like pushd.
X AUTO_RESUME (-W)
X Treat single word simple commands without redirec-
X tion as candidates for resumption of an existing
X job.
X BGNICE (-6)
X Run all background jobs at a lower priority. This
X option is set by default.
X BRACECCL
X Allow brace expansions of the form {a-zA-Z}, etc.
X CDABLEVARS (-T)
X If the argument to a cd command is not a direc-
X tory, but a parameter exists by the same name
X whose value begins with a /, try to change to the
X directory specified by the parameter's value.
X CHASELINKS (-w)
X Resolve symbolic links to their true values.
X CORRECT (-0)
X Try to correct the spelling of commands.
X CORRECT_ALL (-O)
X Try to correct the spelling of all arguments in a
X line.
X CSH_JUNKIE_LOOPS
X Allow loop bodies to take the form "list; end"
X instead of "do list; done".
X CSH_JUNKIE_QUOTES
X Complain if a quoted expression runs off the end
X of a line; prevent quoted expressions from con-
X taining unescaped newlines.
X CSH_NULL_GLOB
X If a pattern for filename generation has no
X matches, delete the pattern from the argument
X list; do not report an error unless all the pat-
X terns in a command have no matches. Overrides
X NULLGLOB.
X ERREXIT (-e)
X If a command has a non-zero exit status, execute
X the ERR trap, if set, and exit.
X EXTENDED_GLOB
X Treat the # and ^ characters as part of patterns
X for filename generation, etc.
X GLOB_COMPLETE
X Like MENU_COMPLETE, except that the current word
X is expanded using normal shell expansion instead
X of completion. If no matches are found, a * is
X added to the end of the word, and expansion is
X attempted again.
X GLOB_DOTS (-4)
X Do not require a leading . in a filename to be
X matched explicitly.
X HASH_CMDS
X Place the location of each command in the hash
X table the first time it is executed. If this
X option is unset, no path hashing will be done at
X all.
X HASH_DIRS
X Whenever a command is executed, hash the directory
X containing it, as well as all directories that
X occur earlier in the path. Has no effect if
X HASH_CMDS is unset.
X HASH_LIST_ALL
X Whenever a command completion is attempted, make
X sure the entire command path is hashed first.
X This makes the first completion slower.
X HIST_IGNORE_DUPS (-h)
X Do not enter command lines into the history list
X if they are duplicates of the previous event.
X HIST_IGNORE_SPACE (-g)
X Do not enter command lines into the history list
X if they begin with a blank.
X HISTLIT (-j)
X Use literal (unparsed) versions of the history
X lines in the editor.
X HIST_NO_STORE
X Remove the history (fc -l) command from the his-
X tory when invoked.
X HIST_VERIFY
X Whenever the user enters a line with history sub-
X stitution, don't execute the line directly;
X instead, perform history substitution and reload
X the line into the editing buffer.
X IGNORE_BRACES (-I)
X Do not perform brace expansion.
X IGNOREEOF (-7)
X Do not exit on end-of-file. Require the use of
X exit or logout instead.
X INTERACTIVE (-i)
X This is an interactive shell.
X INTERACTIVE_COMMENTS (-k)
X Allow comments even in interactive shells.
X KSH_OPTION_PRINT
X Alters the way options settings are printed.
X LIST_TYPES (-X)
X When listing files that are possible completions,
X show the type of each file with a trailing identi-
X fying mark.
X LOGIN (-l)
X This is a login shell.
X LONG_LIST_JOBS (-R)
X List jobs in the long format by default.
X MAIL_WARNING (-U)
X Print a warning message if a mail file has been
X accessed since the shell last checked.
X MARKDIRS (-8)
X Append a trailing / to all directory names result-
X ing from filename generation (globbing).
X MENU_COMPLETE (-Y)
X On an ambiguous completion, instead of listing
X possibilities, insert the first match. Then when
X completion is requested again, remove the first
X match and insert the second match, etc. When
X there are no more matches, go back to the first
X one again. reverse-menu-complete may be used to
X loop through the list in the other direction.
X MENU_COMPLETE_BEEP
X Beep on an ambiguous menu completion.
X MONITOR (-m)
X Allow job control. Set by default in interactive
X shells.
X NO_BAD_PATTERN (-2)
X If a pattern for filename generation is badly
X formed, leave it unchanged in the argument list
X instead of printing an error.
X NO_BANG_HIST (-K)
X Do not perform textual history substitution. Do
X not treat the ! character specially.
X NOBEEP (-B)
X Do not beep.
X NO_CLOBBER (-1)
X Prevents > redirection from truncating existing
X files. >! may be used to truncate a file instead.
X Also prevents >> from creating files. >>! may be
X used instead.
X NO_EQUALS
X Don't perform = filename substitution.
X NOEXEC (-n)
X Read commands and check them for syntax errors,
X but do not execute them.
X NOGLOB (-F)
X Disable filename generation.
X NO_HIST_BEEP
X Don't beep when an attempt is made to access a
X history entry which isn't there.
X NOHUP
X Don't send the HUP signal to running jobs when the
X shell exits.
X NO_LIST_BEEP
X Don't beep on an ambiguous completion.
X NO_NOMATCH (-3)
X If a pattern for filename generation has no
X matches, leave it unchanged in the argument list
X instead of printing an error.
X NO_PROMPT_CR (-V)
X Don't print a carriage return just before printing
X a prompt in the line editor.
X NO_RCS (-f)
X Do not source the .zshenv, .zshrc, .zlogin, .zlo-
X gout, or .zprofile files.
X NO_SHORT_LOOPS
X Disallow the short forms of for, select, if, and
X function constructs.
X NOTIFY (-5)
X Report the status of background jobs immediately,
X rather than waiting until just before printing a
X prompt.
X NOUNSET (-u)
X Treat unset parameters as an error when substitut-
X ing.
X NULLGLOB (-G)
X If a pattern for filename generation has no
X matches, delete the pattern from the argument list
X instead of reporting an error. Overrides
X NO_NOMATCH.
X NUMERICGLOBSORT
X If numeric filenames are matched by a filename
X generation pattern, sort the filenames numerically
X rather than lexicographically.
X OVERSTRIKE
X Start up the line editor in overstrike mode.
X PATH_DIRS (-Q)
X Perform a path search even on command names with
X slashes in them. Thus if "/usr/local/bin" is in
X the user's path, and he types "X11/xinit", the
X command "/usr/local/bin/X11/xinit" will be exe-
X cuted (assuming it exists).
X PRINT_EXIT_VALUE (-C)
X Print the exit value of programs with non-zero
X exit status.
X PUSHD_IGNORE_DUPS
X Don't push multiple copies of the same directory
X onto the directory stack.
X PUSHD_MINUS
X See popd below.
X PUSHD_SILENT (-E)
X Do not print the directory stack after pushd or
X popd.
X PUSHD_TO_HOME (-D)
X Have pushd with no arguments act like pushd $HOME.
X RC_EXPAND_PARAM (-P)
X See Parameter Expansion.
X RC_QUOTES
X Allow the character sequence '' to signify a sin-
X gle quote within singly quoted strings.
X RECEXACT (-S)
X In completion, recognize exact matches even if
X they are ambiguous.
X RMSTARSILENT (-H)
X Do not query the user before executing "rm *" or
X "rm path/*".
X SHINSTDIN (-s)
X Read commands from the standard input.
X SH_WORD_SPLIT (-y)
X See Parameter Expansion.
X SINGLE_LINE_ZLE (-M)
X Use single-line command line editing instead of
X multi-line.
X SUN_KEYBOARD_HACK (-L)
X If a line ends with a backquote, and there are an
X odd number of backquotes on the line, ignore the
X trailing backquote. This is useful on some key-
X boards where the return key is too small, and the
X backquote key lies annoyingly close to it.
X VERBOSE (-v)
X Print shell input lines as they are read.
X XTRACE (-x)
X Print commands and their arguments as they are
X executed.
X ZLE (-Z)
X Use the zsh line editor.
END_OF_FILE
if test 11726 -ne `wc -c <'help/unsetopt'`; then
echo shar: \"'help/unsetopt'\" unpacked with wrong size!
fi
# end of 'help/unsetopt'
fi
if test -f 'src/parse.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/parse.c'\"
else
echo shar: Extracting \"'src/parse.c'\" \(18751 characters\)
sed "s/^X//" >'src/parse.c' <<'END_OF_FILE'
X/*
X *
X * parse.c - parser


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 YYERROR { tok = LEXERR; return NULL; }
X#define YYERRORV { tok = LEXERR; return; }
X
X#define make_list() allocnode(N_LIST)
X#define make_sublist() allocnode(N_SUBLIST)
X#define make_pline() allocnode(N_PLINE)
X#define make_cmd() allocnode(N_CMD)
X#define make_forcmd() allocnode(N_FOR)
X#define make_casecmd() allocnode(N_CASE)
X#define make_ifcmd() allocnode(N_IF)
X#define make_whilecmd() allocnode(N_WHILE)
X#define make_varnode() allocnode(N_VARASG)
X#define make_cond() allocnode(N_COND)
X
X/*
X * event : ENDINPUT
X * | SEPER
X * | sublist [ SEPER | AMPER ]
X */
XList parse_event() /**/
X{
X tok = ENDINPUT;
X incmdpos = 1;
X yylex();
X return par_event();
X}
X
XList par_event() /**/
X{
XSublist sl;
XList l = NULL;
X
X while (tok == SEPER) {
X if (isnewlin > 0) return NULL;
X yylex();
X }
X if (tok == ENDINPUT) return NULL;
X if (sl = par_sublist())
X if (tok == ENDINPUT) {
X l = make_list();
X l->type = SYNC; l->left = sl;
X } else if (tok == SEPER) {
X l = make_list();
X l->type = SYNC; l->left = sl;
X if (isnewlin <= 0) yylex();
X } else if (tok == AMPER) {
X l = make_list();
X l->type = ASYNC; l->left = sl;
X yylex();
X } else
X l = NULL;
X if (!l) {
X if (errflag) { yyerror(); return NULL; }
X yyerror();
X errflag = 0;
X if (isnewlin <= 0) {
X int c;
X
X hwbegin();
X while ((c = hgetc()) != '\n' && !lexstop);
X if (c == '\n') hungetc('\n');
X hwaddc(HISTSPACE);
X hwadd();


X }
X errflag = 1;
X return NULL;

X } else {
X l->right = par_event();
X }


X return l;
X}
X

XList parse_list() /**/
X{
X tok = ENDINPUT;
X incmdpos = 1;
X yylex();
X return par_list();
X}
X
X/*
X * list : { SEPER } [ sublist [ { SEPER | AMPER } list ] ]
X */
XList par_list() /**/
X{
XSublist sl;
XList l = NULL;
X
X while (tok == SEPER) yylex();
X if (sl = par_sublist())
X if (tok == SEPER || tok == AMPER) {
X l = make_list();
X l->left = sl;
X l->type = (tok == SEPER) ? SYNC : ASYNC;
X incmdpos = 1;
X while (tok == SEPER || tok == AMPER) yylex();
X l->right = par_list();
X } else {
X l = make_list();
X l->left = sl;
X l->type = SYNC;
X }


X return l;
X}
X

XList par_list1() /**/
X{
XSublist sl;
XList l = NULL;
X
X if (sl = par_sublist()) {
X l = make_list();
X l->type = SYNC;
X l->left = sl;
X }
X return l;
X}
X
X/*
X * sublist : sublist2 [ ( DBAR | DAMPER ) { SEPER } sublist ]
X */
XSublist par_sublist() /**/
X{
XSublist sl;
X
X if (sl = par_sublist2())
X if (tok == DBAR || tok == DAMPER) {
X int qtok = tok;
X yylex();
X while (tok == SEPER) yylex();
X sl->right = par_sublist();
X sl->type = (qtok == DBAR) ? ORNEXT : ANDNEXT;
X }
X return sl;
X}
X
X/*
X * sublist2 : [ COPROC | BANG ] pline
X */
XSublist par_sublist2() /**/
X{
XSublist sl;
XPline p;
X
X sl = make_sublist();
X if (tok == COPROC) { sl->flags |= PFLAG_COPROC; yylex(); }
X else if (tok == BANG) { sl->flags |= PFLAG_NOT; yylex(); }
X if (!(p = par_pline()) && !sl->flags)
X return NULL;
X sl->left = p;
X return sl;
X}
X
X/*
X * pline : cmd [ ( BAR | BARAMP ) { SEPER } pline ]
X */
XPline par_pline() /**/
X{
XCmd c;
XPline p,p2;
X
X if (!(c = par_cmd()))
X return NULL;
X if (tok == BAR) {
X yylex();
X while (tok == SEPER) yylex();
X p2 = par_pline();
X p = make_pline();
X p->left = c; p->right = p2; p->type = PIPE;
X return p;
X } else if (tok == BARAMP) {
X struct redir *rdr = alloc(sizeof *rdr);
X rdr->type = MERGEOUT; rdr->fd1 = 2; rdr->fd2 = 1;
X addnode(c->redir,rdr);
X
X yylex();
X p2 = par_pline();
X p = make_pline();
X p->left = c; p->right = p2; p->type = PIPE;
X return p;
X } else {
X p = make_pline();
X p->left = c; p->type = END;
X return p;
X }
X}
X
X/*
X * cmd : { redir } ( for | case | if | while | repeat |
X * subsh | funcdef | time | dinbrack | simple ) { redir }
X */
XCmd par_cmd() /**/
X{
XCmd c;
X
X c = make_cmd();
X c->args = newlist();
X c->redir = newlist();
X c->vars = newlist();
X while (IS_REDIROP(tok))
X par_redir(c->redir);
X switch (tok) {
X case FOR: case FOREACH: case SELECT: par_for(c); break;
X case CASE: par_case(c); break;
X case IF: par_if(c); break;
X case WHILE: case UNTIL: par_while(c); break;
X case REPEAT: par_repeat(c); break;
X case INPAR: case INBRACE: par_subsh(c); break;
X case FUNC: par_funcdef(c); break;
X case TIME: par_time(c); break;
X case DINBRACK: par_dinbrack(c); break;
X default: if (!par_simple(c)) return NULL; break;
X }
X while (IS_REDIROP(tok))
X par_redir(c->redir);
X incmdpos = 1;
X incasepat = 0;
X incond = 0;


X return c;
X}
X

X/*
X * for : ( FOR[EACH] | SELECT ) name ( "in" wordlist | INPAR wordlist OUTPAR )
X { SEPER } ( DO list DONE | INBRACE list OUTBRACE |
X list ZEND | list1 )
X */
Xvoid par_for(c) /**/
XCmd c;
X{
Xstruct forcmd *f;
Xint csh = (tok == FOREACH || isset(CSHJUNKIELOOPS));
X
X f = make_forcmd();
X c->type = (tok == SELECT) ? CSELECT : CFOR;
X incmdpos = 0;
X yylex();
X if (tok != STRING) YYERRORV;
X f->name = tokstr;
X incmdpos = 1;
X yylex();
X if (tok == STRING && !strcmp(tokstr,"in")) {
X f->inflag = 1;
X incmdpos = 0;
X yylex();
X c->args = par_wordlist();
X if (tok != SEPER) YYERRORV;
X } else if (tok == INPAR) {
X f->inflag = 1;
X incmdpos = 0;
X yylex();
X c->args = par_nl_wordlist();
X if (tok != OUTPAR) YYERRORV;
X incmdpos = 1;
X yylex();
X }
X incmdpos = 1;
X while (tok == SEPER) yylex();
X if (tok == DO) {
X yylex();
X f->list = par_list();
X if (tok != DONE) YYERRORV;
X yylex();
X } else if (tok == INBRACE) {
X yylex();
X f->list = par_list();
X if (tok != OUTBRACE) YYERRORV;
X yylex();
X } else if (csh) {
X f->list = par_list();
X if (tok != ZEND) YYERRORV;
X yylex();
X } else if (isset(NOSHORTLOOPS)) {
X YYERRORV;
X } else
X f->list = par_list1();
X c->u.forcmd = f;
X}
X
X/*
X * case : CASE STRING { SEPER } ( "in" | INBRACE )
X { { SEPER } STRING { BAR STRING } OUTPAR list [ DSEMI ] }
X { SEPER } ( "esac" | OUTBRACE )
X */
Xvoid par_case(c) /**/
XCmd c;
X{
Xstruct casecmd **ccp;
Xint brflag;
X
X c->type = CCASE;
X incmdpos = 0;
X yylex();
X if (tok != STRING) YYERRORV;
X addnode(c->args,tokstr);
X incmdpos = 1;
X yylex();
X while (tok == SEPER) yylex();
X if (!(tok == STRING && !strcmp(tokstr,"in")) && tok != INBRACE) YYERRORV;
X brflag = (tok == INBRACE);
X incasepat = 1;
X incmdpos = 0;
X yylex();
X ccp = &c->u.casecmd;
X for (;;) {
X char *str;
X struct casecmd *cc;
X
X *ccp = cc = make_casecmd();
X while (tok == SEPER) yylex();
X if (tok == OUTBRACE) {
X yylex();
X break;
X }
X if (tok != STRING) YYERRORV;
X if (!strcmp(tokstr,"esac")) {
X yylex();
X break;
X }
X str = tokstr;
X yylex();
X while (tok == BAR) {
X char *str2;
X int sl = strlen(str);
X
X yylex();
X if (tok != STRING) YYERRORV;
X str2 = alloc(sl+strlen(tokstr)+1);
X strcpy(str2,str);
X str2[sl] = Bar;
X strcpy(str2+sl+1,tokstr);
X str = str2;
X yylex();
X }
X if (tok != OUTPAR) YYERRORV;
X incasepat = 0;
X incmdpos = 1;
X yylex();
X cc->pat = str;
X cc->list = par_list();
X ccp = &cc->next;
X if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag)) {
X yylex();
X break;
X }
X if (tok != DSEMI) YYERRORV;
X incasepat = 1;
X incmdpos = 0;
X yylex();
X }
X *ccp = NULL;
X}
X
X/*
X * if : { ( IF | ELIF ) { SEPER } ( INPAR list OUTPAR | list )
X { SEPER } ( THEN list | INBRACE list OUTBRACE | list1 ) }
X [ FI | ELSE list FI | ELSE { SEPER } INBRACE list OUTBRACE ]
X (you get the idea...?)
X */
Xvoid par_if(c) /**/
XCmd c;
X{
Xstruct ifcmd *i,**ip;
Xint xtok;
X
X c->type = CIF;
X ip = &c->u.ifcmd;
X for (;;) {
X xtok = tok;
X yylex();
X if (xtok == FI)
X break;
X while (tok == SEPER) yylex();
X if (xtok == ELSE)
X break;
X if (!(xtok == IF || xtok == ELIF)) YYERRORV;
X *ip = i = make_ifcmd();
X ip = &i->next;
X if (tok == INPAR) {
X yylex();
X i->ifl = par_list();
X if (tok != OUTPAR) YYERRORV;
X incmdpos = 1;
X yylex();
X } else {
X i->ifl = par_list();
X incmdpos = 1;
X }
X while (tok == SEPER) yylex();
X xtok = FI;
X if (tok == THEN) {
X yylex();
X i->thenl = par_list();
X incmdpos = 1;
X } else if (tok == INBRACE) {
X yylex();
X i->thenl = par_list();
X if (tok != OUTBRACE) YYERRORV;
X yylex();
X incmdpos = 1;
X if (tok == SEPER) break;
X } else if (isset(NOSHORTLOOPS)) {
X YYERRORV;
X } else {
X i->thenl = par_list1();
X incmdpos = 1;
X break;
X }
X }
X if (xtok == ELSE) {
X *ip = i = make_ifcmd();
X if (tok == INBRACE) {
X yylex();
X i->thenl = par_list();
X if (tok != OUTBRACE) YYERRORV;
X yylex();
X } else {
X i->thenl = par_list();
X if (tok != FI) YYERRORV;
X yylex();


X }
X }
X}
X
X/*

X * while : ( WHILE | UNTIL ) ( INPAR list OUTPAR | list ) { SEPER }
X ( DO list DONE | INBRACE list OUTBRACE | list ZEND )
X */
Xvoid par_while(c) /**/
XCmd c;
X{
Xstruct whilecmd *w;
X
X c->type = CWHILE;
X w = c->u.whilecmd = make_whilecmd();
X w->cond = (tok == UNTIL);
X yylex();
X if (tok == INPAR) {
X yylex();
X w->cont = par_list();
X if (tok != OUTPAR) YYERRORV;
X yylex();
X } else {
X w->cont = par_list();
X }
X incmdpos = 1;
X while (tok == SEPER) yylex();
X if (tok == DO) {
X yylex();
X w->loop = par_list();
X if (tok != DONE) YYERRORV;
X yylex();
X } else if (tok == INBRACE) {
X yylex();
X w->loop = par_list();
X if (tok != OUTBRACE) YYERRORV;
X yylex();
X } else if (isset(CSHJUNKIELOOPS)) {
X w->loop = par_list();
X if (tok != ZEND) YYERRORV;
X yylex();
X } else
X YYERRORV;
X}
X
X/*
X * repeat : REPEAT STRING { SEPER } ( DO list DONE | list1 )
X */
Xvoid par_repeat(c) /**/
XCmd c;
X{
X c->type = CREPEAT;
X incmdpos = 0;
X yylex();
X if (tok != STRING) YYERRORV;
X addnode(c->args,tokstr);
X incmdpos = 1;
X yylex();
X while (tok == SEPER) yylex();
X if (tok == DO) {
X yylex();
X c->u.list = par_list();
X if (tok != DONE) YYERRORV;
X yylex();
X } else {
X c->u.list = par_list1();
X }
X}
X
X/*
X * subsh : ( INPAR | INBRACE ) list ( OUTPAR | OUTBRACE )
X */
Xvoid par_subsh(c) /**/
XCmd c;
X{
X c->type = (tok == INPAR) ? SUBSH : CURSH;
X yylex();
X c->u.list = par_list();
X if (tok != ((c->type == SUBSH) ? OUTPAR : OUTBRACE)) YYERRORV;
X yylex();
X}
X
X/*
X * funcdef : FUNCTION wordlist [ INOUTPAR ] { SEPER }
X * ( list1 | INBRACE list OUTBRACE )
X */
Xvoid par_funcdef(c) /**/
XCmd c;
X{
X nocorrect = 1;
X incmdpos = 0;
X yylex();
X c->type = FUNCDEF;
X c->args = newlist();
X incmdpos = 1;
X while (tok == STRING) {
X if (*tokstr == Inbrace && !tokstr[1]) { tok = INBRACE; break; }
X addnode(c->args,tokstr);
X yylex();
X }
X nocorrect = 0;
X if (tok == INOUTPAR) yylex();
X while (tok == SEPER) yylex();
X if (tok == INBRACE) {
X yylex();
X c->u.list = par_list();
X if (tok != OUTBRACE) YYERRORV;
X yylex();
X } else if (isset(NOSHORTLOOPS)) {
X YYERRORV;
X } else
X c->u.list = par_list1();
X}
X
X/*
X * time : TIME sublist2
X */
Xvoid par_time(c) /**/
XCmd c;
X{
X yylex();
X c->type = ZCTIME;
X c->u.pline = par_sublist2();
X}
X
X/*
X * dinbrack : DINBRACK cond DOUTBRACK
X */
Xvoid par_dinbrack(c) /**/
XCmd c;
X{
X c->type = COND;
X incond = 1;
X incmdpos = 0;
X yylex();
X c->u.cond = par_cond();
X if (tok != DOUTBRACK) YYERRORV;
X incond = 0;
X incmdpos = 1;
X yylex();
X}
X
X/*
X * simple : { COMMAND | EXEC | NOGLOB | NOCORRECT | DASH }
X { STRING | ENVSTRING | ENVARRAY wordlist OUTPAR | redir }
X [ INOUTPAR { SEPER } ( list1 | INBRACE list OUTBRACE ) ]
X */
XCmd par_simple(c) /**/
XCmd c;
X{
Xint isnull = 1;
X
X c->type = SIMPLE;
X for (;;) {
X if (tok == COMMAND) c->flags |= CFLAG_COMMAND;
X else if (tok == EXEC) c->flags |= CFLAG_EXEC;
X else if (tok == NOGLOB) c->flags |= CFLAG_NOGLOB;
X else if (tok == NOCORRECT) nocorrect = 1;
X else if (tok == DASH) c->flags = CFLAG_DASH;
X else break;
X yylex();
X }
X if (tok == AMPER) YYERROR;
X for (;;) {
X if (tok == STRING) {
X incmdpos = 0;
X addnode(c->args,tokstr);
X yylex();
X } else if (tok == ENVSTRING) {
X struct varasg *v = make_varnode();
X v->type = PMFLAG_s;
X equalsplit(v->name = tokstr,&v->str);
X addnode(c->vars,v);
X yylex();
X } else if (tok == ENVARRAY) {
X struct varasg *v = make_varnode();
X int oldcmdpos = incmdpos;
X v->type = PMFLAG_A;
X incmdpos = 0;
X v->name = tokstr;
X yylex();
X v->arr = par_nl_wordlist();
X if (tok != OUTPAR) YYERROR;
X incmdpos = oldcmdpos;
X yylex();
X addnode(c->vars,v);
X } else if (IS_REDIROP(tok)) {
X par_redir(c->redir);
X } else if (tok == INOUTPAR) {
X incmdpos = 1;
X yylex();
X while (tok == SEPER) yylex();
X if (tok == INBRACE) {
X yylex();
X c->u.list = par_list();
X if (tok != OUTBRACE) YYERROR;
X yylex();
X } else if (isset(NOSHORTLOOPS)) {
X YYERROR;
X } else
X c->u.list = par_list1();
X c->type = FUNCDEF;
X } else break;
X isnull = 0;
X }
X if (isnull && empty(c->redir)) return NULL;
X if (full(c->args)) {
X if (underscore)
X free(underscore);
X underscore = ztrdup(getdata(lastnode(c->args)));
X untokenize(underscore);
X }
X incmdpos = 1;


X return c;
X}
X

X/*
X * cond : cond_1 { SEPER } [ DBAR { SEPER } cond ]
X */
XCond par_cond() /**/
X{
XCond c,c2;
X
X c = par_cond_1();
X while (tok == SEPER) yylex();
X if (tok == DBAR) {
X yylex();
X while (tok == SEPER) yylex();
X c2 = make_cond();
X c2->left = c;
X c2->right = par_cond();
X c2->type = COND_OR;
X return c2;
X }
X return c;
X}
X
X/*
X * cond_1 : cond_2 { SEPER } [ DAMPER { SEPER } cond_1 ]
X */
XCond par_cond_1() /**/
X{
XCond c,c2;
X
X c = par_cond_2();
X while (tok == SEPER) yylex();
X if (tok == DAMPER) {
X yylex();
X while (tok == SEPER) yylex();
X c2 = make_cond();
X c2->left = c;
X c2->right = par_cond_1();
X c2->type = COND_AND;
X return c2;
X }
X return c;
X}
X
X/*
X * cond_2 : BANG cond_2
X | INPAR { SEPER } cond_2 { SEPER } OUTPAR
X | STRING STRING STRING
X | STRING STRING
X | STRING ( INANG | OUTANG ) STRING
X */
XCond par_cond_2() /**/
X{
XCond c,c2;
Xchar *s1,*s2,*s3;
Xint xtok;
X
X if (tok == BANG) {
X yylex();
X c = par_cond_2();
X c2 = make_cond();
X c2->left = c;
X c2->type = COND_NOT;
X return c2;
X }
X if (tok == INPAR) {
X yylex();
X while (tok == SEPER) yylex();
X c = par_cond();
X while (tok == SEPER) yylex();
X if (tok != OUTPAR) YYERROR;
X yylex();
X return c;
X }
X if (tok != STRING) YYERROR;
X s1 = tokstr;
X yylex();
X xtok = tok;
X if (tok == INANG || tok == OUTANG) {
X yylex();
X if (tok != STRING) YYERROR;
X s3 = tokstr;
X yylex();
X c = make_cond();
X c->left = s1;
X c->right = s3;
X c->type = (xtok == INANG) ? COND_STRLT : COND_STRGTR;
X c->types[0] = c->types[1] = NT_STR;
X return c;
X }
X if (tok != STRING) YYERROR;
X s2 = tokstr;
X yylex();
X if (tok == STRING) {
X s3 = tokstr;
X yylex();
X return par_cond_triple(s1,s2,s3);
X } else
X return par_cond_double(s1,s2);
X}
X
X/*
X * redir : ( OUTANG | ... | TRINANG ) STRING
X */
Xvoid par_redir(l) /**/
XLklist l;
X{
Xchar *toks;
Xstruct redir *fn = allocnode(N_REDIR);
Xint mergerror = 0;
Xint oldcmdpos,oldnc;
X
X oldcmdpos = incmdpos;
X incmdpos = 0;
X oldnc = nocorrect;
X if (tok != INANG) nocorrect = 1;
X fn->type = redirtab[tok-OUTANG];
X fn->fd1 = tokfd;
X yylex();
X if (tok != STRING && tok != ENVSTRING) YYERRORV;
X toks = tokstr;
X incmdpos = oldcmdpos;
X nocorrect = oldnc;
X yylex();
X
X/* assign default fd */
X
X if (fn->fd1 == -1)
X fn->fd1 = IS_READFD(fn->type) ? 0 : 1;
X
X/* > >(...) or < <(...) */
X
X if ((*toks == Inang || *toks == Outang) && toks[1] == Inpar) {
X if ((fn->type & ~1) == WRITE) fn->type = OUTPIPE;
X else if (fn->type == READ) fn->type = INPIPE;
X else YYERRORV;
X fn->name = toks;
X
X/* <<[-] name */
X
X } else if (fn->type == HEREDOC || fn->type == HEREDOCDASH) {
X char tbuf[256], *tlin = NULL;
X int tsiz = 0, l;
X /* Save the rest of the current line for later tokenization */
X if (!isnewlin) {
X while (hgets(tbuf, 256) != NULL) {
X l = strlen(tbuf);
X if (tsiz == 0) {
X tlin = ztrdup(tbuf); /* Test for failure? */
X tsiz = l;
X } else {
X tlin = realloc(tlin,tsiz+l+1); /* Test for failure? */
X strcpy(&tlin[tsiz], tbuf);
X tsiz += l;
X }
X if (tbuf[l-1] == '\n') break;
X }
X }
X /* Now grab the document */
X fn->name = gethere(toks,fn->type);
X fn->type = HERESTR;
X /* Put back the saved line to resume tokenizing */
X if (tsiz > 0) {
X hungets(tlin);
X free(tlin);
X }
X
X/* >& name or >>& name */
X
X } else if (IS_ERROR_REDIR(fn->type) && getfdstr(toks) == FD_WORD) {
X mergerror = 1;
X fn->name = toks;
X fn->type = UN_ERROR_REDIR(fn->type);
X
X/* >>& and >>&! are only valid with a name after them */
X
X } else if (fn->type == ERRAPP || fn->type == ERRAPPNOW) {
X YYERRORV;
X
X/* >& # */
X


X } else if (fn->type == MERGE || fn->type == MERGEOUT) {

X fn->fd2 = getfdstr(toks);
X if (fn->fd2 == FD_CLOSE) fn->type = CLOSE;
X else if (fn->fd2 == FD_WORD) fn->fd2 = (fn->type==MERGEOUT) ? 1 : 0;
X } else
X fn->name = toks;
X addnode(l,fn);
X if (mergerror)
X {
X struct redir *fe = allocnode(N_REDIR);
X
X fe->fd1 = 2;
X fe->fd2 = fn->fd1;
X fe->type = MERGEOUT;
X addnode(l,fe);
X }
X}
X
X/*
X * wordlist : { STRING }
X */
XLklist par_wordlist() /**/
X{
XLklist l;
X
X l = newlist();
X while (tok == STRING) {
X addnode(l,tokstr);
X yylex();
X }
X return l;
X}
X
X/*
X * nl_wordlist : { STRING | SEPER }
X */
XLklist par_nl_wordlist() /**/
X{
XLklist l;
X
X l = newlist();
X while (tok == STRING || tok == SEPER) {
X if (tok != SEPER)
X addnode(l,tokstr);
X yylex();
X }


X return l;
X}
X

X/* get fd associated with str */
X
Xint getfdstr(s) /**/
Xchar *s;
X{
X if (s[1]) return FD_WORD;
X if (idigit(*s)) return *s-'0';
X if (*s == 'p') return FD_COPROC;
X if (*s == '-') return FD_CLOSE;
X return FD_WORD;
X}
X
XCond par_cond_double(a,b) /**/


Xchar *a;char *b;
X{

XCond n = make_cond();
X
X if (a[0] != '-' || !a[1] || a[2])
X {
X zerr("parse error: condition expected: %s",a,0);
X return NULL;
X }
X n->left = b;
X n->type = a[1];
X n->types[0] = n->types[1] = NT_STR;
X return n;
X}
X
XCond par_cond_triple(a,b,c) /**/
Xchar *a;char *b;char *c;
X{
XCond n = make_cond();
Xstatic char *condstrs[] = {
X "nt","ot","ef","eq","ne","lt","gt","le","ge",NULL
X };
Xint t0;
X
X if ((b[0] == Equals || b[0] == '=') && !b[1])
X n->type = COND_STREQ;
X else if (b[0] == '!' && b[1] == '=' && !b[2])
X n->type = COND_STRNEQ;
X else if (b[0] == '-')
X {
X for (t0 = 0; condstrs[t0]; t0++)
X if (!strcmp(condstrs[t0],b+1))
X break;
X if (condstrs[t0])
X n->type = t0+COND_NT;
X else
X zerr("unrecognized condition: %s",b,0);
X }
X else
X zerr("condition expected: %s",b,0);
X n->left = a;
X n->right = c;
X n->types[0] = n->types[1] = NT_STR;
X return n;
X}
X
Xvoid yyerror() /**/
X{
Xint t0;
X
X for (t0 = 0; t0 != 20; t0++)
X if (!yytext[t0] || yytext[t0] == '\n' || yytext[t0] == HISTSPACE)
X break;
X if (t0 == 20)
X zerr("parse error near `%l...'",yytext,20);
X else if (t0)
X zerr("parse error near `%l'",yytext,t0);
X else
X zerr("parse error",NULL,0);
X}
X
END_OF_FILE
if test 18751 -ne `wc -c <'src/parse.c'`; then
echo shar: \"'src/parse.c'\" unpacked with wrong size!
fi
# end of 'src/parse.c'
fi
echo shar: End of archive 15 \(of 22\).
cp /dev/null ark15isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:26:57 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 66
Archive-name: zsh/part16

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: src/buildzsh src/init.c src/zle_bindings.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:54 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 16 (of 22)."'
if test -f 'src/buildzsh' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/buildzsh'\"
else
echo shar: Extracting \"'src/buildzsh'\" \(18846 characters\)
sed "s/^X//" >'src/buildzsh' <<'END_OF_FILE'
X#! /bin/sh
Xecho
Xecho 'Trying to determine host type...'
X
Xheaderdir=/usr/include
Xarch=`(uname) 2>/dev/null`
Xcase "$arch" in
X"") case `(head -2 /etc/motd) 2>/dev/null` in
X *"HP-UX"*) HPUX=yep; machid=hp9000;;
X *"Iris"*) SGI=yep; host=iris4d;;
X *"Ultrix"*) ULTRIX=yep; host=vax;;
X *"RISC iX"*) ARM=yep; host=arm;;
X *"Umax 4.2"*) ENCORE=yep; host=encore;;
X *"Alliant Concentrix"*) ALLIANT=yep; host=alliant;;
X *"FPS Model 500"*) FPS=yep; host=fps500;;
X *"HCX/UX"*) HARRIS=yep; host=harris;;
X *"nX Operating System"*) BBN=yep; host=`arch`;;
X *)
X if test -d ${headerdir}/caif
X then AIX=yep; host=ibm032
X elif test -d /sys/node_data
X then APOLLO=yep; host=apollo-$ISP
X elif test -f /bin/pyr && /bin/pyr
X then PYR=yes; host=pyr
X elif test -d /NextApps
X then host=next
X if test -d /NextDeveloper/Headers/bsd
X then NEXT=3.x; headerdir=${headerdir}/bsd
X else NEXT=2.x
X fi
X elif test -f /etc/comply
X then SUN=yes; host=sun3
X elif test -f /bin/hinv
X then SGI=yep; host=iris4d
X elif grep ULTRIX ${headerdir}/stdio.h >/dev/null 2>&1
X then ULTRIX=yep; host=vax
X elif grep 'Property of IBM' ${headerdir}/stdio.h >/dev/null 2>&1
X then AIX=yep
X else host=`(tcsh -fc 'echo $HOSTTYPE' || arch || machine || mach || echo $machine) 2>/dev/null`
X fi;;
X esac;;
XHP-UX) HPUX=`uname -r 2>/dev/null || echo yep`; machid=`uname -m`
X case "$machid" in
X "") host=hp9000;;
X 9000/[0-9][0-9][0-9])
X host=`echo "hp$machid" | sed 's,/\(.\)..,s\100,'`;;
X *) host=hp-unknown;;
X esac;;
XAIX*) AIX=yep; machid=`uname -m`
X case "$machid" in
X 00*) host=rs6000;;
X 10*) host=ibm032;;
X 20*) host=ibm032;;
X esac;;
XA/UX) MAC=yep; host=macII;;
Xdgux) DGUX=yep; machid=`uname -m`
X case "$machid" in
X AViiON) host=aviion;;
X esac;;
XSunOS) machid=`uname -m`
X SUN=yep; case "$machid" in
X sun3*) host=sun3;;
X sun4*) host=sun4;;
X *) host=$machid;;
X esac;;
XULTRIX) machid=`uname -m`
X ULTRIX=yep; case "$machid" in
X VAX) host=vax;;
X *) host=$machid;;
X esac;;
XIRIX) SGI=yep; host=iris4d;;
XOSF1) OSF=yep; host=alpha;;
X*) machid=`uname -m`
X case "$machid" in
X mips|IP6|IP7) MIPS=yep; host=mips;;
X *) host=`(tcsh -fc 'echo $HOSTTYPE' || arch || machine || mach || echo $machine || echo $machid) 2>/dev/null`
X esac;;
Xesac
Xif test "$host"
Xthen echo "...looks like a $host"
X case $host in
X mips) if test -d /usr/include/bsd43; then headerdir=/usr/include/bsd43; fi;;
X esac
Xelse echo "...no luck on that score. Continuing..."
Xfi
Xecho '
XBuilding 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 ${headerdir}/sys/resource.h -a ! -f ${headerdir}/sys/elf.h
Xthen echo '/* #define SYSV */'; echo 'looks like a BSDish system...' >&2
Xelse echo '#define SYSV'; echo 'looks like a SYSVish system...' >&2
X PATH=/usr/bin:$PATH; export PATH; echo 'forcing /usr/bin early in PATH' >&2
X if test -f ${headerdir}/sys/elf.h
X then echo '#define SYSVR4'; echo 'looks like a SYSVR4 system...' >&2
X fi
Xfi
Xecho
Xif test "$ULTRIX"
Xthen echo '#define ULTRIX
X/* ULTRIX termios is weird... */
X/* #define TERMIOS */'; echo 'using sgttyb...' >&2
Xelse
Xif test -f ${headerdir}/termios.h -a -z "$HPUX" -a -z "$APOLLO" -a -z "$BBN"
Xthen echo '#define TERMIOS
X/* #define TTY_NEEDS_DRAINING */
X/* #define CLOBBERS_TYPEAHEAD */'
Xecho 'using termios...' >&2
Xelse
Xif grep sgttyb ${headerdir}/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 ${headerdir}/dirent.h -a -z "$ULTRIX"
Xthen echo '#define HAS_DIRENT'; echo 'using <dirent.h>...' >&2
Xelse echo '/*#define HAS_DIRENT*/'; echo 'not using <dirent.h>...' >&2
Xfi
Xecho
Xif test -f ${headerdir}/unistd.h
Xthen echo '#define HAS_UNISTD'; echo 'using <unistd.h>...' >&2
Xelse echo '/*#define HAS_UNISTD*/'; echo 'not using <unistd.h>...' >&2
Xfi
Xecho
Xif test -f ${headerdir}/stdlib.h &&
X grep alloc ${headerdir}/stdlib.h >/dev/null 2>&1
Xthen echo '#define HAS_STDLIB'; echo 'using <stdlib.h>...' >&2
Xelif test -n "${NEXT}"
Xthen echo '#define HAS_STDLIB'; echo 'using <stdlib.h> (where NeXT hid it) ...' >&2
Xelse echo '/*#define HAS_STDLIB*/'; echo 'not using <stdlib.h>...' >&2
Xfi
Xecho
Xif test -f ${headerdir}/string.h
Xthen echo '#define HAS_STRING'; echo 'using <string.h>...' >&2
Xelse echo '/*#define HAS_STRING*/'; echo 'using <strings.h>...' >&2
Xif test "${NEXT}" != "3.x"
Xthen echo '#define strchr index
X#define strrchr rindex'
Xfi
Xfi
Xecho
Xif test -f ${headerdir}/memory.h
Xthen echo '#define HAS_MEMORY'; echo 'using <memory.h>...' >&2
Xelse echo '/*#define HAS_MEMORY*/'; echo 'not using <memory.h>...' >&2
Xif grep memset ${headerdir}/string.h >/dev/null 2>&1
Xthen echo 'using memcpy,memset,memcmp from <string.h>...' >&2
Xelse echo 'redefining memcpy,memset,memcmp...' >&2
Xecho '#define memcpy(dst, src, n) bcopy(src, dst, n)
X#define memset(dst, ch, n) do {\
X char *__DST__ = (char *)(dst);\
X int __N__ = (int)(n), __CH__ = (int)(ch);\
X while (__N__--) { __DST__[__N__] = __CH__; } } while(0)
X#define memcmp(s1, s2, n) bcmp(s1, s2, n)'
Xfi
Xfi
Xecho
Xif test -f ${headerdir}/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
Xif test -f ${headerdir}/utmpx.h
Xthen echo '#define HAS_UTMPX'; echo 'using <utmpx.h>...' >&2
Xutmphdr=${headerdir}/utmpx.h
Xelse echo '/*#define HAS_UTMPX*/'; echo 'not using <utmpx.h>...' >&2
Xutmphdr=${headerdir}/utmp.h
Xfi
Xecho
Xif grep ut_host $utmphdr >/dev/null 2>&1 && test "$host" != mips
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
Xif test -f ${headerdir}/time.h &&
X grep timeval ${headerdir}/time.h >/dev/null 2>&1
Xthen echo '#define HAS_TIME'; echo 'using <time.h>...' >&2
Xelse echo '/*#define HAS_TIME*/'; echo 'using <sys/time.h>...' >&2
Xfi
Xecho
Xif test -f ${headerdir}/wait.h
Xthen echo '#define HAS_WAIT'; echo 'using <wait.h>...' >&2
Xelse echo '/*#define HAS_WAIT*/'; echo 'using <sys/wait.h>...' >&2
Xfi
Xecho
Xecho '/* define this if you have WAITPID */'
Xif man 2 wait 2>/dev/null | sed 's/_.//g' | grep waitpid >/dev/null || \
X grep 'waitpid.*(' ${headerdir}/wait.h >/dev/null 2>&1 || \
X grep 'waitpid.*(' ${headerdir}/sys/wait.h >/dev/null 2>&1
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 ${headerdir}/sys/types.h >/dev/null 2>&1 ||
X test -f ${headerdir}/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 ${headerdir}/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 -n "$NEXT" -a "$NEXT" = "2.x"
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 test "$host" != mips &&
X 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 test "$host" != mips &&
X man tcsetpgrp 2>/dev/null | grep process >/dev/null || \
X grep tcsetpgrp ${headerdir}/unistd.h >/dev/null 2>&1
Xthen echo '#define HAS_TCSETPGRP'; echo 'using tcsetpgrp()...' >&2
Xelse echo '/* #define HAS_TCSETPGRP */'; echo 'not using tcsetpgrp()...' >&2
Xfi
Xecho
Xif grep tcgetattr ${headerdir}/termios.h >/dev/null 2>&1 ||
X grep tcgetattr ${headerdir}/sys/termios.h >/dev/null 2>&1 ||
X grep tcgetattr ${headerdir}/sys/termio.h >/dev/null 2>&1
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 "$SGI" -o "$MIPS"
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 -z "$HPUX" -a -z "$PYR" -a -z "$MIPS" &&
X { man sigrelse 2>/dev/null | grep signal >/dev/null ||
X grep SIGRELSE ${headerdir}/sys/signal.h > /dev/null 2>&1 ; }
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 "$HPUX"
Xthen echo '/* #define HAS_RUSAGE */'; echo 'no getrusage...' >&2
Xelif test -f ${headerdir}/sys/resource.h
Xthen echo '#define HAS_RUSAGE'; echo 'has getrusage...' >&2
Xelse echo '/* #define HAS_RUSAGE */'; echo 'no getrusage...' >&2
Xfi
Xif test "$host" = hp9000s700
Xthen echo '/* kludge RLIM code for HPUX s700 - These limits are all readable,and
X * some like coredumpsize are settable by users
X */
X#define RLIMIT_CPU 0 /* cpu time in milliseconds */
X#define RLIMIT_FSIZE 1 /* maximum file size */
X#define RLIMIT_DATA 2 /* data size */
X#define RLIMIT_STACK 3 /* stack size */
X#define RLIMIT_CORE 4 /* core file size */
X#define RLIMIT_RSS 5 /* resident set size */
X
X#define RLIM_INFINITY 0x7fffffff
X'
Xfi
Xecho '/* define this if you use NIS for your passwd map */'
Xif test -f /usr/bin/ypcat && ypcat passwd.byname >/dev/null 2>&1
Xthen echo '#define HAS_NIS_PASSWD'; echo 'using NIS passwd code...' >&2
Xelse echo '/* #define HAS_NIS_PASSWD */'; echo 'no NIS passwd map, it seems...' >&2
Xfi
Xecho '
X/* define this if your signal handlers return void */'
Xif egrep 'SIG_DFL|sighandler_t' ${headerdir}/signal.h ${headerdir}/sys/signal.h 2>/dev/null |
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 ${headerdir}/signal.h >/dev/null 2>&1 ||
X grep SIGTSTP ${headerdir}/sys/signal.h >/dev/null 2>&1
Xthen echo '/* #define RESETHANDNEEDED */'
Xecho 'signal handlers need no resetting...' >&2
X if test -z "$HPUX" -a -z "$MIPS" &&
X man 2 sigset 2>/dev/null | grep handler >/dev/null
X then echo '#define signal sigset'; echo '.. when installed with sigset()' >&2
X fi
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'
Xif test -z "$host"
Xthen
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
Xfi
Xecho $host'"'
Xecho "using host type $host..." >&2
Xecho
Xecho '/* the default editor for the fc builtin */'
Xecho '#define DEFFCEDIT "vi"'
Xecho
Xif egrep 'UTMP_FILE|_PATH_UTMP' ${headerdir}/utmp.h >/dev/null 2>&1
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'

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#CFLAGS= -O2 -g -Wall -Wno-implicit -Wno-parentheses -Wno-comment $(DFLAGS)
X
Xfoo
Xif test "$MIPS"
Xthen echo 'CC=cc -systype bsd43'
Xelse echo 'CC=cc'
Xfi
Xif test "$APOLLO"
Xthen echo 'CFLAGS= -O -A nansi'
Xelif test "$HPUX"
Xthen export HPUX; echo "CFLAGS= -O `[ "$HPUX" = "7.03" ] && echo -Wc,-Ns5000`"
Xelif test "$ULTRIX"
Xthen echo 'CFLAGS= -O -Olimit 600'
Xelif test "$MIPS"
Xthen echo 'CFLAGS= -O -Olimit 1000 -Wf,-XNd5000 -Wf,-XNl4096'
Xelif test "$OSF"
Xthen echo 'CFLAGS= -O -I/usr/sys/include -I/usr/sys/BINARY -D__rpc_types_h -Dbool_t=int -Denum_t=int'
Xelif test -f ${headerdir}/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'
Xelif cc -v 2>&1 | egrep '^gcc version (1\.9|[2-9])' >/dev/null 2>&1
Xthen echo 'CFLAGS= -O2 -pipe'
Xelse echo 'CFLAGS= -O'
Xfi
Xif test "$SGI"
Xthen
Xif grep '^\+' /etc/passwd >/dev/null 2>&1
Xthen echo 'LIBS= -lcurses -lmalloc -lbsd -lsun'
Xelse echo 'LIBS= -lcurses -lmalloc -lbsd'
Xfi
Xelif test "$BBN"
Xthen echo 'LIBS= -ltermcap -lposix'
Xelif test "$HPUX"
Xthen echo 'LIBS= -ltermcap -lBSD'
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 -o -f /usr/ucblib/libtermcap.a
Xthen
X if test "$AIX"
X then echo 'LIBS= -lcurses'
X else echo 'LIBS= -ltermcap'
X fi
Xelse echo 'LIBS= -lcurses'
Xfi
Xcat <<'foo'

Xfoo
Xexec 1>&2
Xecho done
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
END_OF_FILE
if test 18846 -ne `wc -c <'src/buildzsh'`; then
echo shar: \"'src/buildzsh'\" unpacked with wrong size!
fi
chmod +x 'src/buildzsh'
# end of 'src/buildzsh'
fi
if test -f 'src/init.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/init.c'\"
else
echo shar: Extracting \"'src/init.c'\" \(14274 characters\)
sed "s/^X//" >'src/init.c' <<'END_OF_FILE'
X/*
X *
X * init.c - main loop and initialization routines


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#define GLOBALS
X#include "zsh.h"
X#include <pwd.h>
X
Xstatic int noexitct = 0;
X
Xvoid main(argc,argv,envp) /**/
Xint argc; char **argv; char **envp;
X{
Xchar *zshname;
X
X#ifdef LC_ALL
X setlocale(LC_ALL, "");
X#endif
X environ = envp;
X meminit();
X if (!(zshname = strrchr(argv[0], '/')))
X zshname = argv[0];
X else
X zshname++;
X setflags(zshname);
X parseargs(argv);
X setmoreflags();
X setupvals();
X initialize();
X heapalloc();
X runscripts(zshname);
X for(;;)
X {
X do
X loop(1);
X while (tok != ENDINPUT);
X if (!(isset(IGNOREEOF) && interact))
X {
X#if 0
X if (interact)
X fputs(islogin ? "logout\n" : "exit\n",stderr);
X#endif
X zexit(lastval);
X continue;
X }
X noexitct++;
X if (noexitct >= 10)


X {
X stopmsg = 1;

X zexit(lastval);
X }
X zerrnam("zsh",(!islogin) ? "use 'exit' to exit."
X : "use 'logout' to logout.",NULL,0);
X }
X}
X
X/* keep executing lists until EOF found */
X
Xvoid loop(toplevel) /**/
Xint toplevel;
X{
XList list;
XHeap h = (Heap) peekfirst(heaplist);
X
X pushheap();
X for(;;)
X {
X freeheap();


X if (interact && isset(SHINSTDIN))

X preprompt();
X hbegin(); /* init history mech */
X intr(); /* interrupts on */
X ainit(); /* init alias mech */
X lexinit();
X errflag = 0;
X if (!(list = parse_event()))
X { /* if we couldn't parse a list */
X hend();
X if (tok == ENDINPUT && !errflag)
X break;
X continue;
X }
X if (hend())
X {
X if (stopmsg) /* unset 'you have stopped jobs' flag */
X stopmsg--;
X execlist(list);
X if (toplevel)
X noexitct = 0;
X }
X if (ferror(stderr))
X {
X zerr("write error",NULL,0);
X clearerr(stderr);
X }
X if (subsh) /* how'd we get this far in a subshell? */
X exit(lastval);
X if ((!interact && errflag) || retflag)
X break;
X if (isset('t') || (lastval && isset(ERREXIT)))


X {
X if (sigtrapped[SIGEXIT])
X dotrap(SIGEXIT);

X exit(lastval);
X }
X }
X while ((Heap) peekfirst(heaplist) != h)
X popheap();
X}
X
Xvoid setflags(zshname) /**/
Xconst char *zshname;
X{
Xint c;
X
X for (c = 0; c != 32; c++) opts[c] = OPT_UNSET;
X for (c = 32; c != 128; c++) opts[c] = OPT_INVALID;
X for (c = 'a'; c <= 'z'; c++) opts[c] = opts[c-'a'+'A'] = OPT_UNSET;
X for (c = '0'; c <= '9'; c++) opts[c] = OPT_UNSET;
X opts['A'] = OPT_INVALID;
X opts['i'] = (isatty(0)) ? OPT_SET : OPT_UNSET;
X opts[BGNICE] = opts[NOTIFY] = OPT_SET;
X opts[USEZLE] = (interact && SHTTY != -1) ? OPT_SET : OPT_UNSET;
X opts[HASHCMDS] = opts[HASHLISTALL] = opts[HASHDIRS] = OPT_SET;
X
X /* KSH Mode:
X The following seven options cause zsh to behave more like KSH
X when invoked as "ksh".
X K - don't recognize csh-style history subst
X k - allow interactive comments
X I - don't perform brace expansion
X 3 - don't print error for unmatched wildcards
X H - don't query 'rm *'
X y - split parameters using IFS
X KSHOPTIONPRINT - print options ksh-like
X w...@rcvie.co.at, 1992-05-14
X */
X
X if ( strcmp(zshname, "ksh") == 0 )
X {
X opts['K'] = opts['k'] = opts['I'] = opts['3'] = OPT_SET ;
X opts['H'] = opts['y'] = opts[KSHOPTIONPRINT] = OPT_SET ;
X }
X}
X
Xstatic char *cmd;
X
Xvoid parseargs(argv) /**/
Xchar **argv;
X{
Xchar **x;
Xint bk = 0,action;
XLklist paramlist;
X
X hackzero = argzero = *argv;
X opts[LOGINSHELL] = (**(argv++) == '-') ? OPT_SET : OPT_UNSET;
X SHIN = 0;
X while (!bk && *argv && (**argv == '-' || **argv == '+'))
X {
X action = (**argv == '-') ? OPT_SET : OPT_UNSET;
X while (*++*argv) {
X if (opts[(int)**argv] == OPT_INVALID) {
X zerr("bad option: -%c",NULL,**argv);
X exit(1);
X }
X if (bk = **argv == 'b') break;
X if (**argv == 'c') { /* -c command */
X argv++;
X if (!*argv) {
X zerr("string expected after -c",NULL,0);
X exit(1);
X }
X cmd = *argv;
X opts[INTERACTIVE] = OPT_UNSET;
X opts['c'] = OPT_SET;
X break;
X } else if (**argv == 'o') {
X int c;
X
X if (!*++*argv)
X argv++;
X if (!*argv) {
X zerr("string expected after -o",NULL,0);
X exit(1);
X }
X c = optlookup(*argv);
X if (c == -1)
X zerr("no such option: %s",*argv,0);
X else
X opts[c] = action;
X break;
X } else opts[(int)**argv] = action;
X }
X argv++;
X }
X paramlist = newlist();
X if (*argv)
X {
X if (opts[SHINSTDIN] == OPT_UNSET)
X {
X SHIN = movefd(open(argzero = *argv,O_RDONLY));
X if (SHIN == -1)
X {
X zerr("can't open input file: %s",*argv,0);
X exit(1);
X }
X opts[INTERACTIVE] = OPT_UNSET;
X argv++;
X }
X while (*argv)
X addnode(paramlist,ztrdup(*argv++));
X }
X else
X opts[SHINSTDIN] = OPT_SET;
X pparams = x = zcalloc((countnodes(paramlist)+1)*sizeof(char *));
X while (*x++ = getnode(paramlist));
X free(paramlist);


X argzero = ztrdup(argzero);
X}
X

Xvoid setmoreflags() /**/
X{
X#ifndef NOCLOSEFUNNYFDS
Xint t0;
X#endif
Xlong ttpgrp;
X
X /* stdout,stderr fully buffered */
X#ifdef _IOFBF
X setvbuf(stdout,malloc(BUFSIZ),_IOFBF,BUFSIZ);
X setvbuf(stderr,malloc(BUFSIZ),_IOFBF,BUFSIZ);
X#else
X setbuffer(stdout,malloc(BUFSIZ),BUFSIZ);
X setbuffer(stderr,malloc(BUFSIZ),BUFSIZ);
X#endif
X subsh = 0;
X#ifndef NOCLOSEFUNNYFDS
X /* this works around a bug in some versions of in.rshd */
X for (t0 = 3; t0 != 10; t0++)
X close(t0);
X#endif
X#ifdef JOB_CONTROL
X opts[MONITOR] = (interact) ? OPT_SET : OPT_UNSET;
X if (jobbing) {
X SHTTY = movefd((isatty(0)) ? dup(0) : open("/dev/tty",O_RDWR));


X if (SHTTY == -1)

X opts[MONITOR] = OPT_UNSET;

X else {
X#ifdef TIOCSETD
X#ifdef NTTYDISC
X int ldisc = NTTYDISC;
X ioctl(SHTTY, TIOCSETD, &ldisc);
X#endif
X#endif
X gettyinfo(&shttyinfo); /* get tty state */
X#ifdef sgi
X if (shttyinfo.tio.c_cc[VSWTCH] <= 0) /* hack for irises */
X shttyinfo.tio.c_cc[VSWTCH] = CSWTCH;
X#endif
X savedttyinfo = shttyinfo;
X }
X#ifdef sgi
X setpgrp(0,getpgrp(0));
X#endif
X if ((mypgrp = getpgrp(0)) <= 0)


X opts[MONITOR] = OPT_UNSET;

X else while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) {
X sleep(1);
X mypgrp = getpgrp(0);
X if (mypgrp == gettygrp()) break;
X killpg(mypgrp,SIGTTIN);
X mypgrp = getpgrp(0);
X }
X } else
X SHTTY = -1;
X#else


X opts[MONITOR] = OPT_UNSET;

X SHTTY = movefd((isatty(0)) ? dup(0) : open("/dev/tty",O_RDWR));


X if (SHTTY != -1) {

X gettyinfo(&shttyinfo);
X savedttyinfo = shttyinfo;
X }
X#endif
X}
X
Xstatic long
Xget_baudrate(speedcode)
Xint speedcode;
X{
X switch(speedcode) {
X case B0: return(0L);
X case B50: return(50L);
X case B75: return(75L);
X case B110: return(110L);
X case B134: return(134L);
X case B150: return(150L);
X case B200: return(200L);
X case B300: return(300L);
X case B600: return(600L);
X#ifdef _B900
X case _B900: return(900L);
X#endif
X case B1200: return(1200L);
X case B1800: return(1800L);
X case B2400: return(2400L);
X#ifdef _B3600
X case _B3600: return(3600L);
X#endif
X case B4800: return(4800L);
X#ifdef _B7200
X case _B7200: return(7200L);
X#endif
X case B9600: return(9600L);
X#ifdef B19200
X case B19200: return(19200L);
X#else
X#ifdef EXTA
X case EXTA: return(19200L);
X#endif
X#endif
X#ifdef B38400
X case B38400: return(38400L);
X#else
X#ifdef EXTB
X case EXTB: return(38400L);
X#endif
X#endif
X default: break;
X }
X return(0L);
X}
X
Xvoid setupvals() /**/
X{
Xstruct passwd *pswd;
Xchar *ptr,*s;
X
X curhist = 0;
X histsiz = DEFAULT_HISTSIZE;
X lithistsiz = 5;
X inithist();
X mailcheck = logcheck = 60;
X dirstacksize = -1;
X listmax = 100;
X reporttime = -1;
X bangchar = '!';
X hashchar = '#';
X hatchar = '^';
X termok = 0;
X curjob = prevjob = coprocin = coprocout = -1;
X shtimer = time(NULL); /* init $SECONDS */
X srand((unsigned int) shtimer);
X /* build various hash tables; argument to newhtable is table size */
X aliastab = newhtable(37);
X addreswords();
X paramtab = newhtable(151);
X cmdnamtab = newhtable(37);
X compctltab = newhtable(13);
X initxbindtab();
X nullcmd = ztrdup("cat");
X readnullcmd = ztrdup("more");
X prompt = ztrdup("%m%# ");
X prompt2 = ztrdup("> ");
X prompt3 = ztrdup("?# ");
X prompt4 = ztrdup("+ ");
X sprompt = ztrdup("zsh: correct `%R' to `%r' [nyae]? ");
X term = ztrdup("");
X ppid = getppid();
X#ifdef TIO
X#if defined(HAS_TCCRAP) && defined(TERMIOS)
X baud = cfgetospeed(&shttyinfo.tio);
X if (baud < 100) baud = get_baudrate(baud); /* aren't "standards" great?? */
X#else
X baud = get_baudrate(shttyinfo.tio.c_cflag & CBAUD);
X#endif
X#else
X baud = get_baudrate(shttyinfo.sgttyb.sg_ospeed);
X#endif
X#ifdef TIOCGWINSZ


X if (!(columns = shttyinfo.winsize.ws_col))
X columns = 80;

X if (!(lines = shttyinfo.winsize.ws_row))
X lines = 24;
X#else
X columns = 80;
X lines = 24;
X#endif
X ifs = ztrdup(" \t\n");
X if (pswd = getpwuid(getuid())) {
X username = ztrdup(pswd->pw_name);
X home = ztrdup(pswd->pw_dir);
X } else {
X username = ztrdup("");
X home = ztrdup("/");
X }
X if (ptr = zgetenv("LOGNAME"))
X logname = ztrdup(ptr);
X else
X logname = ztrdup(username);
X timefmt = ztrdup(DEFTIMEFMT);
X watchfmt = ztrdup(DEFWATCHFMT);
X if (!(ttystrname = ztrdup(ttyname(SHTTY))))
X ttystrname = ztrdup("");
X wordchars = ztrdup(DEFWORDCHARS);
X fceditparam = ztrdup(DEFFCEDIT);
X tmpprefix = ztrdup(DEFTMPPREFIX);
X postedit = ztrdup("");
X if (ispwd(home)) pwd = ztrdup(home);
X else if ((ptr = zgetenv("PWD")) && ispwd(ptr)) pwd = ztrdup(ptr);
X else pwd = zgetwd();
X oldpwd = ztrdup(pwd);
X hostnam = zalloc(256);
X underscore = ztrdup("");
X gethostname(hostnam,256);
X mypid = getpid();
X cdpath = mkarray(NULL);
X manpath = mkarray(NULL);
X fignore = mkarray(NULL);
X fpath = mkarray(NULL);
X mailpath = mkarray(NULL);
X watch = mkarray(NULL);
X hosts = mkarray(NULL);
X psvar = mkarray(NULL);
X compctlsetup();
X userdirs = (char **) zcalloc(sizeof(char *)*2);
X usernames = (char **) zcalloc(sizeof(char *)*2);
X userdirsz = 2;
X userdirct = 0;
X adduserdir("",home);
X optarg = ztrdup("");
X zoptind = 1;
X schedcmds = NULL;
X path = (char **) zalloc(4*sizeof *path);
X path[0] = ztrdup("/bin"); path[1] = ztrdup("/usr/bin");
X path[2] = ztrdup("/usr/ucb"); path[3] = NULL;
X inittyptab();
X initlextabs();
X setupparams();
X setparams();
X inittyptab();
X if ((s = zgetenv("EMACS")) && !strcmp(s,"t") && !strcmp(term,"emacs"))
X opts[USEZLE] = OPT_UNSET;
X#ifndef HAS_RUSAGE
X times(&shtms);
X#endif
X}
X
Xvoid compctlsetup() /**/
X{
Xstatic char
X *hs[] = {"telnet","rlogin","ftp","rup","rusers","rsh",NULL},
X *os[] = {"setopt","unsetopt",NULL},
X *vs[] = {"export","typeset","vared","unset",NULL},
X *cs[] = {"which","builtin",NULL},
X *bs[] = {"bindkey",NULL};
X
X compctl_process(hs,CC_HOSTS,NULL);
X compctl_process(os,CC_OPTIONS,NULL);
X compctl_process(vs,CC_VARS,NULL);
X compctl_process(bs,CC_BINDINGS,NULL);
X compctl_process(cs,CC_COMMPATH,NULL);
X cc_compos.mask = CC_COMMPATH;
X cc_default.mask = CC_FILES;
X}
X
Xvoid initialize() /**/
X{
Xint t0;
X#ifdef SYSVR4
X static struct sigaction chldaction;
X#endif
X
X breaks = loops = 0;
X lastmailcheck = time(NULL);
X locallist = NULL;
X dirstack = newlist();
X bufstack = newlist();
X newcmdnamtab();


X inbuf = zalloc(inbufsz = 256);
X inbufptr = inbuf+inbufsz;
X inbufct = 0;

X#ifndef QDEBUG
X signal(SIGQUIT,SIG_IGN);
X#endif
X#ifdef RLIM_INFINITY
X for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
X getrlimit(t0,limits+t0);
X#endif
X hsubl = hsubr = NULL;
X lastpid = 0;


X bshin = fdopen(SHIN,"r");

X#ifdef SYSVR4
X memset(&chldaction, 0, sizeof(chldaction));
X chldaction.sa_handler = handler;
X sigaction(SIGCHLD, &chldaction, NULL);
X#else
X signal(SIGHUP,handler);
X signal(SIGCHLD,handler);
X#endif
X if (jobbing)
X {
X long ttypgrp;
X while ((ttypgrp = gettygrp()) != -1 && ttypgrp != mypgrp)
X kill(0,SIGTTIN);
X if (ttypgrp == -1)
X {


X opts[MONITOR] = OPT_UNSET;

X }
X else
X {


X signal(SIGTTOU,SIG_IGN);
X signal(SIGTSTP,SIG_IGN);
X signal(SIGTTIN,SIG_IGN);
X signal(SIGPIPE,SIG_IGN);

X attachtty(mypgrp);
X }
X }
X if (interact)
X {
X signal(SIGTERM,SIG_IGN);
X#ifdef SIGWINCH
X signal(SIGWINCH,handler);
X#endif
X signal(SIGALRM,handler);
X intr();
X }
X}
X
Xvoid addreswords() /**/
X{
Xstatic char *reswds[] = {
X "do", "done", "esac", "then", "elif", "else", "fi", "for", "case",
X "if", "while", "function", "repeat", "time", "until", "exec", "command",
X "select", "coproc", "noglob", "-", "nocorrect", "foreach", "end", NULL
X };
Xint t0;
X
X for (t0 = 0; reswds[t0]; t0++)
X addhperm(reswds[t0],mkanode(NULL,-1-t0),aliastab,(FFunc) 0);
X}
X
Xvoid runscripts(zshname) /**/
Xchar *zshname;
X{
X /*
X KSH Mode:
X if called as "ksh", we source the standard
X sh/ksh scripts:
X w...@rcvie.co.at 1992/05/14
X */
X
X if ( strcmp(zshname, "ksh") == 0 )
X {
X if (islogin) source("/etc/profile") ;
X if (islogin) sourcehome(".profile");
X source(getsparam("ENV"));
X }
X else if (isset(NORCS))
X {
X#ifdef GLOBALZSHENV
X source(GLOBALZSHENV);
X#endif
X }
X else
X {
X#ifdef GLOBALZSHENV
X source(GLOBALZSHENV);
X#endif
X if (isset(NORCS)) {
X#ifdef GLOBALZPROFILE
X if (islogin) source(GLOBALZPROFILE);
X#endif
X#ifdef GLOBALZSHRC
X if (! isset(NORCS))
X source(GLOBALZSHRC);
X#endif
X#ifdef GLOBALZLOGIN
X if (islogin && ! isset(NORCS))
X source(GLOBALZLOGIN);
X#endif
X } else {
X sourcehome(".zshenv");
X if (interact && ! isset(NORCS)) {
X if (islogin) {
X#ifdef GLOBALZPROFILE
X source(GLOBALZPROFILE);
X if (! isset(NORCS))
X#endif
X sourcehome(".zprofile");
X }
X#ifdef GLOBALZSHRC
X if (! isset(NORCS))
X source(GLOBALZSHRC);
X if (! isset(NORCS))
X#endif
X sourcehome(".zshrc");
X if (islogin && ! isset(NORCS)) {
X#ifdef GLOBALZLOGIN
X source(GLOBALZLOGIN);
X if (! isset(NORCS))
X#endif
X sourcehome(".zlogin");
X }
X }
X }
X }
X if (isset('c'))
X {
X if (SHIN >= 10)
X close(SHIN);
X SHIN = movefd(open("/dev/null",O_RDONLY));
X execstring(cmd);
X stopmsg = 1;
X zexit(lastval);
X }
X if (interact && ! isset(NORCS))
X readhistfile(getsparam("HISTFILE"),0);
X#ifdef TIOCSWINSZ


X if (!(columns = shttyinfo.winsize.ws_col))

X columns = 80;
X if (!(lines = shttyinfo.winsize.ws_row))
X lines = 24;
X#endif
X}
X
Xvoid ainit() /**/
X{
X alstackind = 0; /* reset alias stack */
X alstat = 0;
X isfirstln = 1;
X}
END_OF_FILE
if test 14274 -ne `wc -c <'src/init.c'`; then
echo shar: \"'src/init.c'\" unpacked with wrong size!
fi
# end of 'src/init.c'
fi
if test -f 'src/zle_bindings.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle_bindings.c'\"
else
echo shar: Extracting \"'src/zle_bindings.c'\" \(17791 characters\)
sed "s/^X//" >'src/zle_bindings.c' <<'END_OF_FILE'
X/*
X *
X * zle_bindings.c - commands and keymaps


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#define ZLE
X#include "zsh.h"
X
X

Xstruct zlecmd zlecmds[] = {
X{"accept-and-hold",acceptandhold,0},
X{"accept-and-infer-next-history",acceptandinfernexthistory,0},
X{"accept-and-menu-complete", acceptandmenucomplete, ZLE_MENUCMP},
X{"accept-line",acceptline,0},
X{"accept-line-and-down-history",acceptlineanddownhistory,0},
X{"backward-char",backwardchar,ZLE_MOVEMENT},
X{"backward-delete-char",backwarddeletechar,ZLE_DELETE},
X{"backward-delete-word",backwarddeleteword,ZLE_DELETE},
X{"backward-kill-line",backwardkillline,ZLE_KILL},
X{"backward-kill-word",backwardkillword,ZLE_KILL|ZLE_DELETE},
X{"backward-word",backwardword,ZLE_MOVEMENT},
X{"beginning-of-buffer-or-history",beginningofbufferorhistory,ZLE_MOVEMENT},
X{"beginning-of-history",beginningofhistory,0},
X{"beginning-of-line",beginningofline,ZLE_MOVEMENT},
X{"beginning-of-line-hist",beginningoflinehist,ZLE_MOVEMENT},
X{"capitalize-word",capitalizeword,0},
X{"clear-screen",clearscreen,0},
X{"complete-word",completeword,ZLE_MENUCMP},
X{"copy-prev-word",copyprevword,0},
X{"copy-region-as-kill",copyregionaskill,ZLE_KILL},
X{"delete-char",deletechar,ZLE_DELETE},
X{"delete-char-or-list",deletecharorlist,ZLE_MENUCMP},
X{"delete-word",deleteword,ZLE_DELETE},
X{"digit-argument",digitargument,ZLE_ARG},
X{"down-case-word",downcaseword,0},
X{"down-history",downhistory,0},
X{"down-line-or-history",downlineorhistory,ZLE_MOVEMENT|ZLE_LINEMOVE},
X{"end-of-buffer-or-history",endofbufferorhistory,ZLE_MOVEMENT},
X{"end-of-history",endofhistory,0},
X{"end-of-line",endofline,ZLE_MOVEMENT},
X{"end-of-line-hist",endoflinehist,ZLE_MOVEMENT},
X{"exchange-point-and-mark",exchangepointandmark,ZLE_MOVEMENT},
X{"execute-last-named-cmd",(F) 0,0},
X{"execute-named-cmd",(F) 0,0},
X{"expand-history",expandhistory,0},
X{"expand-or-complete",expandorcomplete,ZLE_MENUCMP},
X{"expand-word",expandword,0},
X{"forward-char",forwardchar,ZLE_MOVEMENT},
X{"forward-word",forwardword,ZLE_MOVEMENT},
X{"get-line",getline,0},
X{"gosmacs-transpose-chars",gosmacstransposechars,0},
X{"history-incremental-search-backward",historyincrementalsearchbackward,0},
X{"history-incremental-search-forward",historyincrementalsearchforward,0},
X{"history-search-backward",historysearchbackward,ZLE_HISTSEARCH},
X{"history-search-forward",historysearchforward,ZLE_HISTSEARCH},
X{"infer-next-history",infernexthistory,0},
X{"insert-last-word",insertlastword,ZLE_INSERT},
X{"kill-buffer",killbuffer,ZLE_KILL},
X{"kill-line",killline,ZLE_KILL},
X{"kill-region",killregion,ZLE_KILL},
X{"kill-whole-line",killwholeline,ZLE_KILL},
X{"list-choices",listchoices,ZLE_DELETE}, /* ZLE_DELETE fixes autoremoveslash */
X{"list-expand",listexpand,ZLE_MENUCMP},
X{"magic-space",magicspace,0},
X{"menu-complete",menucompleteword,ZLE_MENUCMP},
X{"menu-expand-or-complete",menuexpandorcomplete,ZLE_MENUCMP},
X{"overwrite-mode",overwritemode,0},
X{"push-line",pushline,0},
X{"quoted-insert",quotedinsert,ZLE_INSERT},
X{"quote-line",quoteline,0},
X{"quote-region",quoteregion,0},
X{"redisplay",redisplay,0},
X{"reverse-menu-complete",reversemenucomplete,ZLE_MENUCMP},
X{"run-help",processcmd,0},
X{"self-insert",selfinsert,ZLE_INSERT},
X{"self-insert-unmeta",selfinsertunmeta,ZLE_INSERT},
X{"send-break",sendbreak,0},
X{"send-string",sendstring,0},
X{"",(F) 0,0},
X{"set-mark-command",setmarkcommand,0},
X{"spell-word",spellword,0},
X{"toggle-literal-history",toggleliteralhistory,0},
X{"transpose-chars",transposechars,0},
X{"transpose-words",transposewords,0},
X{"undefined-key",undefinedkey,0},
X{"undo",undo,ZLE_UNDO},
X{"universal-argument",universalargument,ZLE_ARG},
X{"up-case-word",upcaseword,0},
X{"up-history",uphistory,0},
X{"up-line-or-history",uplineorhistory,ZLE_LINEMOVE|ZLE_MOVEMENT},
X{"vi-add-eol",viaddeol,0},
X{"vi-add-next",viaddnext,0},
X{"vi-backward-blank-word",vibackwardblankword,ZLE_MOVEMENT},
X{"vi-backward-char",vibackwardchar,ZLE_MOVEMENT},
X{"vi-backward-delete-char",vibackwarddeletechar,ZLE_KILL},
X{"vi-beginning-of-line",vibeginningofline,ZLE_MOVEMENT},
X{"vi-caps-lock-panic",vicapslockpanic,0},
X{"vi-change",vichange,0},
X{"vi-change-eol",vichangeeol,0},
X{"vi-change-whole-line",vichangewholeline,0},
X{"vi-cmd-mode",vicmdmode,0},
X{"vi-delete",videlete,ZLE_KILL},
X{"vi-delete-char",videletechar,ZLE_KILL},
X{"vi-digit-or-beginning-of-line",(F) 0,0},
X{"vi-end-of-line",viendofline,ZLE_MOVEMENT},
X{"vi-fetch-history",vifetchhistory,0},
X{"vi-find-next-char",vifindnextchar,ZLE_MOVEMENT},
X{"vi-find-next-char-skip",vifindnextcharskip,ZLE_MOVEMENT},
X{"vi-find-prev-char",vifindprevchar,ZLE_MOVEMENT},
X{"vi-find-prev-char-skip",vifindprevcharskip,ZLE_MOVEMENT},
X{"vi-first-non-blank",vifirstnonblank,ZLE_MOVEMENT},
X{"vi-forward-blank-word",viforwardblankword,ZLE_MOVEMENT},
X{"vi-forward-blank-word-end",viforwardblankwordend,ZLE_MOVEMENT},
X{"vi-forward-char",viforwardchar,ZLE_MOVEMENT},
X{"vi-forward-word-end",viforwardwordend,ZLE_MOVEMENT},
X{"vi-goto-column",vigotocolumn,ZLE_MOVEMENT},
X{"vi-goto-mark",vigotomark,ZLE_MOVEMENT},
X{"vi-goto-mark-line",vigotomarkline,ZLE_MOVEMENT},
X{"vi-history-search-backward",vihistorysearchbackward,0},
X{"vi-history-search-forward",vihistorysearchforward,0},
X{"vi-indent",viindent,0},
X{"vi-insert",viinsert,0},
X{"vi-insert-bol",viinsertbol,0},
X{"vi-join",vijoin,0},
X{"vi-match-bracket",vimatchbracket,ZLE_MOVEMENT},
X{"vi-open-line-above",viopenlineabove,0},
X{"vi-open-line-below",viopenlinebelow,0},
X{"vi-oper-swap-case",vioperswapcase,0},
X{"vi-put-after",viputafter,ZLE_YANK},
X{"vi-repeat-change",virepeatchange,ZLE_ARG},
X{"vi-repeat-find",virepeatfind,ZLE_MOVEMENT},
X{"vi-repeat-search",virepeatsearch,ZLE_MOVEMENT},
X{"vi-replace",vireplace,0},
X{"vi-replace-chars",vireplacechars,0},
X{"vi-rev-repeat-find",virevrepeatfind,ZLE_MOVEMENT},
X{"vi-rev-repeat-search",virevrepeatsearch,ZLE_MOVEMENT},
X{"vi-set-buffer",visetbuffer,0},
X{"vi-set-mark",visetmark,0},
X{"vi-substitute",visubstitute,0},
X{"vi-swap-case",viswapcase,0},
X{"vi-undo-change",undo,0},
X{"vi-unindent",viunindent,0},
X{"vi-yank",viyank,0},
X{"vi-yank-eol",viyankeol,0},
X{"which-command",processcmd,0},
X{"yank",yank,ZLE_YANK|ZLE_NAMEDBUFFER},
X{"yank-pop",yankpop,ZLE_YANK},
X{"emacs-forward-word",emacsforwardword,ZLE_MOVEMENT},
X{"emacs-backward-word",emacsbackwardword,ZLE_MOVEMENT},
X{"kill-word",killword,ZLE_KILL},
X{"vi-kill-line",vikillline,0},
X{"vi-backward-kill-word",vibackwardkillword,ZLE_KILL},
X{"expand-cmd-path",expandcmdpath,0},
X{"neg-argument",negargument,ZLE_NEGARG|ZLE_ARG},
X{"pound-insert",poundinsert,0},
X{"vi-forward-word",viforwardword,ZLE_MOVEMENT},
X{"vi-backward-word",vibackwardword,ZLE_MOVEMENT},
X{"up-line-or-search",uplineorsearch,ZLE_MOVEMENT|ZLE_LINEMOVE|ZLE_HISTSEARCH},
X{"down-line-or-search",downlineorsearch,ZLE_MOVEMENT|ZLE_LINEMOVE|ZLE_HISTSEARCH},
X{"",(F) 0,0}
X};
X
Xint emacsbind[256] = {
X/* ^@ */ z_setmarkcommand,
X/* ^A */ z_beginningofline,
X/* ^B */ z_backwardchar,
X/* ^C */ z_sendbreak,
X/* ^D */ z_deletecharorlist,
X/* ^E */ z_endofline,
X/* ^F */ z_forwardchar,
X/* ^G */ z_undefinedkey,
X/* ^H */ z_backwarddeletechar,
X/* ^I */ z_expandorcomplete,
X/* ^J */ z_acceptline,
X/* ^K */ z_killline,
X/* ^L */ z_clearscreen,
X/* ^M */ z_acceptline,
X/* ^N */ z_downlineorhistory,
X/* ^O */ z_acceptlineanddownhistory,
X/* ^P */ z_uplineorhistory,
X/* ^Q */ z_pushline,
X/* ^R */ z_historyincrementalsearchbackward,
X/* ^S */ z_historyincrementalsearchforward,
X/* ^T */ z_transposechars,
X/* ^U */ z_killwholeline,
X/* ^V */ z_quotedinsert,
X/* ^W */ z_backwardkillword,
X/* ^X */ z_sequenceleadin,
X/* ^Y */ z_yank,
X/* ^Z */ z_undefinedkey,
X/* ^[ */ z_sequenceleadin,
X/* ^\ */ z_undefinedkey,
X/* ^] */ z_undefinedkey,
X/* ^^ */ z_undefinedkey,
X/* ^_ */ z_undo,
X/* */ z_selfinsert,
X/* ! */ z_selfinsert,
X/* " */ z_selfinsert,
X/* # */ z_selfinsert,
X/* $ */ z_selfinsert,
X/* % */ z_selfinsert,
X/* & */ z_selfinsert,
X/* ' */ z_selfinsert,
X/* ( */ z_selfinsert,
X/* ) */ z_selfinsert,
X/* * */ z_selfinsert,
X/* + */ z_selfinsert,
X/* , */ z_selfinsert,
X/* - */ z_selfinsert,
X/* . */ z_selfinsert,
X/* / */ z_selfinsert,
X/* 0 */ z_selfinsert,
X/* 1 */ z_selfinsert,
X/* 2 */ z_selfinsert,
X/* 3 */ z_selfinsert,
X/* 4 */ z_selfinsert,
X/* 5 */ z_selfinsert,
X/* 6 */ z_selfinsert,
X/* 7 */ z_selfinsert,
X/* 8 */ z_selfinsert,
X/* 9 */ z_selfinsert,
X/* : */ z_selfinsert,
X/* ; */ z_selfinsert,
X/* < */ z_selfinsert,
X/* = */ z_selfinsert,
X/* > */ z_selfinsert,
X/* ? */ z_selfinsert,
X/* @ */ z_selfinsert,
X/* A */ z_selfinsert,
X/* B */ z_selfinsert,
X/* C */ z_selfinsert,
X/* D */ z_selfinsert,
X/* E */ z_selfinsert,
X/* F */ z_selfinsert,
X/* G */ z_selfinsert,
X/* H */ z_selfinsert,
X/* I */ z_selfinsert,
X/* J */ z_selfinsert,
X/* K */ z_selfinsert,
X/* L */ z_selfinsert,
X/* M */ z_selfinsert,
X/* N */ z_selfinsert,
X/* O */ z_selfinsert,
X/* P */ z_selfinsert,
X/* Q */ z_selfinsert,
X/* R */ z_selfinsert,
X/* S */ z_selfinsert,
X/* T */ z_selfinsert,
X/* U */ z_selfinsert,
X/* V */ z_selfinsert,
X/* W */ z_selfinsert,
X/* X */ z_selfinsert,
X/* Y */ z_selfinsert,
X/* Z */ z_selfinsert,
X/* [ */ z_selfinsert,
X/* \ */ z_selfinsert,
X/* ] */ z_selfinsert,
X/* ^ */ z_selfinsert,
X/* _ */ z_selfinsert,
X/* ` */ z_selfinsert,
X/* a */ z_selfinsert,
X/* b */ z_selfinsert,
X/* c */ z_selfinsert,
X/* d */ z_selfinsert,
X/* e */ z_selfinsert,
X/* f */ z_selfinsert,
X/* g */ z_selfinsert,
X/* h */ z_selfinsert,
X/* i */ z_selfinsert,
X/* j */ z_selfinsert,
X/* k */ z_selfinsert,
X/* l */ z_selfinsert,
X/* m */ z_selfinsert,
X/* n */ z_selfinsert,
X/* o */ z_selfinsert,
X/* p */ z_selfinsert,
X/* q */ z_selfinsert,
X/* r */ z_selfinsert,
X/* s */ z_selfinsert,
X/* t */ z_selfinsert,
X/* u */ z_selfinsert,
X/* v */ z_selfinsert,
X/* w */ z_selfinsert,
X/* x */ z_selfinsert,
X/* y */ z_selfinsert,
X/* z */ z_selfinsert,
X/* { */ z_selfinsert,
X/* | */ z_selfinsert,
X/* } */ z_selfinsert,
X/* ~ */ z_selfinsert,
X/* ^? */ z_backwarddeletechar,
X/* M-^@ */ z_undefinedkey,
X/* M-^A */ z_undefinedkey,
X/* M-^B */ z_undefinedkey,
X/* M-^C */ z_undefinedkey,
X/* M-^D */ z_listchoices,
X/* M-^E */ z_undefinedkey,
X/* M-^F */ z_undefinedkey,
X/* M-^G */ z_undefinedkey,
X/* M-^H */ z_backwardkillword,
X/* M-^I */ z_selfinsertunmeta,
X/* M-^J */ z_selfinsertunmeta,
X/* M-^K */ z_undefinedkey,
X/* M-^L */ z_clearscreen,
X/* M-^M */ z_selfinsertunmeta,
X/* M-^N */ z_undefinedkey,
X/* M-^O */ z_undefinedkey,
X/* M-^P */ z_undefinedkey,
X/* M-^Q */ z_undefinedkey,
X/* M-^R */ z_undefinedkey,
X/* M-^S */ z_undefinedkey,
X/* M-^T */ z_undefinedkey,
X/* M-^U */ z_undefinedkey,
X/* M-^V */ z_undefinedkey,
X/* M-^W */ z_undefinedkey,
X/* M-^X */ z_undefinedkey,
X/* M-^Y */ z_undefinedkey,
X/* M-^Z */ z_undefinedkey,
X/* M-^[ */ z_undefinedkey,
X/* M-^\ */ z_undefinedkey,
X/* M-^] */ z_undefinedkey,
X/* M-^^ */ z_undefinedkey,
X/* M-^_ */ z_copyprevword,
X/* M- */ z_expandhistory,
X/* M-! */ z_expandhistory,
X/* M-" */ z_quoteregion,
X/* M-# */ z_undefinedkey,
X/* M-$ */ z_spellword,
X/* M-% */ z_undefinedkey,
X/* M-& */ z_undefinedkey,
X/* M-' */ z_quoteline,
X/* M-( */ z_undefinedkey,
X/* M-) */ z_undefinedkey,
X/* M-* */ z_undefinedkey,
X/* M-+ */ z_undefinedkey,
X/* M-, */ z_undefinedkey,
X/* M-- */ z_negargument,
X/* M-. */ z_insertlastword,
X/* M-/ */ z_undefinedkey,
X/* M-0 */ z_digitargument,
X/* M-1 */ z_digitargument,
X/* M-2 */ z_digitargument,
X/* M-3 */ z_digitargument,
X/* M-4 */ z_digitargument,
X/* M-5 */ z_digitargument,
X/* M-6 */ z_digitargument,
X/* M-7 */ z_digitargument,
X/* M-8 */ z_digitargument,
X/* M-9 */ z_digitargument,
X/* M-: */ z_undefinedkey,
X/* M-; */ z_undefinedkey,
X/* M-< */ z_beginningofbufferorhistory,
X/* M-= */ z_undefinedkey,
X/* M-> */ z_endofbufferorhistory,
X/* M-? */ z_whichcommand,
X/* M-@ */ z_undefinedkey,
X/* M-A */ z_acceptandhold,
X/* M-B */ z_backwardword,
X/* M-C */ z_capitalizeword,
X/* M-D */ z_deleteword,
X/* M-E */ z_undefinedkey,
X/* M-F */ z_forwardword,
X/* M-G */ z_getline,
X/* M-H */ z_runhelp,
X/* M-I */ z_undefinedkey,
X/* M-J */ z_undefinedkey,
X/* M-K */ z_undefinedkey,
X/* M-L */ z_downcaseword,
X/* M-M */ z_undefinedkey,
X/* M-N */ z_historysearchforward,
X/* M-O */ z_undefinedkey,
X/* M-P */ z_historysearchbackward,
X/* M-Q */ z_pushline,
X/* M-R */ z_toggleliteralhistory,
X/* M-S */ z_spellword,
X/* M-T */ z_transposewords,
X/* M-U */ z_upcaseword,
X/* M-V */ z_undefinedkey,
X/* M-W */ z_copyregionaskill,
X/* M-X */ z_undefinedkey,
X/* M-Y */ z_undefinedkey,
X/* M-Z */ z_undefinedkey,
X/* M-[ */ z_sequenceleadin,
X/* M-\ */ z_undefinedkey,
X/* M-] */ z_undefinedkey,
X/* M-^ */ z_undefinedkey,
X/* M-_ */ z_insertlastword,
X/* M-` */ z_undefinedkey,
X/* M-a */ z_acceptandhold,
X/* M-b */ z_backwardword,
X/* M-c */ z_capitalizeword,
X/* M-d */ z_deleteword,
X/* M-e */ z_undefinedkey,
X/* M-f */ z_forwardword,
X/* M-g */ z_getline,
X/* M-h */ z_runhelp,
X/* M-i */ z_undefinedkey,
X/* M-j */ z_undefinedkey,
X/* M-k */ z_undefinedkey,
X/* M-l */ z_downcaseword,
X/* M-m */ z_undefinedkey,
X/* M-n */ z_historysearchforward,
X/* M-o */ z_undefinedkey,
X/* M-p */ z_historysearchbackward,
X/* M-q */ z_pushline,
X/* M-r */ z_toggleliteralhistory,
X/* M-s */ z_spellword,
X/* M-t */ z_transposewords,
X/* M-u */ z_upcaseword,
X/* M-v */ z_undefinedkey,
X/* M-w */ z_copyregionaskill,
X/* M-x */ z_executenamedcmd,
X/* M-y */ z_yankpop,
X/* M-z */ z_executelastnamedcmd,
X/* M-{ */ z_undefinedkey,
X/* M-| */ z_vigotocolumn,
X/* M-} */ z_undefinedkey,
X/* M-~ */ z_undefinedkey,
X/* M-^? */ z_backwardkillword,
X};
X
Xint viinsbind[32] = {
X/* ^@ */ z_undefinedkey,
X/* ^A */ z_selfinsert,
X/* ^B */ z_selfinsert,
X/* ^C */ z_sendbreak,
X/* ^D */ z_listchoices,
X/* ^E */ z_selfinsert,
X/* ^F */ z_selfinsert,
X/* ^G */ z_selfinsert,
X/* ^H */ z_vibackwarddeletechar,
X/* ^I */ z_expandorcomplete,
X/* ^J */ z_acceptline,
X/* ^K */ z_killline,
X/* ^L */ z_clearscreen,
X/* ^M */ z_acceptline,
X/* ^N */ z_selfinsert,
X/* ^O */ z_selfinsert,
X/* ^P */ z_selfinsert,
X/* ^Q */ z_selfinsert,
X/* ^R */ z_redisplay,
X/* ^S */ z_selfinsert,
X/* ^T */ z_selfinsert,
X/* ^U */ z_vikillline,
X/* ^V */ z_quotedinsert,
X/* ^W */ z_vibackwardkillword,
X/* ^X */ z_selfinsert,
X/* ^Y */ z_selfinsert,
X/* ^Z */ z_selfinsert,
X/* ^[ */ z_vicmdmode,
X/* ^\ */ z_selfinsert,
X/* ^] */ z_selfinsert,
X/* ^^ */ z_selfinsert,
X/* ^_ */ z_selfinsert,
X};
X
Xint vicmdbind[128] = {
X/* ^@ */ z_undefinedkey,
X/* ^A */ z_beginningofline,
X/* ^B */ z_undefinedkey,
X/* ^C */ z_sendbreak,
X/* ^D */ z_listchoices,
X/* ^E */ z_endofline,
X/* ^F */ z_undefinedkey,
X/* ^G */ z_listexpand,
X/* ^H */ z_backwarddeletechar,
X/* ^I */ z_completeword,
X/* ^J */ z_acceptline,
X/* ^K */ z_killline,
X/* ^L */ z_clearscreen,
X/* ^M */ z_acceptline,
X/* ^N */ z_downhistory,
X/* ^O */ z_undefinedkey,
X/* ^P */ z_uphistory,
X/* ^Q */ z_undefinedkey,
X/* ^R */ z_redisplay,
X/* ^S */ z_undefinedkey,
X/* ^T */ z_undefinedkey,
X/* ^U */ z_killbuffer,
X/* ^V */ z_undefinedkey,
X/* ^W */ z_backwardkillword,
X/* ^X */ z_expandorcomplete,
X/* ^Y */ z_undefinedkey,
X/* ^Z */ z_undefinedkey,
X/* ^[ */ z_sequenceleadin,
X/* ^\ */ z_undefinedkey,
X/* ^] */ z_undefinedkey,
X/* ^^ */ z_undefinedkey,
X/* ^_ */ z_undefinedkey,
X/* */ z_viforwardchar,
X/* ! */ z_undefinedkey,
X/* " */ z_visetbuffer,
X/* # */ z_poundinsert,
X/* $ */ z_viendofline,
X/* % */ z_vimatchbracket,
X/* & */ z_undefinedkey,
X/* ' */ z_vigotomarkline,
X/* ( */ z_undefinedkey,
X/* ) */ z_undefinedkey,
X/* * */ z_undefinedkey,
X/* + */ z_downlineorhistory,
X/* , */ z_virevrepeatfind,
X/* - */ z_uplineorhistory,
X/* . */ z_virepeatchange,
X/* / */ z_vihistorysearchbackward,
X/* 0 */ z_vidigitorbeginningofline,
X/* 1 */ z_digitargument,
X/* 2 */ z_digitargument,
X/* 3 */ z_digitargument,
X/* 4 */ z_digitargument,
X/* 5 */ z_digitargument,
X/* 6 */ z_digitargument,
X/* 7 */ z_digitargument,
X/* 8 */ z_digitargument,
X/* 9 */ z_digitargument,
X/* : */ z_undefinedkey,
X/* ; */ z_virepeatfind,
X/* < */ z_viunindent,
X/* = */ z_listchoices,
X/* > */ z_viindent,
X/* ? */ z_vihistorysearchforward,
X/* @ */ z_undefinedkey,
X/* A */ z_viaddeol,
X/* B */ z_vibackwardblankword,
X/* C */ z_vichangeeol,
X/* D */ z_killline,
X/* E */ z_viforwardblankwordend,
X/* F */ z_vifindprevchar,
X/* G */ z_vifetchhistory,
X/* H */ z_vicapslockpanic,
X/* I */ z_viinsertbol,
X/* J */ z_historysearchforward,
X/* K */ z_historysearchbackward,
X/* L */ z_undefinedkey,
X/* M */ z_undefinedkey,
X/* N */ z_virevrepeatsearch,
X/* O */ z_viopenlineabove,
X/* P */ z_yank,
X/* Q */ z_undefinedkey,
X/* R */ z_vireplace,
X/* S */ z_vichangewholeline,
X/* T */ z_vifindprevcharskip,
X/* U */ z_undefinedkey,
X/* V */ z_undefinedkey,
X/* W */ z_viforwardblankword,
X/* X */ z_vibackwarddeletechar,
X/* Y */ z_viyankeol,
X/* Z */ z_undefinedkey,
X/* [ */ z_undefinedkey,
X/* \ */ z_completeword,
X/* ] */ z_undefinedkey,
X/* ^ */ z_vifirstnonblank,
X/* _ */ z_undefinedkey,
X/* ` */ z_vigotomark,
X/* a */ z_viaddnext,
X/* b */ z_vibackwardword,
X/* c */ z_vichange,
X/* d */ z_videlete,
X/* e */ z_viforwardwordend,
X/* f */ z_vifindnextchar,
X/* g */ z_undefinedkey,
X/* h */ z_vibackwardchar,
X/* i */ z_viinsert,
X/* j */ z_downlineorhistory,
X/* k */ z_uplineorhistory,
X/* l */ z_viforwardchar,
X/* m */ z_visetmark,
X/* n */ z_virepeatsearch,
X/* o */ z_viopenlinebelow,
X/* p */ z_viputafter,
X/* q */ z_undefinedkey,
X/* r */ z_vireplacechars,
X/* s */ z_visubstitute,
X/* t */ z_vifindnextcharskip,
X/* u */ z_viundochange,
X/* v */ z_undefinedkey,
X/* w */ z_viforwardword,
X/* x */ z_videletechar,
X/* y */ z_viyank,
X/* z */ z_undefinedkey,
X/* { */ z_undefinedkey,
X/* | */ z_vigotocolumn,
X/* } */ z_undefinedkey,
X/* ~ */ z_viswapcase,
X/* ^? */ z_backwarddeletechar,
X};
X
END_OF_FILE
if test 17791 -ne `wc -c <'src/zle_bindings.c'`; then
echo shar: \"'src/zle_bindings.c'\" unpacked with wrong size!
fi
# end of 'src/zle_bindings.c'
fi
echo shar: End of archive 16 \(of 22\).
cp /dev/null ark16isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:27:54 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 67
Archive-name: zsh/part17

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: help/popd man/man1/zsh.1.03 src/builtin.c.02 src/subst.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:55 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 17 (of 22)."'
if test -f 'help/popd' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/popd'\"
else
echo shar: Extracting \"'help/popd'\" \(609 characters\)
sed "s/^X//" >'help/popd' <<'END_OF_FILE'
X popd [ +-n ]
X Removes entries from the directory stack. With no
X arguments, removes the top directory from the stack,
X and performs a cd to the new top directory. With an
X argument of the form +n, remove the nth entry counting
X from the left of the list shown by the dirs command,
X starting with zero, and change to that directory. With
X an argument of the form -n, remove the nth entry count-
X ing from the right. If the PUSHD_MINUS option is set,
X the meanings of + and - in this context are swapped.
END_OF_FILE
if test 609 -ne `wc -c <'help/popd'`; then
echo shar: \"'help/popd'\" unpacked with wrong size!
fi
# end of 'help/popd'
fi
if test -f 'man/man1/zsh.1.03' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'man/man1/zsh.1.03'\"
else
echo shar: Extracting \"'man/man1/zsh.1.03'\" \(17067 characters\)
sed "s/^X//" >'man/man1/zsh.1.03' <<'END_OF_FILE'
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).
XIf the first character of argument zero passed to the shell
Xis \-, or if the \-\fBl\fP flag is present, then the shell is
Xassumed to be a login shell, and commands
Xare read from /etc/zprofile and then $ZDOTDIR/.zprofile.
XThen, if the shell is interactive and the \fBNO_RCS\fP option is unset,
Xcommands are read from /etc/zshrc and then $ZDOTDIR/.zshrc.
XFinally, if the shell is a login shell, /etc/zlogin and $ZDOTDIR/.zlogin
Xare read.
X.PP
XIf the \fBNO_RCS\fP option is set within /etc/zshenv, then only /etc/zprofile,
X/etc/zshrc, and /etc/zlogin are read, and the $ZDOTDIR files are skipped.
XIf the \-\fBf\fP flag is present, only /etc/zshenv is read, and all other
Xinitialization files are skipped.
X.PP
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/.zprofile
X.br
X$ZDOTDIR/.zshrc
X.br
X$ZDOTDIR/.zlogin
X.br
X$ZDOTDIR/.zlogout
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 (p...@ttisms.com)
X.SH AVAILABILITY


XThe latest official release of zsh is available via anonymous ftp from

Xcs.ucsd.edu (132.239.51.3), in the directory pub/zsh. The beta release
Xof zsh 2.4 is available from carlo.phys.uva.nl (145.18.220.25), in the
Xdirectory pub/bas/zsh. This man page is current to zsh 2.3.1.
X.SH "UNDOCUMENTED FEATURES"
XKnown only to the recipients of the zsh mailing list, zsh-...@cs.uow.edu.au.
XIf you run into problems, please send your questions and patches to the
Xmailing list. To join the list, send email to zsh-r...@cs.uow.edu.au.
END_OF_FILE
if test 17067 -ne `wc -c <'man/man1/zsh.1.03'`; then
echo shar: \"'man/man1/zsh.1.03'\" unpacked with wrong size!
fi
# end of 'man/man1/zsh.1.03'
fi
if test -f 'src/builtin.c.02' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/builtin.c.02'\"
else
echo shar: Extracting \"'src/builtin.c.02'\" \(16952 characters\)
sed "s/^X//" >'src/builtin.c.02' <<'END_OF_FILE'
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 (b = builtins; b->name; b++)
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;
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 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[(int)*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 if (c == INTERACTIVE)
X zerr("can't change option: %s",arg,0);
X else
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[(int)*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[(int)opp->id] == 1)


X opts[(int)opp->id] = OPT_SET;

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


X opts[(int)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_MEMLOCK
X case RLIMIT_MEMLOCK: printf("locked-in-memory size (kb) "); t0 /= 1024; break;
X#endif
X#ifdef RLIMIT_NPROC
X case RLIMIT_NPROC: printf("processes "); break;
X#endif
X#ifdef RLIMIT_OFILE
X case RLIMIT_OFILE: printf("open files "); 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_MEMLOCK
X else if (ops['l'])
X res = RLIMIT_MEMLOCK;
X#endif
X#ifdef RLIMIT_NPROC
X else if (ops['p'])
X res = RLIMIT_NPROC;
X#endif
X#ifdef RLIMIT_OFILE
X else if (ops['o'])
X res = RLIMIT_OFILE;
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#ifdef RLIMIT_MEMLOCK
X case RLIMIT_MEMLOCK:
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 = "\0"; }
X else if (!argv[1]) {
X zerrnam(name,"variable name expected after -k",NULL,0);
X return 1;
X } else { usrkeys = *++argv; *argv = "\0"; }
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}
END_OF_FILE
if test 16952 -ne `wc -c <'src/builtin.c.02'`; then
echo shar: \"'src/builtin.c.02'\" unpacked with wrong size!
fi
# end of 'src/builtin.c.02'
fi
if test -f 'src/subst.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/subst.c'\"
else
echo shar: Extracting \"'src/subst.c'\" \(16309 characters\)
sed "s/^X//" >'src/subst.c' <<'END_OF_FILE'
X/*
X *
X * subst.c - various substitutions


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 <pwd.h>
X
X/* do substitutions before fork */
X
Xvoid prefork(list) /**/
XLklist list;
X{
XLknode node = firstnode(list);
Xint qt;
X
X while (node)
X {
X char *str,*str3;
X
X str = str3 = getdata(node);
X if ((*str == Inang || *str == Outang || *str == Equals) &&
X str[1] == Inpar)
X {
X if (*str == Inang)
X setdata(node,getoutproc(str+2)); /* <(...) */
X else if (*str == Equals)
X setdata(node,getoutputfile(str+2)); /* =(...) */
X else
X setdata(node,getinproc(str+2)); /* >(...) */
X if (!getdata(node))
X {
X zerr("parse error in process substitution",NULL,0);
X return;
X }
X }
X else while (*str)
X {
X if ((qt = *str == Qstring) || *str == String)
X if (str[1] != Inpar)
X if (str[1] == Inbrack)
X {
X arithsubst((vptr*) &str,&str3); /* $[...] */
X setdata(node,str3);
X str = str3;
X continue;
X }
X else
X {
X paramsubst(list,node,str,str3,qt);


X if (errflag)
X return;

X str3 = str = getdata(node);
X continue;
X }
X str++;
X if (errflag)
X return;
X }
X if (*(char *) getdata(node))
X remnulargs(getdata(node));
X if (unset(IGNOREBRACES))
X while (hasbraces(getdata(node)))
X xpandbraces(list,&node);
X filesub((char **) getaddrdata(node));


X if (errflag)
X return;

X incnode(node);
X }
X}
X
Xvoid postfork(list,doglob) /**/
XLklist list;int doglob;
X{
XLknode node = firstnode(list);
Xint glb = 1;
X
X badcshglob = 0;
X if (isset(NOGLOBOPT) || !doglob)
X glb = 0;
X while (node)
X {
X char *str3,*str;
X
X str = str3 = getdata(node);
X while (*str)
X {
X if (((*str == String || *str == Qstring) && str[1] == Inpar) ||
X *str == Tick || *str == Qtick)
X {
X Lknode n = prevnode(node);
X
X commsubst(list,node,str,str3,
X (*str == Qstring || *str == Qtick)); /* `...`,$(...) */


X if (errflag)
X return;

X str = str3 = getdata(node = nextnode(n));
X continue;
X }
X str++;
X }
X if (glb)
X {
X if (haswilds(getdata(node)))
X glob(list,&node);


X if (errflag)
X return;
X }

X incnode(node);
X }
X if (badcshglob == 1) zerr("no match",NULL,0);
X}
X
X/* perform substitution on a single word */
X
Xvoid singsub(s) /**/
Xchar **s;
X{
XLklist foo;
Xchar *t;
X
X for (t = *s; *t; t++)
X if (*t == String)
X *t = Qstring;
X else if (*t == Tick)
X *t = Qtick;
X foo = newlist();
X addnode(foo,*s);
X prefork(foo);


X if (errflag)
X return;

X postfork(foo,0);


X if (errflag)
X return;

X *s = ugetnode(foo);
X if (firstnode(foo))
X zerr("ambiguous: %s",*s,0);
X}
X
X/* strdup, but returns "Nularg" if this is a null string */
X
Xvptr nstrdup(s) /**/
Xvptr s;
X{


Xchar *t = s;
X

X if (!*t)
X return strdup(nulstring);
X return strdup(t);
X}
X
Xchar *dynread(stop) /**/


Xint stop;
X{
Xint bsiz = 256,ct = 0,c;
Xchar *buf = zalloc(bsiz),*ptr;
X
X ptr = buf;

X while ((c = hgetc()) != stop)


X {
X *ptr++ = c;

X if (++ct == bsiz)
X {
X buf = realloc(buf,bsiz *= 2);
X ptr = buf+ct;
X }
X }

X *ptr = 0;


X return buf;
X}
X

Xint filesub(namptr) /**/
Xchar **namptr;
X{
Xchar *str = *namptr,*cnam;
X
X if (*str == Tilde && str[1] != '=')
X {
X if (str[1] == '+' && (str[2] == '/' || str[2] == '\0'))
X {
X char *foo = strdup(pwd); /* ~+ */
X
X str+=2;
X modify(&foo,&str);
X *namptr = dyncat(pwd,str);
X return 1;
X }
X else if (str[1] == '-' && (str[2] == '/' || str[2] == '\0'))
X {
X char *foo; /* ~- */
X
X if (cnam = oldpwd)
X foo = cnam;
X else
X foo = pwd;
X str += 2;
X foo = strdup(foo);
X modify(&foo,&str);
X *namptr = dyncat(foo,str);
X return 1;
X }
X if (ialpha(str[1])) /* ~foo */
X {
X char *ptr,*hom;
X
X for (ptr = ++str; *ptr && iuser(*ptr); ptr++)
X if (*ptr == '-')
X *ptr = '-';
X if (*ptr && *ptr != '/') return 0;
X if (!(hom = gethome(str,ptr-str)))
X {
X zerr("user not found: %l",str,ptr-str);
X return 0;
X }
X modify(&hom,&ptr);
X *namptr = dyncat(hom,ptr);
X return 1;
X }
X else if (str[1] == '/') /* ~/foo */
X {
X *namptr = dyncat(home,str+1);
X return 1;
X }
X else if (!str[1]) /* ~ by itself */
X {
X *namptr = strdup(home);


X return 1;
X }
X }

X if (*str == Equals && iuser(str[1]) && unset(NOEQUALS))
X {
X char *ptr,*s,*ds;
X int val;
X
X if (ialpha(str[1])) /* =foo */
X {
X char sav,*pp;
X
X for (pp = str+1; *pp && *pp != ':'; pp++);
X sav = *pp;
X *pp = '\0';
X if (!(cnam = findcmd(str+1)))
X {
X zerr("%s not found",str+1,0);
X return 0;
X }
X *namptr = strdup(cnam);
X free(cnam);
X if ((*pp = sav) == ':')
X {
X modify(namptr,&pp);
X s = *namptr;
X *namptr = dyncat(*namptr,pp);
X }
X return 1;
X }
X if (str[1] == '-') /* =- */
X {
X val = -1;
X ptr = str+2;
X }
X else
X val = zstrtol(str+1,&ptr,10); /* =# */
X ds = dstackent(val);
X if (!ds)
X return 1;
X s = strdup(ds);
X modify(&s,&ptr);
X *namptr = dyncat(s,ptr);
X return 1;
X }


X return 0;
X}
X

X/* get a named directory */
X
Xchar *gethome(user,len) /**/
Xchar *user;int len;
X{
Xchar sav,*str,*ret_val;
Xstruct passwd *pw;
X
X if (len == 0)
X return strdup(home);
X sav = user[len];
X user[len] = '\0';
X if ((getparamtype(user,len) == PMFLAG_s) &&
X (str = getsparamval(user,len)) && *str == '/')
X {
X str = strdup(str);
X adduserdir(user,str);
X user[len] = sav;
X return str;
X }
X permalloc(); /* fixes iris bug--getpwnam calls strdup! */
X pw = getpwnam(user);
X lastalloc();
X if (!pw) {
X user[len] = sav;
X return NULL;
X }
X str = xsymlink(pw->pw_dir);
X adduserdir(user,str);
X user[len] = sav;
X ret_val = strdup(str);
X free(str);
X return ret_val;
X}
X
X/* `...`, $(...) */
X
Xvoid commsubst(l,n,str3,str,qt) /**/
XLklist l;Lknode n;char *str3;char *str;int qt;
X{
Xchar *str2;
XLknode where = prevnode(n);
XLklist pl;
X
X if (*str3 == Tick || *str3 == Qtick)
X {
X *str3 = '\0';
X for (str2 = ++str3; *str3 != Tick && *str3 != Qtick; str3++);
X *str3++ = '\0';
X }
X else
X {
X *str3++ = '\0';
X for (str2 = ++str3; *str3 != Outpar; str3++);
X *str3++ = '\0';
X }
X uremnode(l,n);
X if (!(pl = getoutput(str2,qt)))
X {
X if (!errflag)
X zerr("parse error in command substitution",NULL,0);
X return;
X }
X if (full(pl))
X {
X setdata(firstnode(pl),dyncat(str,peekfirst(pl)));
X setdata(lastnode(pl),dyncat(getdata(lastnode(pl)),str3));
X inslist(pl,where,l);
X }
X else
X insnode(l,where,dyncat(str,str3));
X}
X
X/* parameter substitution */
X
X#define isstring(c) (c == '$' || c == String || c == Qstring)
X#define isbrace(c) (c == '{' || c == Inbrace)
X
Xvoid paramsubst(l,n,aptr,bptr,qt) /**/
XLklist l;Lknode n;char *aptr;char *bptr;int qt;
X{
Xchar *s = aptr,*u,*idbeg,*idend,*ostr = bptr;
Xint brs; /* != 0 means ${...}, otherwise $... */
Xint colf; /* != 0 means we found a colon after the name */
Xint doub = 0; /* != 0 means we have %%, not %, or ##, not # */
Xint isarr = 0;
Xint plan9 = isset(RCEXPANDPARAM);
Xint getlen = 0;
Xint vunset = 0;
Xint spbreak = isset(SHWORDSPLIT) && !qt;
Xchar *val = NULL,**aval = NULL;
Xint vlen;
Xint fwidth = 0;
XValue v;


X
X *s++ = '\0';

X if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' &&
X *s != '!' && *s != '$' && *s != String && *s != Qstring &&
X *s != '?' && *s != Quest && *s != '_' &&
X *s != '*' && *s != Star && *s != '@' && *s != '{' &&
X *s != Inbrace && *s != '=' && *s != Hat && *s != '^') {
X s[-1] = '$';
X return;
X }
X if (brs = (*s == '{' || *s == Inbrace)) s++;
X for (;;) {
X if (*s == '^' || *s == Hat)
X plan9 ^= 1,s++;
X else if (*s == '=')
X spbreak ^= 1,s++;
X else if ((*s == '#' || *s == Pound) && (iident(s[1])
X || s[1] == '*' || s[1] == Star || s[1] == '@'
X || (isstring(s[1]) && isbrace(s[2]) && iident(s[3]))))
X getlen = 1,s++;
X else
X break;
X }
X
X idbeg = s;
X if (isstring(*s) && isbrace(s[1])) {
X int bct, sav;
X
X val = s;
X for (bct = 1, s += 2; *s && bct; ++s)
X if (*s == Inbrace || *s == '{')
X ++bct;
X else if (*s == Outbrace || *s == '}')
X --bct;
X sav = *s;
X *s = 0;
X singsub(&val);
X *s = sav;
X isarr = 0;
X v = (Value) NULL;
X } else if (!(v = getvalue(&s,1))) {
X vunset = 1;
X } else
X if (isarr = v->isarr) {
X aval = getarrvalue(v);
X if (qt && isarr > 0) {
X val = spacejoin(aval);
X isarr = 0;
X }
X }
X else {
X val = getstrvalue(v);
X fwidth = v->pm->ct;
X switch (v->pm->flags & (PMFLAG_L | PMFLAG_R | PMFLAG_Z)) {
X char *t;
X int t0;
X
X case PMFLAG_L:
X case PMFLAG_L|PMFLAG_Z:
X t = val;
X if (v->pm->flags & PMFLAG_Z)
X while (*t == '0') t++;
X else
X while (isep(*t)) t++;
X val = ncalloc(fwidth+1);
X val[fwidth] = '\0';
X if ((t0 = strlen(t)) > fwidth)
X t0 = fwidth;
X memset(val,' ',fwidth);
X strncpy(val,t,t0);
X break;
X case PMFLAG_R:
X case PMFLAG_Z:
X case PMFLAG_Z|PMFLAG_R:
X if (strlen(val) < fwidth) {
X t = ncalloc(fwidth+1);
X memset(t,(v->pm->flags & PMFLAG_R) ? ' ' : '0',fwidth);
X if ((t0 = strlen(val)) > fwidth)
X t0 = fwidth;
X strcpy(t+(fwidth-t0),val);
X val = t;
X } else {
X t = ncalloc(fwidth+1);
X t[fwidth] = '\0';
X strncpy(t,val+strlen(val)-fwidth,fwidth);
X val = t;
X }
X break;
X }
X switch (v->pm->flags & (PMFLAG_l | PMFLAG_u)) {
X char *t;
X
X case PMFLAG_l:
X t = val;


X for (;*t;t++)

X *t = tulower(*t);
X break;
X case PMFLAG_u:
X t = val;


X for (;*t;t++)

X *t = tuupper(*t);
X break;
X }
X }
X idend = s;
X if (colf = *s == ':') s++;
X
X /* check for ${..?...} or ${..=..} or one of those. Only works
X if the name is in braces. */
X
X if (brs && (*s == '-' || *s == '=' || *s == '?' || *s == '+' || *s == '#' ||
X *s == '%' || *s == Quest || *s == Pound)) {
X if (v && isarr && (*s == '%' || *s == '#' || *s == Pound)) {
X zerr("operator requires a scalar",NULL,0);
X return;
X }
X if (*s == s[1]) {
X s++;
X doub = 1;
X }
X u = ++s;
X if (brs) {
X int bct = 1;
X
X for (;;) {
X if (*s == '{' || *s == Inbrace)
X bct++;
X else if (*s == '}' || *s == Outbrace)
X bct--;
X if (!bct || !*s)
X break;
X s++;
X }
X } else {
X while (*s++);
X s--;
X }
X if (*s) *s++ = '\0';
X if (colf && !vunset)
X vunset = (isarr) ? !*aval : !*val;
X switch ((int)(unsigned char)u[-1]) {
X case '-':
X if (vunset)
X val = strdup(u), isarr = 0;
X break;
X case '=':
X if (vunset) {
X char sav = *idend;
X
X *idend = '\0';
X setsparam(idbeg,ztrdup(val = strdup(u)));
X *idend = sav;
X isarr = 0;
X }
X break;
X case '?':
X case (int)STOUC(Quest):
X if (vunset) {
X zerr("%s",(*u) ? u : "parameter not set",0);
X if (!interact)
X exit(1);
X return;
X }
X break;
X case '+':
X if (vunset)
X val = strdup("");
X else
X val = strdup(u);
X isarr = 0;
X break;
X case '#':
X case (int)STOUC(Pound):
X if (vunset)
X val = strdup("");
X singsub(&u);
X getmatch(&val,u,doub);


X break;
X case '%':

X if (vunset)
X val = strdup("");
X singsub(&u);
X getmatch(&val,u,doub+2);
X break;
X }
X } else { /* no ${...=...} or anything, but possible modifiers. */
X if (vunset) {
X if (isset(NOUNSET)) {
X zerr("parameter not set",NULL,0);
X return;
X }
X val = strdup("");
X }
X if (colf) {
X s--;
X if (!isarr) modify(&val,&s);
X else {
X char *ss = s;
X char **ap = aval;
X char **pp = aval = (char **)ncalloc(sizeof(char *)*(arrlen(aval)+1));
X while (*pp = *ap++) {
X ss = s;
X modify(pp++,&ss);
X }
X s = ss;
X }
X }
X if (brs) {
X if (*s != '}' && *s != Outbrace) {
X zerr("closing brace expected",NULL,0);
X return;
X }
X s++;
X }


X }
X if (errflag)
X return;

X if (getlen) {
X long len = 0;
X char buf[14];
X
X if (isarr) {
X char **ctr;
X for (ctr = aval; *ctr; ctr++,len++);
X } else
X len = strlen(val);
X sprintf(buf,"%ld",len);
X val = strdup(buf);
X isarr = 0;
X }
X if (isarr)
X if (!aval || !aval[0]) {
X val = strdup("");
X isarr = 0;
X } else if (!aval[1]) {
X val = aval[0];
X isarr = 0;
X }
X if (!qt && spbreak) {
X if (isarr)
X val = spacejoin(aval);
X isarr = 1;
X aval = spacesplit(val);
X if (!aval || !aval[0]) {
X val = strdup("");
X isarr = 0;
X } else if (!aval[1]) {
X val = aval[0];
X isarr = 0;
X }
X /* if only one member, not really an array */
X if (!aval[1])
X isarr = 0;
X }
X if (isarr)
X if (plan9) {
X int dlen;
X char *y;
X char *x;
X
X vlen = strlen(aval[0]);
X if (qt && vlen == 0)
X y = ncalloc((dlen = (char *) aptr-bptr+strlen(s)+1)+nulstrlen);
X else
X y = ncalloc((dlen = (char *) aptr-bptr+strlen(s)+1)+vlen);
X setdata(n,y);
X strcpy(y,ostr);
X strcat(y, (qt && vlen == 0) ? nulstring : aval[0]);
X strcat(y,s);
X while (*++aval) {
X vlen = strlen(*aval);
X if (qt && vlen == 0)
X x = ncalloc(dlen+nulstrlen);
X else
X x = ncalloc(dlen+vlen);
X strcpy(x,ostr);
X strcat(x, (qt && vlen == 0) ? nulstring : *aval);
X strcat(x,s);
X insnode(l,n,x), incnode(n);
X }
X } else {
X char *zz;
X
X vlen = strlen(aval[0]);
X if (qt && vlen == 0)
X zz = ncalloc((char *) aptr-(bptr)+nulstrlen+1);
X else
X zz = ncalloc((char *) aptr-(bptr)+vlen+1);
X setdata(n,zz);
X strcpy(zz,ostr);
X strcat(zz, (qt && vlen == 0) ? nulstring : *aval);
X aval++;
X while (aval[1]) {
X insnode(l,n,
X (qt && strlen(*aval) == 0) ? strdup(nulstring) : *aval);
X incnode(n);
X aval++;
X }
X vlen = strlen(*aval);
X if (qt && vlen == 0) {
X zz = ncalloc(nulstrlen+strlen(s)+1);
X strcpy(zz,nulstring);
X }
X else {
X zz = ncalloc(vlen+strlen(s)+1);
X strcpy(zz,*aval);
X }
X strcat(zz,s);
X insnode(l,n,zz);
X }
X else {
X vlen = strlen(val);
X if (qt && vlen == 0)
X bptr = ncalloc((char *) aptr-bptr+nulstrlen+strlen(s)+1);
X else
X bptr = ncalloc((char *) aptr-bptr+vlen+strlen(s)+1);
X setdata(n,bptr);
X strcpy(bptr,ostr);
X strcat(bptr, (qt && vlen == 0) ? nulstring : val);
X strcat(bptr,s);
X }
X}
X
X/* arithmetic substitution */
X
Xvoid arithsubst(aptr,bptr) /**/
Xvptr *aptr;char **bptr;
X{
Xchar *s = *aptr,*t,buf[16];
Xlong v;
X
X *s = '\0';
X for (; *s != Outbrack; s++);
X *s++ = '\0';
X v = matheval((char *) *aptr+2);
X sprintf(buf,"%ld",v);
X t = ncalloc(strlen(*bptr)+strlen(buf)+strlen(s)+1);
X strcpy(t,*bptr);
X strcat(t,buf);
X strcat(t,s);
X *bptr = t;
X}
X
Xvoid modify(str,ptr) /**/
Xchar **str;char **ptr;
X{
Xchar *ptr1,*ptr2,*ptr3,del,*lptr, sav;
Xint gbal;
X
X if (**ptr == ':')
X *str = strdup(*str);
X while (**ptr == ':')
X {
X lptr = *ptr;
X (*ptr)++;
X gbal = 0;
Xhere:
X switch(*(*ptr)++)
X {
X case 'h': remtpath(str); break;
X case 'r': remtext(str); break;
X case 'e': rembutext(str); break;
X case 't': remlpaths(str); break;
X case 'l': downcase(str); break;
X case 'u': upcase(str); break;
X case 's':


X if (hsubl)
X free(hsubl);

X if (hsubr)
X free(hsubr);

X ptr1 = *ptr;
X del = *ptr1++;
X for (ptr2 = ptr1; *ptr2 != del && *ptr2; ptr2++);
X if (!*ptr2)
X {
X zerr("bad subtitution",NULL,0);
X return;
X }
X *ptr2++ = '\0';
X for (ptr3 = ptr2; *ptr3 != del && *ptr3; ptr3++);
X if (sav = *ptr3)
X *ptr3++ = '\0';
X hsubl = ztrdup(ptr1);
X hsubr = ztrdup(ptr2);
X ptr2[-1] = del;
X if (sav)
X ptr3[-1] = sav;
X *ptr = ptr3;


X case '&':
X if (hsubl && hsubr)

X subst(str,hsubl,hsubr,gbal);
X break;
X case 'g': gbal = 1; goto here;
X default: *ptr = lptr; return;
X }
X }
X}
X
X/* get a directory stack entry */
X
Xchar *dstackent(val) /**/
Xint val;
X{
XLknode node;
X
X if ((val < 0 && !firstnode(dirstack)) || !val--)
X return pwd;
X if (val < 0)
X node = lastnode(dirstack);
X else
X for (node = firstnode(dirstack); node && val; val--,incnode(node));
X if (!node)
X {
X zerr("not enough dir stack entries.",NULL,0);
X return NULL;
X }
X return getdata(node);
X}
X
X/* make an alias hash table node */
X
Xstruct alias *mkanode(txt,cmflag) /**/
Xchar *txt;int cmflag;
X{
Xstruct alias *ptr = (Alias) zcalloc(sizeof *ptr);
X
X ptr->text = txt;
X ptr->cmd = cmflag;
X ptr->inuse = 0;
X return ptr;
X}
END_OF_FILE
if test 16309 -ne `wc -c <'src/subst.c'`; then
echo shar: \"'src/subst.c'\" unpacked with wrong size!
fi
# end of 'src/subst.c'
fi
echo shar: End of archive 17 \(of 22\).
cp /dev/null ark17isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:28:20 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 68
Archive-name: zsh/part18

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: func/namedir help/typeset src/lex.c src/zle_main.c
# src/zle_misc.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:55 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 18 (of 22)."'
if test -f 'func/namedir' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/namedir'\"
else
echo shar: Extracting \"'func/namedir'\" \(412 characters\)
sed "s/^X//" >'func/namedir' <<'END_OF_FILE'
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.
END_OF_FILE
if test 412 -ne `wc -c <'func/namedir'`; then
echo shar: \"'func/namedir'\" unpacked with wrong size!
fi
chmod +x 'func/namedir'
# end of 'func/namedir'
fi
if test -f 'help/typeset' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/typeset'\"
else
echo shar: Extracting \"'help/typeset'\" \(3168 characters\)
sed "s/^X//" >'help/typeset' <<'END_OF_FILE'
X declare [ arg ... ]
X Same as typeset.
X functions [ +-tu ] [ name ... ]
X Equivalent to typeset -f.
X integer
X Same as typeset -i.
X local
X Same as typeset.
X typeset [ +-LRZfilrtux [n]] [ name[=value] ] ...
X Set attributes and values for shell parameters. When
X invoked inside a function, if name is not already
X defined, a new parameter is created which will be unset
X when the function completes. The following attributes
X are valid:
X -L Left justify and remove leading blanks from value.
X If n is nonzero, it defines the width of the
X field; otherwise it is determined by the width of
X the value of the first assignment. When the
X parameter is printed, it is filled on the right
X with blanks or truncated if necessary to fit the
X field. Leading zeros are removed if the -Z flag
X is also set.
X -R Right justify and fill with leading blanks. If n
X is nonzero if defines the width of the field; oth-
X erwise it is determined by the width of the value
X of the first assignment. When the parameter is
X printed, the field is left filled with blanks or
X truncated from the end.
X -Z Right justify and fill with leading zeros if the
X first non-blank character is a digit and the -L
X flag has not been set. If n is nonzero it defines
X the width of the field; otherwise it is determined
X by the width of the value of the first assignment.
X -f The names refer to functions rather than parame-
X ters. No assignments can be made, and the only
X other valid flags are -t and -u. The flag -t
X turns on execution tracing for this function. The
X flag -u causes this function to be marked for
X autoloading. The fpath parameter will be searched
X to find the function definition when the function
X is first referenced.
X -i Use an internal integer representation. If i is
X nonzero it defines the output arithmetic base,
X otherwise it is determined by the first assign-
X ment.
X -l Convert to lower case.
X -r The given names are marked readonly.
X -t Tags the named parameters. Tags have no special
X meaning to the shell.
X -u Convert to upper case.
X -x Mark for automatic export to the environment of
X subsequently executed commands.
X
X Using + rather than - causes these flags to be turned off.
X If no arguments are given but flags are specified, a list of
X named parameters which have these flags set is printed.
X Using + instead of - keeps their values from being printed.
X If no arguments or options are given, the names and attri-
X butes of all parameters are printed.
END_OF_FILE
if test 3168 -ne `wc -c <'help/typeset'`; then
echo shar: \"'help/typeset'\" unpacked with wrong size!
fi
# end of 'help/typeset'
fi
if test -f 'src/lex.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/lex.c'\"
else
echo shar: Extracting \"'src/lex.c'\" \(16177 characters\)
sed "s/^X//" >'src/lex.c' <<'END_OF_FILE'
X/*
X *
X * lex.c - lexical analysis


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/* lexical state */
X
Xstatic int xincmdpos,xincond,xincasepat,dbparens,xdbparens,xalstat;
Xstatic char *xhlastw;
X
Xstatic int xisfirstln, xisfirstch, xhistremmed, xhistdone,
X xspaceflag, xstophist, xlithist, xalstackind,xhlinesz;
Xstatic char *xhline, *xhptr;
X
X/* save the lexical state */
X
X/* is this a hack or what? */
X
Xvoid lexsave() /**/
X{
X xincmdpos = incmdpos;
X xincond = incond;
X xincasepat = incasepat;
X xdbparens = dbparens;
X xalstat = alstat;
X xalstackind = alstackind;
X xisfirstln = isfirstln;
X xisfirstch = isfirstch;
X xhistremmed = histremmed;
X xhistdone = histdone;
X xspaceflag = spaceflag;
X xstophist = stophist;
X xlithist = lithist;
X xhline = chline;
X xhptr = hptr;
X xhlastw = hlastw;
X xhlinesz = hlinesz;
X inredir = 0;
X}
X
X/* restore lexical state */
X
Xvoid lexrestore() /**/
X{
X incmdpos = xincmdpos;
X incond = xincond;
X incasepat = xincasepat;
X dbparens = xdbparens;
X alstat = xalstat;
X isfirstln = xisfirstln;
X isfirstch = xisfirstch;
X histremmed = xhistremmed;
X histdone = xhistdone;
X spaceflag = xspaceflag;
X stophist = xstophist;
X lithist = xlithist;
X chline = xhline;
X hptr = xhptr;
X hlastw = xhlastw;
X clearalstack();
X alstackind = xalstackind;
X hlinesz = xhlinesz;
X lexstop = errflag = 0;
X}
X
Xvoid yylex() /**/
X{
X if (tok == LEXERR) return;
X do
X tok = gettok();
X while (tok != ENDINPUT && exalias());
X if (tok != NEWLIN) isnewlin = 0;
X else isnewlin = (inbufct) ? -1 : 1;
X if (tok == SEMI || tok == NEWLIN) tok = SEPER;
X}
X
Xvoid ctxtlex() /**/
X{
Xstatic int oldpos;
X
X yylex();
X switch (tok) {
X case SEPER: case NEWLIN: case SEMI: case DSEMI: case AMPER:
X case INPAR: case INBRACE: case DBAR: case DAMPER: case BAR:
X case BARAMP: case INOUTPAR: case DO: case THEN: case ELIF:
X case ELSE: incmdpos = 1; break;
X case STRING: /* case ENVSTRING: */ case ENVARRAY: case OUTPAR:
X case CASE: incmdpos = 0; break;
X }
X if (IS_REDIROP(tok) || tok == FOR || tok == FOREACH || tok == SELECT) {
X inredir = 1;
X oldpos = incmdpos;
X incmdpos = 0;
X } else if (inredir) {
X incmdpos = oldpos;
X inredir = 0;
X }
X}
X
X#define LX1_BKSLASH 0
X#define LX1_COMMENT 1
X#define LX1_NEWLIN 2
X#define LX1_SEMI 3
X#define LX1_BANG 4
X#define LX1_AMPER 5
X#define LX1_BAR 6
X#define LX1_INPAR 7
X#define LX1_OUTPAR 8
X#define LX1_INBRACE 9
X#define LX1_OUTBRACE 10
X#define LX1_INBRACK 11
X#define LX1_OUTBRACK 12
X#define LX1_INANG 13
X#define LX1_OUTANG 14
X#define LX1_OTHER 15
X
X#define LX2_BREAK 0
X#define LX2_OUTPAR 1
X#define LX2_BAR 2
X#define LX2_STRING 3
X#define LX2_INBRACK 4
X#define LX2_OUTBRACK 5
X#define LX2_TILDE 6
X#define LX2_INPAR 7
X#define LX2_INBRACE 8
X#define LX2_OUTBRACE 9
X#define LX2_OUTANG 10
X#define LX2_INANG 11
X#define LX2_EQUALS 12
X#define LX2_BKSLASH 13
X#define LX2_QUOTE 14
X#define LX2_DQUOTE 15
X#define LX2_BQUOTE 16
X#define LX2_OTHER 17
X
Xunsigned char lexact1[256],lexact2[256],lextok2[256];
X
Xvoid initlextabs() /**/
X{
Xint t0;
Xstatic char *lx1 = "\\q\n;!&|(){}[]<>xx";
Xstatic char *lx2 = "x)|$[]~({}><=\\\'\"`x";
X
X for (t0 = 0; t0 != 256; t0++) {
X lexact1[t0] = LX1_OTHER;
X lexact2[t0] = LX2_OTHER;
X lextok2[t0] = t0;
X }
X for (t0 = 0; lx1[t0]; t0++)
X if (lx1[t0] != 'x')
X lexact1[(int)lx1[t0]] = t0;
X for (t0 = 0; lx2[t0]; t0++)
X if (lx2[t0] != 'x')
X lexact2[(int)lx2[t0]] = t0;
X lexact2[';'] = LX2_BREAK;
X lexact2['&'] = LX2_BREAK;
X lextok2[','] = Comma;
X lextok2['*'] = Star;
X lextok2['?'] = Quest;
X lextok2['{'] = Inbrace;
X lextok2['['] = Inbrack;
X lextok2['$'] = String;
X}
X
X/* initialize lexical state */
X
Xvoid lexinit() /**/
X{
X incond = incasepat = nocorrect =
X dbparens = alstat = lexstop = 0;
X incmdpos = 1;
X tok = ENDINPUT;
X if (isset(EXTENDEDGLOB))
X {
X lextok2['#'] = Pound;
X lextok2['^'] = Hat;
X }
X else
X {
X lextok2['#'] = '#';
X lextok2['^'] = '^';
X }
X}
X
Xint len = 0,bsiz = 256;
Xchar *bptr;
X
X/* add a char to the string buffer */
X
Xvoid add(c) /**/
Xint c;
X{
X *bptr++ = c;
X if (bsiz == ++len)
X {
X int newbsiz;
X
X newbsiz = bsiz * 8;
X while (newbsiz < inbufct)
X newbsiz *= 2;
X bptr = len+(tokstr = hrealloc(tokstr,bsiz,newbsiz));
X bsiz = newbsiz;
X }
X}
X
Xstatic void unadd()
X{
X bptr--; len--;
X}
X
Xint gettok() /**/
X{
Xint bct = 0,pct = 0,brct = 0;
Xint c,d,intpos = 1;
Xint peekfd = -1,peek,ninbracks;
X
Xbeginning:
X hlastw = NULL;
X tokstr = NULL;
X parbegin = -1;
X while (iblank(c = hgetc()) && !lexstop);
X isfirstln = 0;
X wordbeg = inbufct;
X hwbegin();
X hwaddc(c);
X if (dbparens) /* handle ((...)) */
X {
X pct = 2;
X peek = STRING;
X len = dbparens = 0;
X bptr = tokstr = ncalloc(bsiz = 256);
X for (;;)
X {
X if (c == '(')
X pct++;
X else if (c == ')')
X pct--;
X else if (c == '\n')
X {
X zerr("parse error: )) expected",NULL,0);
X peek = LEXERR;
X return peek;
X }
X else if (c == '$')
X c = String;
X if (pct >= 2)
X add(c);
X if (pct)
X c = hgetc();
X else
X break;
X }
X *bptr = '\0';
X return peek;
X }
X if (idigit(c)) /* handle 1< foo */
X {
X d = hgetc();
X hungetc(d);
X lexstop = 0;
X if (d == '>' || d == '<')
X {
X peekfd = c-'0';
X c = hgetc();
X }
X }
X
X /* chars in initial position in word */
X
X if (c == hashchar &&
X (isset(INTERACTIVECOMMENTS) ||
X (!zleparse && (!interact || unset(SHINSTDIN) || strin))))
X {
X /* History is handled here to prevent extra newlines
X * being inserted into the history.
X *
X * Also ignore trailing spaces to prevent history from
X * changing. If trailing spaces are not ignored then
X * each time a comment inside a command (a 'for' loop
X * is a good example) is seen an extra space is appended
X * to the end of the comment causing a new history entry
X * even if HISTIGNOREDUPS is set.
X */
X int nsp = 0; /* number of contiguos spaces */
X while ((c = hgetch()) != '\n' && !lexstop) {
X if (c == ' ')
X ++nsp;
X else {
X while (nsp) {
X hwaddc(' ');
X --nsp;
X }
X hwaddc(c);
X }
X }
X if (c == '\n') {
X hwadd();
X hwbegin();
X hwaddc(c);
X peek = NEWLIN;
X } else {
X peek = (errflag) ? LEXERR : ENDINPUT;
X errflag = 1;
X }
X return peek;
X }
X if (lexstop)
X return (errflag) ? LEXERR : ENDINPUT;
X switch (lexact1[(unsigned char) c])
X {
X case LX1_BKSLASH:
X d = hgetc();
X if (d == '\n')
X goto beginning;
X hungetc(d);
X break;
X case LX1_NEWLIN: return NEWLIN;
X case LX1_SEMI:
X d = hgetc();
X if (d != ';')
X {
X hungetc(d);
X return SEMI;
X }
X return DSEMI;
X case LX1_BANG:
X d = hgetc();
X hungetc(d);
X if (!inblank(d))
X break;
X if (incmdpos || incond)
X return BANG;
X break;
X case LX1_AMPER:
X d = hgetc();
X if (d != '&')
X {
X hungetc(d);
X return AMPER;
X }
X return DAMPER;
X case LX1_BAR:
X d = hgetc();
X if (d == '|')
X return DBAR;
X else if (d == '&')
X return BARAMP;
X hungetc(d);
X return BAR;
X case LX1_INPAR:
X d = hgetc();
X if (d == '(' && incmdpos)
X {
X tokstr = strdup("let");
X dbparens = 1;
X return STRING;
X }
X else if (d == ')')
X return INOUTPAR;
X hungetc(d);
X if (!(incond || incmdpos))
X break;
X return INPAR;
X case LX1_OUTPAR: return OUTPAR;
X case LX1_INBRACE: if (!incmdpos) break; return INBRACE;
X case LX1_OUTBRACE: return OUTBRACE;
X case LX1_INBRACK:
X if (!incmdpos)
X break;
X d = hgetc();
X if (d == '[')
X return DINBRACK;
X hungetc(d);
X break;
X case LX1_OUTBRACK:
X if (!incond)
X break;
X d = hgetc();
X if (d == ']')
X return DOUTBRACK;
X hungetc(d);
X break;
X case LX1_INANG:
X d = hgetc();
X if ((!incmdpos && d == '(') || incasepat ||
X idigit(d) || d == '-' || d == '>') {
X hungetc(d);
X break;
X } else if (d == '<') {
X int e = hgetc();
X
X if (e == '(') {
X hungetc(e);
X hungetc(d);
X peek = INANG;
X } else if (e == '<')
X peek = TRINANG;
X else if (e == '-')
X peek = DINANGDASH;
X else {
X hungetc(e);
X peek = DINANG;
X }
X } else if (d == '&')
X peek = INANGAMP;
X else {
X peek = INANG;
X hungetc(d);
X }
X tokfd = peekfd;
X return peek;
X case LX1_OUTANG:
X d = hgetc();
X if (d == '(')
X {
X hungetc(d);
X break;
X }
X else if (d == '&')
X {
X d = hgetc();
X if (d == '!')
X peek = OUTANGAMPBANG;
X else
X {
X hungetc(d);
X peek = OUTANGAMP;
X }
X }
X else if (d == '!')
X peek = OUTANGBANG;
X else if (d == '>')
X {
X d = hgetc();
X if (d == '&')
X {
X d = hgetc();
X if (d == '!')
X peek = DOUTANGAMPBANG;
X else
X {
X hungetc(d);
X peek = DOUTANGAMP;
X }
X }
X else if (d == '!')
X peek = DOUTANGBANG;
X else if (d == '(')
X {
X hungetc(d);
X hungetc('>');
X peek = OUTANG;
X }
X else
X {
X hungetc(d);
X peek = DOUTANG;
X if (isset(NOCLOBBER)) hwaddc('!');
X }
X }
X else
X {
X hungetc(d);
X peek = OUTANG;
X if (isset(NOCLOBBER)) hwaddc('!');
X }
X tokfd = peekfd;
X return peek;
X }
X
X /* we've started a string, now get the rest of it, performing
X tokenization */
X
X peek = STRING;
X len = 0;
X bptr = tokstr = ncalloc(bsiz = 256);
X for(;;)
X {
X int act;
X int d;
X
X if (inblank(c) && !bct)
X act = LX2_BREAK;
X else
X {
X act = lexact2[(unsigned char) c];
X c = lextok2[(unsigned char) c];
X }
X switch (act)
X {
X case LX2_BREAK: goto brk;
X case LX2_OUTPAR:
X if (!pct)
X goto brk;
X c = Outpar;
X pct--;
X break;
X case LX2_BAR:
X if (!pct && !incasepat)
X goto brk;
X c = Bar;
X break;
X case LX2_STRING:
X d = hgetc();
X if (d == '[')
X {
X add(String);
X add(Inbrack);
X ninbracks = 1;
X while (ninbracks && (c = hgetc()) && !lexstop) {
X if (c == '[') ninbracks++;
X else if (c == ']') ninbracks--;
X if (ninbracks) add(c);
X }
X c = Outbrack;
X }
X else if (d == '(')
X {
X add(String);
X if (skipcomm()) { peek = LEXERR; goto brk; }
X c = Outpar;
X }
X else
X hungetc(d);
X break;
X case LX2_INBRACK: brct++; break;
X case LX2_OUTBRACK:
X if (incond && !brct)
X goto brk;
X brct--;
X c = Outbrack;
X break;
X case LX2_TILDE: /* if (intpos) */ c = Tilde; break;
X case LX2_INPAR:
X d = hgetc();
X hungetc(d);
X if (d == ')' || (incmdpos && peek != ENVSTRING))
X goto brk;
X pct++;
X c = Inpar;
X break;
X case LX2_INBRACE: bct++; break;
X case LX2_OUTBRACE:
X if (!bct)
X goto brk;
X bct--;
X c = Outbrace;
X break;
X case LX2_OUTANG:
X d = hgetc();
X if (d != '(')
X {
X hungetc(d);
X goto brk;
X }
X add(Outang);
X if (skipcomm()) { peek = LEXERR; goto brk; }
X c = Outpar;
X break;
X case LX2_INANG:
X d = hgetc();
X if (!(idigit(d) || d == '-' || d == '>' || d == '(' || d == ')'))
X {
X hungetc(d);
X goto brk;
X }
X c = Inang;
X if (d == '(')
X {
X add(c);
X if (skipcomm()) { peek = LEXERR; goto brk; }
X c = Outpar;
X }
X else if (d == ')')
X hungetc(d);
X else
X {
X add(c);
X c = d;
X while (c != '>' && !lexstop)
X add(c),c = hgetc();
X c = Outang;
X }
X break;
X case LX2_EQUALS:
X if (intpos)
X {
X d = hgetc();
X if (d != '(')
X {
X hungetc(d);
X c = Equals;
X }
X else
X {
X add(Equals);
X if (skipcomm()) { peek = LEXERR; goto brk; }
X c = Outpar;
X }
X }
X else if (peek != ENVSTRING && incmdpos && !bct)
X {
X d = hgetc();
X if (d == '(' && incmdpos)
X {
X *bptr = '\0';
X return ENVARRAY;
X }
X hungetc(d);
X peek = ENVSTRING;
X intpos = 2;
X }
X break;
X case LX2_BKSLASH:
X c = hgetc();
X if (c == '\n')
X {
X c = hgetc();
X continue;
X }
X add(Bnull);
X add(c);
X c = hgetc();
X continue;
X case LX2_QUOTE:
X add(Snull);
X
X /* we add the Nularg to prevent this:
X
X echo $PA'TH'
X
X from printing the path. */


X
X for (;;) {

X while ((c = hgetc()) != '\'' && !lexstop) {
X if (isset(CSHJUNKIEQUOTES) && c == '\n') {
X if (bptr[-1] == '\\') unadd(); else break;
X }
X add(c);


X }
X if (c != '\'') {

X zerr("unmatched \'",NULL,0);
X peek = LEXERR;
X goto brk;
X }
X d = hgetc();
X if (d != '\'' || unset(RCQUOTES)) break;
X add(c);
X }
X hungetc(d);
X c = Snull;
X break;
X case LX2_DQUOTE:
X add(Dnull);
X while ((c = hgetc()) != '\"' && !lexstop)
X if (c == '\\')
X {
X c = hgetc();
X if (c != '\n')
X {
X if (c != '$' && c != '\\' && c != '\"' && c != '`')
X add('\\');
X add(c);
X }
X }
X else {
X if (isset(CSHJUNKIEQUOTES) && c == '\n') {
X if (bptr[-1] == '\\') unadd(); else break;
X }
X if (c == '$') {
X d = hgetc();
X if (d == '(') {
X add(Qstring);
X if (skipcomm()) { peek = LEXERR; goto brk; }
X c = Outpar;
X } else if (d == '[') {
X add(String);
X add(Inbrack);
X while ((c = hgetc()) != ']' && !lexstop)
X add(c);
X c = Outbrack;
X } else {
X c = Qstring;
X hungetc(d);
X }
X } else if (c == '`')
X c = Qtick;
X add(c);


X }
X if (c != '\"') {

X zerr("unmatched \"",NULL,0);
X peek = LEXERR;
X goto brk;
X }
X c = Dnull;
X break;
X case LX2_BQUOTE:
X add(Tick);
X parbegin = inbufct;
X while ((c = hgetc()) != '`' && !lexstop)
X if (c == '\\')
X {
X c = hgetc();
X if (c != '\n')
X {
X if (c != '`' && c != '\\' && c != '$')
X add('\\');
X add(c);
X }
X }
X else {
X if (isset(CSHJUNKIEQUOTES) && c == '\n') {
X if (bptr[-1] == '\\') unadd(); else break;
X }
X add(c);


X }
X if (c != '`') {

X if (!zleparse) zerr("unmatched `",NULL,0);
X peek = LEXERR;
X goto brk;
X }
X c = Tick;
X parbegin = -1;
X break;
X }
X add(c);
X c = hgetc();
X if (intpos)
X intpos--;


X if (lexstop)
X break;
X }

Xbrk:
X hungetc(c);
X *bptr = '\0';
X return peek;
X}
X
X/* expand aliases, perhaps */
X
Xint exalias() /**/
X{
Xstruct alias *an;
Xchar *s,*t;
X
X s = yytext = hwadd();
X for (t = s; *t && *t != HISTSPACE; t++);
X if (!*t)
X t = NULL;
X else
X *t = '\0';
X if (interact && isset(SHINSTDIN) && !strin && !incasepat && tok == STRING &&
X (isset(CORRECTALL) || (isset(CORRECT) && incmdpos)) && !nocorrect)
X spckword(&tokstr,&s,&t,!incmdpos,1);
X if (zleparse && !alstackind) {
X int zp = zleparse;
X gotword(s);
X if (zp && !zleparse) {
X if (t) *t = HISTSPACE;


X return 0;
X }
X }

X an = gethnode(s,aliastab);
X if (t) *t = HISTSPACE;
X if (alstackind != MAXAL && an && !an->inuse)
X if (!(an->cmd && !incmdpos && alstat != ALSTAT_MORE)) {
X if (an->cmd < 0) {
X tok = DO-an->cmd-1;
X return 0;
X } else {
X an->inuse = 1;
X hungets(ALPOPS);
X hungets((alstack[alstackind++] = an)->text);
X alstat = 0;
X /* remove from history if it begins with space */
X if (isset(HISTIGNORESPACE) && an->text[0] == ' ') remhist();
X lexstop = 0;


X return 1;
X }
X }

X return 0;
X}
X

X/* skip (...) */
X
Xint skipcomm() /**/
X{
Xint pct = 1,c;
X
X parbegin = inbufct;
X c = Inpar;
X do
X {
X add(c);
X c = hgetc();
X if (itok(c) || lexstop)
X break;
X else if (c == '(') pct++;
X else if (c == ')') pct--;
X else if (c == '\\')
X {
X add(c);
X c = hgetc();
X }
X else if (c == '\'')
X {
X add(c);
X while ((c = hgetc()) != '\'' && !lexstop)
X add(c);
X }
X else if (c == '\"')
X {
X add(c);
X while ((c = hgetc()) != '\"' && !lexstop)
X if (c == '\\')
X {
X add(c);
X add(hgetc());
X }
X else add(c);
X }
X else if (c == '`')
X {
X add(c);
X while ((c = hgetc()) != '`' && !lexstop)
X if (c == '\\') add(c), add(hgetc());
X else add(c);
X }
X }
X while(pct);
X if (!lexstop) parbegin = -1;
X return lexstop;
X}
END_OF_FILE
if test 16177 -ne `wc -c <'src/lex.c'`; then
echo shar: \"'src/lex.c'\" unpacked with wrong size!
fi
# end of 'src/lex.c'
fi
if test -f 'src/zle_main.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle_main.c'\"
else
echo shar: Extracting \"'src/zle_main.c'\" \(15021 characters\)
sed "s/^X//" >'src/zle_main.c' <<'END_OF_FILE'
X/*
X *
X * zle_main.c - main routines for line editor


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#define ZLEGLOBALS
X#define ZLE
X#include "zsh.h"
X#include <sys/types.h>
X#include <sys/errno.h>
X#ifdef HAS_SYS_SELECT
X#include <sys/select.h>
X#endif
X
Xstatic Key cky;
X
X/* set up terminal */
X
Xvoid setterm() /**/
X{
Xstruct ttyinfo ti;
X#ifdef CLOBBERS_TYPEAHEAD
X#ifdef FIONREAD
Xlong val;
X#endif
X#endif
X
X#ifdef CLOBBERS_TYPEAHEAD
X#ifdef FIONREAD
X ioctl(SHTTY, FIONREAD, &val);
X if (val) return;
X#endif
X#endif
X inittty();


X ti = shttyinfo;
X#ifdef TIO

X ti.tio.c_lflag &= ~(ICANON|ECHO
X#ifdef FLUSHO
X |FLUSHO
X#endif
X );
X ti.tio.c_cc[VQUIT] =
X#ifdef VDISCARD
X ti.tio.c_cc[VDISCARD] =
X#endif
X#ifdef VSUSP
X ti.tio.c_cc[VSUSP] =
X#endif
X#ifdef VDSUSP
X ti.tio.c_cc[VDSUSP] =
X#endif
X#ifdef VSWTCH
X ti.tio.c_cc[VSWTCH] =
X#endif
X VDISABLEVAL;


X ti.tio.c_cc[VMIN] = 1;
X ti.tio.c_cc[VTIME] = 0;

X ti.tio.c_iflag &= ~(INLCR|ICRNL);
X#else
X ti.sgttyb.sg_flags = (ti.sgttyb.sg_flags | CBREAK) & ~ECHO;
X ti.lmodes &= ~LFLUSHO;
X ti.tchars.t_quitc =
X ti.ltchars.t_suspc =
X ti.ltchars.t_flushc =
X ti.ltchars.t_dsuspc = ti.ltchars.t_lnextc = -1;
X#endif
X#ifdef TTY_NEEDS_DRAINING
X drainoutput();


X#endif
X settyinfo(&ti);
X}
X

Xvoid unsetterm() /**/


X{
X settyinfo(&shttyinfo);
X}
X

Xstatic char *kungetbuf;
Xstatic int kungetct,kungetsz;
X
Xvoid ungetkey(ch) /**/
Xint ch;
X{
X if (kungetct == kungetsz)
X kungetbuf = realloc(kungetbuf,kungetsz *= 2);
X kungetbuf[kungetct++] = ch;
X}
X
Xvoid ungetkeys(s,len) /**/
Xchar *s;int len;
X{
X s += len;
X while (len--)
X ungetkey(*--s);
X}
X
X#if (defined(hpux) || defined(pyr)) && defined(HAS_SELECT)
Xstatic int
Xbreakread(fd, buf, n)
Xint fd, n;
Xchar *buf;
X{
X fd_set f;
X
X FD_ZERO(&f);
X FD_SET(fd, &f);
X return(select(fd+1, &f, NULL, NULL, NULL) == -1 ? -1 : read(fd, buf, n));
X}
X#define read breakread
X#endif
X
Xunsigned int getkey(tmok) /**/
Xint tmok;
X{
Xchar cc;
Xunsigned int ret;
Xint die = 0, r;
X
X if (kungetct)
X ret = (unsigned int) (unsigned char) kungetbuf[--kungetct];
X else {
X while ( (r = read(0,&cc,1)) != 1){
X if ( r == 0 ){
X stopmsg = 1;
X zexit(1);
X }
X if (errno == EINTR) {
X if (!errflag)
X continue;
X errflag = 0;
X if (tmok)
X return -1;
X return 3;
X } else if (errno == EWOULDBLOCK) {
X fcntl(0,F_SETFL,0);
X } else if (errno == EIO && !die) {
X ret = jobbing;
X jobbingv = 1;
X attachtty(mypgrp);
X refresh(); /* kludge! */
X jobbingv = ret;
X die = 1;
X } else if (errno != 0) {
X zerr("error on TTY read: %e",NULL,errno);
X stopmsg = 1;
X zexit(1);
X }
X }
X ret = (unsigned int) (unsigned char) cc;
X }
X if (vichgflag) {
X if (vichgbufptr == vichgbufsz)
X vichgbuf = realloc(vichgbuf,vichgbufsz *= 2);
X vichgbuf[vichgbufptr++] = ret;
X }


X return ret;
X}
X

X/* read a line */
X
Xunsigned char *zleread(ppt,ppt2,plen) /**/
Xunsigned char *ppt;unsigned char *ppt2;int plen;
X{
Xint z;
Xlong costmult;
Xunsigned char *s;
X#ifdef HAS_SELECT
Xstruct timeval tv;
Xfd_set foofd;
X
X tv.tv_sec = 0;
X#endif
X fflush(stdout);
X fflush(stderr);
X intr();
X costmult = 3840000L/((baud) ? baud : 2400);
X insmode = unset(OVERSTRIKE); eofsent = 0; resetneeded =0 ;
X pmpt = (char *)ppt;
X pmpt2 = (char *)ppt2;
X permalloc();
X histline = curhist;
X pptlen = plen;
X resetneeded = 1;
X#ifdef HAS_SELECT
X FD_ZERO(&foofd);
X#endif
X undoing = 1;
X line = zalloc(linesz = 256);
X *line = '\0';
X virangeflag = lastcmd = done = cs = ll = mark = 0;
X curhistline = NULL;
X mult = 1;
X vibufspec = 0;
X bindtab = mainbindtab;
X addedslash = vichgflag = 0;
X viinsbegin = 0;
X statusline = NULL;
X if (s = getnode(bufstack))
X {
X setline((char *) s);
X free(s);
X if (stackcs != -1)
X {
X cs = stackcs;
X stackcs = -1;
X if (cs > ll)
X cs = ll;
X }
X if (stackhist != -1)
X {
X histline = stackhist;
X stackhist = -1;
X }
X }
X initundo();
X if (unset(NOPROMPTCR))
X putchar('\r');
X if (tmout)
X alarm(tmout);
X refresh();
X errflag = retflag = 0;
X while (!done && !errflag)
X {
X struct zlecmd *zc;
X
X statusline = NULL;
X bindk = getkeycmd();
X if (c == 4 && !ll)
X {
X eofsent = 1;
X break;
X }
X if (bindk != -1)
X {
X zc = zlecmds+bindk;
X if (!(lastcmd & ZLE_ARG))
X mult = 1;
X if ((lastcmd & ZLE_UNDO) != (zc->flags & ZLE_UNDO) && undoing)
X addundo();
X if (!(zc->flags & ZLE_MENUCMP)) {
X if (menucmp) freemenu();
X if (addedslash && !(zc->flags & ZLE_DELETE) &&
X !((zc->flags & ZLE_INSERT) && c != ' ')) {
X backdel(1);
X }
X addedslash = 0;
X }
X if (zc->func)
X (*zc->func)();
X lastcmd = zc->flags;
X if (!(lastcmd & ZLE_UNDO) && undoing) addundo();
X }
X else
X {
X errflag = 1;
X break;
X }
X#ifdef HAS_SELECT
X FD_SET(0,&foofd);
X if ((tv.tv_usec = cost*costmult) > 500000)
X tv.tv_usec = 500000;
X#endif
X if (!kungetct
X#ifdef HAS_SELECT
X && select(1,&foofd,NULL,NULL,&tv) <= 0
X#endif
X )
X refresh();
X }
X if (menucmp)
X freemenu();
X statusline = NULL;
X trashzle();
X alarm(0);
X z = strlen((char *)line);
X line[z] = '\n';
X line[z+1] = 0;
X heapalloc();
X if (curhistline)
X free(curhistline);
X if (eofsent)
X {
X free(line);
X line = NULL;
X }
X zleactive = 0;
X freeundo();
X return line;
X}
X
Xint getkeycmd() /**/
X{
Xchar buf[10];
Xint t0,ret;
XKey ky;
X
X t0 = 1;
X cky = NULL;
X if ((c = getkey(1)) == -1)
X return -1;
X if ((ret = bindtab[c]) == z_sequenceleadin)
X {
X buf[0] = (c) ? c : 0x80;
X for (;;)
X {
X c = getkey(0);
X buf[t0++] = (c) ? c : 0x80;
X buf[t0] = '\0';
X if (!(ky = (Key) gethnode(buf,xbindtab)))
X return z_undefinedkey;
X if (ky->func != z_sequenceleadin)
X {
X cky = ky;
X ret = ky->func;


X break;
X }
X }
X }

X if (ret == z_vidigitorbeginningofline)
X ret = (lastcmd & ZLE_ARG) ? z_digitargument : z_beginningofline;
X else if (ret == z_executenamedcmd)
X ret = executenamedcommand();
X else if (ret == z_executelastnamedcmd)
X ret = lastnamed;


X return ret;
X}
X

Xvoid sendstring() /**/
X{
Xchar buf[2];
X
X buf[0] = c;
X buf[1] = '\0';
X if (!cky)
X cky = (Key) gethnode(buf,xbindtab);
X ungetkeys(cky->str,cky->len);
X}
X
XKey makefunckey(fun) /**/
Xint fun;
X{
XKey ky = zcalloc(sizeof *ky);
X
X ky->func = fun;
X return ky;
X}
X
X/* initialize the bindings */
X
Xvoid initxbindtab() /**/
X{
Xint t0,vi = 0;
Xchar buf[3],*s;
X
X lastnamed = z_undefinedkey;
X if (s = zgetenv("VISUAL")) {
X if (ztrstr(s,"vi"))
X vi = 1;
X }
X else if ((s = zgetenv("EDITOR")) && ztrstr(s,"vi"))
X vi = 1;
X if (vi) {
X for (t0 = 0; t0 != 32; t0++)
X mainbindtab[t0] = viinsbind[t0];
X for (t0 = 32; t0 != 256; t0++)
X mainbindtab[t0] = z_selfinsert;
X mainbindtab[127] = z_backwarddeletechar;
X } else {


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

X mainbindtab[t0] = emacsbind[t0];
X for (t0 = 128; t0 != 256; t0++)
X mainbindtab[t0] = z_selfinsert;
X }
X for (t0 = 0200; t0 != 0240; t0++)
X mainbindtab[t0] = z_undefinedkey;
X for (t0 = 0; t0 != 128; t0++)
X altbindtab[t0] = vicmdbind[t0];
X for (t0 = 128; t0 != 256; t0++)
X altbindtab[t0] = emacsbind[t0];
X bindtab = mainbindtab;
X kungetbuf = zalloc(kungetsz = 32);
X kungetct = 0;
X xbindtab = newhtable(67);
X addhperm("\33\133C",makefunckey(z_forwardchar),xbindtab,(FFunc) 0);
X addhperm("\33\133D",makefunckey(z_backwardchar),xbindtab,(FFunc) 0);
X addhperm("\33\133A",makefunckey(z_uplineorhistory),xbindtab,(FFunc) 0);
X addhperm("\33\133B",makefunckey(z_downlineorhistory),xbindtab,(FFunc) 0);
X addhperm("\30*",makefunckey(z_expandword),xbindtab,(FFunc) 0);
X addhperm("\30g",makefunckey(z_listexpand),xbindtab,(FFunc) 0);
X addhperm("\30G",makefunckey(z_listexpand),xbindtab,(FFunc) 0);
X addhperm("\30\16",makefunckey(z_infernexthistory),xbindtab,(FFunc) 0);
X addhperm("\30\13",makefunckey(z_killbuffer),xbindtab,(FFunc) 0);
X addhperm("\30\6",makefunckey(z_vifindnextchar),xbindtab,(FFunc) 0);
X addhperm("\30\17",makefunckey(z_overwritemode),xbindtab,(FFunc) 0);
X addhperm("\30\25",makefunckey(z_undo),xbindtab,(FFunc) 0);
X addhperm("\30\26",makefunckey(z_vicmdmode),xbindtab,(FFunc) 0);
X addhperm("\30\12",makefunckey(z_vijoin),xbindtab,(FFunc) 0);
X addhperm("\30\2",makefunckey(z_vimatchbracket),xbindtab,(FFunc) 0);
X addhperm("\30s",makefunckey(z_historyincrementalsearchforward),
X xbindtab,(FFunc) 0);
X addhperm("\30r",makefunckey(z_historyincrementalsearchbackward),
X xbindtab,(FFunc) 0);
X addhperm("\30u",makefunckey(z_undo),xbindtab,(FFunc) 0);
X addhperm("\30\30",makefunckey(z_exchangepointandmark),
X xbindtab,(FFunc) 0);
X addhperm("run-help",mkanode(ztrdup("man"),1),aliastab,(FFunc) 0);
X addhperm("which-command",mkanode(ztrdup("whence"),1),aliastab,(FFunc) 0);
X strcpy(buf,"\33q");
X for (t0 = 128; t0 != 256; t0++)
X if (emacsbind[t0] != z_undefinedkey) {
X buf[1] = t0 & 0x7f;
X addhnode(ztrdup(buf),makefunckey(emacsbind[t0]),xbindtab,(FFunc) 0);
X }
X for (t0 = 0; t0 != 36; t0++) vibuf[t0] = NULL;
X for (t0 = 0; t0 != 26; t0++) vimarkline[t0] = 0;
X stackhist = stackcs = -1;
X vichgbufsz = 0;
X vichgbuf = NULL;
X usernamescached=0;
X}
X
Xchar *getkeystring(s,len) /**/
Xchar *s;int *len;
X{
Xstatic char buf[512];
Xchar *t = buf;
Xint x,metanext = 0;
X
X for (;*s;s++)
X {
X if (*s == '\\' && s[1])
X switch(*++s)
X {
X case 'a': *t++ = '\07'; break;
X case 'n': *t++ = '\n'; break;
X case 'b': *t++ = '\010'; break;


X case 't': *t++ = '\t'; break;
X case 'v': *t++ = '\v'; break;

X case 'f': *t++ = '\f'; break;

X case 'r': *t++ = '\r'; break;

X case 'e': *t++ = '\033'; break;
X case 'M':
X if (s[1] == '-')
X s++;
X metanext = 2;
X break;
X default:
X if (idigit(*s))
X {
X for (x = 0; idigit(*s); s++)
X x = x*8+(*s-'0');
X s--;
X *t++ = x;
X }
X else
X *t++ = *s;
X break;
X }
X else if (*s == '^')
X if (*++s == '?')
X *t++ = 0x7f;
X else
X *t++ = *s & 0x9f;
X else
X *t++ = *s;
X if (metanext && !(--metanext))
X {
X t[-1] |= 0x80;
X metanext = 0;
X }
X if (t > buf+500)
X break;
X }
X *t = '\0';
X *len = t-buf;


X return buf;
X}
X

Xvoid printbind(s,len) /**/
Xchar *s;int len;
X{
Xint ch;
X
X while (len--)
X {
X ch = (unsigned char) *s++;
X if (ch & 0x80)
X {
X printf("\\M-");
X ch &= 0x7f;
X }
X if (icntrl(ch))
X switch(ch)
X {
X case 0x7f: printf("^?"); break;
X default: printf("^%c",(ch|0x40)); break;
X }
X else
X putchar(ch);
X }
X}
X
Xvoid printbinding(str,k) /**/
Xchar *str;Key k;
X{
X if (k->func == z_sequenceleadin)
X return;
X putchar('\"');
X printbind(str,strlen(str));
X printf("\"\t");
X if (k->func == z_sendstring)
X {
X putchar('\"');
X printbind(k->str,k->len);
X printf("\"\n");
X }
X else
X printf("%s\n",zlecmds[k->func].name);
X}
X
Xint bin_bindkey(name,argv,ops,junc) /**/
Xchar *name;char **argv;char *ops;int junc;
X{
Xint t0 = 0,len;
Xchar *s;
Xint func,*tab;
X
X tab = (ops['a']) ? altbindtab : mainbindtab;
X if (ops['v'] || ops['e'] || ops['d'])
X {
X if (*argv)
X {
X zerrnam(name,"too many arguments",NULL,0);
X return 1;
X }
X if (ops['d'] || ops['e'])
X if (ops['m'])
X for (t0 = 0; t0 != 256; t0++)
X tab[t0] = emacsbind[t0];
X else
X {
X for (t0 = 0; t0 != 128; t0++)
X tab[t0] = emacsbind[t0];
X for (t0 = 128; t0 != 256; t0++)
X tab[t0] = z_selfinsert;
X }
X else
X {
X for (t0 = 0; t0 != 32; t0++)
X mainbindtab[t0] = viinsbind[t0];
X for (t0 = 32; t0 != 256; t0++)
X mainbindtab[t0] = z_selfinsert;
X mainbindtab[127] = z_backwarddeletechar;
X }
X for (t0 = 0; t0 != 128; t0++)
X altbindtab[t0] = vicmdbind[t0];
X for (t0 = 128; t0 != 256; t0++)
X altbindtab[t0] = emacsbind[t0];
X for (t0 = 0200; t0 != 0240; t0++)
X tab[t0] = z_undefinedkey;


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

X {
X char buf[2];
X
X buf[0] = 'x'; buf[1] = '\0';
X for (t0 = 0; t0 != 256; t0++)
X {
X buf[0] = t0;
X putchar('\"');
X printbind(buf,1);
X if (t0 < 254 && tab[t0] == tab[t0+1] && tab[t0] == tab[t0+2])
X {
X printf("\" to \"");
X while (tab[t0] == tab[t0+1]) t0++;
X buf[0] = t0;
X printbind(buf,1);
X }
X printf("\"\t%s\n",zlecmds[tab[t0]].name);
X }
X listhtable(xbindtab,(HFunc) printbinding);
X return 0;
X }
X while (*argv)
X {
X s = getkeystring(*argv++,&len);
X if (len > 8)
X {
X zerrnam(name,"in-string too long",NULL,0);
X return 1;
X }
X if (!*argv || ops['r'])
X {
X Key ky;
X
X ky = gethnode(s,xbindtab);
X if (len == 1)
X func = tab[(unsigned char) *s];
X else
X func = (ky) ? ky->func : z_undefinedkey;
X if (func == z_undefinedkey)
X {
X zerrnam(name,"in-string is not bound",NULL,0);
X return 1;
X }
X if (ops['r'])
X {
X if (len == 1)
X tab[(unsigned char) *s] = z_undefinedkey;
X else
X {
X while (strlen(s) > 1)
X {
X free(remhnode(s,xbindtab));
X s[strlen(s)-1] = '\0';
X }
X }
X continue;
X }
X if (func == z_sendstring)
X {
X printbind(ky->str,ky->len);


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

X printf("%s\n",zlecmds[func].name);
X return 0;
X }
X if (!ops['s'])
X {
X for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
X if (!strcmp(*argv,zlecmds[t0].name))
X break;
X if (t0 == ZLECMDCOUNT)
X {
X zerr("undefined function: %s",*argv,0);
X return 1;
X }
X func = t0;
X }
X else
X func = z_sendstring;
X if (len == 1)
X {
X Key ky;
X
X tab[(unsigned char) *s] = (ops['s']) ? z_sendstring : t0;
X if (ops['s'])
X {
X addhnode(ztrdup(s),ky = makefunckey(z_sendstring),xbindtab,freekey);
X ky->str = ztrdup(getkeystring(*argv,&ky->len));
X }
X }
X else
X {
X int t1;
X Key ky;
X
X if (tab[(unsigned char) *s] != z_undefinedkey &&
X tab[(unsigned char) *s] != z_sequenceleadin)
X {
X zerrnam(name,"in-string has already bound prefix",NULL,0);
X return 1;
X }
X tab[(unsigned char) *s] = z_sequenceleadin;
X if (!s[1])
X s[1] = 0x80;
X for (t1 = 1; t1 != len-1; t1++)
X {
X char sav;
X
X sav = s[t1+1];
X s[t1+1] = '\0';
X ky = gethnode(s,xbindtab);
X if (ky && ky->func != z_sequenceleadin)
X {
X zerrnam(name,"in-string has already bound prefix",NULL,0);
X return 1;
X }
X if (!ky)
X addhnode(ztrdup(s),makefunckey(z_sequenceleadin),xbindtab,
X freekey);
X if (!sav)
X sav = 0x80;
X s[t1+1] = sav;
X }
X addhnode(ztrdup(s),ky = makefunckey(func),xbindtab,freekey);
X if (ops['s'])
X ky->str = ztrdup(getkeystring(*argv,&ky->len));
X }
X argv++;


X }
X return 0;
X}
X

Xvoid freekey(x) /**/
Xvptr x;
X{
XKey k = x;
X
X if (k->str)
X free(k->str);
X free(k);
X}
X
X/* this is mostly stolen from bash's draino() */
X
Xvoid drainoutput() /**/
X{
Xint n = 0;
X
X if (!baud) return;
X#ifdef TIOCOUTQ
X#ifdef HAS_SELECT
X while ((ioctl(SHTTY,TIOCOUTQ,&n) >= 0) && n) {
X struct timeval tv;
X tv.tv_sec = n/baud;
X tv.tv_usec = ((n%baud)*1000000)/baud;
X select (0,(fd_set *)0,(fd_set *)0,(fd_set *)0,&tv);
X }
X#endif
X#endif
X}
X
END_OF_FILE
if test 15021 -ne `wc -c <'src/zle_main.c'`; then
echo shar: \"'src/zle_main.c'\" unpacked with wrong size!
fi
# end of 'src/zle_main.c'
fi
if test -f 'src/zle_misc.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle_misc.c'\"
else
echo shar: Extracting \"'src/zle_misc.c'\" \(15185 characters\)
sed "s/^X//" >'src/zle_misc.c' <<'END_OF_FILE'
X/*
X *
X * zle_misc.c - miscellaneous editor routines


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#define ZLE
X#include "zsh.h"
X
X

Xvoid selfinsert() /**/
X{
Xint ncs = cs+mult;
X
X if (mult < 0) { mult = -mult; ncs = cs; }
X if (insmode || ll == cs)
X spaceinline(mult);
X else if (mult+cs > ll)
X spaceinline(ll-(mult+cs));
X while (mult--)
X line[cs++] = c;
X cs = ncs;
X}
X
Xvoid selfinsertunmeta() /**/
X{
X c &= 0x7f;
X if (c == '\r') c = '\n';
X selfinsert();
X}
X
Xvoid deletechar() /**/
X{
X if (mult < 0) { mult = -mult; backwarddeletechar(); return; }
X if (c == 4 && !ll)
X {
X eofsent = 1;
X return;
X }
X if (!(cs+mult > ll || line[cs] == '\n'))
X {
X cs += mult;
X backdel(mult);
X }


X else
X feep();
X}

X
Xvoid backwarddeletechar() /**/
X{
X if (mult < 0) { mult = -mult; deletechar(); return; }
X if (mult > cs)
X mult = cs;
X backdel(mult);
X}
X
Xvoid vibackwarddeletechar() /**/
X{
X if (mult < 0) { mult = -mult; videletechar(); return; }
X if (mult > cs)
X mult = cs;
X if (cs-mult < viinsbegin) { feep(); return; }
X backkill(mult,1);
X}
X
Xvoid vikillline() /**/
X{
X if (viinsbegin > cs) { feep(); return; }
X backdel(cs-viinsbegin);
X}
X
Xvoid killwholeline() /**/
X{
Xint i,fg;
X
X if (mult < 0) return;
X while (mult--)
X {
X if (fg = (cs && cs == ll))
X cs--;
X while (cs && line[cs-1] != '\n') cs--;
X for (i = cs; i != ll && line[i] != '\n'; i++);
X forekill(i-cs+(i != ll),fg);
X }
X}
X
Xvoid killbuffer() /**/
X{
X cs = 0;
X forekill(ll,0);
X}
X
Xvoid backwardkillline() /**/
X{
Xint i = 0;
X
X if (mult < 0) { mult = -mult; killline(); return; }
X while (mult--)
X {
X while (cs && line[cs-1] != '\n') cs--,i++;
X if (mult && cs && line[cs-1] == '\n')
X cs--,i++;
X }
X forekill(i,1);
X}
X
Xvoid gosmacstransposechars() /**/
X{
Xint cc;
X
X if (cs < 2 || line[cs-1] == '\n' || line[cs-2] == '\n')
X {
X if (line[cs] == '\n' || line[cs+1] == '\n')
X {


X feep();
X return;
X }

X cs += (cs == 0 || line[cs-1] == '\n') ? 2 : 1;
X }
X cc = line[cs-2];
X line[cs-2] = line[cs-1];
X line[cs-1] = cc;
X}
X
Xvoid transposechars() /**/
X{
Xint cc, ct;
Xint neg = mult < 0;
X
X if (neg) mult = -mult;
X while (mult--) {
X if (!(ct = cs) || line[cs-1] == '\n') {
X if (ll == cs || line[cs] == '\n') {
X feep();
X return;
X }
X if (!neg) cs++;
X ct++;
X }
X if (neg) {
X if (cs && line[cs-1] != '\n') {
X cs--;
X if (ct > 1 && line[ct-2] != '\n') ct--;
X }
X } else {
X if (cs != ll && line[cs] != '\n') cs++;
X }
X if (ct == ll || line[ct] == '\n') ct--;
X if (ct < 1 || line[ct-1] == '\n') {


X feep();
X return;
X }

X cc = line[ct-1];
X line[ct-1] = line[ct];
X line[ct] = cc;
X }
X}
X
Xvoid poundinsert() /**/
X{
X if (*line != '#') {
X cs = 0;
X spaceinline(1);
X *line = '#';
X } else {
X cs = 0;
X foredel(1);
X }
X done = 1;
X}
X
Xvoid acceptline() /**/
X{
X done = 1;
X}
X
Xvoid acceptandhold() /**/
X{
X pushnode(bufstack,ztrdup((char *) line));
X stackcs = cs;
X done = 1;
X}
X
Xvoid killline() /**/
X{
Xint i = 0;
X
X if (mult < 0) { mult = -mult; backwardkillline(); return; }
X while (mult--) {
X if (line[cs] == '\n')
X cs++,i++;
X while (cs != ll && line[cs] != '\n') cs++,i++;
X }
X backkill(i,0);
X}
X
Xvoid killregion() /**/
X{
X if (mark > ll)
X mark = ll;
X if (mark > cs)
X forekill(mark-cs,0);
X else
X backkill(cs-mark,1);
X}
X
Xvoid copyregionaskill() /**/
X{
X if (mark > ll)
X mark = ll;
X if (mark > cs)
X cut(cs,mark-cs,0);
X else
X cut(mark,cs-mark,1);
X}
X
Xstatic int kct,yankb,yanke;
X
Xvoid yank() /**/
X{
Xint cc;
Xchar *buf = cutbuf;
X
X if (!cutbuf) {
X feep();
X return;
X }
X if (mult < 0) return;
X if (vibufspec) {
X vibufspec = tolower(vibufspec);
X vibufspec += (idigit(vibufspec)) ? -'1'+26 : -'a';
X if (!(buf = vibuf[vibufspec])) {
X feep();
X vibufspec = 0;
X return;
X }
X vibufspec = 0;
X }
X yankb = cs;
X while (mult--) {
X kct = kringnum;
X cc = strlen(buf);
X spaceinline(cc);
X strncpy((char *) line+cs,buf,cc);
X cs += cc;
X yanke = cs;
X }
X}
X
Xvoid viputafter() /**/
X{
Xint cc;
Xchar *buf = cutbuf;
X
X if (!cutbuf) {
X feep();
X return;
X }
X if (mult < 0) return;
X if (vibufspec) {
X vibufspec = tolower(vibufspec);
X vibufspec += (idigit(vibufspec)) ? -'1'+26 : -'a';
X if (!(buf = vibuf[vibufspec])) {
X feep();
X vibufspec = 0;
X return;
X }
X vibufspec = 0;
X }
X if (strchr(buf,'\n')) {
X cs = findeol();
X if (cs == ll) { spaceinline(1); line[cs] = '\n'; }
X }
X if (cs != ll) cs++;
X yankb = cs;
X while (mult--) {
X kct = kringnum;
X cc = strlen(buf);
X spaceinline(cc);
X strncpy((char *) line+cs,buf,cc);
X cs += cc;
X yanke = cs;
X }
X cs = yankb;
X}
X
Xvoid yankpop() /**/
X{
Xint cc;
X
X if (!(lastcmd & ZLE_YANK) || !kring[kct]) {


X feep();
X return;
X }

X cs = yankb;
X foredel(yanke-yankb);
X cc = strlen(kring[kct]);
X spaceinline(cc);
X strncpy((char *) line+cs,kring[kct],cc);
X cs += cc;
X yanke = cs;
X kct = (kct-1) & (KRINGCT-1);
X}
X
Xvoid overwritemode() /**/
X{
X insmode ^= 1;
X}
X
Xvoid undefinedkey() /**/
X{
X feep();
X}
X
Xvoid quotedinsert() /**/
X{
X#ifndef TIO
Xstruct sgttyb sob;
X sob = shttyinfo.sgttyb;
X sob.sg_flags = (sob.sg_flags|RAW) & ~ECHO;
X ioctl(SHTTY,TIOCSETN,&sob);
X#endif
X c = getkey(0);
X#ifndef TIO
X setterm();
X#endif
X if (c) selfinsert(); else feep();
X}
X
Xvoid digitargument() /**/
X{
X int sign = (mult < 0 || (lastcmd & ZLE_NEGARG)) ? -1 : 1;
X if ((lastcmd & (ZLE_ARG|ZLE_NEGARG)) != ZLE_ARG)
X mult = 0;
X mult = mult*10 + sign*(c&0xf);
X}
X
Xvoid negargument() /**/
X{
X if (lastcmd & ZLE_ARG) feep();
X mult = -1;
X}
X
Xvoid universalargument() /**/
X{
X if (!(lastcmd & ZLE_ARG))
X mult = 4;
X else
X mult *= 4;
X}
X
Xvoid copyprevword() /**/
X{
Xint len,t0;
X
X for (t0 = cs-1; t0 >= 0; t0--)
X if (iword(line[t0]))
X break;
X for (; t0 >= 0; t0--)
X if (!iword(line[t0]))
X break;
X if (t0)
X t0++;
X len = cs-t0;
X spaceinline(len);
X strncpy((char *) line+cs,(char *) line+t0,len);
X cs += len;
X}
X
Xvoid sendbreak() /**/
X{
X errflag = done = 1;
X}
X
Xvoid undo() /**/
X{
Xchar *s;
Xstruct undoent *ue;
X
X ue = undos+undoct;
X if (!ue->change)
X {


X feep();
X return;
X }

X line[ll] = '\0';
X s = ztrdup((char *) line+ll-ue->suff);
X sizeline((ll = ue->pref+ue->suff+ue->len)+1);
X strncpy((char *) line+ue->pref,ue->change,ue->len);
X strcpy((char *) line+ue->pref+ue->len,s);
X free(s);
X ue->change = NULL;
X undoct = (undoct-1) & (UNDOCT-1);
X cs = ue->cs;
X}
X
Xvoid quoteregion() /**/
X{
Xchar *s,*t;
Xint x,y;
X
X if (mark > ll)
X mark = ll;
X if (mark < cs)
X {
X x = mark;
X mark = cs;
X cs = x;
X }
X s = hcalloc((y = mark-cs)+1);
X strncpy(s,(char *) line+cs,y);
X s[y] = '\0';
X foredel(mark-cs);
X t = makequote(s);
X spaceinline(x = strlen(t));
X strncpy((char *) line+cs,t,x);
X mark = cs;
X cs += x;
X}
X
Xvoid quoteline() /**/
X{
Xchar *s;
X
X line[ll] = '\0';
X s = makequote((char *) line);
X setline(s);
X}
X
Xchar *makequote(s) /**/
Xchar *s;
X{
Xint qtct = 0;
Xchar *l,*ol;
X
X for (l = s; *l; l++)
X if (*l == '\'')
X qtct++;
X l = ol = halloc((qtct*3)+3+strlen(s));
X *l++ = '\'';


X for (; *s; s++)

X if (*s == '\'')

X {
X *l++ = '\'';
X *l++ = '\\';
X *l++ = '\'';
X *l++ = '\'';
X }
X else
X *l++ = *s;
X *l++ = '\'';
X *l = '\0';
X return ol;
X}
X
X#define NAMLEN 70
X
Xint executenamedcommand() /**/
X{
Xchar buf[NAMLEN],*ptr;
Xint len,ch,t0;
X
X strcpy(buf,"execute: ");
X ptr = buf+9;
X len = 0;
X statusline = buf;
X refresh();
X for (;ch = getkey(1);refresh())
X {
X switch (ch)
X {
X case 8: case 127:
X if (len)
X {
X len--;
X *--ptr = '\0';
X }
X break;
X case 23:
X while (len && (len--, *--ptr != '-'))
X *ptr = '\0';
X break;
X case 21:
X len = 0;
X ptr = buf+9;
X *ptr = '\0';
X break;
X case 10: case 13: goto brk;
X case 7: case -1: statusline = NULL; return z_undefinedkey;
X case 9: case 32:
X {
X Lklist ll;
X int ambig = 100;
X
X heapalloc();
X ll = newlist();
X for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
X if (strpfx(buf+9,zlecmds[t0].name))
X {
X int xx;
X
X addnode(ll,zlecmds[t0].name);
X xx = pfxlen(peekfirst(ll),zlecmds[t0].name);
X if (xx < ambig)
X ambig = xx;
X }
X permalloc();
X if (empty(ll))
X feep();
X else if (!nextnode(firstnode(ll)))
X {
X strcpy(buf+9,peekfirst(ll));
X ptr = buf+(len = strlen(buf));
X }
X else
X {
X strcpy(buf+9,peekfirst(ll));
X len = ambig;
X ptr = buf+9+len;
X *ptr = '\0';
X feep();
X listmatches(ll,NULL);
X }
X break;
X }
X default:
X if (len == NAMLEN-10 || icntrl(ch))
X feep();
X else
X *ptr++ = ch, *ptr = '\0', len++;
X break;
X }
X }
Xbrk:
X statusline = NULL;
X ptr = buf+9;
X for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
X if (!strcmp(ptr,zlecmds[t0].name))
X break;
X if (t0 != ZLECMDCOUNT)
X return lastnamed = t0;
X else
X return z_undefinedkey;
X}
X
Xvoid vijoin() /**/
X{
Xint x;
X
X if ((x = findeol()) == ll)
X {


X feep();
X return;
X }

X cs = x+1;
X for (x = 1; cs != ll && iblank(line[cs]); cs++,x++);
X backdel(x);
X spaceinline(1);
X line[cs] = ' ';
X}
X
Xvoid viswapcase() /**/
X{
X if (cs < ll)
X {
X int ch = line[cs];
X
X if (islower(ch))
X ch = tuupper(ch);
X else if (isupper(ch))
X ch = tulower(ch);
X line[cs++] = ch;
X }
X}
X
Xvoid vicapslockpanic() /**/
X{
Xchar ch;
X
X statusline = "press a lowercase key to continue";
X refresh();
X do
X ch = getkey(0);
X while (!islower(ch));
X}
X
Xvoid visetbuffer() /**/
X{
Xint ch;
X
X ch = getkey(1);
X if (!ialnum(ch)) {


X feep();
X return;
X }

X vibufspec = ch;
X}
X
Xstatic char *bp;
Xstatic int lensb,countp;
X
Xvoid stradd(d) /**/
Xchar *d;
X{
X while (*bp++ = *d++);
X bp--;
X}
X
Xint putstr(d) /**/
Xint d;
X{
X *bp++ = d;
X if (countp)
X lensb++;


X return 0;
X}
X

X#define tstradd(X) \
X if (termok && unset(SINGLELINEZLE)) { \
X char tbuf[2048],*tptr = tbuf; \
X if (tgetstr(X,&tptr)) \
X tputs(tbuf,1,putstr); \
X } \
X break
X
X/* get a prompt string */
X
Xchar *putprompt(fm,lenp,isspell) /**/
Xchar *fm;int *lenp;int isspell;
X{
Xchar *ss,*bl0;
Xstatic char buf0[256],buf1[256],buf2[256],*buf;
Xchar buf3[MAXPATHLEN];
Xint t0,bracepos = 0,arg;
Xstruct tm *tm;
Xtime_t timet;
X
X lensb = 0; countp = 1;
X if (!fm) { *lenp = 0; return ""; }
X /* KLUDGE ALERT! What we have here are three buffers:
X * buf1 and buf2 alternate between PS1 and PS2, though which is
X * which is indeterminate depending on spellchecking, "select",
X * etc. -- those operations also share these two buffers.
X * buf0 is used for any prompting that manages to happen while
X * zleread() is in progress (signal traps, etc.), because
X * zleread() re-uses the pointers returned to buf1 and buf2
X * and will be confused if either of those is overwritten.
X */
X buf = zleactive ? buf0 : ((buf == buf1) ? buf2 : buf1);
X bp = bl0 = buf;
X if (!columns) columns = 80;
X clearerr(stdin);
X for(;*fm;fm++) {
X if (bp-buf >= 220)
X break;
X arg = 0;
X if (*fm == '%')
X {
X if (idigit(*++fm))
X {
X arg = zstrtol(fm, &fm, 10);
X }
X switch (*fm)
X {
X case '~':
X t0 = finddir(pwd);


X if (t0 != -1) {

X *bp++ = '~';
X stradd(usernames[t0]);
X stradd(pwd+strlen(userdirs[t0]));
X break;
X }
X case 'd': case '/': stradd(pwd); break;
X case 'c': case '.':
X t0 = finddir(pwd);


X if (t0 != -1) {

X sprintf(buf3,"~%s%s",usernames[t0],
X pwd+strlen(userdirs[t0]));
X } else {
X strcpy(buf3,pwd);
X }
X if (!arg) arg++;
X for (ss = buf3+strlen(buf3); ss > buf3; ss--)
X if (*ss == '/' && !--arg) {
X ss++;
X break;
X }
X if (*ss == '/' && ss[1] && (ss != buf3)) ss++;
X stradd(ss);


X break;
X case 'C':

X strcpy(buf3,pwd);
X if (!arg) arg++;
X for (ss = buf3+strlen(buf3); ss > buf3; ss--)
X if (*ss == '/' && !--arg) {
X ss++;
X break;
X }
X if (*ss == '/' && ss[1] && (ss != buf3)) ss++;
X stradd(ss);
X break;
X case 'h': case '!':
X sprintf(bp,"%d",curhist);
X bp += strlen(bp);
X break;
X case 'M': stradd(hostnam); break;
X case 'm':
X if (!arg) arg++;
X for (ss = hostnam; *ss; ss++)
X if (*ss == '.' && !--arg)
X break;
X t0 = *ss;
X *ss = '\0';
X stradd(hostnam);
X *ss = t0;
X break;
X case 'S': tstradd("so"); /* <- this is a macro */
X case 's': tstradd("se");
X case 'B': tstradd("md");
X case 'b': tstradd("me");
X case 'U': tstradd("us");
X case 'u': tstradd("ue");
X case '{': bracepos = bp-buf; countp = 0; break;
X case '}': lensb += (bp-buf)-bracepos; countp = 1; break;
X case 't': case '@':
X timet = time(NULL);
X tm = localtime(&timet);
X ztrftime(bp,16,"%l:%M%p",tm);
X if (*bp == ' ')
X chuck(bp);
X bp += strlen(bp);
X break;
X case 'T':
X timet = time(NULL);
X tm = localtime(&timet);
X ztrftime(bp,16,"%k:%M",tm);
X bp += strlen(bp);
X break;
X case '*':
X timet = time(NULL);
X tm = localtime(&timet);
X ztrftime(bp,16,"%k:%M:%S",tm);
X bp += strlen(bp);
X break;
X case 'n': stradd(username); break;
X case 'w':
X timet = time(NULL);
X tm = localtime(&timet);
X ztrftime(bp,16,"%a %e",tm);
X bp += strlen(bp);


X break;
X case 'W':

X timet = time(NULL);
X tm = localtime(&timet);
X ztrftime(bp,16,"%m/%d/%y",tm);
X bp += strlen(bp);
X break;
X case 'D':
X strcpy(buf3, "%y-%m-%d");
X if (fm[1] == '{') {
X for (ss = fm + 1, t0 = 0; *ss; ++ss)
X if (*ss == '{')
X ++t0;
X else if (*ss == '}')
X if (--t0 == 0)
X break;
X if (*ss == '}' && t0 == 0) {
X t0 = (ss - 1) - (fm + 1);
X strncpy(buf3, fm + 2, t0);
X buf3[t0] = 0;
X fm = ss;
X }
X }
X timet = time(NULL);
X tm = localtime(&timet);
X ztrftime(bp,16,buf3,tm);
X bp += strlen(bp);


X break;
X case 'l':

X if (*ttystrname) stradd((strncmp(ttystrname,"/dev/tty",8) ?
X ttystrname+5 : ttystrname+8));
X else stradd("()");


X break;
X case '?':

X sprintf(bp,"%d",lastval);
X bp += strlen(bp);
X break;
X case '%': *bp++ = '%'; break;
X case '#': *bp++ = (geteuid()) ? '%' : '#'; break;
X case 'v':
X if (!arg) arg++;
X /* The number 35 here comes from 256-220-1, where 256 is
X * sizeof(buf), 220 is from the overflow test made at the
X * top of the loop, and 1 is for the \0 byte at the end.
X */
X if (arrlen(psvar) >= arg && strlen(psvar[arg-1]) < 35)
X stradd(psvar[arg-1]);
X else
X stradd("");


X break;
X case 'r':

X if (isspell)
X {
X stradd(rstring);
X break;
X }
X case 'R':
X if (isspell)
X {
X stradd(Rstring);
X break;
X }
X default:
X *bp++ = '%'; *bp++ = *fm;
X break;
X }
X }
X else if (*fm == '!') {
X sprintf(bp,"%d",curhist);
X bp += strlen(bp);
X } else {
X if (fm[0] == '\\' && fm[1])
X fm++;
X if ((*bp++ = *fm) == '\n')
X bl0 = bp, lensb = 0;
X }
X }
X *lenp = (bp-bl0)-lensb;
X *lenp %= columns;
X if (*lenp == columns-1) {
X *lenp = 0;
X *bp++ = ' ';
X }
X *bp = '\0';


X return buf;
X}
X

END_OF_FILE
if test 15185 -ne `wc -c <'src/zle_misc.c'`; then
echo shar: \"'src/zle_misc.c'\" unpacked with wrong size!
fi
# end of 'src/zle_misc.c'
fi
echo shar: End of archive 18 \(of 22\).
cp /dev/null ark18isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:28:47 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 69
Archive-name: zsh/part19

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: doc/intro.troff.02 help/setopt src/math.c src/table.c
# src/zle_hist.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:55 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 19 (of 22)."'
if test -f 'doc/intro.troff.02' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'doc/intro.troff.02'\"
else
echo shar: Extracting \"'doc/intro.troff.02'\" \(9993 characters\)
sed "s/^X//" >'doc/intro.troff.02' <<'END_OF_FILE'
XIn general, parameters with names in all lowercase are arrays;
Xassignments to them take the form:
X.Ds
X\fIname\fR\fC=(\fR \fIelem\fR ...\ \fC)\fR
X.De
XParameters with names in all uppercase are strings. If there is
Xboth an array and a string version of the same parameter, the
Xstring version is a colon-separated list, like \fBPATH\fR.
X.PP
X\fBHISTFILE\fR is the name of the history file, where the history


Xis saved when a shell exits.

X.Ds


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.De
X.PP


XIn zsh, if you say

X.Ds
X% >file
X.DZ
Xthe command \fCcat\fR is normally assumed:
X.Ds


X% >file
Xfoo!
X^D
X% cat file
Xfoo!

X.DZ
XThus, you can view a file simply by typing:
X.Ds
X% <file
Xfoo!
X.DZ
XHowever, this is not csh or sh compatible. To correct this,
Xchange the value of the parameter \fBNULLCMD\fR,
Xwhich is \fCcat\fR by default.
X.Ds
X% NULLCMD=:
X% >file
X% ls -l file
X-rw-r--r-- 1 pfalstad 0 May 24 05:41 file
X.DZ
XIf \fCNULLCMD\fR is unset, the shell reports an error if no
Xcommand is specified (like csh).
X.Ds
X% unset NULLCMD
X% >file
Xzsh: redirection with no command
X.De
XActually, \fBREADNULLCMD\fR is used whenever you have a null command
Xreading input from a single file. Thus, you can set \fBREADNULLCMD\fP
Xto \fCmore\fP or \fCless\fP rather than \fCcat\fP. Also, if you
Xset \fBNULLCMD\fR to \fC:\fP for sh compatibility, you can still read
Xfiles with \fC< file\fR if you leave \fBREADNULLCMD\fP set to \fCmore\fP.
X.SH
XPrompting
X.PP
XThe default prompt for zsh is:
X.Ds
Xphoenix% echo $PROMPT
X%m%#
X.De
XThe \fC%m\fR stands for the short form of the current hostname,
Xand the \fC%#\fR stands for a \fC%\fR or a \fC#\fR, depending on whether
Xthe shell is running as root or not.
Xzsh supports many other control sequences
Xin the \fBPROMPT\fR variable.
X.Ds
X% PROMPT='%/> '
X/u/pfalstad/etc/TeX/zsh>
X
X% PROMPT='%~> '
X~/etc/TeX/zsh>
X
X% PROMPT='%h %~> '
X6 ~/etc/TeX/zsh>
X.DZ
X\fC%h\fR represents the number of current history event.
X.Ds
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.DZ
XAlso available is the \fBRPROMPT\fR parameter.
XIf this is set, the shell puts a prompt on the \fIright\fR side
Xof the screen.
X.Ds
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.DZ
XThese special escape sequences can also be used with the
X\fC-P\fR option to \fCprint\fR:
X.Ds
X% print -P %h tty%l
X15 ttyp1
X.De
X.PP
XThe \fBPOSTEDIT\fR parameter is printed whenever the editor exits.
XThis can be useful for termcap tricks. To highlight the prompt
Xand command line while leaving command output unhighlighted, try this:
X.Ds
X% POSTEDIT=`echotc se`
X% PROMPT='%S%% '
X.De
X.SH
XLogin/logout watching
X.PP
XYou can specify login or logout events to monitor
Xby setting the \fBwatch\fR variable.
XNormally, this is done by specifying a list of usernames.
X.Ds
X% watch=( pfalstad subbarao sukthnkr egsirer )
X.DZ
XThe \fClog\fR command reports all people logged in
Xthat you are watching for.
X.Ds
X% log
Xpfalstad has logged on p0 from mickey.
Xpfalstad has logged on p5 from mickey.
X% \fR...\fC
Xsubbarao has logged on p8 from phoenix.
X% \fR...\fC
Xsubbarao has logged off p8 from phoenix.
X% \fR...\fC
Xsukthnkr has logged on p8 from dew.
X% \fR...\fC
Xsukthnkr has logged off p8 from dew.
X.DZ
XIf you specify hostnames with an \fC@\fR prepended,
Xthe shell will watch for all users logging in from
Xthe specified host.
X.Ds
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.DZ
XIf you give a tty name with a \fC%\fR prepended, the shell
Xwill watch for all users logging in on that tty.
X.Ds
X% watch=( %ttyp0 %console )
X% log
Xroot has logged on console from .
Xpfalstad has logged on p0 from mickey.
X.DZ
XThe format of the reports may also be changed.
X.Ds
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.DZ
XIf you have a \fC.friends\fR file in your home directory,
Xa convenient way to make zsh watch for all your friends
Xis to do this:
X.Ds
X% watch=( $(< ~/.friends) )
X% echo $watch
Xsubbarao maruchck root sukthnkr \fR...
X.De
XIf watch is set to \fCall\fR, then all users logging in or out
Xwill be reported.
X.SH
XOptions
X.PP
XSome options have already been mentioned; here are a few more:
X.Ds
X% cd /
X% setopt autocd
X% bin
X% pwd
X/bin
X% ../etc
X% pwd
X/etc
X.DZ
XUsing the \fIAUTOCD\fR option, you can simply type the name
Xof a directory, and it will become the current directory.
X.Ds
X% setopt cdablevars
X% foo=/tmp
X% cd foo
X/tmp
X.De
XWith \fICDABLEVARS\fR, if the argument to \fCcd\fR is the name of a
Xparameter whose value is a valid directory, it will become
Xthe current directory.
X.PP
X\fICORRECT\fR turns on spelling correction for commands,
Xand the \fICORRECTALL\fR option turns on spelling correction
Xfor all arguments.
X.Ds
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.De
XIf you press \fCy\fR
Xwhen the shell asks you if you want to correct a word, it will
Xbe corrected. If you press \fCn\fR, it will be left alone.
XPressing \fCa\fR aborts the command, and pressing \fCe\fR brings the line
Xup for editing again, in case you agree the word is spelled wrong
Xbut you don't like the correction.
X.PP
XNormally, a quoted expression may contain a newline:
X.Ds
X% echo '
X> foo
X> '
X
Xfoo
X
X%
X.DZ
XWith \fICSHJUNKIEQUOTES\fR set, this is illegal, as it is
Xin csh.
X.Ds
X% setopt cshjunkiequotes
X% ls 'foo
Xzsh: unmatched '
X.DZ
X\fIGLOBDOTS\fR lets files beginning with a \fC.\fR be matched without
Xexplicitly specifying the dot.
X.Ds
X% ls -d *x*
XMailboxes
X% setopt globdots
X% ls -d *x*
X\&.exrc .pnewsexpert .xserverrc
X\&.mushexpert .xinitrc Mailboxes
X.DZ
X\fIHISTIGNOREDUPS\fR prevents the current line from being
Xsaved in the history if it is the same as the previous one;
X\fIHISTIGNORESPACE\fR prevents the current line from being
Xsaved if it begins with a space.
X.Ds
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.DZ
X\fIIGNOREBRACES\fR turns off csh-style brace expansion.
X.Ds
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.DZ
X\fIIGNOREEOF\fR forces the user to type \fCexit\fR or \fClogout\fR,
Xinstead of just pressing \fI^D\fP.
X.Ds
X% setopt ignoreeof
X% ^D
Xzsh: use 'exit' to exit.
X.DZ
X\fIINTERACTIVECOMMENTS\fR turns on interactive comments;
Xcomments begin with a \fC#\fR.
X.Ds
X% setopt interactivecomments
X% date # this is a comment
XFri May 24 06:54:14 EDT 1991
X.DZ
X\fINOCLOBBER\fR prevents you from accidentally
Xoverwriting an existing file.
X.Ds
X% setopt noclobber
X% cat /dev/null >~/.zshrc
Xzsh: file exists: /u/pfalstad/.zshrc
X.DZ
XIf you really do want to clobber a file, you can use the
X\fC>!\fR operator.
XTo make things easier in this case, the \fC>\fR is stored in
Xthe history list as a \fC>!\fR:
X.Ds
X% cat /dev/null >! ~/.zshrc
X% cat /etc/motd > ~/.zshrc
Xzsh: file exists: /u/pfalstad/.zshrc
X% !!
Xcat /etc/motd >! ~/.zshrc
X% \fR...
X.DZ
X\fIRCQUOTES\fR lets you use a more elegant method for including
Xsingle quotes in a singly quoted string:
X.Ds
X% echo '"don'\e''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.De
XFinally,
X\fISUNKEYBOARDHACK\fR wins the award for the strangest option.
XIf a line ends with \fC`\fR, and there are an odd number of them
Xon the line, the shell will ignore the trailing \fC`\fR. This
Xis provided for keyboards whose RETURN key is too small,
Xand too close to the \fC`\fR key.
X.Ds
X% setopt sunkeyboardhack
X% date`
XFri May 24 06:55:38 EDT 1991
X.De
X.SH
XClosing Comments
X.PP
XI would be happy to receive mail
Xif anyone has any tricks or ideas to add to this document, or
Xif there are some points that could be made clearer or covered
Xmore thoroughly. Please notify me of any errors in this
Xdocument.
END_OF_FILE
if test 9993 -ne `wc -c <'doc/intro.troff.02'`; then
echo shar: \"'doc/intro.troff.02'\" unpacked with wrong size!
fi
# end of 'doc/intro.troff.02'
fi
if test -f 'help/setopt' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/setopt'\"
else
echo shar: Extracting \"'help/setopt'\" \(11726 characters\)
sed "s/^X//" >'help/setopt' <<'END_OF_FILE'

if test 11726 -ne `wc -c <'help/setopt'`; then
echo shar: \"'help/setopt'\" unpacked with wrong size!
fi
# end of 'help/setopt'
fi
if test -f 'src/math.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/math.c'\"
else
echo shar: Extracting \"'src/math.c'\" \(10353 characters\)
sed "s/^X//" >'src/math.c' <<'END_OF_FILE'
X/*
X *
X * math.c - mathematical expression evaluation


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

Xstatic char *ptr;
X
Xtypedef int LV;
X
Xstatic long yyval;
Xstatic LV yylval;
X
X/* nonzero means we are not evaluating, just parsing */
X
Xstatic int noeval = 0;
X
X/* != 0 means recognize unary plus, minus, etc. */
X
Xstatic int unary = 1;
X
Xvoid mathparse DCLPROTO((int));
X
X/* LR = left-to-right associativity
X RL = right-to-left associativity
X BOO = short-circuiting boolean */
X
X#define LR 0
X#define RL 1
X#define BOOL 2
X
X#define M_INPAR 0
X#define M_OUTPAR 1
X#define NOT 2
X#define COMP 3
X#define POSTPLUS 4
X#define POSTMINUS 5
X#define UPLUS 6
X#define UMINUS 7
X#define AND 8
X#define XOR 9
X#define OR 10
X#define MUL 11
X#define DIV 12
X#define MOD 13
X#define PLUS 14
X#define MINUS 15
X#define SHLEFT 16
X#define SHRIGHT 17
X#define LES 18
X#define LEQ 19
X#define GRE 20
X#define GEQ 21
X#define DEQ 22
X#define NEQ 23
X#define DAND 24
X#define DOR 25
X#define DXOR 26
X#define QUEST 27
X#define COLON 28
X#define EQ 29
X#define PLUSEQ 30
X#define MINUSEQ 31
X#define MULEQ 32
X#define DIVEQ 33
X#define MODEQ 34
X#define ANDEQ 35
X#define XOREQ 36
X#define OREQ 37
X#define SHLEFTEQ 38
X#define SHRIGHTEQ 39
X#define DANDEQ 40
X#define DOREQ 41
X#define DXOREQ 42
X#define COMMA 43
X#define EOI 44
X#define PREPLUS 45
X#define PREMINUS 46
X#define NUM 47
X#define ID 48
X#define TOKCOUNT 49
X
X/* precedences */
X
Xstatic int prec[TOKCOUNT] = {
X 1,137,2,2,2,
X 2,2,2,4,5,
X 6,7,7,7,8,
X 8,3,3,9,9,
X 9,9,10,10,11,
X 12,12,13,13,14,
X 14,14,14,14,14,
X 14,14,14,14,14,
X 14,14,14,15,200,
X 2,2,0,0,
X};
X
X#define TOPPREC 15
X#define ARGPREC (15-1)
X
Xstatic int type[TOKCOUNT] = {
X LR,LR,RL,RL,RL,
X RL,RL,RL,LR,LR,
X LR,LR,LR,LR,LR,
X LR,LR,LR,LR,LR,
X LR,LR,LR,LR,BOOL,
X BOOL,LR,RL,RL,RL,
X RL,RL,RL,RL,RL,
X RL,RL,RL,RL,RL,
X BOOL,BOOL,RL,RL,RL,
X RL,RL,LR,LR,
X};
X
X#define LVCOUNT 32
X
X/* list of lvalues (variables) */
X
Xstatic int lvc;
Xstatic char *lvals[LVCOUNT];
X
Xint zzlex() /**/
X{
X for(;;)
X switch (*ptr++)
X {
X case '+':
X if (*ptr == '+' && (unary || !ialnum(*ptr)))
X {
X ptr++;
X return (unary) ? PREPLUS : POSTPLUS;
X }
X if (*ptr == '=') { unary = 1; ptr++; return PLUSEQ; }
X return (unary) ? UPLUS : PLUS;
X case '-':
X if (*ptr == '-' && (unary || !ialnum(*ptr)))
X {
X ptr++;
X return (unary) ? PREMINUS : POSTMINUS;
X }
X if (*ptr == '=') { unary = 1; ptr++; return MINUSEQ; }
X return (unary) ? UMINUS : MINUS;
X case '(': unary = 1; return M_INPAR;
X case ')': return M_OUTPAR;
X case '!': if (*ptr == '=')
X { unary = 1; ptr++; return NEQ; }
X return NOT;
X case '~': return COMP;
X case '&': unary = 1;
X if (*ptr == '&') { if (*++ptr == '=')
X { ptr++; return DANDEQ; } return DAND; }
X else if (*ptr == '=') { ptr++; return ANDEQ; } return AND;
X case '|': unary = 1;
X if (*ptr == '|') { if (*++ptr == '=')
X { ptr++; return DOREQ; } return DOR; }
X else if (*ptr == '=') { ptr++; return OREQ; } return OR;
X case '^': unary = 1;
X if (*ptr == '^') { if (*++ptr == '=')
X { ptr++; return DXOREQ; } return DXOR; }
X else if (*ptr == '=') { ptr++; return XOREQ; } return XOR;
X case '*': unary = 1;
X if (*ptr == '=') { ptr++; return MULEQ; } return MUL;
X case '/': unary = 1;
X if (*ptr == '=') { ptr++; return DIVEQ; } return DIV;
X case '%': unary = 1;
X if (*ptr == '=') { ptr++; return MODEQ; } return MOD;
X case '<': unary = 1; if (*ptr == '<')
X { if (*++ptr == '=') { ptr++; return SHLEFTEQ; } return SHLEFT; }
X else if (*ptr == '=') { ptr++; return LEQ; } return LES;
X case '>': unary = 1; if (*ptr == '>')
X { if (*++ptr == '=') { ptr++; return SHRIGHTEQ; } return SHRIGHT; }
X else if (*ptr == '=') { ptr++; return GEQ; } return GRE;
X case '=': unary = 1; if (*ptr == '=') { ptr++; return DEQ; }
X return EQ;
X case '?': unary = 1; return QUEST;
X case ':': unary = 1; return COLON;
X case ',': unary = 1; return COMMA;
X case '\0': unary = 1; ptr--; return EOI;
X case '[': unary = 0;
X { int base = zstrtol(ptr,&ptr,10);
X if (*ptr == ']') ptr++;
X yyval = zstrtol(ptr,&ptr,lastbase = base);
X return NUM; }
X case ' ': case '\t':
X break;
X default:
X if (idigit(*--ptr))
X { unary = 0; yyval = zstrtol(ptr,&ptr,10); return NUM; }
X if (iident(*ptr) || *ptr == '$')
X {
X char *p,q;
X
X if (*ptr == '$')
X ptr++;
X p = ptr;
X if (lvc == LVCOUNT)
X {
X zerr("too many identifiers (complain to author)",NULL,0);
X return EOI;
X }
X unary = 0;
X while(iident(*++ptr));
X q = *ptr;
X *ptr = '\0';
X lvals[yylval = lvc++] = ztrdup(p);
X *ptr = q;
X return ID;
X }
X return EOI;
X }
X}
X
X/* the value stack */
X
X#define STACKSZ 100
Xint mtok; /* last token */
Xint sp = -1; /* stack pointer */
Xstruct mathvalue {
X LV lval;
X long val;
X } stack[STACKSZ];
X
Xvoid push(val,lval)
Xlong val;LV lval;
X{
X if (sp == STACKSZ-1)
X zerr("stack overflow",NULL,0);
X else
X sp++;
X stack[sp].val = val;
X stack[sp].lval = lval;
X}
X
Xlong getvar(s)
XLV s;
X{
Xlong t;
X
X if (!(t = getiparam(lvals[s])))
X return 0;
X return t;
X}
X
Xlong setvar(s,v)
XLV s;long v;
X{
X if (s == -1 || s >= lvc)
X {
X zerr("lvalue required",NULL,0);
X return 0;
X }
X if (noeval)
X return v;
X setiparam(lvals[s],v);


X return v;
X}
X

Xint notzero(a) /**/
Xint a;
X{
X if (a == 0)
X {
X zerr("division by zero",NULL,0);
X return 0;
X }


X return 1;
X}
X

X#define pop2() { b = stack[sp--].val; a = stack[sp--].val; }
X#define pop3() {c=stack[sp--].val;b=stack[sp--].val;a=stack[sp--].val;}
X#define nolval() {stack[sp].lval= -1;}
X#define pushv(X) { push(X,-1); }
X#define pop2lv() { pop2() lv = stack[sp+1].lval; }
X#define set(X) { push(setvar(lv,X),lv); }
X
Xvoid op(what) /**/
Xint what;
X{
Xlong a,b,c;
XLV lv;
X
X if (sp < 0)
X {
X zerr("bad math expression: stack empty",NULL,0);
X return;
X }
X switch(what) {
X case NOT: stack[sp].val = !stack[sp].val; nolval(); break;
X case COMP: stack[sp].val = ~stack[sp].val; nolval(); break;
X case POSTPLUS: ( void ) setvar(stack[sp].lval,stack[sp].val+1); break;
X case POSTMINUS: ( void ) setvar(stack[sp].lval,stack[sp].val-1); break;
X case UPLUS: nolval(); break;
X case UMINUS: stack[sp].val = -stack[sp].val; nolval(); break;
X case AND: pop2(); pushv(a&b); break;
X case XOR: pop2(); pushv(a^b); break;
X case OR: pop2(); pushv(a|b); break;
X case MUL: pop2(); pushv(a*b); break;
X case DIV: pop2(); if (notzero(b)) pushv(a/b); break;
X case MOD: pop2(); if (notzero(b)) pushv(a%b); break;
X case PLUS: pop2(); pushv(a+b); break;
X case MINUS: pop2(); pushv(a-b); break;
X case SHLEFT: pop2(); pushv(a<<b); break;
X case SHRIGHT: pop2(); pushv(a>>b); break;
X case LES: pop2(); pushv((long)(a<b)); break;
X case LEQ: pop2(); pushv((long)(a<=b)); break;
X case GRE: pop2(); pushv((long)(a>b)); break;
X case GEQ: pop2(); pushv((long)(a>=b)); break;
X case DEQ: pop2(); pushv((long)(a==b)); break;
X case NEQ: pop2(); pushv((long)(a!=b)); break;
X case DAND: pop2(); pushv((long)(a&&b)); break;
X case DOR: pop2(); pushv((long)(a||b)); break;
X case DXOR: pop2(); pushv((long)((a&&!b)||(!a&&b))); break;
X case QUEST: pop3(); pushv((a)?b:c); break;
X case COLON: break;
X case EQ: b = stack[sp].val; sp -= 2; lv = stack[sp+1].lval;
X set(b); break;
X case PLUSEQ: pop2lv(); set(a+b); break;
X case MINUSEQ: pop2lv(); set(a-b); break;
X case MULEQ: pop2lv(); set(a*b); break;
X case DIVEQ: pop2lv(); if (notzero(b)) set(a/b); break;
X case MODEQ: pop2lv(); if (notzero(b)) set(a%b); break;
X case ANDEQ: pop2lv(); set(a&b); break;
X case XOREQ: pop2lv(); set(a^b); break;
X case OREQ: pop2lv(); set(a|b); break;
X case SHLEFTEQ: pop2lv(); set(a<<b); break;
X case SHRIGHTEQ: pop2lv(); set(a>>b); break;
X case DANDEQ: pop2lv(); set((long)(a&&b)); break;
X case DOREQ: pop2lv(); set((long)(a||b)); break;
X case DXOREQ: pop2lv(); set((long)((a&&!b)||(!a&&b))); break;
X case COMMA: b = stack[sp].val; sp -= 2; pushv(b); break;
X case PREPLUS: stack[sp].val = setvar(stack[sp].lval,
X stack[sp].val+1); break;
X case PREMINUS: stack[sp].val = setvar(stack[sp].lval,
X stack[sp].val-1); break;
X default: zerr("out of integers",NULL,0); exit(1);
X }
X}
X
Xvoid bop(tk) /**/
Xint tk;
X{
X switch (tk) {
X case DAND: case DANDEQ: if (!stack[sp].val) noeval++; break;
X case DOR: case DOREQ: if (stack[sp].val) noeval++; break;
X };
X}
X
Xlong mathevall(s,prek,ep) /**/
Xchar *s;int prek;char **ep;
X{
Xint t0;
X
X lastbase = -1;
X for (t0 = 0; t0 != LVCOUNT; t0++)
X lvals[t0] = NULL;
X lvc = 0;
X ptr = s;
X sp = -1;
X unary = 1;
X mathparse(prek);
X *ep = ptr;
X if (sp)
X zerr("bad math expression: unbalanced stack",NULL,0);
X for (t0 = 0; t0 != lvc; t0++)
X free(lvals[t0]);
X return stack[0].val;
X}
X
Xlong matheval(s) /**/
Xchar *s;
X{
Xchar *junk;
Xlong x;
X
X if (!*s)
X return 0;
X x = mathevall(s,TOPPREC,&junk);
X if (*junk)
X zerr("bad math expression: illegal character: %c",NULL,*junk);
X return x;
X}
X
Xlong mathevalarg(s,ss) /**/
Xchar *s;char **ss;
X{
Xlong x;
X
X x = mathevall(s,ARGPREC,ss);
X if (mtok == COMMA)
X (*ss)--;
X return x;
X}
X
X/* operator-precedence parse the string and execute */
X
Xvoid mathparse(pc) /**/
Xint pc;


X{
X if (errflag)
X return;

X mtok = zzlex();
X while (prec[mtok] <= pc)


X {
X if (errflag)
X return;

X if (mtok == NUM)
X push(yyval,-1);
X else if (mtok == ID)
X push(getvar(yylval),yylval);
X else if (mtok == M_INPAR)
X {
X mathparse(TOPPREC);
X if (mtok != M_OUTPAR)
X exit(1);
X }
X else if (mtok == QUEST)
X {
X int q = stack[sp].val;
X if (!q) noeval++;
X mathparse(prec[QUEST]-1);
X if (!q) noeval--; else noeval++;
X mathparse(prec[QUEST]);
X if (q) noeval--;
X op(QUEST);
X continue;
X }
X else
X {
X int otok = mtok,onoeval = noeval;
X
X if (type[otok] == BOOL)
X bop(otok);
X mathparse(prec[otok]-(type[otok] != RL));
X noeval = onoeval;
X op(otok);
X continue;
X }
X mtok = zzlex();
X }
X}
X
END_OF_FILE
if test 10353 -ne `wc -c <'src/math.c'`; then
echo shar: \"'src/math.c'\" unpacked with wrong size!
fi
# end of 'src/math.c'
fi
if test -f 'src/table.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/table.c'\"
else
echo shar: Extracting \"'src/table.c'\" \(6815 characters\)
sed "s/^X//" >'src/table.c' <<'END_OF_FILE'
X/*
X *
X * table.c - linked lists and hash tables


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#define TABLE_C
X#include "zsh.h"
X
X/* get an empty linked list header */
X
XLklist newlist() /**/
X{
XLklist list;
X
X list = (Lklist) alloc(sizeof *list);
X list->first = 0;
X list->last = (Lknode) list;
X return list;
X}
X
X/* get an empty hash table */
X
XHashtab newhtable(size) /**/
Xint size;
X{
XHashtab ret;
X
X ret = (Hashtab) zcalloc(sizeof *ret);
X ret->hsize = size;
X ret->nodes = (Hashnode*) zcalloc(size*sizeof(Hashnode));


X return ret;
X}
X

X/* Peter Weinberger's hash function */
X
Xint hasher(s) /**/
Xchar *s;
X{
Xunsigned hash = 0,g;


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

X hash = (hash << 4) + *s;
X if (g = hash & 0xf0000000) {
X hash ^= g;
X hash ^= g >> 24;
X }
X }
X return hash;
X}
X
X/* add a node to a hash table */
X
Xvoid Addhnode(nam,dat,ht,freefunc,canfree) /**/
Xchar *nam;vptr dat;Hashtab ht;FFunc freefunc;int canfree;
X{
Xint hval = hasher(nam) % ht->hsize;
Xstruct hashnode **hp = ht->nodes+hval,*hn;
X
X for (; *hp; hp = &(*hp)->next)
X if (!strcmp((*hp)->nam,nam)) {
X if ((*hp)->canfree) free((*hp)->nam);
X hn = dat;
X hn->next = (*hp)->next;
X if (!freefunc) zerr("attempt to call NULL freefunc",NULL,0);
X else freefunc(*hp);
X *hp = hn;
X hn->nam = nam;
X hn->canfree = canfree;
X return;
X }
X hn = (Hashnode) dat;
X hn->nam = nam;
X hn->canfree = canfree;
X hn->next = ht->nodes[hval];
X ht->nodes[hval] = hn;
X if (++ht->ct == ht->hsize*4) expandhtab(ht);
X}
X
X/* add a node to command hash table */
X
Xvoid addhcmdnode(nam,pnam) /**/
Xchar *nam;char **pnam;
X{
Xint hval = hasher(nam) % cmdnamtab->hsize;
Xstruct hashnode *hp = cmdnamtab->nodes[hval],*hn;
XCmdnam cc;
X
X for (; hp; hp = hp->next) if (!strcmp(hp->nam,nam)) return;


X cc = (Cmdnam) zcalloc(sizeof *cc);

X cc->type = EXCMD;
X cc->u.nam = tricat(*pnam,"/",nam);
X cc->pcomp = pnam;
X hn = (Hashnode) cc;
X hn->nam = ztrdup(nam);
X hn->canfree = 1;
X hn->next = cmdnamtab->nodes[hval];
X cmdnamtab->nodes[hval] = hn;
X if (++cmdnamtab->ct == cmdnamtab->hsize*4) expandhtab(cmdnamtab);
X}
X
X/* expand hash tables when they get too many entries */
X
Xvoid expandhtab(ht) /**/
XHashtab ht;
X{
Xstruct hashnode **arr,**ha,*hn,*hp;
Xint osize = ht->hsize,nsize = osize*8;
X
X ht->hsize = nsize;
X arr = ht->nodes;
X ht->nodes = (Hashnode*) zcalloc(nsize*sizeof(struct hashnode *));
X for (ha = arr; osize; osize--,ha++)
X for (hn = *ha; hn; ) {
X hp = hn->next;
X Addhnode(hn->nam,(vptr)hn,ht,(FFunc) 0,hn->canfree);
X hn = hp;
X }
X free(arr);
X}
X
X/* get an entry in a hash table */
X
Xvptr gethnode(nam,ht) /**/
Xchar *nam;Hashtab ht;
X{
Xint hval = hasher(nam) % ht->hsize;
Xstruct hashnode *hn = ht->nodes[hval];
X
X for (; hn; hn = hn->next) if (!strcmp(hn->nam,nam)) return (vptr)hn;


X return NULL;
X}
X

Xvoid freehtab(ht,freefunc) /**/
XHashtab ht;FFunc freefunc;
X{
Xint val;
Xstruct hashnode *hn,**hp = &ht->nodes[0],*next;
X
X for (val = ht->hsize; val; val--,hp++)
X for (hn = *hp; hn; ) {
X next = hn->next;
X if (hn->canfree) free(hn->nam);
X freefunc(hn);
X hn = next;
X }
X free(ht->nodes);
X free(ht);
X}
X
X/* remove a hash table entry and return a pointer to it */
X
Xvptr remhnode(nam,ht) /**/
Xchar *nam;Hashtab ht;
X{
Xint hval = hasher(nam) % ht->hsize;
Xstruct hashnode *hn = ht->nodes[hval],*hp;
X
X if (!hn) return NULL;
X if (!strcmp(hn->nam,nam)) {
X ht->nodes[hval] = hn->next;
X if (hn->canfree) free(hn->nam);
X ht->ct--;
X return (vptr)hn;
X }
X for (hp = hn, hn = hn->next; hn; hn = (hp = hn)->next)
X if (!strcmp(hn->nam,nam)) {
X hp->next = hn->next;
X if (hn->canfree) free(hn->nam);
X ht->ct--;
X return (vptr)hn;


X }
X return NULL;
X}
X

X/* insert a node in a linked list after 'llast' */
X
Xvoid insnode(list,llast,dat) /**/
XLklist list;Lknode llast;vptr dat;
X{
XLknode tmp;
X
X tmp = llast->next;
X llast->next = (Lknode) alloc(sizeof *tmp);
X llast->next->last = llast;
X llast->next->dat = dat;
X llast->next->next = tmp;
X if (tmp) tmp->last = llast->next;
X else list->last = llast->next;
X}
X
Xvoid addnodeinorder(x,dat) /**/
XLklist x; char *dat;
X{
XLknode y, l = NULL;
Xint val = 123;
X
X for (y = firstnode(x); y; incnode(y)) {
X if ((val = forstrcmp((char **) &y->dat, &dat)) >= 0) break;
X l = y;
X }
X if (!val) return;
X if (l == NULL) insnode(x, (Lknode) x, dat);
X else insnode(x, l, dat);
X}
X
X
X/* remove a node from a linked list */
X
Xvptr remnode(list,nd) /**/
XLklist list;Lknode nd;
X{
Xvptr dat;
X
X nd->last->next = nd->next;
X if (nd->next) nd->next->last = nd->last;
X else list->last = nd->last;
X dat = nd->dat;
X free(nd);
X return dat;
X}
X
X/* remove a node from a linked list */
X
Xvptr uremnode(list,nd) /**/
XLklist list;Lknode nd;
X{
Xvptr dat;
X
X nd->last->next = nd->next;
X if (nd->next) nd->next->last = nd->last;
X else list->last = nd->last;
X dat = nd->dat;
X return dat;
X}
X
X/* delete a character in a string */
X
Xvoid chuck(str) /**/
Xchar *str;
X{
X while (str[0] = str[1]) str++;
X}
X
X/* get top node in a linked list */
X
Xvptr getnode(list) /**/
XLklist list;
X{
Xvptr dat;
XLknode node = list->first;
X
X if (!node)
X return NULL;
X dat = node->dat;
X list->first = node->next;
X if (node->next)
X node->next->last = (Lknode) list;
X else
X list->last = (Lknode) list;
X free(node);
X return dat;
X}
X
X/* get top node in a linked list without freeing */
X
Xvptr ugetnode(list) /**/
XLklist list;
X{
Xvptr dat;
XLknode node = list->first;
X
X if (!node)
X return NULL;
X dat = node->dat;
X list->first = node->next;
X if (node->next)
X node->next->last = (Lknode) list;
X else
X list->last = (Lknode) list;
X return dat;
X}
X
Xvoid freetable(tab,freefunc) /**/
XLklist tab;FFunc freefunc;
X{
XLknode node = tab->first,next;
X
X while (node) {
X next = node->next;
X if (freefunc) freefunc(node->dat);
X free(node);
X node = next;
X }
X free(tab);
X}
X
Xchar *ztrstr(s,t) /**/


Xchar *s;char *t;
X{

Xchar *p1,*p2;


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

X for (p1 = s, p2 = t; *p2; p1++,p2++)
X if (*p1 != *p2) break;
X if (!*p2) return (char *) s;


X }
X return NULL;
X}
X

X/* insert a list in another list */
X
Xvoid inslist(l,where,x) /**/
XLklist l;Lknode where;Lklist x;
X{
XLknode nx = where->next;
X
X if (!l->first) return;
X where->next = l->first;
X l->last->next = nx;
X l->first->last = where;
X if (nx) nx->last = l->last;
X else x->last = l->last;
X}
X
Xint countnodes(x) /**/
XLklist x;
X{
XLknode y;
Xint ct = 0;
X
X for (y = firstnode(x); y; incnode(y),ct++);
X return ct;
X}
X
END_OF_FILE
if test 6815 -ne `wc -c <'src/table.c'`; then
echo shar: \"'src/table.c'\" unpacked with wrong size!
fi
# end of 'src/table.c'
fi
if test -f 'src/zle_hist.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle_hist.c'\"
else
echo shar: Extracting \"'src/zle_hist.c'\" \(11190 characters\)
sed "s/^X//" >'src/zle_hist.c' <<'END_OF_FILE'
X/*
X *
X * zle_hist.c - history editing


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#define ZLE
X#include "zsh.h"
X

Xvoid toggleliteralhistory() /**/
X{
Xchar *s;
X
X if (histline == curhist)
X {


X if (curhistline)
X free(curhistline);

X curhistline = ztrdup(UTOSCP(line));
X }
X lithist ^= 1;
X if (!(s = qgetevent(histline)))
X feep();
X else
X sethistline(STOUCP(s));
X}
X
Xvoid uphistory() /**/
X{
Xchar *s;
X
X if (mult < 0) { mult = -mult; downhistory(); return; }
X if (histline == curhist)
X {


X if (curhistline)
X free(curhistline);

X curhistline = ztrdup(UTOSCP(line));
X }
X histline -= mult;
X if (!(s = qgetevent(histline)))
X {
X if (unset(NOHISTBEEP)) feep();
X histline += mult;
X }
X else
X sethistline(STOUCP(s));
X}
X
Xvoid uplineorhistory() /**/
X{
Xint ocs = cs;
X
X if (mult < 0) { mult = -mult; downlineorhistory(); return; }
X if ((lastcmd & ZLE_LINEMOVE) != ZLE_LINEMOVE)
X lastcol = cs-findbol();
X cs = findbol();
X while (mult) {
X if (!cs)
X break;
X cs--;
X cs = findbol();
X mult--;
X }
X if (mult) {
X cs = ocs;
X if (virangeflag) {


X feep();
X return;
X }

X uphistory();
X } else {
X int x = findeol();
X if ((cs += lastcol) > x)
X cs = x;
X }
X}
X
Xvoid uplineorsearch() /**/
X{
Xint ocs = cs;
X
X if (mult < 0) { mult = -mult; downlineorsearch(); return; }
X if ((lastcmd & ZLE_LINEMOVE) != ZLE_LINEMOVE)
X lastcol = cs-findbol();
X cs = findbol();
X while (mult) {
X if (!cs)
X break;
X cs--;
X cs = findbol();
X mult--;
X }
X if (mult) {
X cs = ocs;
X if (virangeflag) {


X feep();
X return;
X }

X historysearchbackward();
X } else {
X int x = findeol();
X if ((cs += lastcol) > x)
X cs = x;
X }
X}
X
Xvoid downlineorhistory() /**/
X{
Xint ocs = cs;
X
X if (mult < 0) { mult = -mult; uplineorhistory(); return; }
X if ((lastcmd & ZLE_LINEMOVE) != ZLE_LINEMOVE)
X lastcol = cs-findbol();
X while (mult) {
X int x = findeol();
X if (x == ll)
X break;
X cs = x+1;
X mult--;
X }
X if (mult) {
X cs = ocs;
X if (virangeflag) {


X feep();
X return;
X }

X downhistory();
X } else {
X int x = findeol();
X if ((cs += lastcol) > x)
X cs = x;
X }
X}
X
Xvoid downlineorsearch() /**/
X{
Xint ocs = cs;
X
X if (mult < 0) { mult = -mult; uplineorsearch(); return; }
X if ((lastcmd & ZLE_LINEMOVE) != ZLE_LINEMOVE)
X lastcol = cs-findbol();
X while (mult) {
X int x = findeol();
X if (x == ll)
X break;
X cs = x+1;
X mult--;
X }
X if (mult) {
X cs = ocs;
X if (virangeflag) {


X feep();
X return;
X }

X historysearchforward();
X } else {
X int x = findeol();
X if ((cs += lastcol) > x)
X cs = x;
X }
X}
X
Xvoid acceptlineanddownhistory() /**/
X{
Xchar *s,*t;
X
X if (!(s = qgetevent(histline+1)))


X {
X feep();
X return;
X }

X pushnode(bufstack,t = ztrdup(s));


X for (; *t; t++)

X if (*t == HISTSPACE)

X *t = ' ';
X done = 1;
X stackhist = histline+1;
X}
X
Xvoid downhistory() /**/
X{
Xchar *s;
X
X if (mult < 0) { mult = -mult; uphistory(); return; }
X histline += mult;
X if (!(s = qgetevent(histline)))
X {
X if (unset(NOHISTBEEP)) feep();
X histline -= mult;
X return;
X }
X sethistline(STOUCP(s));
X}
X
Xstatic int histpos;
X
Xvoid historysearchbackward() /**/
X{
Xint t0,ohistline = histline;
Xchar *s;
X
X if (histline == curhist)
X {


X if (curhistline)
X free(curhistline);

X curhistline = ztrdup(UTOSCP(line));
X }
X if (lastcmd & ZLE_HISTSEARCH) t0 = histpos;
X else for (t0 = 0; line[t0] && iword(line[t0]); t0++);
X histpos = t0;


X for (;;)
X {

X histline--;
X if (!(s = qgetevent(histline)))
X {
X feep();
X histline = ohistline;
X return;
X }
X if (!hstrncmp(s,UTOSCP(line),t0) && hstrcmp(s,UTOSCP(line)))
X break;
X }
X sethistline(STOUCP(s));
X}
X
Xvoid historysearchforward() /**/
X{
Xint t0,ohistline = histline;
Xchar *s;
X
X if (histline == curhist)
X {


X if (curhistline)
X free(curhistline);

X curhistline = ztrdup(UTOSCP(line));
X }
X if (lastcmd & ZLE_HISTSEARCH) t0 = histpos;
X else for (t0 = 0; line[t0] && iword(line[t0]); t0++);
X histpos = t0;


X for (;;)
X {

X histline++;
X if (!(s = qgetevent(histline)))
X {
X feep();
X histline = ohistline;
X return;
X }
X if (!hstrncmp(s,UTOSCP(line),t0) && hstrcmp(s,UTOSCP(line)))
X break;
X }
X sethistline(STOUCP(s));
X}
X
Xvoid beginningofbufferorhistory() /**/
X{
X if (findbol())
X cs = 0;
X else
X beginningofhistory();
X}
X
Xvoid beginningofhistory() /**/
X{
Xchar *s;
X
X if (histline == curhist)
X {


X if (curhistline)
X free(curhistline);

X curhistline = ztrdup(UTOSCP(line));
X }
X if (!(s = qgetevent(firsthist())))
X {
X if (unset(NOHISTBEEP)) feep();
X return;
X }
X histline = firsthist();
X sethistline(STOUCP(s));
X}
X
Xvoid endofbufferorhistory() /**/
X{
X if (findeol() != ll)
X cs = ll;
X else
X endofhistory();
X}
X
Xvoid endofhistory() /**/
X{
X if (histline == curhist) {
X if (unset(NOHISTBEEP)) feep();
X } else
X {
X histline = curhist;
X sethistline(STOUCP(curhistline));
X }
X}
X
Xvoid insertlastword() /**/
X{
Xchar *s,*t;
Xint len,z = lithist;
X
X /* multiple calls will now search back through the history, pem */
X static char *lastinsert;
X static int lasthist, lastpos;
X int evhist = curhist - 1;
X
X if (lastinsert) {
X int len = strlen(lastinsert);
X int pos = cs;
X if ( lastpos <= pos &&
X len == pos - lastpos &&
X strncmp(lastinsert, (char *) &line[lastpos], len) == 0) {
X evhist = --lasthist;
X cs = lastpos;
X foredel(pos-cs);
X }
X free(lastinsert);
X lastinsert = NULL;
X }
X lithist = 0;
X if (!(s = qgetevent(evhist), lithist = z, s))


X {
X feep();
X return;
X }

X for (t = s+strlen(s); t > s; t--)
X if (*t == HISTSPACE)
X break;
X if (t != s)
X t++;

X lasthist = evhist;
X lastpos = cs;
X lastinsert = ztrdup(t);
X spaceinline(len = strlen(t));
X strncpy((char *) line+cs,t,len);


X cs += len;
X}
X

Xchar *qgetevent(ev) /**/
Xint ev;
X{
X if (ev > curhist)
X return NULL;
X return ((ev == curhist) ? curhistline : quietgetevent(ev));
X}
X
Xvoid pushline() /**/
X{
X if (mult < 0) return;
X pushnode(bufstack,ztrdup(UTOSCP(line)));
X while (--mult)
X pushnode(bufstack,ztrdup(""));
X stackcs = cs;
X *line = '\0';
X ll = cs = 0;
X}
X
Xvoid getline() /**/
X{
Xchar *s = getnode(bufstack);
X
X if (!s)
X feep();
X else
X {
X int cc;
X
X cc = strlen(s);
X spaceinline(cc);
X strncpy((char *) line+cs,s,cc);
X cs += cc;
X free(s);
X }
X}
X
Xvoid historyincrementalsearchbackward() /**/
X{
X doisearch(-1);
X}
X
Xvoid historyincrementalsearchforward() /**/
X{
X doisearch(1);
X}
X
Xvoid doisearch(dir) /**/
Xint dir;
X{
Xchar *s,*oldl;
Xchar ibuf[256],*sbuf = ibuf+10;
Xint sbptr = 0,ch,ohl = histline,ocs = cs;
Xint nomatch,chequiv = 0;
X
X strcpy(ibuf,"i-search: ");
X statusline = ibuf;
X oldl = ztrdup(UTOSCP(line));
X if (histline == curhist)
X {


X if (curhistline)
X free(curhistline);

X curhistline = ztrdup(UTOSCP(line));


X }
X for (;;)

X {
X nomatch = 0;
X if (sbptr > 1 || (sbptr == 1 && sbuf[0] != '^'))
X {
X int ohistline = histline;


X
X for (;;)

X {
X char *t;
X
X if (!(s = qgetevent(histline)))
X {
X feep();
X nomatch = 1;
X histline = ohistline;
X break;
X }
X if ((sbuf[0] == '^') ?
X (t = (hstrncmp(s,sbuf+1,sbptr-1)) ? NULL : s) :
X (t = hstrnstr(s,sbuf,sbptr)))
X if (!(chequiv && !hstrcmp(UTOSCP(line),s)))
X {
X sethistline(STOUCP(s));
X cs = t-s+sbptr-(sbuf[0] == '^');
X break;
X }
X histline += dir;
X }
X chequiv = 0;
X }
X refresh();
X if ((ch = getkey(1)) == -1)
X break;
X if (ch == 22 || ch == 17) {
X if ((ch = getkey(1)) == -1)
X break;
X } else if (ch == 24) { /* ^XS and ^XR */
X if ((ch = getkey(1)) == -1)
X break;
X if (ch != 's' && ch != 'r') {
X ungetkey(24);
X ungetkey(ch);
X break;
X }
X ungetkey(ch & 0x1f);
X continue;
X } else if (ch == 8 || ch == 127) {
X if (sbptr)
X sbuf[--sbptr] = '\0';
X else
X feep();
X histline = ohl;
X continue;
X } else if (ch == 7 || ch == 3) {
X setline(oldl);
X cs = ocs;
X histline = ohl;
X statusline = NULL;
X break;
X } else if (ch == 27)
X break;
X else if (ch == 10 || ch == 13) {
X ungetkey(ch);
X break;
X } else if (ch == 18) {
X ohl = (histline += (dir = -1));
X chequiv = 1;
X continue;
X } else if (ch == 19) {
X ohl = (histline += (dir = 1));
X chequiv = 1;
X continue;
X } else if (!(ch & 0x60)) {
X ungetkey(ch);
X break;
X }
X if (!nomatch && sbptr != 39 && !icntrl(ch)) {
X sbuf[sbptr++] = ch;
X sbuf[sbptr] = '\0';
X }
X }
X free(oldl);


X statusline = NULL;
X}

X
Xvoid acceptandinfernexthistory() /**/
X{
Xint t0;
Xchar *s,*t;
X
X done = 1;
X for (t0 = histline-2;;t0--)
X {
X if (!(s = qgetevent(t0)))
X return;
X if (!hstrncmp(s,UTOSCP(line),ll))
X break;
X }
X if (!(s = qgetevent(t0+1)))
X return;
X pushnode(bufstack,t = ztrdup(s));


X for (; *t; t++)

X if (*t == HISTSPACE)

X *t = ' ';
X stackhist = t0+1;
X}
X
Xvoid infernexthistory() /**/
X{
Xint t0;
Xchar *s,*t;
X
X if (!(t = qgetevent(histline-1)))


X {
X feep();
X return;
X }

X for (t0 = histline-2;;t0--)
X {
X if (!(s = qgetevent(t0)))
X {
X feep();
X return;
X }
X if (!strcmp(s,t))
X break;
X }
X if (!(s = qgetevent(t0+1)))


X {
X feep();
X return;
X }

X histline = t0+1;
X sethistline(STOUCP(s));
X}
X
Xvoid vifetchhistory() /**/
X{
Xchar *s;
X
X if (mult < 0) return;
X if (histline == curhist) {


X if (!(lastcmd & ZLE_ARG)) {

X cs = ll;
X cs = findbol();
X return;
X }
X if (curhistline)
X free(curhistline);
X curhistline = ztrdup(UTOSCP(line));
X }
X if (!(lastcmd & ZLE_ARG)) mult = curhist;
X if (!(s = qgetevent(mult)))
X feep();
X else {
X histline = mult;
X sethistline(STOUCP(s));
X }
X}
X
Xint getvisrchstr() /**/
X{
Xstatic char sbuf[80];
Xint sptr = 1;
X
X if (visrchstr)
X {
X free(visrchstr);
X visrchstr = NULL;
X }
X statusline = sbuf;
X sbuf[0] = c;
X sbuf[1] = '\0';
X while (sptr)
X {
X refresh();
X c = getkey(0);
X if (c == '\r' || c == '\n' || c == '\033')
X {
X visrchstr = ztrdup(sbuf+1);
X return 1;
X }
X if (c == '\b' || c == 127)
X {
X sbuf[--sptr] = '\0';
X continue;
X }
X if (sptr != 79)
X {
X sbuf[sptr++] = c;
X sbuf[sptr] = '\0';
X }
X }


X return 0;
X}
X

Xvoid vihistorysearchforward() /**/
X{
X visrchsense = 1;
X if (getvisrchstr())
X virepeatsearch();
X}
X
Xvoid vihistorysearchbackward() /**/
X{
X visrchsense = -1;
X if (getvisrchstr())
X virepeatsearch();
X}
X
Xvoid virepeatsearch() /**/
X{
Xint ohistline = histline,t0;
Xchar *s;
X
X if (!visrchstr)


X {
X feep();
X return;
X }

X t0 = strlen(visrchstr);
X if (histline == curhist)
X {


X if (curhistline)
X free(curhistline);

X curhistline = ztrdup(UTOSCP(line));


X }
X for (;;)

X {
X histline += visrchsense;
X if (!(s = qgetevent(histline)))
X {
X feep();
X histline = ohistline;
X return;
X }
X if (!hstrcmp(UTOSCP(line),s))
X continue;
X if (*visrchstr == '^')
X {
X if (!hstrncmp(s,visrchstr+1,t0-1))


X break;
X }
X else

X if (hstrnstr(s,visrchstr,t0))
X break;
X }
X sethistline(STOUCP(s));
X}
X
Xvoid virevrepeatsearch() /**/
X{
X visrchsense = -visrchsense;
X virepeatsearch();
X visrchsense = -visrchsense;
X}
X
END_OF_FILE
if test 11190 -ne `wc -c <'src/zle_hist.c'`; then
echo shar: \"'src/zle_hist.c'\" unpacked with wrong size!
fi
# end of 'src/zle_hist.c'
fi
echo shar: End of archive 19 \(of 22\).
cp /dev/null ark19isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:29:09 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 70
Archive-name: zsh/part20

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: doc/intro.txt.02 help/limit help/source src/funcs.h
# src/text.c src/watch.c src/zle.h src/zle_vi.c src/zle_word.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:55 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 20 (of 22)."'
if test -f 'doc/intro.txt.02' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'doc/intro.txt.02'\"
else
echo shar: Extracting \"'doc/intro.txt.02'\" \(8938 characters\)
sed "s/^X//" >'doc/intro.txt.02' <<'END_OF_FILE'


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
X
X - 39 -
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
END_OF_FILE
if test 8938 -ne `wc -c <'doc/intro.txt.02'`; then
echo shar: \"'doc/intro.txt.02'\" unpacked with wrong size!
fi
# end of 'doc/intro.txt.02'
fi
if test -f 'help/limit' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/limit'\"
else
echo shar: Extracting \"'help/limit'\" \(1253 characters\)
sed "s/^X//" >'help/limit' <<'END_OF_FILE'
X limit [ -h ] [ resource [ limit ] ] ...
X limit -s
X Limit the resource consumption of children of the
X current shell. If limit is not specified, print the
X current limit placed on resource; otherwise set the
X limit to the specified value. If the -h flag is given,
X use hard limits instead of soft limits. If no resource
X is given, print all limits.
X
X resource is one of:
X
X cputime
X Maximum CPU seconds per process.
X filesize
X Largest single file allowed.
X datasize
X Maximum data size (including stack) for each pro-
X cess.
X stacksize
X Maximum stack size for each process.
X coredumpsize
X Maximum size of a core dump.
X resident
X Maximum resident set size.
X descriptors
X Maximum value for a file descriptor.
X
X limit is a number, with an optional scaling factor, as
X follows:
X
X nh hours.
X nk kilobytes. This is the default for all but cpu-
X time.
X nm megabytes or minutes.
X mm:ss
X minutes and seconds.
END_OF_FILE
if test 1253 -ne `wc -c <'help/limit'`; then
echo shar: \"'help/limit'\" unpacked with wrong size!
fi
# end of 'help/limit'
fi
if test -f 'help/source' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/source'\"
else
echo shar: Extracting \"'help/source'\" \(552 characters\)
sed "s/^X//" >'help/source' <<'END_OF_FILE'
X source file [ arg ... ]
X . file [ arg ... ]
X Read and execute commands from file in the current
X shell environment. If file does not contain a slash,
X the shell looks in the components of path to find the
X directory containing file. If any arguments arg are
X given, they become the positional parameters; the old
X positional parameters are restored when the file is
X done executing. The exit status is the exit status of
X the last command executed.
END_OF_FILE
if test 552 -ne `wc -c <'help/source'`; then
echo shar: \"'help/source'\" unpacked with wrong size!
fi
# end of 'help/source'
fi
if test -f 'src/funcs.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/funcs.h'\"
else
echo shar: Extracting \"'src/funcs.h'\" \(1219 characters\)
sed "s/^X//" >'src/funcs.h' <<'END_OF_FILE'
Xstruct asgment;
Xstruct utmp;
Xstruct hp;
Xtypedef struct hp *Hp;
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)()));
END_OF_FILE
if test 1219 -ne `wc -c <'src/funcs.h'`; then
echo shar: \"'src/funcs.h'\" unpacked with wrong size!
fi
# end of 'src/funcs.h'
fi
if test -f 'src/text.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/text.c'\"
else
echo shar: Extracting \"'src/text.c'\" \(8624 characters\)
sed "s/^X//" >'src/text.c' <<'END_OF_FILE'
X/*
X *
X * text.c - textual representations of syntax trees


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

Xstatic char *tptr,*tbuf,*tlim;
Xstatic int tsiz,tindent,tnewlins;
X
X/* add a character to the text buffer */
X
Xvoid taddchr(c) /**/
Xint c;
X{
X *tptr++ = c;
X if (tptr == tlim) {
X if (!tbuf) { tptr--; return; }
X tbuf = realloc(tbuf,tsiz *= 2);
X tlim = tbuf+tsiz;
X tptr = tbuf+tsiz/2;
X }
X}
X
X/* add a string to the text buffer */
X
Xvoid taddstr(s) /**/
Xchar *s;
X{


Xint sl = strlen(s);
X

X while (tptr+sl >= tlim) {
X int x = tptr-tbuf;
X
X if (!tbuf) return;
X tbuf = realloc(tbuf,tsiz *= 2);
X tlim = tbuf+tsiz;
X tptr = tbuf+x;
X }
X strcpy(tptr,s);
X tptr += sl;
X}
X
X/* add an integer to the text buffer */
X
Xvoid taddint(x) /**/
Xint x;
X{
Xchar buf[10];
X
X sprintf(buf,"%d",x);
X taddstr(buf);
X}
X
X/* add a newline, or something equivalent, to the text buffer */
X
Xvoid taddnl() /**/
X{
Xint t0;
X
X if (tnewlins)
X {
X taddchr('\n');
X for (t0 = 0; t0 != tindent; t0++)
X taddchr('\t');
X }
X else
X taddstr("; ");
X}
X
X/* get a permanent textual representation of n */
X
Xchar *getpermtext(n) /**/
Xstruct node *n;
X{
X tnewlins = 1;
X tbuf = zalloc(tsiz = 32);
X tptr = tbuf;
X tlim = tbuf+tsiz;
X tindent = 1;
X gettext2(n);
X *tptr = '\0';
X untokenize(tbuf);
X return tbuf;
X}
X
X/* get a representation of n in a job text buffer */
X
Xchar *getjobtext(n) /**/
Xstruct node *n;
X{
Xstatic char jbuf[JOBTEXTSIZE];
X
X tnewlins = 0;
X tbuf = NULL;
X tptr = jbuf;
X tlim = tptr+JOBTEXTSIZE-1;
X tindent = 1;
X gettext2(n);
X *tptr = '\0';
X untokenize(jbuf);
X return jbuf;
X}
X
X#define gt2(X) gettext2((struct node *) (X))
X
X/*
X "gettext2" or "type checking and how to avoid it"
X an epic function by Paul Falstad
X*/
X
X#define _Cond(X) ((Cond) (X))
X#define _Cmd(X) ((Cmd) (X))
X#define _Pline(X) ((Pline) (X))
X#define _Sublist(X) ((Sublist) (X))
X#define _List(X) ((List) (X))
X#define _casecmd(X) ((struct casecmd *) (X))
X#define _ifcmd(X) ((struct ifcmd *) (X))
X#define _whilecmd(X) ((struct whilecmd *) (X))
X
Xvoid gettext2(n) /**/
Xstruct node *n;
X{
XCmd nn;
XCond nm;
X
X if (!n)
X return;
X switch (n->type)
X {
X case N_LIST:
X gt2(_List(n)->left);
X if (_List(n)->type == ASYNC)
X taddstr(" &");
X simplifyright(_List(n));
X if (_List(n)->right)
X {
X if (tnewlins)
X taddnl();
X else
X taddstr((_List(n)->type == ASYNC) ? " " : "; ");
X gt2(_List(n)->right);
X }
X break;
X case N_SUBLIST:
X if (_Sublist(n)->flags & PFLAG_NOT)
X taddstr("! ");
X if (_Sublist(n)->flags & PFLAG_COPROC)
X taddstr("coproc ");
X gt2(_Sublist(n)->left);
X if (_Sublist(n)->right)
X {
X taddstr((_Sublist(n)->type == ORNEXT) ? " || " : " && ");
X gt2(_Sublist(n)->right);
X }
X break;
X case N_PLINE:
X gt2(_Pline(n)->left);
X if (_Pline(n)->type == PIPE)
X {
X taddstr(" | ");
X gt2(_Pline(n)->right);
X }
X break;
X case N_CMD:
X nn = _Cmd(n);
X if (nn->flags & CFLAG_EXEC)
X taddstr("exec ");
X if (nn->flags & CFLAG_COMMAND)
X taddstr("command ");
X switch (nn->type)
X {
X case SIMPLE:
X getsimptext(nn);
X break;
X case SUBSH:
X taddstr("( ");
X tindent++;
X gt2(nn->u.list);
X tindent--;
X taddstr(" )");
X break;
X case ZCTIME:
X taddstr("time ");
X tindent++;
X gt2(nn->u.pline);
X tindent--;
X break;
X case FUNCDEF:
X taddlist(nn->args);
X taddstr(" () {");
X tindent++;
X taddnl();
X gt2(nn->u.list);
X tindent--;
X taddnl();
X taddstr("}");
X break;
X case CURSH:
X taddstr("{ ");
X tindent++;
X gt2(nn->u.list);
X tindent--;
X taddstr(" }");
X break;
X case CFOR:
X case CSELECT:
X taddstr((nn->type == CFOR) ? "for " : "select ");
X taddstr(nn->u.forcmd->name);
X if (nn->u.forcmd->inflag)
X {
X taddstr(" in ");
X taddlist(nn->args);
X }
X taddnl();
X taddstr("do");
X tindent++;
X taddnl();
X gt2(nn->u.forcmd->list);
X taddnl();
X tindent--;
X taddstr("done");
X break;
X case CIF:
X gt2(nn->u.ifcmd);
X taddstr("fi");
X break;
X case CCASE:
X taddstr("case ");
X taddlist(nn->args);
X taddstr(" in");
X tindent++;
X taddnl();
X gt2(nn->u.casecmd);
X tindent--;
X if (tnewlins)
X taddnl();
X else
X taddchr(' ');
X taddstr("esac");
X break;
X case COND:
X taddstr("[[ ");
X gt2(nn->u.cond);
X taddstr(" ]]");
X break;
X case CREPEAT:
X taddstr("repeat ");
X taddlist(nn->args);
X taddnl();
X taddstr("do");
X tindent++;
X taddnl();
X gt2(nn->u.list);
X tindent--;
X taddnl();
X taddstr("done");
X break;
X case CWHILE:
X gt2(nn->u.whilecmd);
X break;
X }
X getredirs(nn);
X break;
X case N_COND:
X nm = _Cond(n);
X switch (nm->type)
X {
X case COND_NOT:
X taddstr("! ");
X gt2(nm->left);
X break;
X case COND_AND:
X taddstr("( ");
X gt2(nm->left);
X taddstr(" && ");
X gt2(nm->right);
X taddstr(" )");
X break;
X case COND_OR:
X taddstr("( ");
X gt2(nm->left);
X taddstr(" || ");
X gt2(nm->right);
X taddstr(" )");
X break;
X default:
X {
X static char *c1[] = {
X " = "," != "," < "," > "," -nt "," -ot "," -ef "," -eq ",
X " -ne "," -lt "," -gt "," -le "," -ge "
X };
X if (nm->right)
X taddstr(nm->left);
X if (nm->type <= COND_GE)
X taddstr(c1[nm->type-COND_STREQ]);
X else
X {
X char c2[5];
X c2[0] = ' '; c2[1] = '-';
X c2[2] = nm->type;
X c2[3] = ' '; c2[4] = '\0';
X taddstr(c2);
X }
X taddstr((nm->right) ? nm->right : nm->left);
X }
X break;
X }
X break;
X case N_CASE:
X taddstr(_casecmd(n)->pat);
X taddstr(") ");
X tindent++;
X gt2(_casecmd(n)->list);
X tindent--;
X taddstr(";;");
X if (tnewlins)
X taddnl();
X else
X taddchr(' ');
X gt2(_casecmd(n)->next);
X break;
X case N_IF:
X if (_ifcmd(n)->ifl)
X {
X taddstr("if ");
X tindent++;
X gt2(_ifcmd(n)->ifl);
X tindent--;
X taddnl();
X taddstr("then");
X }
X else
X taddchr('e');
X tindent++;
X taddnl();
X gt2(_ifcmd(n)->thenl);
X tindent--;
X taddnl();
X if (_ifcmd(n)->next)
X {
X taddstr("els");
X gt2(_ifcmd(n)->next);
X }
X break;
X case N_WHILE:
X taddstr((_whilecmd(n)->cond) ? "until " : "while ");
X tindent++;
X gt2(_whilecmd(n)->cont);
X tindent--;
X taddnl();
X taddstr("do");
X tindent++;
X taddnl();
X gt2(_whilecmd(n)->loop);
X tindent--;
X taddnl();
X taddstr("done");


X break;
X }
X}
X

Xvoid getsimptext(cmd) /**/
XCmd cmd;
X{
XLknode n;
X
X for (n = firstnode(cmd->vars); n; incnode(n))
X {
X struct varasg *v = getdata(n);
X
X taddstr(v->name);
X taddchr('=');
X if ((v->type & PMTYPE) == PMFLAG_A)
X {
X taddchr('(');
X taddlist(v->arr);
X taddstr(") ");
X }
X else
X {
X taddstr(v->str);
X taddchr(' ');
X }
X }
X taddlist(cmd->args);
X}
X
Xvoid getredirs(cmd) /**/
XCmd cmd;
X{
XLknode n;
Xstatic char *fstr[] = {
X ">",">!",">>",">>!",">&",">&!",">>&",">>&!","<","<<",
X "<<-","<<<","<&",">&-","..",".."
X };
X
X taddchr(' ');
X for (n = firstnode(cmd->redir); n; incnode(n))
X {
X struct redir *f = getdata(n);
X
X switch(f->type)
X {
X case WRITE: case WRITENOW: case APP: case APPNOW: case READ:
X case HERESTR:
X if (f->fd1 != ((f->type == READ) ? 0 : 1))
X taddchr('0'+f->fd1);
X taddstr(fstr[f->type]);
X taddchr(' ');
X taddstr(f->name);
X taddchr(' ');
X break;
X case MERGE: case MERGEOUT:
X if (f->fd1 != ((f->type == MERGEOUT) ? 1 : 0))
X taddchr('0'+f->fd1);
X taddstr(fstr[f->type]);
X if (f->fd2 == FD_COPROC)
X taddchr('p');
X else
X taddint(f->fd2);
X taddchr(' ');
X break;
X case CLOSE:
X taddchr(f->fd1+'0');
X taddstr(">&- ");
X break;
X case INPIPE:
X case OUTPIPE:
X if (f->fd1 != ((f->type == INPIPE) ? 0 : 1))
X taddchr('0'+f->fd1);
X taddstr((f->type == INPIPE) ? "< " : "> ");
X taddstr(f->name);
X taddchr(' ');
X break;
X }
X }
X tptr--;
X}
X
Xvoid taddlist(l) /**/
XLklist l;
X{
XLknode n;
X


X for (n = firstnode(l); n; incnode(n))

X {
X taddstr(getdata(n));
X taddchr(' ');
X }
X tptr--;
X}
END_OF_FILE
if test 8624 -ne `wc -c <'src/text.c'`; then
echo shar: \"'src/text.c'\" unpacked with wrong size!
fi
# end of 'src/text.c'
fi
if test -f 'src/watch.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/watch.c'\"
else
echo shar: Extracting \"'src/watch.c'\" \(7710 characters\)
sed "s/^X//" >'src/watch.c' <<'END_OF_FILE'
X/*
X *
X * watch.c - login/logout watching


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

Xstatic int wtabsz;
Xstruct utmp *wtab;
Xstatic time_t lastutmpcheck;
X
X/* get the time of login/logout for WATCH */
X
Xtime_t getlogtime(u,inout) /**/
Xstruct utmp *u;int inout;
X{
XFILE *in;
Xstruct utmp uu;
Xint first = 1;
Xint srchlimit = 50; /* max number of wtmp records to search */
X
X if (inout)
X return u->ut_time;
X if (!(in = fopen(WTMP_FILE,"r")))
X return time(NULL);
X fseek(in,0,2);
X do
X {
X if (fseek(in,((first) ? -1 : -2)*sizeof(struct utmp),1))
X {
X fclose(in);
X return time(NULL);


X }
X first = 0;

X if (!fread(&uu,sizeof(struct utmp),1,in))
X {
X fclose(in);
X return time(NULL);
X }
X if (uu.ut_time < lastwatch || !srchlimit--)
X {
X fclose(in);
X return time(NULL);
X }
X }
X while (memcmp(&uu,u,sizeof(struct utmp)));
X do
X if (!fread(&uu,sizeof(struct utmp),1,in))
X {
X fclose(in);
X return time(NULL);
X }
X while (strncmp(uu.ut_line,u->ut_line,sizeof(u->ut_line)));
X fclose(in);
X return uu.ut_time;
X}
X
X/* print a login/logout event */
X
Xvoid watchlog2(inout,u,fmt) /**/
Xint inout;struct utmp *u;char *fmt;
X{
Xchar *p,buf[40],*bf;
Xint i;
Xtime_t timet;
Xstruct tm *tm;
X
X while (*fmt)
X if (*fmt != '%')
X putchar(*fmt++);
X else


X {
X fmt++;
X switch(*fmt++)
X {

X case 'n':
X printf("%.*s",sizeof(u->ut_name),u->ut_name);
X break;
X case 'a':
X printf("%s",(!inout) ? "logged off" : "logged on");
X break;
X case 'l':
X if (!strncmp(u->ut_line, "tty", 3))
X printf("%.*s",sizeof(u->ut_line)-3,u->ut_line+3);
X else
X printf("%.*s",sizeof(u->ut_line),u->ut_line);
X break;
X#ifdef UTMP_HOST
X case 'm':
X for (p = u->ut_host,i = sizeof(u->ut_host); i && *p;i--,p++)
X {
X if (*p == '.' && !idigit(p[1]))
X break;
X putchar(*p);
X }
X break;
X case 'M':
X printf("%.*s",sizeof(u->ut_host),u->ut_host);
X break;
X#endif
X case 't':
X case '@':
X timet = getlogtime(u,inout);
X tm = localtime(&timet);
X ztrftime(buf,40,"%l:%M%p",tm);
X printf("%s",(*buf == ' ') ? buf+1 : buf);


X break;
X case 'T':

X timet = getlogtime(u,inout);
X tm = localtime(&timet);
X ztrftime(buf,40,"%k:%M",tm);
X printf("%s",buf);
X break;
X case 'w':
X timet = getlogtime(u,inout);
X tm = localtime(&timet);
X ztrftime(buf,40,"%a %e",tm);
X printf("%s",buf);


X break;
X case 'W':

X timet = getlogtime(u,inout);
X tm = localtime(&timet);
X ztrftime(buf,40,"%m/%d/%y",tm);
X printf("%s",buf);


X break;
X case 'D':

X timet = getlogtime(u,inout);
X tm = localtime(&timet);
X ztrftime(buf,40,"%y-%m-%d",tm);
X printf("%s",buf);


X break;
X case '%':

X putchar('%');
X break;
X case 'S':
X bf = buf;
X if (tgetstr("so",&bf))
X fputs(buf,stdout);
X break;
X case 's':
X bf = buf;
X if (tgetstr("se",&bf))
X fputs(buf,stdout);
X break;
X case 'B':
X bf = buf;
X if (tgetstr("md",&bf))
X fputs(buf,stdout);


X break;
X case 'b':

X bf = buf;
X if (tgetstr("me",&bf))
X fputs(buf,stdout);
X break;
X case 'U':
X bf = buf;
X if (tgetstr("us",&bf))
X fputs(buf,stdout);


X break;
X case 'u':

X bf = buf;
X if (tgetstr("ue",&bf))
X fputs(buf,stdout);
X break;
X default:
X putchar('%');
X putchar(fmt[-1]);
X break;
X }
X }


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

X/* check the List for login/logouts */
X
Xvoid watchlog(inout,u,w,fmt) /**/
Xint inout;struct utmp *u;char **w;char *fmt;
X{
Xchar *v,*vv,sav;
Xint bad;
X
X if (*w && !strcmp(*w,"all"))
X {
X watchlog2(inout,u,fmt);
X return;
X }
X if (*w && !strcmp(*w,"notme") &&
X strncmp(u->ut_name, username, sizeof(u->ut_name)))
X {
X watchlog2(inout,u,fmt);
X return;
X }
X for (; *w; w++)
X {
X bad = 0;
X v = *w;
X if (*v != '@' && *v != '%')
X {
X for (vv = v; *vv && *vv != '@' && *vv != '%'; vv++);
X sav = *vv;
X *vv = '\0';
X if (strncmp(u->ut_name,v,sizeof(u->ut_name)))
X bad = 1;
X *vv = sav;
X v = vv;


X }
X for (;;)

X if (*v == '%')
X {
X for (vv = ++v; *vv && *vv != '@'; vv++);
X sav = *vv;
X *vv = '\0';
X if (strncmp(u->ut_line,v,sizeof(u->ut_line)))
X bad = 1;
X *vv = sav;
X v = vv;
X }
X#ifdef UTMP_HOST
X else if (*v == '@')
X {
X for (vv = ++v; *vv && *vv != '%'; vv++);
X sav = *vv;
X *vv = '\0';
X if (strncmp(u->ut_host,v,strlen(v)))
X bad = 1;
X *vv = sav;
X v = vv;
X }
X#endif
X else
X break;
X if (!bad)
X {
X watchlog2(inout,u,fmt);


X return;
X }
X }
X}

X
X/* compare 2 utmp entries */
X
Xint ucmp(u,v) /**/
Xstruct utmp *u;struct utmp *v;
X{
X if (u->ut_time == v->ut_time)
X return strncmp(u->ut_line,v->ut_line,sizeof(u->ut_line));
X return u->ut_time - v->ut_time;
X}
X
X/* initialize the user List */
X
Xvoid readwtab() /**/
X{
Xstruct utmp *uptr;
Xint wtabmax = 32;
XFILE *in;
X
X wtabsz = 0;
X if (!(in = fopen(UTMP_FILE,"r"))) return;
X uptr = wtab = (struct utmp *) zalloc(wtabmax*sizeof(struct utmp));
X while (fread(uptr,sizeof(struct utmp),1,in))
X#ifdef USER_PROCESS
X if (uptr->ut_type == USER_PROCESS)
X#else
X if (uptr->ut_name[0])
X#endif
X {
X uptr++;
X if (++wtabsz == wtabmax)
X uptr = (wtab = (struct utmp *) realloc((vptr) wtab,(wtabmax*=2)*
X sizeof(struct utmp)))+wtabsz;
X }
X fclose(in);
X if (wtabsz)
X qsort((vptr)wtab,wtabsz,sizeof(struct utmp),
X (int (*) DCLPROTO((const void *, const void *)))ucmp);
X}
X
X/* check for login/logout events; executed before each prompt
X if WATCH is set */
X
Xvoid dowatch() /**/
X{
Xchar **s = watch;
Xchar *fmt = (watchfmt) ? watchfmt : DEFWATCHFMT;
XFILE *in;
Xint utabsz = 0,utabmax = wtabsz+4,uct,wct;
Xstruct utmp *utab,*uptr,*wptr;
Xstruct stat st;
X
X holdintr();
X if (!fmt)
X fmt = "%n has %a %l from %m.";
X if (!wtab) {
X readwtab();
X noholdintr();
X return;
X }
X if ((stat(UTMP_FILE,&st) == -1) || (st.st_mtime <= lastutmpcheck))
X return;
X lastutmpcheck = st.st_mtime;
X uptr = utab = (struct utmp *) zalloc(utabmax*sizeof(struct utmp));
X if (!(in = fopen(UTMP_FILE,"r"))) {
X free(utab);
X return;
X }
X while (fread(uptr,sizeof *uptr,1,in))
X#ifdef USER_PROCESS
X if (uptr->ut_type == USER_PROCESS)
X#else
X if (uptr->ut_name[0])
X#endif
X {
X uptr++;
X if (++utabsz == utabmax)
X uptr = (utab = (struct utmp *) realloc((vptr) utab,(utabmax*=2)*
X sizeof(struct utmp)))+utabsz;
X }
X fclose(in);
X noholdintr();
X if (errflag) {
X free(utab);
X return;
X }
X if (utabsz)
X qsort((vptr)utab,utabsz,sizeof(struct utmp),
X (int (*) DCLPROTO((const void *, const void *)))ucmp);
X
X wct = wtabsz; uct = utabsz;
X uptr = utab; wptr = wtab;
X if (errflag) {
X free(utab);
X return;
X }
X while ((uct || wct) && !errflag)
X if (!uct || (wct && ucmp(uptr,wptr) > 0))
X wct--,watchlog(0,wptr++,s,fmt);
X else if (!wct || (uct && ucmp(uptr,wptr) < 0))
X uct--,watchlog(1,uptr++,s,fmt);
X else
X uptr++,wptr++,wct--,uct--;
X free(wtab);
X wtab = utab;
X wtabsz = utabsz;
X fflush(stdout);
X}
X
Xint bin_log(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
X if (!watch)
X return 1;
X if (wtab)
X free(wtab);
X wtab = (struct utmp *) zalloc(1);
X wtabsz = 0;
X lastutmpcheck = 0;
X dowatch();


X return 0;
X}
X

END_OF_FILE
if test 7710 -ne `wc -c <'src/watch.c'`; then
echo shar: \"'src/watch.c'\" unpacked with wrong size!
fi
# end of 'src/watch.c'
fi
if test -f 'src/zle.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle.h'\"
else
echo shar: Extracting \"'src/zle.h'\" \(8560 characters\)
sed "s/^X//" >'src/zle.h' <<'END_OF_FILE'
X/*
X *
X * zle.h - header file for line editor


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#ifdef ZLEGLOBALS
X#define ZLEXTERN
X#else
X#define ZLEXTERN extern
X#endif
X
X#ifdef ZLE
X
X/* cursor position */
XZLEXTERN int cs;
X
X/* line length */
XZLEXTERN int ll;
X
X/* size of line buffer */
XZLEXTERN int linesz;
X
X/* location of mark */
XZLEXTERN int mark;
X
X/* last character pressed */
XZLEXTERN int c;
X
X/* the z_ binding id for this key */
XZLEXTERN int bindk;
X
X/* command argument */
XZLEXTERN int mult;
X
X/* insert mode/overwrite mode flag */
XZLEXTERN int insmode;
X
X/* cost of last update */
XZLEXTERN int cost;
X
X/* flags associated with last command */
XZLEXTERN int lastcmd;
X
X/* column position before last LINEMOVE movement */
XZLEXTERN int lastcol;
X
X/* != 0 if we're getting a vi range */
XZLEXTERN int virangeflag;
X
X/* kludge to get cw and dw to work right */
XZLEXTERN int wordflag;
X
X/* Another kludge to lazy cache the usernames. Win on large systems */
XZLEXTERN int usernamescached;
X#endif
X
X/* last named command done */
XZLEXTERN int lastnamed;
X
X/* != 0 if we're done editing */
XZLEXTERN int done;
X
X/* length of prompt on screen */
XZLEXTERN int pptlen;
X
X/* current history line number */
XZLEXTERN int histline;
X
XZLEXTERN int eofsent;
X
X/* != 0 if we need to call resetvideo() */
XZLEXTERN int resetneeded;
X
X/* != 0 if the line editor is active */
XZLEXTERN int zleactive;
X
X/* the line buffer */
XZLEXTERN unsigned char *line;
X
X/* the cut buffer */
XZLEXTERN char *cutbuf;
X
X/* prompt and rprompt */
XZLEXTERN char *pmpt, *pmpt2;
X
X/* the last line in the history (the current one) */
XZLEXTERN char *curhistline;
X
X/* the status line */
XZLEXTERN char *statusline;
X
X/* 1 if a complete added a slash at the end of a directory name */
XZLEXTERN int addedslash;
X
X/*
X the current history line and cursor position for the top line
X on the buffer stack
X*/
X
XZLEXTERN int stackhist,stackcs;
X
X/* != 0 if we are in the middle of a menu completion */
XZLEXTERN int menucmp;
X
X/* != 0 if we are making undo records */
XZLEXTERN int undoing;
X
X/* last vi change buffer */
XZLEXTERN int vichgbufsz,vichgbufptr,vichgflag;
XZLEXTERN char *vichgbuf;
X
XZLEXTERN int viinsbegin;
X
Xtypedef void bindfunc DCLPROTO((void));
Xtypedef bindfunc *F;
X
Xstruct key {


X struct hashnode *next; int canfree; char *nam; /* hash data */

X int func; /* function code for this key */
X char *str; /* string corresponding to this key,
X if func = z_sequenceleadin */
X int len; /* length of string */
X };
Xstruct zlecmd {
X char *name; /* name of function */
X F func; /* handler function */
X int flags;
X };
X
X/* undo event */
X
Xstruct undoent {
X int pref; /* number of initial chars unchanged */
X int suff; /* number of trailing chars unchanged */
X int len; /* length of changed chars */
X int cs; /* cursor pos before change */
X char *change; /* NOT null terminated */
X };
X
X#define UNDOCT 64
X
Xstruct undoent undos[UNDOCT];
X
X/* the line before last mod (for undo purposes) */
XZLEXTERN unsigned char *lastline;
X
X/* buffer specified with "x */
XZLEXTERN int vibufspec;
X
XZLEXTERN int undoct,lastcs;
X
XZLEXTERN char *visrchstr;
XZLEXTERN int visrchsense;
X
X#define ZLE_MOVEMENT 1
X#define ZLE_MENUCMP 2
X#define ZLE_UNDO 4
X#define ZLE_YANK 8
X#define ZLE_LINEMOVE 16
X#define ZLE_ARG 32
X#define ZLE_NAMEDBUFFER 128
X#define ZLE_KILL (64|ZLE_NAMEDBUFFER)
X#define ZLE_HISTSEARCH 256
X#define ZLE_NEGARG 512
X#define ZLE_INSERT 1024
X#define ZLE_DELETE 2048
X
Xtypedef struct key *Key;
X
XZLEXTERN int *bindtab;
Xextern int emacsbind[256];
XZLEXTERN int altbindtab[256],mainbindtab[256];
Xextern int viinsbind[],vicmdbind[];
XZLEXTERN int vimarkcs[27],vimarkline[27];
X
X#define KRINGCT 8
XZLEXTERN char *kring[KRINGCT];
XZLEXTERN int kringnum;
XZLEXTERN char *vibuf[36];
X
X#define z_acceptandhold 0
X#define z_acceptandinfernexthistory 1
X#define z_acceptandmenucomplete 2
X#define z_acceptline 3
X#define z_acceptlineanddownhistory 4
X#define z_backwardchar 5
X#define z_backwarddeletechar 6
X#define z_backwarddeleteword 7
X#define z_backwardkillline 8
X#define z_backwardkillword 9
X#define z_backwardword 10
X#define z_beginningofbufferorhistory 11
X#define z_beginningofhistory 12
X#define z_beginningofline 13
X#define z_beginningoflinehist 14
X#define z_capitalizeword 15
X#define z_clearscreen 16
X#define z_completeword 17
X#define z_copyprevword 18
X#define z_copyregionaskill 19
X#define z_deletechar 20
X#define z_deletecharorlist 21
X#define z_deleteword 22
X#define z_digitargument 23
X#define z_downcaseword 24
X#define z_downhistory 25
X#define z_downlineorhistory 26
X#define z_endofbufferorhistory 27
X#define z_endofhistory 28
X#define z_endofline 29
X#define z_endoflinehist 30
X#define z_exchangepointandmark 31
X#define z_executelastnamedcmd 32
X#define z_executenamedcmd 33
X#define z_expandhistory 34
X#define z_expandorcomplete 35
X#define z_expandword 36
X#define z_forwardchar 37
X#define z_forwardword 38
X#define z_getline 39
X#define z_gosmacstransposechars 40
X#define z_historyincrementalsearchbackward 41
X#define z_historyincrementalsearchforward 42
X#define z_historysearchbackward 43
X#define z_historysearchforward 44
X#define z_infernexthistory 45
X#define z_insertlastword 46
X#define z_killbuffer 47
X#define z_killline 48
X#define z_killregion 49
X#define z_killwholeline 50
X#define z_listchoices 51
X#define z_listexpand 52
X#define z_magicspace 53
X#define z_menucompleteword 54
X#define z_menuexpandorcomplete 55
X#define z_overwritemode 56
X#define z_pushline 57
X#define z_quotedinsert 58
X#define z_quoteline 59
X#define z_quoteregion 60
X#define z_redisplay 61
X#define z_reversemenucomplete 62
X#define z_runhelp 63
X#define z_selfinsert 64
X#define z_selfinsertunmeta 65
X#define z_sendbreak 66
X#define z_sendstring 67
X#define z_sequenceleadin 68
X#define z_setmarkcommand 69
X#define z_spellword 70
X#define z_toggleliteralhistory 71
X#define z_transposechars 72
X#define z_transposewords 73
X#define z_undefinedkey 74
X#define z_undo 75
X#define z_universalargument 76
X#define z_upcaseword 77
X#define z_uphistory 78
X#define z_uplineorhistory 79
X#define z_viaddeol 80
X#define z_viaddnext 81
X#define z_vibackwardblankword 82
X#define z_vibackwardchar 83
X#define z_vibackwarddeletechar 84
X#define z_vibeginningofline 85
X#define z_vicapslockpanic 86
X#define z_vichange 87
X#define z_vichangeeol 88
X#define z_vichangewholeline 89
X#define z_vicmdmode 90
X#define z_videlete 91
X#define z_videletechar 92
X#define z_vidigitorbeginningofline 93
X#define z_viendofline 94
X#define z_vifetchhistory 95
X#define z_vifindnextchar 96
X#define z_vifindnextcharskip 97
X#define z_vifindprevchar 98
X#define z_vifindprevcharskip 99
X#define z_vifirstnonblank 100
X#define z_viforwardblankword 101
X#define z_viforwardblankwordend 102
X#define z_viforwardchar 103
X#define z_viforwardwordend 104
X#define z_vigotocolumn 105
X#define z_vigotomark 106
X#define z_vigotomarkline 107
X#define z_vihistorysearchbackward 108
X#define z_vihistorysearchforward 109
X#define z_viindent 110
X#define z_viinsert 111
X#define z_viinsertbol 112
X#define z_vijoin 113
X#define z_vimatchbracket 114
X#define z_viopenlineabove 115
X#define z_viopenlinebelow 116
X#define z_vioperswapcases 117
X#define z_viputafter 118
X#define z_virepeatchange 119
X#define z_virepeatfind 120
X#define z_virepeatsearch 121
X#define z_vireplace 122
X#define z_vireplacechars 123
X#define z_virevrepeatfind 124
X#define z_virevrepeatsearch 125
X#define z_visetbuffer 126
X#define z_visetmark 127
X#define z_visubstitute 128
X#define z_viswapcase 129
X#define z_viundochange 130
X#define z_viunindent 131
X#define z_viyank 132
X#define z_viyankeol 133
X#define z_whichcommand 134
X#define z_yank 135
X#define z_yankpop 136
X#define z_emacsbackwardword 137
X#define z_emacsforwardword 138
X#define z_killword 139
X#define z_vikillline 140
X#define z_vibackwardkillword 141
X#define z_expandcmdpath 142
X#define z_negargument 143
X#define z_poundinsert 144
X#define z_viforwardword 145
X#define z_vibackwardword 146
X#define z_uplineorsearch 147
X#define z_downlineorsearch 148
X#define ZLECMDCOUNT 149
X
Xextern struct zlecmd zlecmds[];
X
END_OF_FILE
if test 8560 -ne `wc -c <'src/zle.h'`; then
echo shar: \"'src/zle.h'\" unpacked with wrong size!
fi
# end of 'src/zle.h'
fi
if test -f 'src/zle_vi.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle_vi.c'\"
else
echo shar: Extracting \"'src/zle_vi.c'\" \(5195 characters\)
sed "s/^X//" >'src/zle_vi.c' <<'END_OF_FILE'
X/*
X *
X * zle_vi.c - vi-specific functions


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#define ZLE
X#include "zsh.h"
X
X

Xstatic void startvichange(im)
Xint im;
X{
X insmode = im;
X if (vichgbuf) free(vichgbuf);
X vichgbuf = zalloc(vichgbufsz = 16);
X vichgbuf[0] = c;
X vichgbufptr = 1;
X vichgflag = 1;
X viinsbegin = cs;
X}
X
Xstatic void startvitext(im)
Xint im;
X{
X startvichange(im);
X bindtab = mainbindtab;
X undoing = 0;
X}
X
Xint vigetkey() /**/
X{
Xint ch;
X
X if ((ch = getkey(0)) == -1)
X return 0;
X if (ch == 22)
X {
X if ((ch = getkey(0)) == -1)
X return 0;
X return ch;
X }


X else if (ch == 27)

X return 0;
X return ch;
X}
X
Xint getvirange(wf) /**/
Xint wf;
X{
Xint k2,t0,startline,endline;
X
X startline = findbol();
X endline = findeol();
X for (;;) {
X k2 = getkeycmd();
X if (k2 == -1) {
X feep();
X return -1;
X }
X if (zlecmds[k2].flags & ZLE_ARG)
X (*zlecmds[k2].func)();
X else
X break;
X }
X if (k2 == bindk) {
X findline(&cs,&t0);
X return (t0 == ll) ? t0 : t0+1;
X }
X if (!(zlecmds[k2].flags & ZLE_MOVEMENT)) {
X feep();
X return -1;
X }
X t0 = cs;
X
X virangeflag = 1;
X wordflag = wf;
X (*zlecmds[k2].func)();
X wordflag = virangeflag = 0;
X if (cs == t0) {
X feep();
X return -1;
X }
X if (startline != findbol()) {
X if (zlecmds[k2].flags & ZLE_LINEMOVE) {
X if (cs < t0) {
X cs = startline;
X t0 = findeol()+1;
X } else {
X t0 = startline;
X cs = findeol()+1;
X }
X } else {
X if (cs < startline) cs = startline;
X else if (cs >= endline) cs = endline-1;
X }
X }
X if (cs > t0) {
X k2 = cs;
X cs = t0;
X t0 = k2;
X }


X return t0;
X}
X

Xvoid viaddnext() /**/
X{
X if (cs != ll)
X cs++;
X startvitext(1);
X}
X
Xvoid viaddeol() /**/
X{
X cs = findeol();
X startvitext(1);
X}
X
Xvoid viinsert() /**/
X{
X startvitext(1);
X}
X
Xvoid viinsertbol() /**/
X{
X cs = findbol();
X startvitext(1);
X}
X
Xvoid videlete() /**/
X{
Xint c2;
X
X startvichange(1);
X if ((c2 = getvirange(0)) == -1)
X { vichgflag = 0; return; }
X forekill(c2-cs,0);
X vichgflag = 0;
X}
X
Xvoid videletechar() /**/
X{
X if (mult < 0) { mult = -mult; vibackwarddeletechar(); return; }


X if (c == 4 && !ll) {

X eofsent = 1;
X return;
X }


X if (!(cs+mult > ll || line[cs] == '\n')) {

X if ( vichgbuf == NULL ) vichgbuf = zalloc ( vichgbufsz = 16 );
X vichgbufptr = 1;
X vichgbuf[0] = c;
X cs += mult;
X backkill(mult,0);
X if (cs && (cs == ll || line[cs] == '\n')) cs--;


X } else
X feep();
X}

X
Xvoid vichange() /**/
X{
Xint c2;
X
X startvichange(1);
X if ((c2 = getvirange(1)) == -1)
X { vichgflag = 0; return; }
X forekill(c2-cs,0);
X bindtab = mainbindtab;
X undoing = 0;
X}
X
Xvoid visubstitute() /**/


X{
X if (mult < 0) return;

X if (findeol()-cs < mult) mult = findeol()-cs;
X if (mult) {
X foredel(mult);
X startvitext(1);
X }
X}
X
Xvoid vichangeeol() /**/
X{
X killline();
X startvitext(1);
X}
X
Xvoid vichangewholeline() /**/
X{
Xint cq;
X
X findline(&cs,&cq);
X foredel(cq-cs);
X startvitext(1);
X}
X
Xvoid viyank() /**/
X{
Xint c2;
X
X if ((c2 = getvirange(0)) == -1) return;
X cut(cs,c2-cs,0);
X}
X
Xvoid viyankeol() /**/
X{
Xint x = findeol();
X
X if (x == cs)
X feep();
X else
X cut(cs,x-cs,0);
X}
X
Xvoid vireplace() /**/
X{
X startvitext(0);
X}
X
Xvoid vireplacechars() /**/
X{
Xint ch;


X
X if (mult < 0) return;

X if (mult+cs > ll) {
X feep();
X return;
X }
X startvichange(1);
X if (ch = vigetkey()) while (mult--) line[cs++] = ch;
X vichgflag = 0;
X cs--;
X}
X
Xvoid vicmdmode() /**/
X{
X bindtab = altbindtab;
X if (cs) cs--;
X undoing = 1;
X if (vichgflag) vichgflag = 0;
X}
X
Xvoid viopenlinebelow() /**/
X{
X cs = findeol();
X spaceinline(1);
X line[cs++] = '\n';
X startvitext(1);
X}
X
Xvoid viopenlineabove() /**/
X{
X cs = findbol();
X spaceinline(1);
X line[cs] = '\n';
X startvitext(1);
X}
X
Xvoid vioperswapcase() /**/
X{
Xint c2;
X
X if ((c2 = getvirange(0)) == -1)
X return;
X while (cs < c2)


X {
X int ch = line[cs];
X
X if (islower(ch))
X ch = tuupper(ch);
X else if (isupper(ch))
X ch = tulower(ch);

X line[cs++] = ch;
X }
X}
X
Xvoid virepeatchange() /**/
X{
X if (!vichgbuf || bindtab == mainbindtab || vichgflag) feep();
X else ungetkeys(vichgbuf,vichgbufptr);
X}
X
Xvoid viindent() /**/
X{
Xint c2,endcs,t0,rmult;
X
X if (mult < 0) { mult = -mult; viunindent(); return; }
X rmult = mult;
X if ((c2 = getvirange(0)) == -1)
X return;
X if (cs != findbol()) { feep(); return; }
X endcs = cs+rmult;
X while (cs < c2) {
X spaceinline(rmult);
X for (t0 = 0; t0 != rmult; t0++) line[cs++] = '\t';
X cs = findeol()+1;
X }
X cs = endcs;
X}
X
Xvoid viunindent() /**/
X{
Xint c2,endcs,t0,rmult;
X
X rmult = mult;
X if (mult < 0) { mult = -mult; viindent(); return; }
X if ((c2 = getvirange(0)) == -1)
X return;
X if (cs != findbol()) { feep(); return; }
X endcs = cs;
X while (cs < c2) {
X for (t0 = 0; t0 != rmult && line[cs] == '\t'; t0++) foredel(1);
X cs = findeol()+1;
X }
X cs = endcs;
X}
END_OF_FILE
if test 5195 -ne `wc -c <'src/zle_vi.c'`; then
echo shar: \"'src/zle_vi.c'\" unpacked with wrong size!
fi
# end of 'src/zle_vi.c'
fi
if test -f 'src/zle_word.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle_word.c'\"
else
echo shar: Extracting \"'src/zle_word.c'\" \(6652 characters\)
sed "s/^X//" >'src/zle_word.c' <<'END_OF_FILE'
X/*
X *
X * zle_word.c - word-related editor functions


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#define ZLE
X#include "zsh.h"
X
X

Xvoid forwardword() /**/
X{
X if (mult < 0) { mult = -mult; backwardword(); return; }
X while (mult--) {
X while (cs != ll && iword(line[cs])) cs++;
X if (wordflag && !mult) return;
X while (cs != ll && !iword(line[cs])) cs++;
X }
X}
X
Xvoid viforwardword() /**/
X{
X if (mult < 0) { mult = -mult; backwardword(); return; }
X while (mult--) {
X if (iident(line[cs])) while (cs != ll && iident(line[cs])) cs++;
X else while (cs != ll && !iident(line[cs]) && !iblank(line[cs])) cs++;
X if (wordflag && !mult) return;
X while (cs != ll && iblank(line[cs])) cs++;
X }
X}
X
Xvoid viforwardblankword() /**/
X{
X if (mult < 0) { mult = -mult; vibackwardblankword(); return; }
X while (mult--) {
X while (cs != ll && !iblank(line[cs])) cs++;
X if (wordflag && !mult) return;
X while (cs != ll && iblank(line[cs])) cs++;
X }
X}
X
Xvoid emacsforwardword() /**/
X{
X if (mult < 0) { mult = -mult; emacsbackwardword(); return; }
X while (mult--)
X {
X while (cs != ll && !iword(line[cs])) cs++;
X if (wordflag && !mult) return;
X while (cs != ll && iword(line[cs])) cs++;
X }
X}
X
Xvoid viforwardblankwordend() /**/


X{
X if (mult < 0) return;

X while (mult--) {
X while (cs != ll && iblank(line[cs+1])) cs++;
X while (cs != ll && !iblank(line[cs+1])) cs++;
X }
X if (cs != ll && virangeflag) cs++;
X}
X
Xvoid viforwardwordend() /**/
X{
X if (mult < 0) { mult = -mult; backwardword(); return; }
X while (mult--) {
X if (iblank(line[cs+1])) while (cs != ll && iblank(line[cs+1])) cs++;
X if (iident(line[cs+1])) while (cs != ll && iident(line[cs+1])) cs++;
X else while (cs != ll && !iident(line[cs+1]) && !iblank(line[cs+1])) cs++;
X }
X if (cs != ll && virangeflag) cs++;
X}
X
Xvoid backwardword() /**/
X{
X if (mult < 0) { mult = -mult; forwardword(); return; }
X while (mult--) {
X while (cs && !iword(line[cs-1])) cs--;
X while (cs && iword(line[cs-1])) cs--;
X }
X}
X
Xvoid vibackwardword() /**/
X{
X if (mult < 0) { mult = -mult; backwardword(); return; }
X while (mult--) {
X while (cs && iblank(line[cs-1])) cs--;
X if (iident(line[cs-1])) while (cs && iident(line[cs-1])) cs--;
X else while (cs && !iident(line[cs-1]) && !iblank(line[cs-1])) cs--;
X }
X}
X
Xvoid vibackwardblankword() /**/
X{
X if (mult < 0) { mult = -mult; viforwardblankword(); return; }
X while (mult--) {
X while (cs && iblank(line[cs-1])) cs--;
X while (cs && !iblank(line[cs-1])) cs--;
X }
X}
X
Xvoid emacsbackwardword() /**/
X{
X if (mult < 0) { mult = -mult; emacsforwardword(); return; }
X while (mult--) {
X while (cs && !iword(line[cs-1])) cs--;
X while (cs && iword(line[cs-1])) cs--;
X }
X}
X
Xvoid backwarddeleteword() /**/
X{
Xint x = cs;
X
X if (mult < 0) { mult = -mult; deleteword(); return; }
X while (mult--) {
X while (x && !iword(line[x-1])) x--;
X while (x && iword(line[x-1])) x--;
X }
X backdel(cs-x);
X}
X
Xvoid vibackwardkillword() /**/
X{
Xint x = cs;
X
X if (mult < 0) { feep(); return; }
X /* this taken from "vibackwardword" */
X while (mult--) {
X while ((x > viinsbegin) && iblank(line[x-1])) x--;
X if (iident(line[x-1])) while ((x > viinsbegin) && iident(line[x-1])) x--;
X else while ((x > viinsbegin) && !iident(line[x-1]) && !iblank(line[x-1])) x--;
X }
X /*
X while (mult--) {
X while ( (x > viinsbegin) && (iwordsep(line[x-1]))) x--;
X while ( (x > viinsbegin) && (!iwordsep(line[x-1]))) x--;
X }
X */
X backkill(cs-x,1);
X}
X
Xvoid backwardkillword() /**/
X{
Xint x = cs;
X
X if (mult < 0) { mult = -mult; killword(); return; }
X while (mult--) {
X while (x && !iword(line[x-1])) x--;
X while (x && iword(line[x-1])) x--;
X }
X backkill(cs-x,1);
X}
X
X
Xvoid upcaseword() /**/
X{
Xint neg = mult < 0, ocs = cs;
X


X if (neg) mult = -mult;
X while (mult--) {

X while (cs != ll && !iword(line[cs])) cs++;
X while (cs != ll && iword(line[cs])) {
X line[cs] = tuupper(line[cs]);
X cs++;
X }
X }
X if (neg) cs = ocs;
X}
X
Xvoid downcaseword() /**/
X{
Xint neg = mult < 0, ocs = cs;
X


X if (neg) mult = -mult;
X while (mult--) {

X while (cs != ll && !iword(line[cs])) cs++;
X while (cs != ll && iword(line[cs])) {
X line[cs] = tulower(line[cs]);
X cs++;
X }
X }
X if (neg) cs = ocs;
X}
X
Xvoid capitalizeword() /**/
X{
Xint first;
Xint neg = mult < 0, ocs = cs;
X

X if (neg) mult = -mult;
X while (mult--) {

X first = 1;
X while (cs != ll && !iword(line[cs])) cs++;
X while (cs != ll && iword(line[cs])) {
X line[cs] = (first) ? tuupper(line[cs]) : tulower(line[cs]);
X first = 0;
X cs++;
X }
X }
X if (neg) cs = ocs;
X}
X
Xvoid deleteword() /**/
X{
Xint x = cs;
X
X if (mult < 0) { mult = -mult; backwarddeleteword(); return; }
X while (mult--) {
X while (x != ll && !iword(line[x])) x++;
X while (x != ll && iword(line[x])) x++;
X }
X foredel(x-cs);
X}
X
Xvoid killword() /**/
X{
Xint x = cs;
X
X if (mult < 0) { mult = -mult; backwardkillword(); return; }
X while (mult--) {
X while (x != ll && !iword(line[x])) x++;
X while (x != ll && iword(line[x])) x++;
X }
X forekill(x-cs,0);
X}
X
Xvoid transposewords() /**/
X{
Xint p1,p2,p3,p4,x = cs;
Xchar *temp,*pp;
Xint neg = mult < 0, ocs = cs;
X


X if (neg) mult = -mult;
X while (mult--) {

X while (x != ll && line[x] != '\n' && !iword(line[x]))
X x++;
X if (x == ll || line[x] == '\n') {
X x = cs;
X while (x && line[x-1] != '\n' && !iword(line[x]))
X x--;
X if (!x || line[x-1] == '\n') {


X feep();
X return;
X }
X }

X for (p4 = x; p4 != ll && iword(line[p4]); p4++);
X for (p3 = p4; p3 && iword(line[p3-1]); p3--);
X if (!p3) {


X feep();
X return;
X }

X for (p2 = p3; p2 && !iword(line[p2-1]); p2--);
X if (!p2) {


X feep();
X return;
X }

X for (p1 = p2; p1 && iword(line[p1-1]); p1--);
X pp = temp = halloc(p4-p1+1);
X struncpy(&pp,UTOSCP(line+p3),p4-p3);
X struncpy(&pp,UTOSCP(line+p2),p3-p2);
X struncpy(&pp,UTOSCP(line+p1),p2-p1);
X strncpy((char *) line+p1,temp,p4-p1);
X cs = p4;
X }
X if (neg) cs = ocs;
X}
END_OF_FILE
if test 6652 -ne `wc -c <'src/zle_word.c'`; then
echo shar: \"'src/zle_word.c'\" unpacked with wrong size!
fi
# end of 'src/zle_word.c'
fi
echo shar: End of archive 20 \(of 22\).
cp /dev/null ark20isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:29:33 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 71
Archive-name: zsh/part21

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: NOTES func/run-help func/zed help/alias help/cd
# help/compctl help/dirs help/echo help/elif help/else help/for
# help/foreach help/function help/getopts help/if help/kill
# help/print help/select help/set help/ttyctl help/ulimit
# help/unhash help/unset help/whence help/which src/cond.c
# src/loop.c src/mem.c src/zle_move.c src/zle_utils.c
# Wrapped by mattson@odin on Sat Feb 6 14:41:56 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 21 (of 22)."'
if test -f 'NOTES' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'NOTES'\"
else
echo shar: Extracting \"'NOTES'\" \(507 characters\)
sed "s/^X//" >'NOTES' <<'END_OF_FILE'
XImportant notes:
X
X1. Stuff like "ls *.sdofij 2>/dev/null" to suppress error messages
X produced by the shell doesn'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 !.
END_OF_FILE
if test 507 -ne `wc -c <'NOTES'`; then
echo shar: \"'NOTES'\" unpacked with wrong size!
fi
# end of 'NOTES'
fi
if test -f 'func/run-help' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/run-help'\"
else
echo shar: Extracting \"'func/run-help'\" \(376 characters\)
sed "s/^X//" >'func/run-help' <<'END_OF_FILE'
X#! /bin/zsh
X# zsh script to peruse the help directory
X#
Xif [[ $1 = "-l" ]]; then
X if [[ ${HELPDIR:-} != "" ]]; then
X echo 'Here is a list of topics for which help is available:'
X echo ""
X ls $HELPDIR
X else
X echo 'There is no help available at this time'
X fi
Xelif [[ ${HELPDIR:-} != "" && -r $HELPDIR/$1 ]]
Xthen
X ${PAGER:-more} $HELPDIR/$1
Xelse
X man $1
Xfi
END_OF_FILE
if test 376 -ne `wc -c <'func/run-help'`; then
echo shar: \"'func/run-help'\" unpacked with wrong size!
fi
chmod +x 'func/run-help'
# end of 'func/run-help'
fi
if test -f 'func/zed' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/zed'\"
else
echo shar: Extracting \"'func/zed'\" \(511 characters\)
sed "s/^X//" >'func/zed' <<'END_OF_FILE'
X#!/bin/zsh
X# Edit small files with the command line editor.
X# You can even stick bits of the history list in it.
X
Xlocal var
X
X# (Don't) catch interrupts
X# trap 'bindkey "^M" accept-line ; trap - 2 3; return 0' 2 3
X
Xbindkey "^M" self-insert-unmeta
Xbindkey "^X^W" accept-line
X
X[[ -z "$1" ]] && echo 'Usage: zed filename' && return 1
X[[ -f $1 ]] && var="$(<$1)"
Xvared var
Xprint -R "$var" >! $1
X
Xbindkey "^M" accept-line
Xbindkey "^X^W" undefined-key
X
X# (Don't) release interrupts
X# trap - 2 3
X
Xreturn 0
X
X#End of zed
END_OF_FILE
if test 511 -ne `wc -c <'func/zed'`; then
echo shar: \"'func/zed'\" unpacked with wrong size!
fi
chmod +x 'func/zed'
# end of 'func/zed'
fi
if test -f 'help/alias' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/alias'\"
else
echo shar: Extracting \"'help/alias'\" \(781 characters\)
sed "s/^X//" >'help/alias' <<'END_OF_FILE'


X alias [ -g ] [ name[=value] ] ...
X With no arguments, print the list of aliases in the
X form name=value on the standard output. For each name
X with a corresponding value, define an alias with that
X value. A trailing space in value causes the next word
X to be checked for alias substitution. If the -g flag
X is present, define a global alias; global aliases are
X expanded even if they do not occur in command position.
X For each name with no value, print the value of name,
X if any. The exit status is nonzero if a name (with no
X value) given for which no alias has been defined.
X unalias name ...
X The alias definition, if any, for each name is removed.
END_OF_FILE

if test 781 -ne `wc -c <'help/alias'`; then
echo shar: \"'help/alias'\" unpacked with wrong size!
fi
# end of 'help/alias'
fi
if test -f 'help/cd' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/cd'\"
else
echo shar: Extracting \"'help/cd'\" \(934 characters\)
sed "s/^X//" >'help/cd' <<'END_OF_FILE'


X cd [ arg ]
X cd old new
X cd +-n
X Change the current directory. In the first form,
X change the current directory to arg, or to the value of
X HOME if arg is not specified. If arg is -, change to
X the value of OLDPWD, the previous directory. If a
X directory named arg is not found in the current direc-

X tory and arg does not begin with a slash, search each


X component of the shell parameter cdpath. If the option

X CDABLEVARS is set, and a parameter named arg exists
X whose value begins with a slash, treat its value as the
X directory.
X
X The second form of cd substitutes the string new for


X the string old in the name of the current directory,
X and tries to change to this new directory.
X

X The third form of cd is equivalent to popd.
X
X chdir
X Same as cd.
END_OF_FILE

if test 934 -ne `wc -c <'help/cd'`; then
echo shar: \"'help/cd'\" unpacked with wrong size!
fi
# end of 'help/cd'
fi
if test -f 'help/compctl' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/compctl'\"
else
echo shar: Extracting \"'help/compctl'\" \(906 characters\)
sed "s/^X//" >'help/compctl' <<'END_OF_FILE'
X compctl [ -cfhovbCD ] [ -k name ] [ arg ... ]
X Control the editor's completion behavior when one of
X arg is the current command. With the -D flag, control
X default completion behavior for commands not assigned
X any special behavior; with -C, control completion when
X there is no current command. The remaining options
X specify the type of command arguments to look for dur-
X ing completion. For example, compctl -hf rlogin is
X equivalent to hostcmds=(rlogin).
X -c Expect command names.
X -f Expect filenames and filesystem paths.
X -h Expect hostnames taken from the $hosts variable.
X -o Expect option names.
X -v Expect variable names.
X -b Expect key binding names.
X -k name
X Expect names taken from the elements of $name.
END_OF_FILE
if test 906 -ne `wc -c <'help/compctl'`; then
echo shar: \"'help/compctl'\" unpacked with wrong size!
fi
# end of 'help/compctl'
fi
if test -f 'help/dirs' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/dirs'\"
else
echo shar: Extracting \"'help/dirs'\" \(517 characters\)
sed "s/^X//" >'help/dirs' <<'END_OF_FILE'
X dirs [ -v ] [ arg ... ]
X With no arguments, print the contents of the directory
X stack. If the -v option is given, number the direc-
X tories in the stack when printing. Directories are
X added to this stack with the pushd command, and removed
X with the cd or popd commands. If arguments are speci-
X fied, load them onto the directory stack, replacing
X anything that was there, and push the current directory
X onto the stack.
END_OF_FILE
if test 517 -ne `wc -c <'help/dirs'`; then
echo shar: \"'help/dirs'\" unpacked with wrong size!
fi
# end of 'help/dirs'
fi
if test -f 'help/echo' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/echo'\"
else
echo shar: Extracting \"'help/echo'\" \(555 characters\)
sed "s/^X//" >'help/echo' <<'END_OF_FILE'
X echo [ -n ] [ arg ... ]
X Write each arg on the standard output, with a space
X separating each one. If the -n flag is not present,
X print a newline at the end. echo recognizes the fol-
X lowing escape sequences:
X \b backspace
X \c don't print an ending newline
X \e escape
X \f form feed
X \n newline
X \r carriage return


X \t horizontal tab
X \v vertical tab

X \\ backslash
X \xxx character code in octal
END_OF_FILE
if test 555 -ne `wc -c <'help/echo'`; then
echo shar: \"'help/echo'\" unpacked with wrong size!
fi
# end of 'help/echo'
fi
if test -f 'help/elif' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/elif'\"
else
echo shar: Extracting \"'help/elif'\" \(550 characters\)
sed "s/^X//" >'help/elif' <<'END_OF_FILE'
X if list
X then list
X [ elif list ; then list ] ...
X [ else list ]
X fi The if list is executed, and, if it returns a zero
X exit status, the then list is executed. Other-
X wise, the elif list is executed and, if its value
X is zero, the then list is executed. If each elif
X list returns nonzero, the else list is executed.
X
X if ( list ) sublist
X A short form of if.
X
X if ( list ) {
X list
X } elif ( list ) {
X list
X } ... else {
X list
X } An alternate form of if.
END_OF_FILE
if test 550 -ne `wc -c <'help/elif'`; then
echo shar: \"'help/elif'\" unpacked with wrong size!
fi
# end of 'help/elif'
fi
if test -f 'help/else' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/else'\"
else
echo shar: Extracting \"'help/else'\" \(550 characters\)
sed "s/^X//" >'help/else' <<'END_OF_FILE'
X if list
X then list
X [ elif list ; then list ] ...
X [ else list ]
X fi The if list is executed, and, if it returns a zero
X exit status, the then list is executed. Other-
X wise, the elif list is executed and, if its value
X is zero, the then list is executed. If each elif
X list returns nonzero, the else list is executed.
X
X if ( list ) sublist
X A short form of if.
X
X if ( list ) {
X list
X } elif ( list ) {
X list
X } ... else {
X list
X } An alternate form of if.
END_OF_FILE
if test 550 -ne `wc -c <'help/else'`; then
echo shar: \"'help/else'\" unpacked with wrong size!
fi
# end of 'help/else'
fi
if test -f 'help/for' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/for'\"
else
echo shar: Extracting \"'help/for'\" \(793 characters\)
sed "s/^X//" >'help/for' <<'END_OF_FILE'
X for name [ in word ... ]
X do list
X done Expand the list of words, and set the parameter
X name to each of them in turn, executing list each
X time. If the in word is omitted, use the posi-
X tional parameters instead of the words.
X
X for name [ in word ... ] ; sublist
X This is a shorthand for for. Though it may cause
X confusion, it is included for convenience; its use
X in scripts is discouraged, unless sublist is a
X command of the form { list }.
X
X foreach name ( word ... )
X list
X end Another form of for.
X
X for name in word ...
X {
X list
X } Another form of for.
X
X for name ( word ... ) {
X list
X } Another form of for.
X
X for name ( word ... ) sublist
X Another form of for.
END_OF_FILE
if test 793 -ne `wc -c <'help/for'`; then
echo shar: \"'help/for'\" unpacked with wrong size!
fi
# end of 'help/for'
fi
if test -f 'help/foreach' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/foreach'\"
else
echo shar: Extracting \"'help/foreach'\" \(793 characters\)
sed "s/^X//" >'help/foreach' <<'END_OF_FILE'
X for name [ in word ... ]
X do list
X done Expand the list of words, and set the parameter
X name to each of them in turn, executing list each
X time. If the in word is omitted, use the posi-
X tional parameters instead of the words.
X
X for name [ in word ... ] ; sublist
X This is a shorthand for for. Though it may cause
X confusion, it is included for convenience; its use
X in scripts is discouraged, unless sublist is a
X command of the form { list }.
X
X foreach name ( word ... )
X list
X end Another form of for.
X
X for name in word ...
X {
X list
X } Another form of for.
X
X for name ( word ... ) {
X list
X } Another form of for.
X
X for name ( word ... ) sublist
X Another form of for.
END_OF_FILE
if test 793 -ne `wc -c <'help/foreach'`; then
echo shar: \"'help/foreach'\" unpacked with wrong size!
fi
# end of 'help/foreach'
fi
if test -f 'help/function' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/function'\"
else
echo shar: Extracting \"'help/function'\" \(360 characters\)
sed "s/^X//" >'help/function' <<'END_OF_FILE'
X function word [ () ] ... { list }
X word ... () { list }
X word ... () sublist
X Define a function which is referenced by any one
X of word. Normally, only one word is provided;
X multiple words are usually only useful for setting
X traps. The body of the function is the list
X between the { and }. See FUNCTIONS below.
END_OF_FILE
if test 360 -ne `wc -c <'help/function'`; then
echo shar: \"'help/function'\" unpacked with wrong size!
fi
# end of 'help/function'
fi
if test -f 'help/getopts' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/getopts'\"
else
echo shar: Extracting \"'help/getopts'\" \(1207 characters\)
sed "s/^X//" >'help/getopts' <<'END_OF_FILE'
X getopts optstring name [ arg ... ]
X Checks arg for legal options. If arg is omitted, use
X the positional parameters. A valid option argument
X begins with a + or a -. An argument not beginning with
X a + or a -, or the argument --, ends the options. opt-
X string contains the letters that getopts recognizes.
X If a letter is followed by a `:', that option is
X expected to have an argument. The options can be
X separated from the argument by blanks.
X
X Each time it is invoked, getopts places the option
X letter it finds in the shell parameter name, prepended
X with a + when arg begins with a +. The index of the
X next arg is stored in OPTIND. The option argument, if
X any, is stored in OPTARG.
X
X A leading : in optstring causes getopts to store the
X letter of the invalid option in OPTARG, and to set name
X to `?' for an unknown option and to `:' when a required
X option is missing. Otherwise, getopts prints an error
X message. The exit status is nonzero when there are no
X more options.
END_OF_FILE
if test 1207 -ne `wc -c <'help/getopts'`; then
echo shar: \"'help/getopts'\" unpacked with wrong size!
fi
# end of 'help/getopts'
fi
if test -f 'help/if' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/if'\"
else
echo shar: Extracting \"'help/if'\" \(550 characters\)
sed "s/^X//" >'help/if' <<'END_OF_FILE'
X if list
X then list
X [ elif list ; then list ] ...
X [ else list ]
X fi The if list is executed, and, if it returns a zero
X exit status, the then list is executed. Other-
X wise, the elif list is executed and, if its value
X is zero, the then list is executed. If each elif
X list returns nonzero, the else list is executed.
X
X if ( list ) sublist
X A short form of if.
X
X if ( list ) {
X list
X } elif ( list ) {
X list
X } ... else {
X list
X } An alternate form of if.
END_OF_FILE
if test 550 -ne `wc -c <'help/if'`; then
echo shar: \"'help/if'\" unpacked with wrong size!
fi
# end of 'help/if'
fi
if test -f 'help/kill' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/kill'\"
else
echo shar: Extracting \"'help/kill'\" \(524 characters\)
sed "s/^X//" >'help/kill' <<'END_OF_FILE'
X kill [ -sig ] job ...
X kill -l
X Sends either SIGTERM or the specified signal to the
X given jobs or processes. Signals are given by number
X or by names (with the prefix "SIG" removed). If the
X signal being sent is not KILL or CONT, then the job
X will be sent a CONT signal if it is stopped. The argu-
X ment job can be the process id of a job not in the job
X list. In the second form, kill -l, the signal names
X are listed.
END_OF_FILE
if test 524 -ne `wc -c <'help/kill'`; then
echo shar: \"'help/kill'\" unpacked with wrong size!
fi
# end of 'help/kill'
fi
if test -f 'help/print' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/print'\"
else
echo shar: Extracting \"'help/print'\" \(1151 characters\)
sed "s/^X//" >'help/print' <<'END_OF_FILE'
X print [ -RnrslzpNDP ] [ -un ] [ arg ... ]
X With no flags or with flag -, the arguments are printed
X on the standard output as described by echo.
X -R, -r
X ignore the escape conventions of echo. The -R
X option will print all subsequent arguments and
X options.
X -s place the results in the history list instead of
X on the standard output.
X -n do not add a newline to the output.
X -l print the arguments separated by newlines instead
X of spaces.
X -N print the arguments separated and terminated by
X nulls.
X -un print the arguments to file descriptor n.
X -p print the arguments to the input of the coprocess.
X -z push the arguments onto the editing buffer stack,
X separated by spaces; no escape sequences are
X recognized.
X -D treat the arguments as directory names, replacing
X prefixes with ~ expressions, as appropriate.
X -P recognize the same escape sequences as in the
END_OF_FILE
if test 1151 -ne `wc -c <'help/print'`; then
echo shar: \"'help/print'\" unpacked with wrong size!
fi
# end of 'help/print'
fi
if test -f 'help/select' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/select'\"
else
echo shar: Extracting \"'help/select'\" \(812 characters\)
sed "s/^X//" >'help/select' <<'END_OF_FILE'
X select name [ in word ... ]
X do list
X done Print the set of words, each preceded by a number.
X If the in word is omitted, use the positional
X parameters. The PROMPT3 prompt is printed and a
X line is read from standard input. If this line
X consists of the number of one of the listed words,
X then the parameter name is set to the word
X corresponding to this number. If this line is
X empty, the selection list is printed again. Oth-
X erwise, the value of the parameter name is set to
X null. The contents of the line read from standard
X input is saved in the parameter REPLY. list is
X executed for each selection until a break or end-
X of-file is encountered.
X
X select name [ in word ] ; sublist
X A short form of select.
END_OF_FILE
if test 812 -ne `wc -c <'help/select'`; then
echo shar: \"'help/select'\" unpacked with wrong size!
fi
# end of 'help/select'
fi
if test -f 'help/set' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/set'\"
else
echo shar: Extracting \"'help/set'\" \(745 characters\)
sed "s/^X//" >'help/set' <<'END_OF_FILE'
X set [ +-options ] [ +-o option name ] ... [ -A name ] [ arg ] ...
X Set the options for the shell and/or set the positional
X parameters, or declare an array. For the meaning of
X the flags, see OPTIONS above. Flags may be specified
X by name using the -o option. If the -A flag is speci-
X fied, name is set to an array containing the given
X args. Otherwise the positional parameters are set. If
X no arguments are given, then the names and values of
X all parameters are printed on the standard output. If
X the only argument is +, the names of all parameters are
X printed.
X unset name ...
X Each named parameter is unset.
END_OF_FILE
if test 745 -ne `wc -c <'help/set'`; then
echo shar: \"'help/set'\" unpacked with wrong size!
fi
# end of 'help/set'
fi
if test -f 'help/ttyctl' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/ttyctl'\"
else
echo shar: Extracting \"'help/ttyctl'\" \(437 characters\)
sed "s/^X//" >'help/ttyctl' <<'END_OF_FILE'
X ttyctl -fu
X The -f option freezes the tty, and -u unfreezes it.
X When the tty is frozen, no changes made to the tty set-
X tings by external programs will be honored by the
X shell; the shell will simply reset the settings to
X their previous values as soon as each command exits.
X Thus, stty and similar programs have no effect when the
X tty is frozen.
END_OF_FILE
if test 437 -ne `wc -c <'help/ttyctl'`; then
echo shar: \"'help/ttyctl'\" unpacked with wrong size!
fi
# end of 'help/ttyctl'
fi
if test -f 'help/ulimit' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/ulimit'\"
else
echo shar: Extracting \"'help/ulimit'\" \(890 characters\)
sed "s/^X//" >'help/ulimit' <<'END_OF_FILE'
X ulimit [ -HSacdfmnt ] [ limit ]
X Set or display a resource limit. The value of limit
X can be a number in the unit specified below or the
X value unlimited. The H and S flags specify whether the
X hard limit or the soft limit for the given resource is
X set.
X -a Lists all of the current resource limits.
X -c The number of 512-byte blocks on the size of core
X dumps.
X -d The number of K-bytes on the size of the data seg-
X ment.
X -f The number of 512-byte blocks on the size of files
X written.
X -m The number of K-bytes on the size of physical
X memory.
X -n The number of file descriptors.
X -s The number of K-bytes on the size of the stack.
X -t The number of CPU seconds to be used.
END_OF_FILE
if test 890 -ne `wc -c <'help/ulimit'`; then
echo shar: \"'help/ulimit'\" unpacked with wrong size!
fi
# end of 'help/ulimit'
fi
if test -f 'help/unhash' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/unhash'\"
else
echo shar: Extracting \"'help/unhash'\" \(362 characters\)
sed "s/^X//" >'help/unhash' <<'END_OF_FILE'
X hash name path
X Puts name in the command hash table, associating it
X with the pathname path. Whenever name is used as a
X command argument, the shell will try to execute the
X file given by path.
X unhash name ...
X The entry in the command hash table, if any, for each
X name is removed.
END_OF_FILE
if test 362 -ne `wc -c <'help/unhash'`; then
echo shar: \"'help/unhash'\" unpacked with wrong size!
fi
# end of 'help/unhash'
fi
if test -f 'help/unset' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/unset'\"
else
echo shar: Extracting \"'help/unset'\" \(745 characters\)
sed "s/^X//" >'help/unset' <<'END_OF_FILE'
X set [ +-options ] [ +-o option name ] ... [ -A name ] [ arg ] ...
X Set the options for the shell and/or set the positional
X parameters, or declare an array. For the meaning of
X the flags, see OPTIONS above. Flags may be specified
X by name using the -o option. If the -A flag is speci-
X fied, name is set to an array containing the given
X args. Otherwise the positional parameters are set. If
X no arguments are given, then the names and values of
X all parameters are printed on the standard output. If
X the only argument is +, the names of all parameters are
X printed.
X unset name ...
X Each named parameter is unset.
END_OF_FILE
if test 745 -ne `wc -c <'help/unset'`; then
echo shar: \"'help/unset'\" unpacked with wrong size!
fi
# end of 'help/unset'
fi
if test -f 'help/whence' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/whence'\"
else
echo shar: Extracting \"'help/whence'\" \(515 characters\)
sed "s/^X//" >'help/whence' <<'END_OF_FILE'
X whence [ -acpv ] name ...
X For each name, indicate how it would be interpreted if
X used as a command name. The -v flag produces a more
X verbose report. The -p flag does a path search for
X name even if it is a shell function, alias, or reserved
X word. The -c flag prints the results in a csh-like
X format. The -a flag does a search for all occurences
X of name throughout the command path.
X
X which
X Same as whence -c.
END_OF_FILE
if test 515 -ne `wc -c <'help/whence'`; then
echo shar: \"'help/whence'\" unpacked with wrong size!
fi
# end of 'help/whence'
fi
if test -f 'help/which' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/which'\"
else
echo shar: Extracting \"'help/which'\" \(515 characters\)
sed "s/^X//" >'help/which' <<'END_OF_FILE'
X whence [ -acpv ] name ...
X For each name, indicate how it would be interpreted if
X used as a command name. The -v flag produces a more
X verbose report. The -p flag does a path search for
X name even if it is a shell function, alias, or reserved
X word. The -c flag prints the results in a csh-like
X format. The -a flag does a search for all occurences
X of name throughout the command path.
X
X which
X Same as whence -c.
END_OF_FILE
if test 515 -ne `wc -c <'help/which'`; then
echo shar: \"'help/which'\" unpacked with wrong size!
fi
# end of 'help/which'
fi
if test -f 'src/cond.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/cond.c'\"
else
echo shar: Extracting \"'src/cond.c'\" \(4069 characters\)
sed "s/^X//" >'src/cond.c' <<'END_OF_FILE'
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[(int)*s];
X if ((i = optlookup(s)) != -1)
X return opts[i];
X zerr("no such option: %s",s,0);


X return 0;
X}
X
END_OF_FILE

if test 4069 -ne `wc -c <'src/cond.c'`; then
echo shar: \"'src/cond.c'\" unpacked with wrong size!
fi
# end of 'src/cond.c'
fi
if test -f 'src/loop.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/loop.c'\"
else
echo shar: Extracting \"'src/loop.c'\" \(4787 characters\)
sed "s/^X//" >'src/loop.c' <<'END_OF_FILE'
X/*
X *
X * loop.c - loop 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

Xint execfor(cmd) /**/
XCmd cmd;
X{
XList list;
Xstruct forcmd *node;
Xchar *str;
XLklist args;


Xint cj = thisjob;
X

X loops++;
X exiting = 0;
X node = cmd->u.forcmd;


X args = cmd->args;

X if (!node->inflag)
X {
X char **x;
X
X args = newlist();
X for (x = pparams; *x; x++)
X addnode(args,ztrdup(*x));
X }
X pushheap();
X while (str = ugetnode(args))
X {
X setsparam(node->name,ztrdup(str));
X list = dupstruct(node->list);
X execlist(list);
X if (breaks)
X {
X breaks--;
X if (breaks || !contflag)
X break;
X contflag = 0;
X }
X if (errflag)
X {
X lastval = 1;
X break;
X }
X freeheap();
X }
X popheap();
X thisjob = cj;
X loops--;


X return lastval;
X}
X

Xint execselect(cmd) /**/
XCmd cmd;
X{
XList list;
Xstruct forcmd *node;
Xchar *str,*s;
XLklist args;
XLknode n;
Xint cj = thisjob,t0;
XFILE *inp;
X
X node = cmd->u.forcmd;


X args = cmd->args;

X if (!node->inflag) {
X char **x;
X
X args = newlist();
X for (x = pparams; *x; x++)
X addnode(args,ztrdup(*x));
X }
X if (empty(args))
X return 1;
X loops++;
X exiting = 0;
X pushheap();
X inp = fdopen(dup((SHTTY==-1)?0:SHTTY),"r");
X for (;;)
X {
X do
X {
X int pl;
X selectlist(args);
X str = putprompt(prompt3,&pl,0);
X if (full(bufstack)) str = (char *) getnode(bufstack);
X else if (interact && SHTTY != -1 && isset(USEZLE)) {
X str = (char *)zleread((unsigned char *)str,NULL,pl);
X } else {
X fprintf(stderr,"%s",str);
X fflush(stderr);
X str = fgets(zalloc(256),256,inp);
X }
X if (!str || errflag)
X {


X fprintf(stderr,"\n");
X fflush(stderr);

X goto done;
X }
X if (s = strchr(str,'\n'))


X *s = '\0';
X }

X while (!*str);
X setsparam("REPLY",ztrdup(str));
X t0 = atoi(str);
X if (!t0)
X str = "";
X else
X {
X for (t0--,n = firstnode(args); n && t0; incnode(n),t0--);
X if (n)
X str = getdata(n);
X else
X str = "";
X }
X setsparam(node->name,ztrdup(str));
X list = dupstruct(node->list);
X execlist(list);
X freeheap();
X if (breaks)
X {
X breaks--;
X if (breaks || !contflag)
X break;
X contflag = 0;
X }
X if (errflag)
X break;
X }
Xdone:
X popheap();
X fclose(inp);
X thisjob = cj;
X loops--;


X return lastval;
X}
X

Xint execwhile(cmd) /**/
XCmd cmd;
X{
XList list;
Xstruct whilecmd *node;


Xint cj = thisjob;
X

X node = cmd->u.whilecmd;
X exiting = 0;
X pushheap();
X loops++;
X for(;;)
X {
X list = dupstruct(node->cont);
X execlist(list);
X if (!((lastval == 0) ^ node->cond)) {
X if (breaks) breaks--;
X break;
X }
X list = dupstruct(node->loop);
X execlist(list);
X if (breaks)
X {
X breaks--;
X if (breaks || !contflag)
X break;
X contflag = 0;
X }
X freeheap();
X if (errflag)
X {
X lastval = 1;
X break;
X }
X }
X popheap();
X thisjob = cj;
X loops--;


X return lastval;
X}
X

Xint execrepeat(cmd) /**/
XCmd cmd;
X{
XList list;
Xint cj = thisjob,count;
X
X exiting = 0;
X if (empty(cmd->args) || nextnode(firstnode(cmd->args)))
X {
X zerr("bad argument for repeat",NULL,0);
X return 1;
X }
X count = atoi(peekfirst(cmd->args));
X pushheap();
X loops++;
X while (count--)
X {
X list = dupstruct(cmd->u.list);
X execlist(list);
X freeheap();
X if (breaks)
X {
X breaks--;
X if (breaks || !contflag)
X break;
X contflag = 0;
X }
X if (lastval)
X break;
X if (errflag)
X {
X lastval = 1;
X break;
X }
X }
X popheap();
X thisjob = cj;
X loops--;


X return lastval;
X}
X

Xint execif(cmd) /**/
XCmd cmd;
X{
Xstruct ifcmd *node;


Xint cj = thisjob;
X

X node = cmd->u.ifcmd;
X exiting = 0;
X while (node)
X {
X if (node->ifl)
X {
X execlist(node->ifl);
X if (lastval)
X {
X node = node->next;
X continue;
X }
X }
X execlist(node->thenl);
X break;
X }


X thisjob = cj;
X return lastval;
X}
X

Xint execcase(cmd) /**/
XCmd cmd;
X{
Xstruct casecmd *node;
Xchar *word;
XLklist args;


Xint cj = thisjob;
X

X node = cmd->u.casecmd;


X args = cmd->args;

X exiting = 0;
X if (firstnode(args) && nextnode(firstnode(args)))
X {
X zerr("too many arguments to case",NULL,0);
X return 1;
X }
X if (empty(args))
X word = strdup("");
X else
X word = peekfirst(args);
X while (node)
X {
X singsub(&(node->pat));
X if (matchpat(word,node->pat))
X break;
X else
X node = node->next;
X }
X if (node && node->list)
X execlist(node->list);


X thisjob = cj;
X return lastval;
X}

END_OF_FILE
if test 4787 -ne `wc -c <'src/loop.c'`; then
echo shar: \"'src/loop.c'\" unpacked with wrong size!
fi
# end of 'src/loop.c'
fi
if test -f 'src/mem.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/mem.c'\"
else
echo shar: Extracting \"'src/mem.c'\" \(5032 characters\)
sed "s/^X//" >'src/mem.c' <<'END_OF_FILE'
X/*
X *
X * mem.c - memory management


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
X mem.c - memory management
X
X This file is part of zsh, the Z shell.
X
X zsh is free software; no one can prevent you from reading the source
X code, or giving it to someone else.
X
X This file is copyrighted under the GNU General Public License, which
X can be found in the file called COPYING.
X
X Copyright (C) 1990, 1991 Paul Falstad
X
X*/
X
X#include "zsh.h"
X#define HEAPSIZE 8192
X
X/*
X
X There are two ways to allocate memory in zsh. The first way is
X to call zalloc/zcalloc, which call malloc/calloc directly. It
X is legal to call realloc() or free() on memory allocated this way.
X The second way is to call halloc/hcalloc, which allocates memory
X from one of the memory pools on the heap stack. A pool can be
X created by calling pushheap(), and destroyed by calling popheap().
X To free the memory in the pool without destroying it, call
X freeheap(); this is equivalent to { popheap(); pushheap(); }
X Memory allocated in this way does not have to be freed explicitly;
X it will all be freed when the pool is destroyed. In fact,
X attempting to free this memory may result in a core dump.
X The pair of pointers ncalloc and alloc may point to either
X zalloc & zcalloc or halloc & hcalloc; permalloc() sets them to the
X former, and heapalloc() sets them to the latter. This can be useful.
X For example, the dupstruct() routine duplicates a syntax tree,
X allocating the new memory for the tree using alloc(). If you want
X to duplicate a structure for a one-time use (i.e. to execute the list
X in a for loop), call heapalloc(), then dupstruct(). If you want
X to duplicate a structure in order to preserve it (i.e. a function
X definition), call permalloc(), then dupstruct().
X
X*/
X
X/* initialize heap stack */
X
Xvoid meminit() /**/
X{
X permalloc();
X heaplist = newlist();
X pushheap();
X}
X
X/* set default allocation to heap stack */
X
Xvoid heapalloc() /**/
X{
X alloc = hcalloc;
X ncalloc = halloc;
X useheap = 1;
X}
X
Xstatic vptr (*lastcalloc) DCLPROTO((int));
Xstatic vptr (*lastncalloc) DCLPROTO((int));
Xstatic int lastuseheap;
X
X/* set default allocation to malloc() */
X
Xvoid permalloc() /**/
X{
X lastcalloc = alloc;
X lastncalloc = ncalloc;
X lastuseheap = useheap;
X alloc = zcalloc;
X ncalloc = zalloc;
X useheap = 0;
X}
X
X/* reset previous default allocation */
X
Xvoid lastalloc() /**/
X{
X alloc = lastcalloc;
X ncalloc = lastncalloc;
X useheap = lastuseheap;
X}
X
Xstruct heap {
X char *pool,*ptr;
X int free;
X struct heap *next;
X };
X
X/* create a memory pool */
X
Xvoid pushheap() /**/
X{
XHeap h;
X
X h = (Heap) zalloc(sizeof *h);
X h->pool = h->ptr = zalloc(HEAPSIZE);
X h->free = HEAPSIZE;
X h->next = NULL;
X permalloc();
X pushnode(heaplist,h);
X lastalloc();
X}
X
X/* reset a memory pool */
X
Xvoid freeheap() /**/
X{


XHeap h = (Heap) peekfirst(heaplist);
X

X freeh(h->next);
X h->next = NULL;
X h->free += (h->ptr-h->pool);
X h->ptr = h->pool;
X}
X
X/* destroy a memory pool */
X
Xvoid popheap() /**/
X{
XHeap h = (Heap) getnode(heaplist);
X
X freeh(h);
X}
X
Xvoid freeh(h) /**/
XHeap h;
X{
X if (h)
X {
X freeh(h->next);


X free(h->pool);
X free(h);
X }

X}
X
X/* allocate memory from the current memory pool */
X
Xvptr halloc(size) /**/
Xint size;
X{
XHeap h = (Heap) peekfirst(heaplist),h2;
Xchar *ret;
X
X size = (size|7)+1;
X while (h && h->free-size < 0)
X h = h->next;
X if (!h) {
X h2 = (Heap) zalloc(sizeof *h2);
X h2->pool = h2->ptr = zalloc(h2->free =
X (size < HEAPSIZE) ? HEAPSIZE : (size|(HEAPSIZE-1))+1);
X h2->next = (Heap) peekfirst(heaplist);
X setdata(firstnode(heaplist),(vptr) h2);
X h = h2;
X }
X h->free -= size;


X ret = h->ptr;

X h->ptr += size;


X return ret;
X}
X

X/* allocate memory from the current memory pool and clear it */
X
Xvptr hcalloc(size) /**/
Xint size;
X{
Xvptr ptr;
X
X ptr = halloc(size);
X memset(ptr,0,size);


X return ptr;
X}
X

Xvptr hrealloc(p,old,new) /**/
Xchar *p;int old;int new;
X{
Xchar *ptr;
X
X ptr = halloc(new);
X memcpy(ptr,p,old);


X return ptr;
X}
X

X/* allocate permanent memory */
X
Xvptr zalloc(l) /**/
Xint l;
X{
Xvptr z;
X
X if (!l) l = 1;
X if (!(z = malloc(l)))
X {
X zerr("fatal error: out of memory",NULL,0);
X exit(1);
X }


X return z;
X}
X

Xvptr zcalloc(size) /**/
Xint size;
X{
Xvptr ptr;
X
X ptr = zalloc(size);
X memset(ptr,0,size);


X return ptr;
X}
X

Xchar *strdup(s) /**/
Xconst char *s;
X{
Xchar *t;
X
X if (!s)
X return NULL;
X t = ncalloc(strlen(s)+1);
X strcpy(t,s);


X return t;
X}
X

Xchar *ztrdup(s) /**/
Xconst char *s;
X{
Xchar *t;
X
X if (!s)
X return NULL;
X t = zalloc(strlen(s)+1);
X strcpy(t,s);


X return t;
X}
X

END_OF_FILE
if test 5032 -ne `wc -c <'src/mem.c'`; then
echo shar: \"'src/mem.c'\" unpacked with wrong size!
fi
# end of 'src/mem.c'
fi
if test -f 'src/zle_move.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle_move.c'\"
else
echo shar: Extracting \"'src/zle_move.c'\" \(5167 characters\)
sed "s/^X//" >'src/zle_move.c' <<'END_OF_FILE'
X/*
X *
X * zle_move.c - editor movement


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#define ZLE
X#include "zsh.h"
X

Xvoid beginningofline() /**/
X{
X if (mult < 0) { mult = -mult; endofline(); return; }
X while (mult--) {
X if (cs == 0)
X return;
X if (line[cs-1] == '\n')
X if (!--cs)
X return;
X while (cs && line[cs-1] != '\n') cs--;
X }
X}
X
Xvoid endofline() /**/
X{
X if (mult < 0) { mult = -mult; beginningofline(); return; }
X while (mult--) {
X if (cs >= ll) {
X cs = ll;
X return;
X }


X if (line[cs] == '\n')

X if (++cs == ll)
X return;
X while (cs != ll && line[cs] != '\n') cs++;
X }
X}
X
Xvoid beginningoflinehist() /**/
X{
X if (mult < 0) { mult = -mult; endoflinehist(); return; }
X while (mult) {
X if (cs == 0)
X break;
X if (line[cs-1] == '\n')
X if (!--cs)
X break;


X while (cs && line[cs-1] != '\n') cs--;

X mult--;
X }
X if (mult) {

X uphistory();
X cs = 0;
X }
X}
X
Xvoid endoflinehist() /**/
X{
X if (mult < 0) { mult = -mult; beginningoflinehist(); return; }
X while (mult) {
X if (cs >= ll) {
X cs = ll;
X break;
X }


X if (line[cs] == '\n')

X if (++cs == ll)
X break;
X while (cs != ll && line[cs] != '\n') cs++;


X mult--;
X }
X if (mult)

X downhistory();
X}
X
Xvoid forwardchar() /**/
X{
X cs += mult;


X if (cs > ll) cs = ll;

X if (cs < 0) cs = 0;
X}
X
Xvoid backwardchar() /**/
X{
X cs -= mult;


X if (cs > ll) cs = ll;

X if (cs < 0) cs = 0;
X}
X
Xvoid setmarkcommand() /**/
X{


X mark = cs;
X}

X
Xvoid exchangepointandmark() /**/
X{
Xint x;
X
X x = mark;
X mark = cs;
X cs = x;
X if (cs > ll)


X cs = ll;
X}

X
Xvoid vigotocolumn() /**/
X{
Xint x,y,ocs = cs;
X
X if (mult > 0) mult--;
X findline(&x,&y);
X if (mult >= 0) cs = x+mult; else cs = y+mult;
X if (cs < x || cs > y) {
X feep();
X cs = ocs;
X }
X}
X
Xvoid vimatchbracket() /**/
X{
Xint ocs = cs,dir,ct;
Xunsigned char oth,me;
X
Xotog:


X if (cs == ll)

X {
X feep();
X cs = ocs;
X return;
X }
X switch(me = line[cs])
X {
X case '{': dir = 1; oth = '}'; break;
X case '}': dir = -1; oth = '{'; break;
X case '(': dir = 1; oth = ')'; break;
X case ')': dir = -1; oth = '('; break;
X case '[': dir = 1; oth = ']'; break;
X case ']': dir = -1; oth = '['; break;
X default: cs++; goto otog;
X }
X ct = 1;
X while (cs >= 0 && cs < ll && ct)
X {
X cs += dir;
X if (line[cs] == oth)
X ct--;
X else if (line[cs] == me)
X ct++;
X }
X if (cs < 0 || cs >= ll)
X {
X feep();
X cs = ocs;
X }
X}
X
Xvoid viforwardchar() /**/
X{
X if (mult < 0) { mult = -mult; vibackwardchar(); return; }
X while (mult--) {
X cs++;
X if (cs >= ll || line[cs] == '\n') {
X cs--;


X break;
X }
X }
X}
X

Xvoid vibackwardchar() /**/
X{
X if (mult < 0) { mult = -mult; viforwardchar(); return; }
X while (mult--) {
X cs--;
X if (cs < 0 || line[cs] == '\n') {
X cs++;


X break;
X }
X }
X}
X

Xvoid viendofline() /**/


X{
X cs = findeol();

X if (!virangeflag && cs != 0 && line[cs-1] != '\n') cs--;
X}
X
Xvoid vibeginningofline() /**/


X{
X cs = findbol();
X}

X
X
Xstatic int vfindchar,vfinddir,tailadd;
X
Xvoid vifindnextchar() /**/
X{
X if (vfindchar = vigetkey())
X {
X vfinddir = 1;
X tailadd = 0;
X virepeatfind();
X }
X}
X
Xvoid vifindprevchar() /**/
X{
X if (vfindchar = vigetkey())
X {
X vfinddir = -1;
X tailadd = 0;
X virepeatfind();
X }
X}
X
Xvoid vifindnextcharskip() /**/
X{
X if (vfindchar = vigetkey())
X {
X vfinddir = 1;
X tailadd = -1;
X virepeatfind();
X }
X}
X
Xvoid vifindprevcharskip() /**/
X{
X if (vfindchar = vigetkey())
X {
X vfinddir = -1;
X tailadd = 1;
X virepeatfind();
X }
X}
X
Xvoid virepeatfind() /**/
X{
Xint ocs = cs;
X
X if (!vfinddir) { feep(); return; }
X if (mult < 0) { mult = -mult; virevrepeatfind(); return; }
X while (mult--)
X {
X do
X cs += vfinddir;
X while (cs >= 0 && cs < ll && line[cs] != vfindchar && line[cs] != '\n');
X if (cs < 0 || cs >= ll || line[cs] == '\n')
X {
X feep();
X cs = ocs;
X return;
X }
X }
X cs += tailadd;
X if (vfinddir == 1 && virangeflag) cs++;
X}
X
Xvoid virevrepeatfind() /**/
X{
X if (mult < 0) { mult = -mult; virepeatfind(); return; }
X vfinddir = -vfinddir;
X virepeatfind();
X vfinddir = -vfinddir;
X}
X
Xvoid vifirstnonblank() /**/


X{
X cs = findbol();

X while (cs != ll && iblank(line[cs]))

X cs++;
X}
X
Xvoid visetmark() /**/
X{
Xint ch;
X
X ch = getkey(1);
X if (ch < 'a' || ch > 'z') {


X feep();
X return;
X }

X ch -= 'a';
X vimarkcs[ch] = cs;
X vimarkline[ch] = histline;
X}
X
Xvoid vigotomark() /**/
X{
Xint ch;
X
X ch = getkey(1);
X if (ch == c) ch = 26;
X else {
X if (ch < 'a' || ch > 'z') {


X feep();
X return;
X }

X ch -= 'a';
X }
X if (!vimarkline[ch]) {
X feep();
X return;
X }
X if (curhist != vimarkline[ch]) {
X mult = vimarkline[ch];
X vifetchhistory();
X if (curhist != vimarkline[ch]) return;
X }
X cs = vimarkcs[ch];
X}
X
Xvoid vigotomarkline() /**/
X{
X vigotomark();
X cs = findbol();
X}
END_OF_FILE
if test 5167 -ne `wc -c <'src/zle_move.c'`; then
echo shar: \"'src/zle_move.c'\" unpacked with wrong size!
fi
# end of 'src/zle_move.c'
fi
if test -f 'src/zle_utils.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/zle_utils.c'\"
else
echo shar: Extracting \"'src/zle_utils.c'\" \(4714 characters\)
sed "s/^X//" >'src/zle_utils.c' <<'END_OF_FILE'
X/*
X *
X * zle_utils.c - miscellaneous line editor utilities


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#define ZLE
X#include "zsh.h"
X

X/* make sure that the line buffer has at least sz chars */
X
Xvoid sizeline(sz) /**/
Xint sz;
X{
X while (sz > linesz)
X line = (unsigned char *)realloc(line,(linesz *= 4)+1);
X}
X
X/* insert space for ct chars at cursor position */
X
Xvoid spaceinline(ct) /**/
Xint ct;
X{
Xint i;
X
X while (ct+ll > linesz)
X line = (unsigned char *)realloc(line,(linesz *= 4)+1);
X for (i = ll; i >= cs; i--)
X line[i+ct] = line[i];
X ll += ct;
X line[ll] = '\0';
X}
X
Xvoid backkill(ct,dir) /**/
Xint ct;int dir;
X{
Xint i = (cs -= ct);
X
X cut(i,ct,dir);
X while (line[i] = line[i+ct])
X i++;
X ll -= ct;
X}
X
Xvoid forekill(ct,dir) /**/
Xint ct;int dir;
X{
Xint i = cs;
X
X cut(i,ct,dir);
X while (line[i] = line[i+ct])
X i++;
X ll -= ct;
X}
X
Xvoid cut(i,ct,dir) /**/
Xint i;int ct;int dir;
X{
X if (vibufspec) {
X int owrite = 1;
X if (vibufspec >= 'A' && vibufspec <= 'Z') {
X owrite = 0; vibufspec = tolower(vibufspec);
X }


X vibufspec += (idigit(vibufspec)) ? - '1' +26 : - 'a';

X if (owrite || !vibuf[vibufspec]) {
X if (vibuf[vibufspec]) free(vibuf[vibufspec]);
X vibuf[vibufspec] = zalloc(ct+1);
X ztrncpy(vibuf[vibufspec],UTOSCP(line+i),ct);
X } else {
X int len = strlen(vibuf[vibufspec]);
X vibuf[vibufspec] = realloc(vibuf[vibufspec],ct+len);
X ztrncpy(vibuf[vibufspec]+len,UTOSCP(line+i),ct);


X }
X vibufspec = 0;

X return;
X }
X if (!cutbuf)
X cutbuf = ztrdup("");
X else if (!(lastcmd & ZLE_KILL)) {
X kringnum = (kringnum+1)&(KRINGCT-1);
X if (kring[kringnum])
X free(kring[kringnum]);
X kring[kringnum] = cutbuf;
X cutbuf = ztrdup("");
X }
X if (dir) {
X char *s = zalloc(strlen(cutbuf)+ct+1);
X strncpy(s,(char *) line+i,ct);
X strcpy(s+ct,cutbuf);
X free(cutbuf);
X cutbuf = s;
X } else {
X int x;
X
X cutbuf = realloc(cutbuf,(x = strlen(cutbuf))+ct+1);
X ztrncpy(cutbuf+x,UTOSCP(line+i),ct);
X }
X}
X
Xvoid backdel(ct) /**/
Xint ct;
X{
Xint i = (cs -= ct);
X
X while (line[i] = line[i+ct])
X i++;
X ll -= ct;
X}
X
Xvoid foredel(ct) /**/
Xint ct;
X{
Xint i = cs;
X
X while (line[i] = line[i+ct])
X i++;
X ll -= ct;
X}
X
Xvoid setline(s) /**/
Xchar *s;
X{
X sizeline(strlen(s));
X strcpy((char *) line,s);
X cs = ll = strlen(s);
X if (cs && bindtab == altbindtab) cs--;
X}
X
Xvoid sethistline(s) /**/
Xunsigned char *s;
X{
X setline(UTOSCP(s));
X for (s = line; *s; s++)
X if (*s == STOUC(HISTSPACE))
X *s = ' ';
X}
X
Xint findbol() /**/


X{
Xint x = cs;
X

X while (x > 0 && line[x-1] != '\n') x--;


X return x;
X}
X

Xint findeol() /**/


X{
Xint x = cs;
X

X while (x != ll && line[x] != '\n') x++;


X return x;
X}
X

Xvoid findline(a,b) /**/
Xint *a;int *b;
X{
X *a = findbol();
X *b = findeol();
X}
X
Xstatic int lastlinelen;
X
Xvoid initundo() /**/
X{
Xint t0;
X
X for (t0 = 0; t0 != UNDOCT; t0++)
X undos[t0].change = NULL;
X undoct = 0;
X lastline = zalloc(lastlinelen = (ll+1 < 32) ? 32 : ll+1);
X strcpy((char *) lastline,(char *) line);
X lastcs = cs;
X}
X
Xvoid addundo() /**/
X{
Xint pf,sf;
Xunsigned char *s,*s2,*t,*t2;
Xstruct undoent *ue;
X
X for (s = line, t = lastline; *s && *s==*t; s++,t++);
X if (!*s && !*t)
X return;
X pf = s-line;
X for (s2 = (unsigned char *)line+strlen((char *) line),
X t2 = lastline+strlen((char *) lastline);
X s2 > s && t > t2 && s2[-1] == t2[-1]; s2--,t2--);
X sf = strlen((char *) s2);
X ue = undos+(undoct = (UNDOCT-1) & (undoct+1));
X ue->pref = pf;
X ue->suff = sf;
X ue->len = t2-t;
X ue->cs = lastcs;
X strncpy(ue->change = halloc(ue->len),(char *) t,ue->len);
X while (ll+1 > lastlinelen)
X {
X free(lastline);
X lastline = zalloc(lastlinelen *= 2);
X }
X strcpy((char *) lastline,(char *) line);
X lastcs = cs;
X}
X
Xvoid freeundo() /**/
X{
X free(lastline);
X}
X
Xint hstrncmp(s,t,len) /**/


Xchar *s;char *t;int len;
X{

X while (len && *s && (*s == *t || (*s == ' ' && *t == HISTSPACE) ||
X (*s == HISTSPACE && *t == ' ')))
X s++,t++,len--;
X return len;
X}
X
Xint hstrcmp(s,t) /**/
Xchar *s;char *t;
X{
X while (*s && (*s == *t || (*s == ' ' && *t == HISTSPACE) ||
X (*s == HISTSPACE && *t == ' ')))
X s++,t++;
X return !(*s == '\0' && *t == '\0');
X}
X
Xchar *hstrnstr(s,t,len) /**/
Xchar *s;char *t;int len;


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

X if (!hstrncmp(t,s,len))
X return s;


X return NULL;
X}
X

END_OF_FILE
if test 4714 -ne `wc -c <'src/zle_utils.c'`; then
echo shar: \"'src/zle_utils.c'\" unpacked with wrong size!
fi
# end of 'src/zle_utils.c'
fi
echo shar: End of archive 21 \(of 22\).
cp /dev/null ark21isdone

The Zsh Mailing List

unread,
Feb 20, 1993, 4:29:57 PM2/20/93
to
Submitted-by: zsh-...@cs.uow.edu.au (The Zsh Mailing List)
Posting-number: Volume 35, Issue 72
Archive-name: zsh/part22

Environment: UNIX
Supersedes: zsh2.2: Volume 29, Issue 97-113

#! /bin/sh


# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sou...@uunet.uu.net if you want that tool.

# Contents: dots/zlogin dots/zshenv func/acx func/cx func/harden
# func/mere func/proto func/randline func/yp func/yu help/bg
# help/break help/builtin help/chpwd help/continue help/coproc
# help/disable help/disown help/echotc help/enable help/eval
# help/exit help/export help/fg help/getln help/hash help/jobs
# help/let help/log help/periodic help/precmd help/readonly
# help/rehash help/repeat help/return help/sched help/shift
# help/suspend help/test help/time help/times help/umask
# help/unfunction help/unlimit help/until help/vared help/wait
# help/while src/version.h
# Wrapped by mattson@odin on Sat Feb 6 14:41:56 1993


PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:

echo ' "shar: End of archive 22 (of 22)."'
if test -f 'dots/zlogin' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dots/zlogin'\"
else
echo shar: Extracting \"'dots/zlogin'\" \(247 characters\)
sed "s/^X//" >'dots/zlogin' <<'END_OF_FILE'
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
END_OF_FILE
if test 247 -ne `wc -c <'dots/zlogin'`; then
echo shar: \"'dots/zlogin'\" unpacked with wrong size!
fi
# end of 'dots/zlogin'
fi
if test -f 'dots/zshenv' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dots/zshenv'\"
else
echo shar: Extracting \"'dots/zshenv'\" \(123 characters\)
sed "s/^X//" >'dots/zshenv' <<'END_OF_FILE'
Xpath=(~/scr ~/bin/$HOSTTYPE
X /usr/princeton/bin /usr/ucb /usr/bin /bin
X /usr/hosts /usr/princeton/bin/X11 /usr/etc /etc .)
END_OF_FILE
if test 123 -ne `wc -c <'dots/zshenv'`; then
echo shar: \"'dots/zshenv'\" unpacked with wrong size!
fi
# end of 'dots/zshenv'
fi
if test -f 'func/acx' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/acx'\"
else
echo shar: Extracting \"'func/acx'\" \(104 characters\)
sed "s/^X//" >'func/acx' <<'END_OF_FILE'
X#! /bin/sh
X#
X# zsh shell function to make its arguments 755
X# also works as an sh script
X#
Xchmod 755 $*
END_OF_FILE
if test 104 -ne `wc -c <'func/acx'`; then
echo shar: \"'func/acx'\" unpacked with wrong size!
fi
chmod +x 'func/acx'
# end of 'func/acx'
fi
if test -f 'func/cx' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/cx'\"
else
echo shar: Extracting \"'func/cx'\" \(109 characters\)
sed "s/^X//" >'func/cx' <<'END_OF_FILE'
X#! /bin/sh
X#
X# zsh shell function to make its arguments executable
X# also works as a sh script
X#
Xchmod +x $*
END_OF_FILE
if test 109 -ne `wc -c <'func/cx'`; then
echo shar: \"'func/cx'\" unpacked with wrong size!
fi
chmod +x 'func/cx'
# end of 'func/cx'
fi
if test -f 'func/harden' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/harden'\"
else
echo shar: Extracting \"'func/harden'\" \(97 characters\)
sed "s/^X//" >'func/harden' <<'END_OF_FILE'
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
END_OF_FILE
if test 97 -ne `wc -c <'func/harden'`; then
echo shar: \"'func/harden'\" unpacked with wrong size!
fi
chmod +x 'func/harden'
# end of 'func/harden'
fi
if test -f 'func/mere' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/mere'\"
else
echo shar: Extracting \"'func/mere'\" \(84 characters\)
sed "s/^X//" >'func/mere' <<'END_OF_FILE'
X#! /bin/sh
X# read a man page in the current directory
Xnroff -man -Tman $1 | less -s
END_OF_FILE
if test 84 -ne `wc -c <'func/mere'`; then
echo shar: \"'func/mere'\" unpacked with wrong size!
fi
chmod +x 'func/mere'
# end of 'func/mere'
fi
if test -f 'func/proto' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/proto'\"
else
echo shar: Extracting \"'func/proto'\" \(194 characters\)
sed "s/^X//" >'func/proto' <<'END_OF_FILE'
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
END_OF_FILE
if test 194 -ne `wc -c <'func/proto'`; then
echo shar: \"'func/proto'\" unpacked with wrong size!
fi
chmod +x 'func/proto'
# end of 'func/proto'
fi
if test -f 'func/randline' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/randline'\"
else
echo shar: Extracting \"'func/randline'\" \(80 characters\)
sed "s/^X//" >'func/randline' <<'END_OF_FILE'
X# get a random line from a file
Xinteger z=$(wc -l <$1)
Xsed -n $[RANDOM%z+1]p $1
END_OF_FILE
if test 80 -ne `wc -c <'func/randline'`; then
echo shar: \"'func/randline'\" unpacked with wrong size!
fi
chmod +x 'func/randline'
# end of 'func/randline'
fi
if test -f 'func/yp' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/yp'\"
else
echo shar: Extracting \"'func/yp'\" \(29 characters\)
sed "s/^X//" >'func/yp' <<'END_OF_FILE'
X#! /bin/sh
Xypmatch $1 passwd
END_OF_FILE
if test 29 -ne `wc -c <'func/yp'`; then
echo shar: \"'func/yp'\" unpacked with wrong size!
fi
chmod +x 'func/yp'
# end of 'func/yp'
fi
if test -f 'func/yu' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'func/yu'\"
else
echo shar: Extracting \"'func/yu'\" \(35 characters\)
sed "s/^X//" >'func/yu' <<'END_OF_FILE'
X#! /bin/sh
Xypmatch $1 passwd.byuid
END_OF_FILE
if test 35 -ne `wc -c <'func/yu'`; then
echo shar: \"'func/yu'\" unpacked with wrong size!
fi
chmod +x 'func/yu'
# end of 'func/yu'
fi
if test -f 'help/bg' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/bg'\"
else
echo shar: Extracting \"'help/bg'\" \(145 characters\)
sed "s/^X//" >'help/bg' <<'END_OF_FILE'
X bg [ job ... ]
X job ... &
X Put each specified job in the background, or the
X current job if none is specified.
END_OF_FILE
if test 145 -ne `wc -c <'help/bg'`; then
echo shar: \"'help/bg'\" unpacked with wrong size!
fi
# end of 'help/bg'
fi
if test -f 'help/break' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/break'\"
else
echo shar: Extracting \"'help/break'\" \(180 characters\)
sed "s/^X//" >'help/break' <<'END_OF_FILE'
X break [ n ]
X Exit from an enclosing for, while, until, select, or
X repeat loop. If n is specified, then break n levels
X instead of just one.
END_OF_FILE
if test 180 -ne `wc -c <'help/break'`; then
echo shar: \"'help/break'\" unpacked with wrong size!
fi
# end of 'help/break'
fi
if test -f 'help/builtin' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/builtin'\"
else
echo shar: Extracting \"'help/builtin'\" \(89 characters\)
sed "s/^X//" >'help/builtin' <<'END_OF_FILE'
X builtin name [ args ] ...
X Executes the builtin name, with the given args.
END_OF_FILE
if test 89 -ne `wc -c <'help/builtin'`; then
echo shar: \"'help/builtin'\" unpacked with wrong size!
fi
# end of 'help/builtin'
fi
if test -f 'help/chpwd' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/chpwd'\"
else
echo shar: Extracting \"'help/chpwd'\" \(96 characters\)
sed "s/^X//" >'help/chpwd' <<'END_OF_FILE'
X chpwd
X Executed whenever the current working directory is
X changed.
END_OF_FILE
if test 96 -ne `wc -c <'help/chpwd'`; then
echo shar: \"'help/chpwd'\" unpacked with wrong size!
fi
# end of 'help/chpwd'
fi
if test -f 'help/continue' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/continue'\"
else
echo shar: Extracting \"'help/continue'\" \(240 characters\)
sed "s/^X//" >'help/continue' <<'END_OF_FILE'
X continue [ num ]
X Resume the next iteration of the enclosing for, while,
X until, select, or repeat loop. If n is specified,
X break out of n - 1 loops and resume at the nth enclos-
X ing loop.
END_OF_FILE
if test 240 -ne `wc -c <'help/continue'`; then
echo shar: \"'help/continue'\" unpacked with wrong size!
fi
# end of 'help/continue'
fi
if test -f 'help/coproc' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/coproc'\"
else
echo shar: Extracting \"'help/coproc'\" \(264 characters\)
sed "s/^X//" >'help/coproc' <<'END_OF_FILE'
X If a pipeline is preceded by coproc, it is executed as a
X coprocess; a two-way pipe is established between it and the
X parent shell. The shell can read from or write to the
X coprocess by means of the >&p and <&p redirection operators.
END_OF_FILE
if test 264 -ne `wc -c <'help/coproc'`; then
echo shar: \"'help/coproc'\" unpacked with wrong size!
fi
# end of 'help/coproc'
fi
if test -f 'help/disable' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/disable'\"
else
echo shar: Extracting \"'help/disable'\" \(269 characters\)
sed "s/^X//" >'help/disable' <<'END_OF_FILE'
X disable arg ...
X Disable the builtin arg temporarily. This allows you
X to use an external command with the same name as a
X shell builtin. Actually the same as unhash. Builtins
X can be enabled with the enable command.
END_OF_FILE
if test 269 -ne `wc -c <'help/disable'`; then
echo shar: \"'help/disable'\" unpacked with wrong size!
fi
# end of 'help/disable'
fi
if test -f 'help/disown' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/disown'\"
else
echo shar: Extracting \"'help/disown'\" \(248 characters\)
sed "s/^X//" >'help/disown' <<'END_OF_FILE'
X disown job ...
X Remove the specified jobs from the job table; the shell
X will no longer report their status, and will not com-
X plain if you try to exit an interactive shell with them
X running or stopped.
END_OF_FILE
if test 248 -ne `wc -c <'help/disown'`; then
echo shar: \"'help/disown'\" unpacked with wrong size!
fi
# end of 'help/disown'
fi
if test -f 'help/echotc' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/echotc'\"
else
echo shar: Extracting \"'help/echotc'\" \(138 characters\)
sed "s/^X//" >'help/echotc' <<'END_OF_FILE'
X echotc cap [ arg ... ]
X Output the termcap string corresponding to the capabil-
X ity cap, with optional arguments.
END_OF_FILE
if test 138 -ne `wc -c <'help/echotc'`; then
echo shar: \"'help/echotc'\" unpacked with wrong size!
fi
# end of 'help/echotc'
fi
if test -f 'help/enable' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/enable'\"
else
echo shar: Extracting \"'help/enable'\" \(124 characters\)
sed "s/^X//" >'help/enable' <<'END_OF_FILE'
X enable arg ...
X Enable the specified builtin commands, presumably dis-
X abled earlier with disable.
END_OF_FILE
if test 124 -ne `wc -c <'help/enable'`; then
echo shar: \"'help/enable'\" unpacked with wrong size!
fi
# end of 'help/enable'
fi
if test -f 'help/eval' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/eval'\"
else
echo shar: Extracting \"'help/eval'\" \(153 characters\)
sed "s/^X//" >'help/eval' <<'END_OF_FILE'
X eval [ arg ... ]
X Read the arguments as input to the shell and execute
X the resulting command(s) in the current shell process.
END_OF_FILE
if test 153 -ne `wc -c <'help/eval'`; then
echo shar: \"'help/eval'\" unpacked with wrong size!
fi
# end of 'help/eval'
fi
if test -f 'help/exit' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/exit'\"
else
echo shar: Extracting \"'help/exit'\" \(275 characters\)
sed "s/^X//" >'help/exit' <<'END_OF_FILE'
X exit [ n ]
X Exit the shell with the exit code specified by n; if
X none is specified, use the exit code from the last com-
X mand executed. An EOF condition will also cause the
X shell to exit, unless the IGNOREEOF option is set.
END_OF_FILE
if test 275 -ne `wc -c <'help/exit'`; then
echo shar: \"'help/exit'\" unpacked with wrong size!
fi
# end of 'help/exit'
fi
if test -f 'help/export' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/export'\"
else
echo shar: Extracting \"'help/export'\" \(160 characters\)
sed "s/^X//" >'help/export' <<'END_OF_FILE'
X export [ name[=value] ... ]
X The specified names are marked for automatic export to
X the environment of subsequently executed commands.
END_OF_FILE
if test 160 -ne `wc -c <'help/export'`; then
echo shar: \"'help/export'\" unpacked with wrong size!
fi
# end of 'help/export'
fi
if test -f 'help/fg' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/fg'\"
else
echo shar: Extracting \"'help/fg'\" \(144 characters\)
sed "s/^X//" >'help/fg' <<'END_OF_FILE'
X fg [ job ... ]
X job ...
X Bring the specified jobs to the foreground. If no job
X is specified, use the current job.
END_OF_FILE
if test 144 -ne `wc -c <'help/fg'`; then
echo shar: \"'help/fg'\" unpacked with wrong size!
fi
# end of 'help/fg'
fi
if test -f 'help/getln' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/getln'\"
else
echo shar: Extracting \"'help/getln'\" \(147 characters\)
sed "s/^X//" >'help/getln' <<'END_OF_FILE'
X getln name ...
X Read the top value from the buffer stack and put it in
X the shell parameter name. Equivalent to read -zr.
END_OF_FILE
if test 147 -ne `wc -c <'help/getln'`; then
echo shar: \"'help/getln'\" unpacked with wrong size!
fi
# end of 'help/getln'
fi
if test -f 'help/hash' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/hash'\"
else
echo shar: Extracting \"'help/hash'\" \(362 characters\)
sed "s/^X//" >'help/hash' <<'END_OF_FILE'


X hash name path
X Puts name in the command hash table, associating it
X with the pathname path. Whenever name is used as a
X command argument, the shell will try to execute the
X file given by path.
X unhash name ...
X The entry in the command hash table, if any, for each
X name is removed.
END_OF_FILE

if test 362 -ne `wc -c <'help/hash'`; then
echo shar: \"'help/hash'\" unpacked with wrong size!
fi
# end of 'help/hash'
fi
if test -f 'help/jobs' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/jobs'\"
else
echo shar: Extracting \"'help/jobs'\" \(202 characters\)
sed "s/^X//" >'help/jobs' <<'END_OF_FILE'
X jobs [ -lp ] [ job ... ]
X Lists information about each given job, or all jobs if
X job is omitted. The -l flag lists process ids, and the
X -p flag lists process groups.
END_OF_FILE
if test 202 -ne `wc -c <'help/jobs'`; then
echo shar: \"'help/jobs'\" unpacked with wrong size!
fi
# end of 'help/jobs'
fi
if test -f 'help/let' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/let'\"
else
echo shar: Extracting \"'help/let'\" \(277 characters\)
sed "s/^X//" >'help/let' <<'END_OF_FILE'
X let arg ...
X Evaluate each arg as an arithmetic expression. See
X ARITHMETIC EVALUATION above for a description of arith-
X metic expressions. The exit status is 0 if the value
X of the last expression is nonzero, and 1 otherwise.
END_OF_FILE
if test 277 -ne `wc -c <'help/let'`; then
echo shar: \"'help/let'\" unpacked with wrong size!
fi
# end of 'help/let'
fi
if test -f 'help/log' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/log'\"
else
echo shar: Extracting \"'help/log'\" \(120 characters\)
sed "s/^X//" >'help/log' <<'END_OF_FILE'
X log List all users currently logged in who are affected by
X the current setting of the watch parameter.
END_OF_FILE
if test 120 -ne `wc -c <'help/log'`; then
echo shar: \"'help/log'\" unpacked with wrong size!
fi
# end of 'help/log'
fi
if test -f 'help/periodic' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/periodic'\"
else
echo shar: Extracting \"'help/periodic'\" \(140 characters\)
sed "s/^X//" >'help/periodic' <<'END_OF_FILE'
X periodic
X If the parameter PERIOD is set, this function is exe-
X cuted every PERIOD seconds, just before a prompt.
END_OF_FILE
if test 140 -ne `wc -c <'help/periodic'`; then
echo shar: \"'help/periodic'\" unpacked with wrong size!
fi
# end of 'help/periodic'
fi
if test -f 'help/precmd' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/precmd'\"
else
echo shar: Extracting \"'help/precmd'\" \(51 characters\)
sed "s/^X//" >'help/precmd' <<'END_OF_FILE'
X precmd
X Executed before each prompt.
END_OF_FILE
if test 51 -ne `wc -c <'help/precmd'`; then
echo shar: \"'help/precmd'\" unpacked with wrong size!
fi
# end of 'help/precmd'
fi
if test -f 'help/readonly' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/readonly'\"
else
echo shar: Extracting \"'help/readonly'\" \(148 characters\)
sed "s/^X//" >'help/readonly' <<'END_OF_FILE'
X readonly [ name[=value] ] ...
X The given names are marked readonly; these names cannot
X be changed by subsequent assignment.
END_OF_FILE
if test 148 -ne `wc -c <'help/readonly'`; then
echo shar: \"'help/readonly'\" unpacked with wrong size!
fi
# end of 'help/readonly'
fi
if test -f 'help/rehash' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/rehash'\"
else
echo shar: Extracting \"'help/rehash'\" \(234 characters\)
sed "s/^X//" >'help/rehash' <<'END_OF_FILE'
X rehash [ -f ]
X Throw out the command hash table and start over. If
X the -f option is set, rescan the command path immedi-
X ately, instead of rebuilding the hash table incremen-
X tally.
END_OF_FILE
if test 234 -ne `wc -c <'help/rehash'`; then
echo shar: \"'help/rehash'\" unpacked with wrong size!
fi
# end of 'help/rehash'
fi
if test -f 'help/repeat' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/repeat'\"
else
echo shar: Extracting \"'help/repeat'\" \(247 characters\)
sed "s/^X//" >'help/repeat' <<'END_OF_FILE'
X repeat word
X do list
X done word is expanded and treated as an arithmetic
X expression, which must evaluate to a number n.
X list is then executed n times.
X
X repeat word sublist
X This is a short form of repeat.
END_OF_FILE
if test 247 -ne `wc -c <'help/repeat'`; then
echo shar: \"'help/repeat'\" unpacked with wrong size!
fi
# end of 'help/repeat'
fi
if test -f 'help/return' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/return'\"
else
echo shar: Extracting \"'help/return'\" \(249 characters\)
sed "s/^X//" >'help/return' <<'END_OF_FILE'
X return [ n ]
X Causes a shell function or . script to return to the
X invoking script with the return status specified by n.
X If n is omitted then the return status is that of the
X last command executed.
END_OF_FILE
if test 249 -ne `wc -c <'help/return'`; then
echo shar: \"'help/return'\" unpacked with wrong size!
fi
# end of 'help/return'
fi
if test -f 'help/sched' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/sched'\"
else
echo shar: Extracting \"'help/sched'\" \(357 characters\)
sed "s/^X//" >'help/sched' <<'END_OF_FILE'
X sched [+]hh:mm command ...
X sched [ -item ]
X Make an entry in the scheduled list of commands to exe-
X cute. The time may be specified in either absolute or
X relative time. With no arguments, prints the list of
X scheduled commands. With the argument -item, removes
X the given item from the list.
END_OF_FILE
if test 357 -ne `wc -c <'help/sched'`; then
echo shar: \"'help/sched'\" unpacked with wrong size!
fi
# end of 'help/sched'
fi
if test -f 'help/shift' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/shift'\"
else
echo shar: Extracting \"'help/shift'\" \(149 characters\)
sed "s/^X//" >'help/shift' <<'END_OF_FILE'
X shift [ n ]
X The positional parameters from $n+1 ... are renamed $1,
X where n is an arithmetic expression that defaults to 1.
END_OF_FILE
if test 149 -ne `wc -c <'help/shift'`; then
echo shar: \"'help/shift'\" unpacked with wrong size!
fi
# end of 'help/shift'
fi
if test -f 'help/suspend' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/suspend'\"
else
echo shar: Extracting \"'help/suspend'\" \(204 characters\)
sed "s/^X//" >'help/suspend' <<'END_OF_FILE'
X suspend [ -f ]
X Suspend the execution of the shell (send it a SIGTSTP)
X until it receives a SIGCONT. If the -f option is not
X given, complain if this is a login shell.
END_OF_FILE
if test 204 -ne `wc -c <'help/suspend'`; then
echo shar: \"'help/suspend'\" unpacked with wrong size!
fi
# end of 'help/suspend'
fi
if test -f 'help/test' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/test'\"
else
echo shar: Extracting \"'help/test'\" \(153 characters\)
sed "s/^X//" >'help/test' <<'END_OF_FILE'
X test arg ...
X [ arg ... ]
X Like the system version of test. Added for compatibil-
X ity; use conditional expressions instead.
END_OF_FILE
if test 153 -ne `wc -c <'help/test'`; then
echo shar: \"'help/test'\" unpacked with wrong size!
fi
# end of 'help/test'
fi
if test -f 'help/time' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/time'\"
else
echo shar: Extracting \"'help/time'\" \(271 characters\)
sed "s/^X//" >'help/time' <<'END_OF_FILE'
X time [ pipeline ]
X The pipeline is executed, and timing statistics
X are reported on the standard error in the form
X specified by the TIMEFMT parameter. If pipeline
X is omitted, print statistics about the shell pro-
X cess and its children.
END_OF_FILE
if test 271 -ne `wc -c <'help/time'`; then
echo shar: \"'help/time'\" unpacked with wrong size!
fi
# end of 'help/time'
fi
if test -f 'help/times' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/times'\"
else
echo shar: Extracting \"'help/times'\" \(131 characters\)
sed "s/^X//" >'help/times' <<'END_OF_FILE'
X times
X Print the accumulated user and system times for the
X shell and for processes run from the shell.
END_OF_FILE
if test 131 -ne `wc -c <'help/times'`; then
echo shar: \"'help/times'\" unpacked with wrong size!
fi
# end of 'help/times'
fi
if test -f 'help/umask' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/umask'\"
else
echo shar: Extracting \"'help/umask'\" \(212 characters\)
sed "s/^X//" >'help/umask' <<'END_OF_FILE'
X umask [ mask ]
X The umask is set to mask. mask can be either an octal
X number or a symbolic value as described in chmod(1).
X If mask is omitted, the current value is printed.
END_OF_FILE
if test 212 -ne `wc -c <'help/umask'`; then
echo shar: \"'help/umask'\" unpacked with wrong size!
fi
# end of 'help/umask'
fi
if test -f 'help/unfunction' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/unfunction'\"
else
echo shar: Extracting \"'help/unfunction'\" \(110 characters\)
sed "s/^X//" >'help/unfunction' <<'END_OF_FILE'
X unfunction name ...
X The function definition, if any, for each name is
X removed.
END_OF_FILE
if test 110 -ne `wc -c <'help/unfunction'`; then
echo shar: \"'help/unfunction'\" unpacked with wrong size!
fi
# end of 'help/unfunction'
fi
if test -f 'help/unlimit' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/unlimit'\"
else
echo shar: Extracting \"'help/unlimit'\" \(253 characters\)
sed "s/^X//" >'help/unlimit' <<'END_OF_FILE'
X unlimit [ -h ] resource ...
X The resource limit for each resource is set to the hard
X limit. If the -h flag is given and the shell is run-
X ning as root, the hard resource limit for each resource
X is removed.
END_OF_FILE
if test 253 -ne `wc -c <'help/unlimit'`; then
echo shar: \"'help/unlimit'\" unpacked with wrong size!
fi
# end of 'help/unlimit'
fi
if test -f 'help/until' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/until'\"
else
echo shar: Extracting \"'help/until'\" \(120 characters\)
sed "s/^X//" >'help/until' <<'END_OF_FILE'
X until list
X do list
X done Execute the do list as long as until list returns
X a nonzero exit status.
END_OF_FILE
if test 120 -ne `wc -c <'help/until'`; then
echo shar: \"'help/until'\" unpacked with wrong size!
fi
# end of 'help/until'
fi
if test -f 'help/vared' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/vared'\"
else
echo shar: Extracting \"'help/vared'\" \(236 characters\)
sed "s/^X//" >'help/vared' <<'END_OF_FILE'
X vared name
X The value of the parameter name is loaded into the edit
X buffer, and the line editor is invoked. When the edi-
X tor exits, name is set to the string value returned by
X the editor.
END_OF_FILE
if test 236 -ne `wc -c <'help/vared'`; then
echo shar: \"'help/vared'\" unpacked with wrong size!
fi
# end of 'help/vared'
fi
if test -f 'help/wait' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/wait'\"
else
echo shar: Extracting \"'help/wait'\" \(352 characters\)
sed "s/^X//" >'help/wait' <<'END_OF_FILE'
X wait [ job ... ]
X Wait for the specified jobs or processes. If job is
X not given then all currently active child processes are
X waited for. Each job can be either a job specification
X or the process-id of a job in the job table. The exit
X status from this command is that of the job waited for.
END_OF_FILE
if test 352 -ne `wc -c <'help/wait'`; then
echo shar: \"'help/wait'\" unpacked with wrong size!
fi
# end of 'help/wait'
fi
if test -f 'help/while' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'help/while'\"
else
echo shar: Extracting \"'help/while'\" \(199 characters\)
sed "s/^X//" >'help/while' <<'END_OF_FILE'
X while list
X do list
X done Execute the do list as long as the while list
X returns a zero exit status.
X
X while ( list ) {
X list
X } An alternate form of while.
END_OF_FILE
if test 199 -ne `wc -c <'help/while'`; then
echo shar: \"'help/while'\" unpacked with wrong size!
fi
# end of 'help/while'
fi
if test -f 'src/version.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/version.h'\"
else
echo shar: Extracting \"'src/version.h'\" \(32 characters\)
sed "s/^X//" >'src/version.h' <<'END_OF_FILE'
X#define VERSIONSTR "zsh v2.3.1"
END_OF_FILE
if test 32 -ne `wc -c <'src/version.h'`; then
echo shar: \"'src/version.h'\" unpacked with wrong size!
fi
# end of 'src/version.h'
fi
echo shar: End of archive 22 \(of 22\).
cp /dev/null ark22isdone


MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 22 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone

echo Concatenating pieces...
cat doc/intro.troff.0[1-9] >doc/intro.troff && rm doc/intro.troff.0[1-9]
cat doc/intro.txt.0[1-9] >doc/intro.txt && rm doc/intro.txt.0[1-9]
cat doc/zsh.texi.0[1-9] >doc/zsh.texi && rm doc/zsh.texi.0[1-9]
cat man/man1/zsh.1.0[1-9] >man/man1/zsh.1 && rm man/man1/zsh.1.0[1-9]
cat src/builtin.c.0[1-9] >src/builtin.c && rm src/builtin.c.0[1-9]

0 new messages