v24i001: zsh2.1 - The Z shell, Part01/19

17 views
Skip to first unread message

Paul Falstad

unread,
Oct 24, 1991, 3:06:13 PM10/24/91
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 24, Issue 1
Archive-name: zsh2.1/part01
Environment: BSD
Supersedes: zsh2.00: Volume 18, Issue 84-98

This is zsh 2.1.0, written by Paul Falstad (pfal...@phoenix.princeton.edu).
I've tested it on the following machines, where it compiled just by running
a shell script:

Sun SPARCServer 4/490 running SunOS 4.1.1
NeXTstation running Mach 2.0
DECSystem-5000 running ULTRIX 4.2
Sun 3/50M running SunOS 4.0
Iris 4D/20 running IRIX 3.3.1
Tahoe running BSD 4.3 tahoe
HP 9000/855 running HP-UX 8.0
HP 9000/370 running HP-UX 7.05

It should be easier to port the shell to different architectures now.
The reason it won't run on SysV-like machines is that I don't have
access to any SysV-like machines. I'd love to have someone help port the
shell to other architectures.

Basically, zsh is a shell with most of the features of tcsh, ksh,
and bash, plus a few more. The input syntax is mostly ksh-like, though
csh syntax is also accepted in most cases; plus, almost all of the
bells and whistles of other shells have been included.

A PostScript version of "An Introduction to the Z Shell" has also been
included with this distribution.

You can ftp the distribution (or just the introduction) from cs.ucsd.edu
(132.239.51.3) as "/pub/zsh/{zsh2.1.0.tar.Z,intro.ps.Z}".

This version supersedes zsh2.0.?. Major changes in this version:

1. Parser was rewritten and improved. All the old syntax is still
accepted, with the addition of some other command forms.

2. Almost all known bugs (from previous releases) have been fixed. It
won't sit around after the connection closes anymore. It won't die
if you press TAB inside a `...` expression. It won't mangle your
tty settings, since it doesn't fiddle with the tty as much. Plus,
lots of little bugs have been fixed.

3. The completion has been improved; hostname completion is supported
now. If you give the shell a list of hosts, you can type
"telnet hostn[tab]" and it will complete the hostname. Plus you can
say "bindkey control-whatever forward-w[tab]", and "vared PRO[tab]",
and "echo $PRIN[tab]", and "setopt cshnul[tab]", and
"mail foobar@foohos[tab]", etc.

4. vi-mode emulation has been improved. All the fancy stuff is there,
like multiple buffers and repeat-last-change, and a real insert mode.

Paul
-----
#!/bin/sh
# This is zsh2.1.0, a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 10/19/1991 01:07 UTC by pfalstad@phoenix
# Source directory /n/homeserver/c/pfalstad/zshdist
#
# existing files will NOT be overwritten unless -c is specified
#
# This is part 1 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 12488 -rw-r--r-- zsh2.1/COPYING
# 10214 -rw-r--r-- zsh2.1/README
# 1295 -rw-r--r-- zsh2.1/dots/zlogin
# 3170 -rw-r--r-- zsh2.1/dots/zshrc
# 104 -rwxr-xr-x zsh2.1/func/acx
# 109 -rwxr-xr-x zsh2.1/func/cx
# 97 -rwxr-xr-x zsh2.1/func/harden
# 84 -rwxr-xr-x zsh2.1/func/mere
# 412 -rwxr-xr-x zsh2.1/func/namedir
# 194 -rwxr-xr-x zsh2.1/func/proto
# 80 -rwxr-xr-x zsh2.1/func/randline
# 29 -rwxr-xr-x zsh2.1/func/yp
# 35 -rwxr-xr-x zsh2.1/func/yu
# 107626 -rw-r--r-- zsh2.1/man/man1/zsh.1
# 755 -rwxr-xr-x zsh2.1/scripts/aproto
# 173 -rwxr-xr-x zsh2.1/scripts/fproto
# 3299 -rwxr-xr-x zsh2.1/scripts/c2z
# 8053 -rwxr-xr-x zsh2.1/src/buildzsh
# 56254 -rw-r--r-- zsh2.1/src/builtin.c
# 4485 -rw-r--r-- zsh2.1/src/cond.c
# 33003 -rw-r--r-- zsh2.1/src/exec.c
# 1198 -rw-r--r-- zsh2.1/src/funcs.h
# 23323 -rw-r--r-- zsh2.1/src/glob.c
# 24813 -rw-r--r-- zsh2.1/src/hist.c
# 12375 -rw-r--r-- zsh2.1/src/init.c
# 14918 -rw-r--r-- zsh2.1/src/jobs.c
# 15750 -rw-r--r-- zsh2.1/src/lex.c
# 4854 -rw-r--r-- zsh2.1/src/loop.c
# 10626 -rw-r--r-- zsh2.1/src/math.c
# 5007 -rw-r--r-- zsh2.1/src/mem.c
# 24528 -rw-r--r-- zsh2.1/src/params.c
# 15253 -rw-r--r-- zsh2.1/src/subst.c
# 6824 -rw-r--r-- zsh2.1/src/table.c
# 8703 -rw-r--r-- zsh2.1/src/text.c
# 30675 -rw-r--r-- zsh2.1/src/utils.c
# 7508 -rw-r--r-- zsh2.1/src/watch.c
# 8481 -rw-r--r-- zsh2.1/src/zle.h
# 17489 -rw-r--r-- zsh2.1/src/zle_bindings.c
# 14557 -rw-r--r-- zsh2.1/src/zle_main.c
# 12102 -rw-r--r-- zsh2.1/src/zle_refresh.c
# 4954 -rw-r--r-- zsh2.1/src/zle_utils.c
# 30146 -rw-r--r-- zsh2.1/src/zsh.h
# 5031 -rw-r--r-- zsh2.1/src/zle_vi.c
# 1927 -rw-r--r-- zsh2.1/src/ztype.h
# 309 -rw-r--r-- zsh2.1/src/lex.pro
# 24239 -rw-r--r-- zsh2.1/src/zle_tricky.c
# 3753 -rw-r--r-- zsh2.1/src/builtin.pro
# 235 -rw-r--r-- zsh2.1/src/cond.pro
# 2109 -rw-r--r-- zsh2.1/src/exec.pro
# 1511 -rw-r--r-- zsh2.1/src/glob.pro
# 1737 -rw-r--r-- zsh2.1/src/hist.pro
# 453 -rw-r--r-- zsh2.1/src/init.pro
# 789 -rw-r--r-- zsh2.1/src/jobs.pro
# 206 -rw-r--r-- zsh2.1/src/loop.pro
# 291 -rw-r--r-- zsh2.1/src/math.pro
# 510 -rw-r--r-- zsh2.1/src/mem.pro
# 3148 -rw-r--r-- zsh2.1/src/params.pro
# 619 -rw-r--r-- zsh2.1/src/subst.pro
# 889 -rw-r--r-- zsh2.1/src/table.pro
# 330 -rw-r--r-- zsh2.1/src/text.pro
# 2983 -rw-r--r-- zsh2.1/src/utils.pro
# 371 -rw-r--r-- zsh2.1/src/watch.pro
# 0 -rw-r--r-- zsh2.1/src/zle_bindings.pro
# 659 -rw-r--r-- zsh2.1/src/zle_main.pro
# 596 -rw-r--r-- zsh2.1/src/zle_refresh.pro
# 759 -rw-r--r-- zsh2.1/src/zle_vi.pro
# 1036 -rw-r--r-- zsh2.1/src/parse.pro
# 1712 -rw-r--r-- zsh2.1/src/zle_tricky.pro
# 18604 -rw-r--r-- zsh2.1/src/parse.c
# 675 -rw-r--r-- zsh2.1/src/zle_utils.pro
# 1429 -rw-r--r-- zsh2.1/src/signals.h.sample
# 5546 -rw-r--r-- zsh2.1/src/zle_move.c
# 9823 -rw-r--r-- zsh2.1/src/zle_misc.c
# 5509 -rw-r--r-- zsh2.1/src/zle_word.c
# 10175 -rw-r--r-- zsh2.1/src/zle_hist.c
# 1119 -rw-r--r-- zsh2.1/src/zle_hist.pro
# 1332 -rw-r--r-- zsh2.1/src/zle_misc.pro
# 909 -rw-r--r-- zsh2.1/src/zle_move.pro
# 658 -rw-r--r-- zsh2.1/src/zle_word.pro
# 137468 -rw-r--r-- zsh2.1/doc/intro.ps
#
if test -r _shar_seq_.tmp; then
echo 'Must unpack archives in sequence!'
echo Please unpack part `cat _shar_seq_.tmp` next
exit 1
fi
# ============= zsh2.1/COPYING ==============
if test ! -d 'zsh2.1'; then
echo 'x - creating directory zsh2.1'
mkdir 'zsh2.1'
fi
if test -f 'zsh2.1/COPYING' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/COPYING (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/COPYING (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/COPYING' &&
X
X GNU GENERAL PUBLIC LICENSE
X Version 1, February 1989
X
X Copyright (C) 1989 Free Software Foundation, Inc.
X 675 Mass Ave, Cambridge, MA 02139, USA
X Everyone is permitted to copy and distribute verbatim copies
X of this license document, but changing it is not allowed.
X
X Preamble
X
X The license agreements of most software companies try to keep users
Xat the mercy of those companies. By contrast, our General Public
XLicense is intended to guarantee your freedom to share and change free
Xsoftware--to make sure the software is free for all its users. The
XGeneral Public License applies to the Free Software Foundation's
Xsoftware and to any other program whose authors commit to using it.
XYou can use it for your programs, too.
X
X When we speak of free software, we are referring to freedom, not
Xprice. Specifically, the General Public License is designed to make
Xsure that you have the freedom to give away or sell copies of free
Xsoftware, that you receive source code or can get it if you want it,
Xthat you can change the software or use pieces of it in new free
Xprograms; and that you know you can do these things.
X
X To protect your rights, we need to make restrictions that forbid
Xanyone to deny you these rights or to ask you to surrender the rights.
XThese restrictions translate to certain responsibilities for you if you
Xdistribute copies of the software, or if you modify it.
X
X For example, if you distribute copies of a such a program, whether
Xgratis or for a fee, you must give the recipients all the rights that
Xyou have. You must make sure that they, too, receive or can get the
Xsource code. And you must tell them their rights.
X
X We protect your rights with two steps: (1) copyright the software, and
X(2) offer you this license which gives you legal permission to copy,
Xdistribute and/or modify the software.
X
X Also, for each author's protection and ours, we want to make certain
Xthat everyone understands that there is no warranty for this free
Xsoftware. If the software is modified by someone else and passed on, we
Xwant its recipients to know that what they have is not the original, so
Xthat any problems introduced by others will not reflect on the original
Xauthors' reputations.
X
X The precise terms and conditions for copying, distribution and
Xmodification follow.
X
X GNU GENERAL PUBLIC LICENSE
X TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
X
X 0. This License Agreement applies to any program or other work which
Xcontains a notice placed by the copyright holder saying it may be
Xdistributed under the terms of this General Public License. The
X"Program", below, refers to any such program or work, and a "work based
Xon the Program" means either the Program or any work containing the
XProgram or a portion of it, either verbatim or with modifications. Each
Xlicensee is addressed as "you".
X
X 1. You may copy and distribute verbatim copies of the Program's source
Xcode as you receive it, in any medium, provided that you conspicuously and
Xappropriately publish on each copy an appropriate copyright notice and
Xdisclaimer of warranty; keep intact all the notices that refer to this
XGeneral Public License and to the absence of any warranty; and give any
Xother recipients of the Program a copy of this General Public License
Xalong with the Program. You may charge a fee for the physical act of
Xtransferring a copy.
X
X 2. You may modify your copy or copies of the Program or any portion of
Xit, and copy and distribute such modifications under the terms of Paragraph
X1 above, provided that you also do the following:
X
X a) cause the modified files to carry prominent notices stating that
X you changed the files and the date of any change; and
X
X b) cause the whole of any work that you distribute or publish, that
X in whole or in part contains the Program or any part thereof, either
X with or without modifications, to be licensed at no charge to all
X third parties under the terms of this General Public License (except
X that you may choose to grant warranty protection to some or all
X third parties, at your option).
X
X c) If the modified program normally reads commands interactively when
X run, you must cause it, when started running for such interactive use
X in the simplest and most usual way, to print or display an
X announcement including an appropriate copyright notice and a notice
X that there is no warranty (or else, saying that you provide a
X warranty) and that users may redistribute the program under these
X conditions, and telling the user how to view a copy of this General
X Public License.
X
X d) You may charge a fee for the physical act of transferring a
X copy, and you may at your option offer warranty protection in
X exchange for a fee.
X
XMere aggregation of another independent work with the Program (or its
Xderivative) on a volume of a storage or distribution medium does not bring
Xthe other work under the scope of these terms.
X
X 3. You may copy and distribute the Program (or a portion or derivative of
Xit, under Paragraph 2) in object code or executable form under the terms of
XParagraphs 1 and 2 above provided that you also do one of the following:
X
X a) accompany it with the complete corresponding machine-readable
X source code, which must be distributed under the terms of
X Paragraphs 1 and 2 above; or,
X
X b) accompany it with a written offer, valid for at least three
X years, to give any third party free (except for a nominal charge
X for the cost of distribution) a complete machine-readable copy of the
X corresponding source code, to be distributed under the terms of
X Paragraphs 1 and 2 above; or,
X
X c) accompany it with the information you received as to where the
X corresponding source code may be obtained. (This alternative is
X allowed only for noncommercial distribution and only if you
X received the program in object code or executable form alone.)
X
XSource code for a work means the preferred form of the work for making
Xmodifications to it. For an executable file, complete source code means
Xall the source code for all modules it contains; but, as a special
Xexception, it need not include source code for modules which are standard
Xlibraries that accompany the operating system on which the executable
Xfile runs, or for standard header files or definitions files that
Xaccompany that operating system.
X
X 4. You may not copy, modify, sublicense, distribute or transfer the
XProgram except as expressly provided under this General Public License.
XAny attempt otherwise to copy, modify, sublicense, distribute or transfer
Xthe Program is void, and will automatically terminate your rights to use
Xthe Program under this License. However, parties who have received
Xcopies, or rights to use copies, from you under this General Public
XLicense will not have their licenses terminated so long as such parties
Xremain in full compliance.
X
X 5. By copying, distributing or modifying the Program (or any work based
Xon the Program) you indicate your acceptance of this license to do so,
Xand all its terms and conditions.
X
X 6. Each time you redistribute the Program (or any work based on the
XProgram), the recipient automatically receives a license from the original
Xlicensor to copy, distribute or modify the Program subject to these
Xterms and conditions. You may not impose any further restrictions on the
Xrecipients' exercise of the rights granted herein.
X
X 7. The Free Software Foundation may publish revised and/or new versions
Xof the General Public License from time to time. Such new versions will
Xbe similar in spirit to the present version, but may differ in detail to
Xaddress new problems or concerns.
X
XEach version is given a distinguishing version number. If the Program
Xspecifies a version number of the license which applies to it and "any
Xlater version", you have the option of following the terms and conditions
Xeither of that version or of any later version published by the Free
XSoftware Foundation. If the Program does not specify a version number of
Xthe license, you may choose any version ever published by the Free Software
XFoundation.
X
X 8. If you wish to incorporate parts of the Program into other free
Xprograms whose distribution conditions are different, write to the author
Xto ask for permission. For software which is copyrighted by the Free
XSoftware Foundation, write to the Free Software Foundation; we sometimes
Xmake exceptions for this. Our decision will be guided by the two goals
Xof preserving the free status of all derivatives of our free software and
Xof promoting the sharing and reuse of software generally.
X
X NO WARRANTY
X
X 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
XOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
XPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
XTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
XPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
XREPAIR OR CORRECTION.
X
X 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
XWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
XREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
XINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
XOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
XTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
XYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
XPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
XPOSSIBILITY OF SUCH DAMAGES.
X
X END OF TERMS AND CONDITIONS
X
X Appendix: How to Apply These Terms to Your New Programs
X
X If you develop a new program, and you want it to be of the greatest
Xpossible use to humanity, the best way to achieve this is to make it
Xfree software which everyone can redistribute and change under these
Xterms.
X
X To do so, attach the following notices to the program. It is safest to
Xattach them to the start of each source file to most effectively convey
Xthe exclusion of warranty; and each file should have at least the
X"copyright" line and a pointer to where the full notice is found.
X
X <one line to give the program's name and a brief idea of what it does.>
X Copyright (C) 19yy <name of author>
X
X This program is free software; you can redistribute it and/or modify
X it under the terms of the GNU General Public License as published by
X the Free Software Foundation; either version 1, or (at your option)
X any later version.
X
X This program is distributed in the hope that it will be useful,
X but WITHOUT ANY WARRANTY; without even the implied warranty of
X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
X GNU General Public License for more details.
X
X You should have received a copy of the GNU General Public License
X along with this program; if not, write to the Free Software
X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
X
XAlso add information on how to contact you by electronic and paper mail.
X
XIf the program is interactive, make it output a short notice like this
Xwhen it starts in an interactive mode:
X
X Gnomovision version 69, Copyright (C) 19xx name of author
X Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
X This is free software, and you are welcome to redistribute it
X under certain conditions; type `show c' for details.
X
XThe hypothetical commands `show w' and `show c' should show the
Xappropriate parts of the General Public License. Of course, the
Xcommands you use may be called something other than `show w' and `show
Xc'; they could even be mouse-clicks or menu items--whatever suits your
Xprogram.
X
XYou should also get your employer (if you work as a programmer) or your
Xschool, if any, to sign a "copyright disclaimer" for the program, if
Xnecessary. Here a sample; alter the names:
X
X Yoyodyne, Inc., hereby disclaims all copyright interest in the
X program `Gnomovision' (a program to direct compilers to make passes
X at assemblers) written by James Hacker.
X
X <signature of Ty Coon>, 1 April 1989
X Ty Coon, President of Vice
X
XThat's all there is to it!
SHAR_EOF
chmod 0644 zsh2.1/COPYING ||
echo 'restore of zsh2.1/COPYING failed'
Wc_c="`wc -c < 'zsh2.1/COPYING'`"
test 12488 -eq "$Wc_c" ||
echo 'zsh2.1/COPYING: original size 12488, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/README ==============
if test -f 'zsh2.1/README' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/README (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/README' &&
Xzsh is free software. See the file COPYING for copying permission.
X
XThis is zsh 2.1.0, written by Paul Falstad (pfal...@phoenix.princeton.edu).
X
XTo get this shell running, cd into the src directory and type
X"buildzsh". I tested it on the following machines, where it compiled
Xjust by running this script:
X
XSun SPARCServer 4/490 running SunOS 4.1.1
XNeXTstation running Mach 2.0
XDECSystem-5000 running ULTRIX 4.2
XSun 3/50M running SunOS 4.0
XIris 4D/20 running IRIX 3.3.1
XTahoe running BSD 4.3 tahoe
XHP 9000/855 running HP-UX 8.0
XHP 9000/370 running HP-UX 7.05
X
XIt should be easier to port the shell to different architectures now.
XThe reason it hasn't been tested on SysV-like machines is that I don't
Xhave access to any SysV-like machines. I'd love to have someone port
Xthe shell to other architectures.
X
XTabstops are 3 spaces. If you're going to look at my code, run it
Xthough "expand -3" first, or set your tab stops to the same as mine.
X
XIf anyone has any questions, suggestions, comments, bugs, flames, or
Xany other mail of any kind, send it to pfal...@phoenix.princeton.edu.
X
XThanks to the following people for help, ideas, comments, patches, etc.:
X
XDavid Dobkin
XJim Mattson
XGoran Larsson
XBart Schaefer
XPaul E. Maisano
XNorbert Kiesel
XJosh Diamond
XPeter Moore
XGeoff Wing
XKent Dickey
XJean-Jacques Moreau
XMichael Brown
XBruce Anderson
XCarson Wilson (too bad my email to him bounces)
XStephen Dum
XLars E. Thon
XMichael Brennan
XXev Gittler
XJarkko Hietaniemi
XZbigniew J Tyrlik
XPierre Racz
XRick Ohnemus
XRichard Dean
XGary D. Kline
XRobert A. Fabian
XByron Rakitzis
XGottfried Necker
XDan Bernstein
XVincent Granet
XJonathan I. Kamens & Bruce Varney
XDavid Wilson
XPeter Gray
XGreg Noel
XPaul Lew
XKartik Subbarao
XMichael Marucheck
XChristopher Pirazzi
XSteve Giovanetti
XKennedy Lemke
XEmin Gun Sirer
XKazuo Itoh
Xlots of other people, I'm sure
X
XModification history:
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 - here documents don't appear in the history, and cannot be
X used inside eval statements
X
SHAR_EOF
chmod 0644 zsh2.1/README ||
echo 'restore of zsh2.1/README failed'
Wc_c="`wc -c < 'zsh2.1/README'`"
test 10214 -eq "$Wc_c" ||
echo 'zsh2.1/README: original size 10214, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/dots/zlogin ==============
if test ! -d 'zsh2.1/dots'; then
echo 'x - creating directory zsh2.1/dots'
mkdir 'zsh2.1/dots'
fi
if test -f 'zsh2.1/dots/zlogin' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/dots/zlogin (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/dots/zlogin (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/dots/zlogin' &&
X#
X# my login file for zsh
X#
Xclear
Xcd
Xstty dec new cr0
X
X# nice little thing that figures out my termtype based on where I logged
X# in from
X
X
X# get the hostname of where I logged in from
Xsetopt nobanghist
XFROM=$(who said that | sed 's/^.*(\([^.:!]*\).*).*$/\1/')
Xunsetopt nobanghist
X
Xcase "$FROM" {
Xlearning*)
X FROMTYPE=SUNOS-4.1
X stty rows 54 ;;
Xunix*)
X FROM=$(hostname)
X FROMTYPE="$(host -t hinfo $FROM | sed 's/^.*HINFO//')" ;;
X*)
X FROMTYPE="$(host -t hinfo $FROM | sed 's/^.*HINFO//')" ;;
X}
X
X# got the type of host from DNS; set up things accordingly
X
Xcase "$FROMTYPE" {
X*CISCO*)
X eval $(tset -s vt100-new)
X FROM=comserv
X export PRINTER=dod; 48; BAUD=1800; ;;
X*MAC-OS*|*MS-DOS*|*IBM*) eval $(tset -s vt100)
X export PRINTER=edwards; FROM=madison;;
X*SUNOS-4.1*) eval $(tset -s xterm); export DISPLAY=$FROM:0.0; FROM=sun
X stty erase ; export PRINTER=ps1 ;;
X*SGI*) eval $(tset -s iris-ansi) ; export PRINTER=gutenberg
X export DISPLAY=$FROM:0.0; FROM=iris; stty erase \^H ;;
X*NCD*) eval $(tset -s vt100) ; export DISPLAY=$FROM:0.0;;
X*) eval $(tset -s -Q '?vt100') ;;
X}
Xcase "$FROM" in dndod*) export PRINTER=dod;; esac
X
Xstty -tabs
Xumask 022
Xexport MAIL=/usr/spool/mail/$USER
XMAILCHECK=60
Xstty columns 80
Xmesg y
Xuptime
Xfortune
Xlog
Xfrom 2>/dev/null
X< notes
Xunlimit
Xlimit core 0
Xmsgs -fp
Xpmsgs -q
SHAR_EOF
chmod 0644 zsh2.1/dots/zlogin ||
echo 'restore of zsh2.1/dots/zlogin failed'
Wc_c="`wc -c < 'zsh2.1/dots/zlogin'`"
test 1295 -eq "$Wc_c" ||
echo 'zsh2.1/dots/zlogin: original size 1295, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/dots/zshrc ==============
if test -f 'zsh2.1/dots/zshrc' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/dots/zshrc (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/dots/zshrc (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/dots/zshrc' &&
X#
X# my rc file for zsh 2.1
X#
X
X# it's actually better to set up the path in .zshenv
Xpath=(~/scr ~/bin/$HOSTTYPE
X ~maruchck/scr ~subbarao/bin ~subbarao/bin/$HOSTTYPE
X ~maruchck/bin ~subbarao/scripts
X /usr/princeton/bin /usr/ucb /usr/bin /bin
X /usr/hosts /usr/princeton/bin/X11 /./usr/lang /./usr/etc /./etc
X ~/src/zsh/bin .)
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 077
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# now you can say "<< foo" to more something
Xa '<<'=more
X
X# global aliases
Xa -g 'GF'='| fgrep -f ~/.friends' G='| grep' M='| less' cex='/u/pup/centrex'
Xa -g cpz=cpirazzi gun=egsirer me=pfalstad mjm=maruchck paswd='<(ypcat passwd)'
Xa -g sub=subbarao 'suk*=sukthnkr' tike=teichbrg
Xa -g phx=phoenix sms=dendrite.siemens.com CS=dynamic
X
X# setenv for csh junkies (including tset)
Xsetenv() { export $1=$2 }
X
X# useful directories
Xcpz=~cpirazzi gun=~egsirer mjm=~maruchck sub=~subbarao
X
Xexport MANPATH=/usr/man:/usr/princeton/man:/u/cad/man:/usr/lang/man
X
X# the rest is for interactive shells only
Xif [[ ! -o interactive ]]
Xthen
X return
Xfi
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
X# useful directories
Xzsh=~/zsh2.00/src
X: ~zsh ~csrc ~cpz ~gun ~mjm ~sub
X
XPROMPT='%l %T %m[%h] '
X
X# prompt on the right side of the screen
XRPROMPT=' %~'
X
X# some environment variables
X!" export MAILCALL='NEW MAIL! '
Xexport NAME='Paul Falstad'
Xexport ORGANIZATION='League For Fighting Chartered Accountancy'
Xexport YOUSAID='In %C you wrote:'
Xexport ATTRIBUTION='%f wrote:'
Xexport SHELL=/u/pfalstad/bin/sun4/zsh
Xexport RNINIT=/u/pfalstad/.rninit
X
X# functions to autoload
X# autoload cx acx mere yu yp randline proto namedir ilogin
X
XMAILCHECK=30
XHISTSIZE=600
XDIRSTACKSIZE=50
X
X# lots of options
Xsetopt notify globdots correct pushdtohome cdablevars autolist \
X sunkeyboardhack correctall autocd recexact longlistjobs mailwarning \
X autoresume histignoredups pushdsilent noclobber \
X autopushd pushdminus extendedglob rcquotes
Xunsetopt bgnice
X
X# watch for my friends
Xwatch=($(cat ~/.friends))
XWATCHFMT='%n %a %l from %m at %t.'
XLOGCHECK=0
X
Xexport LESS=-ainx3
Xunhash p
X
X# some nice bindings
Xbindkey '^X^Z' universal-argument ' ' magic-space
Xbindkey '^X^A' vi-find-prev-char-skip
Xbindkey '^Z' accept-and-hold
Xbindkey -s '\M-/' \\\\
Xbindkey -s '\M-=' \|
SHAR_EOF
chmod 0644 zsh2.1/dots/zshrc ||
echo 'restore of zsh2.1/dots/zshrc failed'
Wc_c="`wc -c < 'zsh2.1/dots/zshrc'`"
test 3170 -eq "$Wc_c" ||
echo 'zsh2.1/dots/zshrc: original size 3170, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/func/acx ==============
if test ! -d 'zsh2.1/func'; then
echo 'x - creating directory zsh2.1/func'
mkdir 'zsh2.1/func'
fi
if test -f 'zsh2.1/func/acx' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/func/acx (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/func/acx (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/func/acx' &&
X#! /bin/sh
X#
X# zsh shell function to make its arguments 755
X# also works as an sh script
X#
Xchmod 755 $*
SHAR_EOF
chmod 0755 zsh2.1/func/acx ||
echo 'restore of zsh2.1/func/acx failed'
Wc_c="`wc -c < 'zsh2.1/func/acx'`"
test 104 -eq "$Wc_c" ||
echo 'zsh2.1/func/acx: original size 104, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/func/cx ==============
if test -f 'zsh2.1/func/cx' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/func/cx (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/func/cx (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/func/cx' &&
X#! /bin/sh
X#
X# zsh shell function to make its arguments executable
X# also works as a sh script
X#
Xchmod +x $*
SHAR_EOF
chmod 0755 zsh2.1/func/cx ||
echo 'restore of zsh2.1/func/cx failed'
Wc_c="`wc -c < 'zsh2.1/func/cx'`"
test 109 -eq "$Wc_c" ||
echo 'zsh2.1/func/cx: original size 109, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/func/harden ==============
if test -f 'zsh2.1/func/harden' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/func/harden (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/func/harden (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/func/harden' &&
X#! /bin/sh
X# harden a link (convert it to a singly linked file)
Xcp $1 $1.foo
Xrm $1
Xmv $1.foo $1
X
SHAR_EOF
chmod 0755 zsh2.1/func/harden ||
echo 'restore of zsh2.1/func/harden failed'
Wc_c="`wc -c < 'zsh2.1/func/harden'`"
test 97 -eq "$Wc_c" ||
echo 'zsh2.1/func/harden: original size 97, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/func/mere ==============
if test -f 'zsh2.1/func/mere' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/func/mere (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/func/mere (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/func/mere' &&
X#! /bin/sh
X# read a man page in the current directory
Xnroff -man -Tman $1 | less -s
SHAR_EOF
chmod 0755 zsh2.1/func/mere ||
echo 'restore of zsh2.1/func/mere failed'
Wc_c="`wc -c < 'zsh2.1/func/mere'`"
test 84 -eq "$Wc_c" ||
echo 'zsh2.1/func/mere: original size 84, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/func/namedir ==============
if test -f 'zsh2.1/func/namedir' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/func/namedir (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/func/namedir (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/func/namedir' &&
X# give a name to a directory
X
X$1=~+
X: ~$1
X
X# for example, if we say: namedir foo
X# where the current directory is /usr/princeton/common/src/news/nntp/inews
X# this will do:
X#
X# foo=/usr/princeton/common/src/news/nntp/inews
X# : ~foo
X#
X# The : ~foo just evaluates ~foo, which declares foo as a named directory.
X# The first time a parameter is used with tilde expansion, it is declared
X# as the name of a named dir.
SHAR_EOF
chmod 0755 zsh2.1/func/namedir ||
echo 'restore of zsh2.1/func/namedir failed'
Wc_c="`wc -c < 'zsh2.1/func/namedir'`"
test 412 -eq "$Wc_c" ||
echo 'zsh2.1/func/namedir: original size 412, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/func/proto ==============
if test -f 'zsh2.1/func/proto' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/func/proto (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/func/proto (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/func/proto' &&
X#! /bin/sh
X# generate prototypes, if your style is the same as mine
Xfor i
Xdo
X rm $i:r.pro 2>/dev/null
X grep -v '[{};:#]' $i | grep '^[A-Za-z]' |
X grep -v static | sed 's/$/;/' >! $i:r.pro
Xdone
SHAR_EOF
chmod 0755 zsh2.1/func/proto ||
echo 'restore of zsh2.1/func/proto failed'
Wc_c="`wc -c < 'zsh2.1/func/proto'`"
test 194 -eq "$Wc_c" ||
echo 'zsh2.1/func/proto: original size 194, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/func/randline ==============
if test -f 'zsh2.1/func/randline' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/func/randline (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/func/randline (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/func/randline' &&
X# get a random line from a file
Xinteger z=$(wc -l <$1)
Xsed -n $[RANDOM%z+1]p $1
SHAR_EOF
chmod 0755 zsh2.1/func/randline ||
echo 'restore of zsh2.1/func/randline failed'
Wc_c="`wc -c < 'zsh2.1/func/randline'`"
test 80 -eq "$Wc_c" ||
echo 'zsh2.1/func/randline: original size 80, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/func/yp ==============
if test -f 'zsh2.1/func/yp' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/func/yp (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/func/yp (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/func/yp' &&
X#! /bin/sh
Xypmatch $1 passwd
SHAR_EOF
chmod 0755 zsh2.1/func/yp ||
echo 'restore of zsh2.1/func/yp failed'
Wc_c="`wc -c < 'zsh2.1/func/yp'`"
test 29 -eq "$Wc_c" ||
echo 'zsh2.1/func/yp: original size 29, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/func/yu ==============
if test -f 'zsh2.1/func/yu' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/func/yu (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/func/yu (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/func/yu' &&
X#! /bin/sh
Xypmatch $1 passwd.byuid
SHAR_EOF
chmod 0755 zsh2.1/func/yu ||
echo 'restore of zsh2.1/func/yu failed'
Wc_c="`wc -c < 'zsh2.1/func/yu'`"
test 35 -eq "$Wc_c" ||
echo 'zsh2.1/func/yu: original size 35, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/man/man1/zsh.1 ==============
if test ! -d 'zsh2.1/man'; then
echo 'x - creating directory zsh2.1/man'
mkdir 'zsh2.1/man'
fi
if test ! -d 'zsh2.1/man/man1'; then
echo 'x - creating directory zsh2.1/man/man1'
mkdir 'zsh2.1/man/man1'
fi
if test -f 'zsh2.1/man/man1/zsh.1' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/man/man1/zsh.1 (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.1/man/man1/zsh.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/man/man1/zsh.1' &&
X.\"
X.TH ZSH 1 "1991 Oct 17"
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 \fIlist\fP \fB) {\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.
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
SHAR_EOF
true || echo 'restore of zsh2.1/man/man1/zsh.1 failed'
fi
echo 'End of zsh2.1.0 part 1'
echo 'File zsh2.1/man/man1/zsh.1 is continued in part 2'
echo 2 > _shar_seq_.tmp
exit 0

exit 0 # Just in case...
--
Kent Landfield INTERNET: ke...@sparky.IMD.Sterling.COM
Sterling Software, IMD UUCP: uunet!sparky!kent
Phone: (402) 291-8300 FAX: (402) 291-4362
Please send comp.sources.misc-related mail to ke...@uunet.uu.net.

Paul Falstad

unread,
Oct 24, 1991, 3:07:13 PM10/24/91
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 24, Issue 2
Archive-name: zsh2.1/part02

Environment: BSD
Supersedes: zsh2.00: Volume 18, Issue 84-98

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


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

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


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

Xunless quoted or removed using the \fBunalias\fP builtin:
X.RS
X.PP
X\fBdo done esac then elif else fi for case
Xif while function repeat time until exec command
Xselect coproc noglob \- nocorrect foreach end\fP
X.RE
X.SH COMMENTS
XIn noninteractive shells, or in interactive shells with the
X\fBINTERACTIVE_COMMENTS\fP option set, a word beginning
Xwith the third character of the \fBHISTCHARS\fP parameter
X(`#' by default) causes that word and all the following
Xcharacters up to a newline to be ignored.
X.SH ALIASING
XEvery token in the shell input is checked to see if there
Xis an alias defined for it.
XIf so, it is replaced by the text of the alias if it is in command
Xposition (if it could be the first word of a simple command),
Xor if the alias is global.
XIf the text ends with a space, the next word in the shell input
Xis treated as though it were in command position for purposes of alias
Xexpansion.
XAn alias is defined using the \fBalias\fP builtin; global aliases
Xmay be defined using the \-\fBg\fP option to that bulitin.
X.PP
XAlias substitution is done on the shell input before any
Xother substitution except history substitution. Therefore,
Xif an alias is defined for the word \fBfoo\fP, alias substitution
Xmay be avoided by quoting part of the word, e.g. \fB\efoo\fP.
XBut there is nothing to prevent an alias being defined
Xfor \fB\efoo\fP as well.
X.SH QUOTING
XA character may be \fIquoted\fP (that is, made
Xto stand for itself) by preceding it with a \e\|.
X\e followed by a newline is ignored.
XAll characters enclosed between a pair of single quotes ('')
Xare quoted.
XA single quote cannot appear within single quotes.
XInside double quotes (""), parameter and command substitution
Xoccurs, and \e quotes the characters \e\|, `, ", and $.
X.SH EXPANSION
XExpansion is performed on the command line after it has been
Xparsed. The types of expansions performed are
X\fIfilename expansion\fP,
X\fIprocess substitution\fP,
X\fIparameter expansion\fP,
X\fIcommand substitution\fP,
X\fIarithmetic expansion\fP,
X\fIbrace expansion\fP,
Xand \fIfilename generation\fP.
X.SS Filename Expansion
XEach word is checked to see if it begins with an unquoted ~.
XIf it does, then the word up to a / is checked to see if it matches
Xthe name of a named directory. If so, then the ~ and the matched portion
Xare replaced with the value of the named directory.
XA ~ by itself or followed by a / is replaced by the value of the
X\fBHOME\fP parameter.
XA ~ followed by a + or a \- is replaced by the value of
X\fBPWD\fP or \fBOLDPWD\fP, respectively.
X.PP
XNamed directories are typically login directories for users on the system.
XThey may also be defined if the text after the ~ is the name
Xof a shell parameter whose value begins with a /.
XIn certain circumstances (in prompts, for instance), when the shell
Xprints a path, the path is checked to see if it has a named
Xdirectory as its prefix. If so, then the prefix portion
Xis replaced with a ~ followed by the name of the directory.
XThe longest match is preferred.
X.PP
XIf a word begins with an unquoted \fB=\fP and the
X\fBNO_EQUALS\fP option is not set,
Xthe remainder of the word is taken as the
Xname of a command or alias. If a command
Xexists by that name, the word is replaced
Xby the full pathname of the command.
XIf an alias exists by that name, the word
Xis replaced with the text of the alias.
XOtherwise the word is checked up to a /
Xto see if it is a number or a \-. If so,
Xthe matched portion is replaced with
Xthe \fIn\fPth directory in the directory stack,
Xwhere \fIn\fP is the number matched, or
Xthe last directory in the directory stack
Xif a \- is matched.
X.SS Process Substitution
XEach command argument of the form
X\fB<(\fIlist\^\fB)\fR
Xor
X\fB>(\fIlist\^\fB)\fR
Xor
X\fB=(\fIlist\^\fB)\fR
Xis subject to process substitution.
XIn the case of the
X.B <
Xor
X.B >
Xforms, the shell will run process
X.I list
Xasynchronously connected to a named pipe (FIFO).
XThe name of this pipe will become the argument to the command.
XIf the form with
X.B >
Xis selected then writing on this file will provide input for
X.IR list .
XIf
X.B <
Xis used,
Xthen the file passed as an argument will
Xbe a named pipe connected to the output of the
X.I list
Xprocess.
XFor example,
X.RS
X.PP
X\fBpaste <(cut \-f1\fP \fIfile1\fB) <(cut \-f3\fP \fIfile2\fB) | tee >(\fIprocess1\fB) >(\fIprocess2\fB)\fR >/dev/null
X.RE
X.PP
X.BR cut s
Xfields 1 and 3 from
Xthe files
X.I file1
Xand
X.I file2
Xrespectively,
X.BR paste s
Xthe results together, and sends it to the processes
X.I process1
Xand
X.IR process2 .
XNote that the file, which is passed as an argument to the command,
Xis a system
Xpipe
Xso programs that expect to
X.BR lseek (2)
Xon the file will not work.
XAlso note that the previous example can be more compactly and
Xefficiently written as:
X.RS
X.PP
X\fBpaste <(cut \-f1\fP \fIfile1\fB) <(cut \-f3\fP \fIfile2\fB) > >(\fIprocess1\fB) > >(\fIprocess2\fB)\fR
X.RE
X.PP
Xthe shell uses pipes instead of a FIFOs to implement the latter
Xtwo process substitutions in the above example.
X.PP
XIf
X.B =
Xis used,
Xthen the file passed as an argument will be the name
Xof a temporary file containing
Xthe output of the
X.I list
Xprocess. This may be used instead of the
X.B <
Xform for a program that expects to \fBlseek\fP(2) on the input file.
X.SS Parameter Expansion
XThe character \fB$\fP is used to introduce parameter expansions.
XSee \fBPARAMETERS\fP below for a description of parameters.
X.PD
X.RS
X.TP
X\fB${\fIname\fB}\fR
XThe value, if any, of the parameter \fIname\fP is substituted.
XThe braces are required with \fIname\fP is followed by
Xa letter, digit, or underscore that is not to be interpreted
Xas part of its name.
XIf \fIname\fP is an array parameter, then the values of each
Xelement of \fIname\fP is substituted, one element per word.
XOtherwise, the expansion results in one word only; no
Xword splitting is done on the result.
X.TP
X\fB${\fIname\fB:\-\fIword\fB}\fR
XIf \fIname\fP is set and is non-null then substitute its
Xvalue; otherwise substitute \fIword\fP.
X.TP
X\fB${\fIname\fB:=\fIword\fB}\fR
XIf \fIname\fP is unset and is null then
Xset it to \fIword\fP; the value of the parameter is then
Xsubstituted.
X.TP
X\fB${\fIname\fB:?\fIword\fB}\fR
XIf \fIname\fP is set and is non-null, then substitute
Xits value; otherwise, print \fIword\fP and exit from the shell.
XIf \fIword\fP is omitted, then a standard message is printed.
X.TP
X\fB${\fIname\fB:+\fIword\fB}\fR
XIf \fIname\fP is set and is non-null then substitute
X\fIword\fP; otherwise substitute nothing.
X.PD 0
X.TP
X\fB${\fIname\fB#\fIpattern\fB}\fR
X.TP
X\fB${\fIname\fB##\fIpattern\fB}\fR
X.PD
XIf the \fIpattern\fP matches the beginning of the value of
X\fIname\fP, then substitute the value of \fIname\fP with
Xthe matched portion deleted; otherwise, just
Xsubstitute the value of \fIname\fP. In the first
Xform, the smallest matching pattern is preferred;
Xin the second form, the largest matching pattern is preferred.
X.PD 0
X.TP
X${\fIname\fB%\fIpattern\fR}
X.TP
X${\fIname\fB%%\fIpattern\fR}
X.PD
XIf the \fIpattern\fP matches the end of the value of
X\fIname\fP, then substitute the value of \fIname\fP with
Xthe matched portion deleted; otherwise, just
Xsubstitute the value of \fIname\fP. In the first
Xform, the smallest matching pattern is preferred;
Xin the second form, the largest matching pattern is preferred.
X.TP
X${\fB#\fIspec\fR}
XIf \fIspec\fP is one of the above substitutions, substitute
Xthe length in characters of the result instead of
Xthe result itself. If \fIspec\fP is an array expression,
Xsubstitute the number of elements of the result.
X.TP
X${\fB^\fIspec\fR}
XToggle the value of the \fBRC_EXPAND_PARAM\fP option for the
Xevaluation of \fIspec\fP.
XWhen this option is set, array expansions of the form
X\fIfoo\fB${\fIxx\fB}\fIbar\fR, where the parameter
X\fIxx\fP is set to (\fIa b c\fP), are substituted with
X\fIfooabar foobbar foocbar\fP instead of the default
X\fIfooa b cbar\fP.
X.TP
X${\fB=\fIspec\fR}
XToggle the value of the \fBSH_WORD_SPLIT\fP option for the
Xevaluation of \fIspec\fP.
XWhen this option is set, parameter values are split into
Xseparate words using \fBIFS\fP as a delimiter
Xbefore substitution.
XThis is done by default in most other shells.
X.PD
X.RE
X.PP
XIf the colon is omitted from one of the above expressions
Xcontaining a colon, then the shell only checks whether
X\fIname\fP is set or not, not whether it is null.
X.SS Command Substitution
XA command enclosed in parentheses
Xpreceded by a dollar sign, like so: $(...) or quoted with grave
Xaccents: `...` is replaced with its standard output.
XIf the substitution is not enclosed in double quotes, the
Xoutput is broken into words using the \fBIFS\fP parameter.
XThe substitution \fB$(cat foo)\fP may be replaced
Xby the equivalent but faster \fB$(<foo)\fP.
X.SS Arithmetic Expansion
XA string of the form \fB$[\fIexp\fB]\fR is substituted
Xwith the value of the arithmetic expression \fIexp\fP.
X\fIexp\fP is treated as if it were within single quotes.
XSee \fBARITHMETIC EVALUATION\fP below.
X.SS Brace Expansion
XA string of the form
X\fIfoo\fB{\fIxx\fB,\fIyy\fB,\fIzz\fB}\fIbar\fR
Xis expanded to the individual words
X\fIfooxxbar\fP, \fIfooyybar\fP, and \fIfoozzbar\fP.
XLeft-to-right order is preserved. This construct
Xmay be nested. Malformed brace expansion expressions,
Xincluding expressions without a comma, are left unchanged
Xby the shell.
X.PP
XAn expression of the form
X\fB{\fIx\fB\-\fIy\fB}\fR,
Xwhere \fIx\fP and \fIy\fP are single characters,
Xis expanded to every character between
X\fIx\fP and \fIy\fP, inclusive.
X.SS Filename Generation
XIf a word contains an unquoted instance of one of the characters
X*, |, <, [, or ?, or the string "****/", 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 end in a
Xlist of qualifiers enclosed in parentheses.
XThe qualifiers
Xspecify which filenames that otherwise match the given pattern
Xwill be inserted in the argument list.
XA qualifier may be any one of the following:
X.PD 0
X.RS
X.TP
X.B /
Xdirectories
X.TP
X.B .
Xplain files
X.TP
X.B @
Xsymbolic links
X.TP
X.B =
Xsockets
X.TP
X.B p
Xnamed pipes (FIFOs)
X.TP
X.B *
Xexecutable plain files (0100)
X.TP
X.B %
Xdevice files (character or block special)
X.TP
X.B r
Xreadable files (0400)
X.TP
X.B w
Xwritable files (0200)
X.TP
X.B x
Xexecutable files (0100)
X.TP
X.B R
Xworld-readable files (0004)
X.TP
X.B W
Xworld-writable files (0002)
X.TP
X.B X
Xworld-executable files (0001)
X.TP
X.B s
Xsetuid files (04000)
X.TP
X.B S
Xsetgid files (02000)
X.TP
X\fBd\fIdev\fR
Xfiles on the device \fIdev\fP
X.TP
X\fBl\fIct\fR
Xfiles having a link count of \fIct\fP
X.TP
X\fBU\fP
Xfiles owned by the effective user id
X.TP
X\fBG\fP
Xfiles owned by the effective group id
X.TP
X\fBu\fInum\fR
Xfiles owned by user id \fInum\fP
X.TP
X\fBg\fInum\fR
Xfiles owned by group id \fInum\fP
X.TP
X\fB^\fP
Xnegates all qualifiers following it
X.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. A "/" at the end of a pattern
Xis equivalent to "(\|/\|)".
X.SH REDIRECTION
XBefore a command is executed, its input and output
Xmay be redirected.
XThe following may appear anywhere in a simple-command
Xor may precede or follow a complex command.
XSubstitution occurs before
X.I word
Xis used except as noted below.
XIf the result of substitution on
X.I word
Xproduces more than one filename,
Xredirection occurs for each
Xseparate filename in turn.
X.TP
X.BI < word
XOpen file
X.I word
Xas standard input.
X.TP
X.BI > word
XOpen file
X.I word
Xas standard output.
XIf the file does not exist then it is created.
XIf the file exists, and the
X.B NOCLOBBER
Xoption is set,
Xthis causes an error;
Xotherwise, it is truncated to zero length.
X.TP
X.BI >! " word"
XSame as
X.BR > ,
Xexcept that the file is truncated to zero length
Xif it exists, even if
X.B NOCLOBBER
Xis set.
X.TP
X.BI >> word
XOpen file
X.I word
Xas standard output.
XIf the file exists then output is appended to it.
XIf the file does not exist, and the
X.B NOCLOBBER
Xoption is set,
Xthis causes an error;
Xotherwise, the file is created.
X.TP
X.BI >>! " word"
XSame as
X.BR >> ,
Xexcept that the file is created if it does not
Xexist, even if
X.B NOCLOBBER
Xis set.
X.TP
X\fB<<\fP[\-] \fIword\fP
XThe shell input is read up to a line that is the same as
X.IR word ,
Xor to an end-of-file.
XNo parameter substitution, command substitution or
Xfilename generation is performed on
X.IR word .
XThe resulting document,
Xcalled a
X.IR here-document ,
Xbecomes
Xthe standard input.
XIf any character of \fIword\fP is quoted with
Xsingle or double quotes (a \e alone is \fInot\fP sufficient),
Xno interpretation
Xis placed upon the characters of the document.
XOtherwise, parameter and command substitution
Xoccurs, \e followed by a newline is removed,
Xand \e must be used to quote the characters
X\e, $, `, and the first character of \fIword\fP.
XIf <<\- is used, then all leading
Xtabs are stripped from \fIword\fP and from the document.
X.TP
X.BI <<< word
XOpen a file containing \fIword\fP, after expansion,
Xas standard input.
X.TP
X.BI <& digit
XThe standard input
Xis duplicated from file descriptor
X.I digit
X(see
X.IR dup (2)).
XSimilarly for standard output using
X\fB>&\fIdigit\fP.
X.TP
X.BI >& word
XSame as
X.BI > word
X\fB2>&\fP1.
X.TP
X.BI >>& word
XSame as
X.BI >> word
X\fB2>&\fP1.
X.TP
X.BI <&\-
XClose the standard input.
X.TP
X.BI >&\-
XClose the standard output.
X.TP
X.BI <&p
XThe input from the coprocess is moved to the standard input.
X.TP
X.BI >&p
XThe output to the coprocess is moved to the standard output.
X.PP
XIf one of the above is preceded by a digit, then the file
Xdescriptor referred to is that specified by the digit
X(instead of the default 0 or 1).
XThe order in which redirections are specified is significant.
Xthe shell evaluates each redirection in terms of the
X.RI ( "file descriptor" ", " file )
Xassociation at the time of evaluation.
XFor example:
X.RS
X.PP
X\&.\|.\|. \|1>\fIfname\^\fP 2>&1
X.RE
X.PP
Xfirst associates file descriptor 1 with file
X.IR fname .
XIt then associates file descriptor 2 with the file associated with file
Xdescriptor 1 (that is,
X.IR fname ).
XIf the order of redirections were reversed, file descriptor 2 would be associated
Xwith the terminal (assuming file descriptor 1 had been) and then file descriptor
X1 would be associated with file
X.IR fname .
X.PP
XIf the user tries to open a file descriptor for writing more than once,
Xthe shell opens the file descriptor as a pipe to a process that copies
Xits input to all the specified outputs, similar to tee(1). Thus:
X.RS
X.PP
X.B date >foo >bar
X.RE
X.PP
Xwrites the date to two files, named "foo" and "bar".
XNote that a pipe is an implicit indirection; thus
X.RS
X.PP
X.B date >foo | cat
X.RE
X.PP
Xwrites the date to the file "foo", and also pipes it to cat.
X.PP
XIf the user tries to open a file descriptor for reading more than once,
Xthe shell opens the file descriptor as a pipe to a process that copies
Xall the specified inputs to its output in the order
Xspecified, similar to cat(1). Thus
X.RS
X.PP
X.B sort <foo <fubar
X.RE
X.PP
Xor even
X.RS
X.PP
X.B sort <f{oo,ubar}
X.RE
X.PP
Xis equivalent to "cat foo bar | sort". Note that
Xa pipe is in implicit indirection; thus
X.RS
X.PP
X.B cat bar | sort <foo
X.RE
X.PP
Xis equivalent to "cat bar foo | sort" (note the order of the inputs).
X.PP
XIf a simple command consists of one or more redirection operators
Xand zero or more parameter assignments, but no command name,
Xthe command \fBcat\fP is assumed. Thus
X.RS
X.PP
X.B < file
X.RE
X.PP
Xprints the contents of \fBfile\fP.
X.PP
XIf a command is followed by
X.B &
Xand job control is not active,
Xthen the default standard input
Xfor the command
Xis the empty file
X.BR /dev/null .
XOtherwise, the environment for the execution of a command contains the
Xfile descriptors of the invoking shell as modified by
Xinput/output specifications.
X.SH "COMMAND EXECUTION"
XIf a command name contains no slashes, the shell attempts to locate
Xit. If there exists a shell function by that name, the function
Xis invoked as described below in \fBFUNCTIONS\fP. If there exists
Xa shell builtin by that name, the builtin is invoked.
X.PP
XOtherwise, the shell searches each element of \fBpath\fP for a
Xdirectory containing an executable file by that name. If the
Xsearch is unsuccessful, the shell prints an error message and returns
Xa nonzero exit status.
X.PP
XIf execution fails because the file is not in executable format,
Xand the file is not a directory, it is assumed to be a shell
Xscript. /bin/sh is spawned to execute it. If the program
Xis a file beginning with \fB#!\fP, the remainder of the first line
Xspecifies an interpreter for the program. The shell will
Xexecute the specified interpreter on operating systems that do
Xnot handle this executable format in the kernel.
X.SH FUNCTIONS
X.PP
XThe
X.B function
Xreserved word is used to define shell functions.
XShell functions are read in and stored internally.
XAlias names are resolved when the function is read.
XFunctions are executed like commands with the arguments
Xpassed as positional parameters.
X(See
X.I Execution
Xbelow).
X.PP
XFunctions execute in the same process as the caller and
Xshare all files
Xand present working directory with the
Xcaller.
XA trap on
X.B EXIT
Xset inside a function
Xis executed after the function completes in the environment
Xof the caller.
X.PP
XThe
X.B return
Xbuiltin is used to return
Xfrom function calls.
X.PP
XFunction identifiers
Xcan be listed with the
X.B functions
Xbuiltin.
XFunctions can be undefined with the
X.B unfunction
Xbuiltin.
X.PP
XThe following functions, if defined, have special meaning to
Xthe shell:
X.PP
X.PD 0
X.TP
X\fBchpwd\fP
XExecuted whenever the current working directory is changed.
X.TP
X\fBprecmd\fP
XExecuted before each prompt.
X.TP
X\fBperiodic\fP
XIf the parameter
X.B PERIOD
Xis set, this function is executed every
X.B PERIOD
Xseconds, just before a prompt.
X.TP
X\fBTRAPxxx\fP
XIf defined and non-null,
Xthis function will be executed whenever the shell
Xcatches a signal \fBSIGxxx\fP, where \fBxxx\fP is a signal
Xname as specified for the \fBkill\fP builtin (see below).
XIn addition, \fBTRAPERR\fP is executed whenever a command has a non-zero
Xexit status, \fBTRAPDEBUG\fP is executed after each command, and
X\fBTRAPEXIT\fP
Xis executed when the shell exits,
Xor when the current function exits if defined
Xinside a function.
XIf a function of this form is defined and null,
Xthe shell and processes spawned by it will ignore \fBSIGxxx\fP.
X.PD
X.SH JOBS
X.PP
XIf the
X.B MONITOR
Xoption is set,
Xan interactive shell associates a \fIjob\fR with each pipeline.
XIt keeps
Xa table of current jobs, printed by the
X.B jobs
Xcommand, and assigns them small integer numbers.
XWhen a job is started asynchronously with
X.BR & ,
Xthe shell prints a line which looks
Xlike:
X.PP
X.DT
X [1] 1234
X.PP
Xindicating that the job which was started asynchronously was job number
X1 and had one (top-level) process, whose process id was 1234.
X.PP
XIf you are running a job and wish to do something else you may hit the key
X\fB^Z\fR (control-Z) which sends a STOP signal to the current job.
Xthe shell will then normally indicate that the job has been `suspended',
Xand print another prompt.
XYou can then manipulate the state of this job,
Xputting it in the background with the
X.B bg
Xcommand, or run some other
Xcommands and then eventually bring the job back into the foreground with
Xthe foreground command
X.BR fg .
XA \fB^Z\fR takes effect immediately and
Xis like an interrupt in that pending output and unread input are discarded
Xwhen it is typed.
X.PP
XA job being run in the background will suspend if it tries to read
Xfrom the terminal.
XBackground jobs are normally allowed to produce output,
Xbut this can be disabled by giving the command ``stty tostop''.
XIf you set this
Xtty option, then background jobs will suspend when they try to produce
Xoutput like they do when they try to read input.
X.PP
XThere are several ways to refer to jobs in the shell.
XA job can be referred to by the process id of any process of the job
Xor by one of the following:
X.PD 0
X.TP
X.BI % number
XThe job with the given number.
X.TP
X.BI % string
XAny job whose command line begins with
X.IR string .
X.TP
X.BI %? string
XAny job whose command line contains
X.IR string .
X.TP
X.BI %%
XCurrent job.
X.TP
X.BI %+
XEquivalent to
X.BR %% .
X.TP
X.BI %\-
XPrevious job.
X.PD
X.PP
XThe shell learns immediately whenever a process changes state.
XIt normally informs you whenever a job becomes blocked so that
Xno further progress is possible. If
X.B notify
Xis not set, it waits until
Xjust before it prints
Xa prompt before it informs you.
X.PP
XWhen the monitor mode is on, each background job that completes
Xtriggers any trap set for
X.BR CHLD .
X.PP
XWhen you try to leave the shell while jobs are running or suspended, you will
Xbe warned that `You have suspended (running) jobs.'
XYou may use the
X.B jobs
Xcommand to see what they are.
XIf you do this or immediately try to
Xexit again, the shell will not warn you a second time; the suspended
Xjobs will be terminated, and the running jobs will be sent
Xa \fBSIGHUP\fP signal.
XTo avoid having the shell terminate the running jobs, either
Xuse the \fBnohup\fP(1) command or the \fBdisown\fP builtin (see below).
X.SH SIGNALS
XThe INT and QUIT signals for an invoked
Xcommand are ignored if the command is followed by
X.B &
Xand job
X.B monitor
Xoption is not active.
XOtherwise, signals have the values
Xinherited by the shell from its parent
X(but see the \fBTRAPxxx\fP special function above).
X.SH HISTORY
XHistory substitution allows you to use words from previous command
Xlines in the command line you are typing. This simplifies spelling
Xcorrections and the repetition of complicated commands or arguments.
XCommand lines are saved in the history list, the size of which
Xis controlled by the
X.B HISTSIZE
Xvariable. The most recent command is retained in any case.
XA history substitution begins with a
X.B !
Xand may occur anywhere on the command line; history
Xsubstitutions do not nest. The
X.B !
Xcan be escaped with
X.B \e
Xto suppress its special meaning.
XSingle or double quotes will \fInot\fP work for this.
X.PP
XInput lines containing history substitutions are echoed on the
Xterminal after being expanded, but before any other
Xsubstitutions take place or the command gets executed.
X.SS Event Designators
X.PP
XAn event designator is a reference to a command-line entry in
Xthe history list.
X.RS
X.PD 0
X.TP
X.B !
XStart a history substitution, except when followed by a blank, newline,
X.BR = ,
Xor
X.BR ( .
X.TP
X.B !!
XRefer to the previous command.
XBy itself, this substitution
Xrepeats the previous command.
X.TP
X.BI ! n
XRefer to command-line
X.IR n .
X.TP
X.BI ! \-n
XRefer to the current command-line minus
X.IR n .
X.TP
X.BI ! str
XRefer to the most recent command starting with
X.IR str .
X.TP
X.BI !? str\fR[\fP ? \fR]\fP
XRefer to the most recent command containing
X.IR str .
X.TP
X.B !#
XRefer to the current command line typed in so far.
X.TP
X.BR !{ .\|.\|. }
XInsulate a history reference from adjacent characters (if necessary).
X.PD
X.RE
X.SS Word Designators
X.PP
XA
X.RB ` : '
Xseparates the event specification from the word designator.
XIt can be omitted if the word designator begins with a
X.BR \*^ ,
X.BR $ ,
X.BR * ,
X.B \-
Xor
X.BR % .
XIf the word is to be selected from the previous command, the second
X.B !
Xcharacter can be omitted from the event specification. For instance,
X.B !!:1
Xand
X.B !:1
Xboth refer to the first word of the previous command, while
X.B !!$
Xand
X.B !$
Xboth refer to the last word in the previous command.
XWord designators include:
X.RS
X.PD 0
X.TP
X.B 0
XThe first input word (command).
X.TP
X.I n
XThe
X.IR n 'th
Xargument.
X.TP
X.B ^
XThe first argument, that is,
X.BR 1 .
X.TP
X.B $
XThe last argument.
X.TP
X.B %
XThe word matched by (the most recent)
X.BI ? s
Xsearch.
X.TP
X.IB x \- y
XA range of words;
X.BI \- y
Xabbreviates
X.BI 0\- y\fR.
X.TP
X.B *
XAll the arguments, or a null value if there is just
Xone word in the event.
X.TP
X.IB x *
XAbbreviates
X.IB x \-$ .
X.TP
X.IB x \-
XLike
X.I x*
Xbut omitting word
X.BR $ .
X.PD
X.RE
X.SS Modifiers
X.PP
XAfter the optional word designator, you can add
Xa sequence of one or more of the following modifiers,
Xeach preceded by a
X.BR : .
XThese modifiers also work on the result
Xof filename and parameter expansion.
X.RS
X.TP
X.B h
XRemove a trailing pathname component, leaving the head.
X.PD 0
X.TP
X.B r
XRemove a trailing suffix of the form
X.RB ` "\&.\fIxxx" ',
Xleaving the basename.
X.TP
X.B e
XRemove all but the suffix.
X.TP
X.B t
XRemove all leading pathname components, leaving the tail.
X.TP
X.B &
XRepeat the previous substitution.
X.TP
X.B g
XApply the change to the first occurrence of a match in each word,
Xby prefixing the above (for example,
X.BR g& ).
X.TP
X.B p
XPrint the new command but do not execute it.
X.TP
X.B q
XQuote the substituted words, escaping further substitutions.
X.TP
X.B x
XLike
X.BR q ,
Xbut break into words at each blank.
X.TP
X.B l
XConvert the words to all lowercase.
X.TP
X.B u
XConvert the words to all uppercase.
X.TP
X.BI s/ l / r\fR[\fP / \fR]\fP
XSubstitute
X.I r
Xfor
X.IR l .
X.PD
X.RE
X.PP
XUnless preceded by a
X.BR g ,
Xthe substitution is done only for the
Xfirst string that matches
X.IR l .
X.PP
XThe left-hand side of substitutions are not regular expressions,
Xbut character strings.
XAny character can be used as the delimiter in place of
X.BR / .
XA backslash quotes the delimiter character.
XThe character
X.BR & ,
Xin the right hand side, is replaced by the text
Xfrom the left-hand-side.
XThe
X.B &
Xcan be quoted with a backslash.
XA null
X.I l
Xuses the previous string either from a
X.I l
Xor from a contextual scan string
X.I s
Xfrom
X.BI !? s\fR.
XYou can omit the rightmost delimiter if a newline
Ximmediately follows
X.IR r ;
Xthe rightmost
X.B ?
Xin a context scan can similarly be omitted.
X.PP
XWithout an event specification, a history reference refers either to the
Xprevious command, or to a previous history reference on the command line
X(if any).
X.PP
XThe character sequence
X.BI ^ foo ^ bar
Xrepeats the last command, replacing the string "foo" with the
Xstring "bar".
X.PP
XIf the shell encounters the character sequence
X\fB!"\fP
Xin the input, the history mechanism is temporarily disabled until
Xthe current list is fully parsed. The
X\fB!"\fP
Xis removed from the input, and any subsequent
X.B !
Xcharacters have no special significance.
X.PP
XA less convenient but more comprehensible
Xform of command history support
Xis provided by the
X.B fc
Xbuiltin (see below).
X.SH "ARITHMETIC EVALUATION"
XAn ability to perform integer arithmetic
Xis provided with the builtin
X.BR let .
XEvaluations are performed using
X.I long
Xarithmetic.
XConstants are of the form
X[\fIbase\fB#\^\fR]\fIn\^\fP
Xwhere
X.I base
Xis a decimal number between two and thirty-six
Xrepresenting the arithmetic base
Xand
X.I n
Xis a number in that base.
XIf
X.I base
Xis omitted
Xthen base 10 is used.
X.PP
XAn arithmetic expression uses nearly the same syntax, precedence, and
Xassociativity of
Xexpressions in C.
XThe following operators are supported (listed in decreasing order
Xof precedence):
X.PP
X.PD 0
X.RS
X.TP
X.B + \- ! \(ap ++ \-\|\-
Xunary plus/minus, logical NOT, complement, {pre,post}{in,de}crement
X.TP
X.B &
Xlogical AND
X.TP
X.B ^
Xlogical XOR
X.TP
X.B |
Xlogical OR
X.TP
X.B * / %
Xmultiplication, division, remainder
X.TP
X.B + \-
Xaddition, subtraction
X.TP
X.B << >>
Xlogical shift left, shift right
X.TP
X.B < > <= >=
Xcomparison
X.TP
X.B == !=
Xequality and inequality
X.TP
X.B &&
Xboolean AND
X.TP
X.B |\|| ^^
Xboolean OR, XOR
X.TP
X.B ? :
Xternary operator
X.TP
X.B
X= += \-= *= /= %= &= ^= |= <<= >>= &&= |\||= ^^=
Xassignment
X.TP
X.B ,
Xcomma operator
X.PD
X.RE
X.PP
XThe operators &&, |\||, &&=, and |\||= are short-circuiting,
Xand only one of the latter two expressions in a ternary operator
Xis evaluated. Note the precedence of the logical AND, OR,
Xand XOR operators.
X.PP
XNamed parameters can be referenced by name within an arithmetic expression
Xwithout using the parameter substitution syntax.
X.PP
XAn internal integer representation of a named parameter
Xcan be specified with the
X.B integer
Xbuiltin.
XArithmetic evaluation is performed on the value of each
Xassignment to a named parameter declared integer
Xin this manner.
X.PP
XSince many of the arithmetic operators require
Xquoting, an alternative form of the
X.B let
Xcommand is provided.
XFor any command which begins with a
X.BR (( ,
Xall the characters until a matching
X.B ))
Xare treated as a quoted expression.
XMore precisely,
X.BR (( ... ))
Xis equivalent to
X.B let
X\fB"\fP...\fB"\fP.
X.SH "CONDITIONAL EXPRESSIONS"
XA \fIconditional expression\fP is used with the
X.B [[
Xcompound command to test attributes of files and to compare strings.
XEach expression can be constructed from one or more
Xof the following unary or binary expressions:
X.PD 0
X.TP
X\fB\-a\fP \fIfile\fP
Xtrue if
X.I file
Xexists.
X.TP
X\fB\-b\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a block special file.
X.TP
X\fB\-c\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a character special file.
X.TP
X\fB\-d\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a directory.
X.TP
X\fB\-f\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is an ordinary file.
X.TP
X\fB\-g\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is has its setgid bit set.
X.TP
X\fB\-k\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is has its sticky bit set.
X.TP
X\fB\-n\fP \fIstring\fP
Xtrue if length of
X.I string
Xis non-zero.
X.TP
X\fB\-o\fP \fIoption\fP
Xtrue if option named
X.I option
Xis on.
X.TP
X\fB\-p\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a fifo special file or a pipe.
X.TP
X\fB\-r\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is readable by current process.
X.TP
X\fB\-s\fP \fIfile\fP
Xtrue if
X.I file
Xexists and has size greater than zero.
X.TP
X\fB\-t\fP \fIfd\fP
Xtrue if file descriptor number
X.I fd
Xis open and associated with a terminal device.
X(note: \fIfd\fP is not optional)
X.TP
X\fB\-u\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is has its setuid bit set.
X.TP
X\fB\-w\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is writable by current process.
X.TP
X\fB\-x\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is executable by current process.
XIf
X.I file
Xexists and is a directory, then the current process
Xhas permission to search in the directory.
X.TP
X\fB\-z\fP \fIstring\fP
Xtrue if length of
X.I string
Xis zero.
X.TP
X\fB\-L\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a symbolic link.
X.TP
X\fB\-O\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is owned by the effective user id of this process.
X.TP
X\fB\-G\fP \fIfile\fP
Xtrue if
X.I file
Xexists and its group matches the effective group id of this process.
X.TP
X\fB\-S\fP \fIfile\fP
Xtrue if
X.I file
Xexists and is a socket.
X.TP
X\fIfile1\fP \fB\-nt\fP \fIfile2\fP
Xtrue if
X.I file1
Xexists and is newer than
X.IR file2 .
X.TP
X\fIfile1\fP \fB\-ot\fP \fIfile2\fP
Xtrue if
X.I file1
Xexists and is older than
X.IR file2 .
X.TP
X\fIfile1\fP \fB\-ef\fP \fIfile2\fP
Xtrue if
X.I file1
Xand
X.I file2
Xexist and refer to the same file.
X.TP
X\fIstring\fP \fB=\fP \fIpattern\fP
Xtrue if
X.I string
Xmatches
X.IR pattern .
X.TP
X\fIstring\fP \fB!=\fP \fIpattern\fP
Xtrue if
X.I string
Xdoes not match
X.IR pattern .
X.TP
X\fIstring1\fP \fB<\fP \fIstring2\fP
Xtrue if
X.I string1
Xcomes before
X.I string2
Xbased on ASCII value of their characters.
X.TP
X\fIstring1\fP \fB>\fP \fIstring2\fP
Xtrue if
X.I string1
Xcomes after
X.I string2
Xbased on ASCII value of their characters.
X.TP
X\fIexp1\fP \fB\-eq\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis equal to
X.IR exp2.
X.TP
X\fIexp1\fP \fB\-ne\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis not equal to
X.IR exp2.
X.TP
X\fIexp1\fP \fB\-lt\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis less than
X.IR exp2.
X.TP
X\fIexp1\fP \fB\-gt\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis greater than
X.IR exp2.
X.TP
X\fIexp1\fP \fB\-le\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis less than or equal to
X.IR exp2.
X.TP
X\fIexp1\fP \fB\-ge\fP \fIexp2\fP
Xtrue if
X.I exp1
Xis greater than or equal to
X.IR exp2.
X.TP
X\fB(\fP \fIexp\fP \fB)\fP
Xtrue if \fIexp\fP is true.
X.TP
X\fB!\fP \fIexp\fP
Xtrue if \fIexp\fP is false.
X.TP
X\fIexp1\fP \fB&&\fP \fIexp2\fP
Xtrue if \fIexp1\fP and \fIexp2\fP are both true.
X.TP
X\fIexp1\fP \fB|\||\fP \fIexp2\fP
Xtrue if either \fIexp1\fP or \fIexp2\fP is true.
X.PD
X.PP
XIn each of the above expressions, if
X.I file
Xis of the form
X\fB/dev/fd/\fP\fIn\fR,
Xwhere
X.I n
Xis an integer,
Xthen the test applied to the open file whose
Xdescriptor number is
X.IR n ,
Xeven if the underlying system does not support
Xthe \fB/dev/fd\fP directory.
X.PD
X.SH "ZSH LINE EDITOR"
XIf the \fBZLE\fP option is set (it is by default)
Xand the shell input is attached to the terminal, the user
Xis allowed to edit command lines.
X.PP
XThere are two display modes. The first, multiline mode, is the default.
XIt only works if the \fBTERM\fP parameter is set to a valid
Xterminal type that can move the cursor up. The second,
Xsingle line mode, is used if \fBTERM\fP is invalid or incapable
Xof moving the cursor up, or if the \fBSINGLE_LINE_ZLE\fP
Xoption is set. This mode is similar to ksh, and uses no
Xtermcap sequences.
X.SS Bindings
XCommand bindings may be set using the \fBbindkey\fP builtin.
XThere are two keymaps\-the main keymap and the alternate keymap.
XThe alternate keymap is bound to vi command mode.
XThe main keymap is bound to emacs mode by default.
XTo bind the main keymap to vi insert mode, use
X\fBbindkey \-v\fP, or set one of the \fBVISUAL\fP or \fBEDITOR\fP
Xenvironment variables to a string containing \fBvi\fP.
X.PP
XThe following is a list of all the key commands
Xand their default bindings in emacs and vi command mode.
X.SS Movement
X.TP
X\fBvi-backward-blank-word\fP (unbound) (B)
XMove backward one word, where a word is defined as a series of
Xnon-blank characters.
X.TP
X\fBbackward-char\fP (^B ESC-[D) (\|)
XMove backward one character.
X.TP
X\fBvi-backward-char\fP (\|) (h)
XMove backward one character, without changing lines.
X.TP
X\fBbackward-word\fP (ESC-B ESC-b) (b)
XMove to the beginning of the previous word.
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\fBemacs-backward-word\fP
XMove to the beginning of the previous word.
X.TP
X\fBemacs-forward-word\fP
XMove to the end of the next word.
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\fBforward-word\fP (ESC-F ESC-f) (w)
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\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-end\fP (unbound) (e)
XMove to the end of the next word.
X.TP
X\fBvi-goto-column\fP (ESC-|) (|)
XMove to the column specified by the numeric argument.
X.TP
X\fBvi-goto-mark\fP (unbound) (`)
XMove to the specified mark.
X.TP
X\fBvi-goto-mark-line\fP (unbound) (')
XMove to beginning of the line containing the specified mark.
X.TP
X\fBvi-repeat-find\fP (unbound) (;)
XRepeat the last \fBvi-find\fP command.
X.TP
X\fBvi-rev-repeat-find\fP (unbound) (,)
XRepeat the last \fBvi-find\fP command in the opposite direction.
X.SS History
X.TP
X\fBbeginning-of-buffer-or-history\fP (ESC-<)
XMove to the beginning of the buffer, or if already there,
Xmove to the first event in the history list.
X.TP
X\fBbeginning-of-line-hist\fP
XMove to the beginning of the line. If already at the
Xbeginning of the buffer, move to the previous history line.
X.TP
X\fBbeginning-of-history\fP
XMove to the first event in the history list.
X.TP
X\fBdown-line-or-history\fP (^N ESC-[B) (+ j)
XMove down a line in the buffer, or if already at the bottom line,
Xmove to the next event in the history list.
X.TP
X\fBdown-history\fP (unbound) (^N)
XMove to the next event in the history list.
X.TP
X\fBend-of-buffer-or-history\fP (ESC->)
XMove to the end of the buffer, or if already there,
Xmove to the last event in the history list.
X.TP
X\fBend-of-line-hist\fP
XMove to the end of the line. If already at the end of
Xthe buffer, move to the next history line.
X.TP
X\fBend-of-history\fP
XMove to the last event in the history list.
X.TP
X\fBvi-fetch-history\fP (unbound) (G)
XFetch the history line specified by the numeric argument.
X.TP
X\fBhistory-incremental-search-backward\fP (^R ^XR)
XSearch backward incrementally for a specified string.
XThe string may begin with `^' to anchor the search to the
Xbeginning of the line.
X.TP
X\fBhistory-incremental-search-forward\fP (^XS)
XSearch forward incrementally for a specified string.
XThe string may begin with `^' to anchor the search to the
Xbeginning of the line.
X.TP
X\fBhistory-search-backward\fP (ESC-P ESC-p) (K)
XSearch backward in the history for a line beginning with the first
Xword in the buffer.
X.TP
X\fBvi-history-search-backward\fP (unbound) (/)
XSearch backward in the history for a specified string.
XThe string may begin with `^' to anchor the search to the
Xbeginning of the line.
X.TP
X\fBhistory-search-forward\fP (ESC-N ESC-n) (J)
XSearch forward in the history for a line beginning with the first
Xword in the buffer.
X.TP
X\fBvi-history-search-forward\fP (unbound) (?)
XSearch forward in the history for a specified string.
XThe string may begin with `^' to anchor the search to the
Xbeginning of the line.
X.TP
X\fBinfer-next-history\fP (^X^N)
XSearch in the history list for a line matching the current one and
Xfetch the event following it.
X.TP
X\fBinsert-last-word\fP (ESC-_ ESC-.)
XInsert the last word from the previous history event at the
Xcursor position.
X.TP
X\fBvi-repeat-search\fP (unbound) (n)
XRepeat the last vi history search.
X.TP
X\fBvi-rev-repeat-search\fP (unbound) (N)
XRepeat the last vi history search, but in reverse.
X.TP
X\fBtoggle-literal-history\fP (ESC-R ESC-r)
XToggle between literal and lexical history. The default is
Xlexical history unless the \fBHISTLIT\fP option is set.
X.TP
X\fBup-line-or-history\fP (^P ESC-[A) (- k)
XMove up a line in the buffer, or if already at the top line,
Xmove to the previous event in the history list.
X.TP
X\fBup-history\fP (unbound) (^P)
XMove to the previous event in the history list.
X.SS Modifying Text
X.TP
X\fBvi-add-eol\fP (unbound) (A)
XMove to the end of the line and enter insert mode.
X.TP
X\fBvi-add-next\fP (unbound) (a)
XMove forward one character and enter insert mode.
X.TP
X\fBbackward-delete-char\fP (^H ^?) (^?)
XDelete the character behind the cursor.
X.TP
X\fBvi-backward-delete-char\fP (unbound) (X)
XDelete the character behind the cursor, without changing lines.
X.TP
X\fBbackward-delete-word\fP
XDelete the word behind the cursor.
X.TP
X\fBbackward-kill-line\fP
XKill from the beginning of the line to the cursor position.
X.TP
X\fBbackward-kill-word\fP (^W ESC-^H ESC-^?)
XKill the word behind the cursor.
X.TP
X\fBvi-backward-kill-word\fP (unbound) (^W)
XKill the word behind the cursor.
X.TP
X\fBcapitalize-word\fP (ESC-C ESC-c)
XCapitalize the current word and move past it.
X.TP
X\fBvi-change\fP (unbound) (c)
XRead a movement command from the keyboard, and kill
Xfrom the cursor position to the endpoint of the movement.
XThen enter insert mode.
XIf the command is \fBvi-change\fP, kill the current line.
X.TP
X\fBvi-change-eol\fP (unbound) (C)
XKill to the end of the line and enter insert mode.
X.TP
X\fBvi-change-whole-line\fP (unbound) (S s)
XKill the current line and enter insert mode.
X.TP
X\fBcopy-region-as-kill\fP (ESC-W ESC-w)
XCopy the area from the cursor to the mark to the kill buffer.
X.TP
X\fBcopy-prev-word\fP (ESC-^_)
XDuplicate the word behind the cursor.
X.TP
X\fBvi-delete\fP (unbound) (d)
XRead a movement command from the keyboard, and kill
Xfrom the cursor position to the endpoint of the movement.
XIf the command is \fBvi-delete\fP, kill the current line.
X.TP
X\fBdelete-char\fP (unbound) (x)
XDelete the character under the cursor.
X.TP
X\fBvi-delete-char\fP (unbound) (x)
XDelete the character under the cursor.
X.TP
X\fBdelete-word\fP (ESC-D ESC-d)
XDelete the current word.
X.TP
X\fBdown-case-word\fP (ESC-L ESC-l)
XConvert the current word to all lowercase and move past it.
X.TP
X\fBkill-word\fP
XKill the current word.
X.TP
X\fBgosmacs-transpose-chars\fP
XExchange the two characters behind the cursor.
X.TP
X\fBvi-indent\fP (unbound) (>)
XIndent a number of lines.
X.TP
X\fBvi-insert\fP (unbound) (i)
XEnter insert mode.
X.TP
X\fBvi-insert-bol\fP (unbound) (I)
XMove to the beginning of the line and enter insert mode.\fP
X.TP
X\fBvi-join\fP (^X^J)
XJoin the current line with the next one.
X.TP
X\fBkill-line\fP (^K) (D)
XKill from the cursor to the end of the line.
X.TP
X\fBkill-region\fP
XKill from the cursor to the mark.
X.TP
X\fBkill-buffer\fP (^X^U) (^U)
XKill the entire buffer.
X.TP
X\fBkill-whole-line\fP (^U) (unbound)
XKill the current line.
X.TP
X\fBvi-match-bracket\fP (^X^B) (%)
XMove to the bracket character (one of {\|}, (\|), or [\|]) that
Xmatches the one under the cursor.
X.TP
X\fBvi-open-line-above\fP (unbound) (O)
XOpen a line above the cursor and enter insert mode.
X.TP
X\fBvi-open-line-below\fP (unbound) (o)
XOpen a line below the cursor and enter insert mode.
X.TP
X\fBvi-oper-swap-case\fP
XRead a movement command from the keyboard, and swap
Xthe case of all characters
Xfrom the cursor position to the endpoint of the movement.
XIf the movement command is \fBvi-oper-swap-case\fP,
Xswap the case of all characters on the current line.
X.TP
X\fBoverwrite-mode\fP (^X^O)
XToggle between overwrite mode and insert mode.
X.TP
X\fBvi-put-after\fP (unbound) (p)
XInsert the contents of the kill buffer after the cursor.
X.TP
X\fBquoted-insert\fP (^V)
XInsert the next character typed into the buffer literally.
X.TP
X\fBquote-line\fP (ESC-')
XQuote the current line; that is, put a ' character at the
Xbeginning and the end, and convert all ' characters
Xto '\e''.
X.TP
X\fBquote-region\fP (ESC-")
XQuote the region from the cursor to the mark.
X.TP
X\fBvi-replace\fP (unbound) (R)
XEnter overwrite mode.
X.TP
X\fBvi-repeat-change\fP (unbound) (.)
XRepeat the last vi mode text modification.
X.TP
X\fBvi-replace-chars\fP (unbound) (r)
XReplace the character under the cursor with a character
Xread from the keyboard.
X.TP
X\fBself-insert\fP (printable characters)
XPut a character in the buffer at the cursor position.
X.TP
X\fBself-insert-unmeta\fP (ESC-^I ESC-^J ESC-^M)
XPut a character in the buffer after stripping the meta bit
Xand converting \fB^M\fP to \fB^J\fP.
X.TP
X\fBvi-substitute\fP (unbound) (s)
XSubstitute the next character(s).
X.TP
X\fBvi-swap-case\fP (unbound) (~)
XSwap the case of the character under the cursor and move past it.
X.TP
X\fBtranspose-chars\fP (^T)
XExchange the two characters to the left of the
Xcursor if at end of line, else exchange the
Xcharacter under the cursor with the character
Xto the left.
X.TP
X\fBtranspose-words\fP (ESC-T ESC-t)
XExchange the current word with the one before it.
X.TP
X\fBvi-unindent\fP (unbound) (<)
XUnindent a number of lines.
X.TP
X\fBup-case-word\fP (ESC-U ESC-u)
XConvert the current word to all caps and move past it.
X.TP
X\fByank\fP (^Y) (P)
XInsert the contents of the kill buffer at the cursor position.
X.TP
X\fByank-pop\fP (ESC-y) (unbound)
XRemove the text just yanked, rotate the kill\-ring,
Xand yank the new top. Only works following
X\fByank\fP or \fByank-pop\fP.
X.TP
X\fBvi-yank\fP (unbound) (y)
XRead a movement command from the keyboard, and copy the region
Xfrom the cursor position to the endpoint of the movement
Xinto the kill buffer.
XIf the command is \fBvi-yank\fP, copy the current line.
X.TP
X\fBvi-yank-eol\fP (unbound) (Y)
XCopy the region from the cursor position to the end of the line
Xinto the kill buffer.
X.SS Arguments
X.TP
X\fBdigit-argument\fP (ESC-0..ESC-9) (0-9)
XStart a new numeric argument, or add to the current one.


SHAR_EOF
true || echo 'restore of zsh2.1/man/man1/zsh.1 failed'
fi

echo 'End of zsh2.1.0 part 2'
echo 'File zsh2.1/man/man1/zsh.1 is continued in part 3'
echo 3 > _shar_seq_.tmp

Paul Falstad

unread,
Oct 24, 1991, 3:07:35 PM10/24/91
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 24, Issue 3
Archive-name: zsh2.1/part03

Environment: BSD
Supersedes: zsh2.00: Volume 18, Issue 84-98

#!/bin/sh
# this is zshar.03 (part 3 of zsh2.1.0)


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

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

if test "$Scheck" != 3; then


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

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

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\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 (BINDCMDS)
XAn array (colon-separated list)
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 (HOSTCMDS)
XAn array (colon separated list) 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 command words, 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 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 (OPTCMDS)
XAn array (colon-separated list) 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.
XIf a component of \fBpath\fP begins with the string "\fB/.\fP",
Xe.g. "\fB/./usr/etc\fP", then that directory is not prescanned.
XThis is useful for directories like /usr/etc which contain
Xonly occasionally-used commands.
X.TP
X.B PROMPT
XThe primary prompt string, printed before a command is read;
Xthe default is "%m%# ".
XThe following escape sequences are recognized:
X.PD


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

X.B %d %/
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 %. %C
XTrailing component of $PWD.
XMay be followed by a digit to get more than one component.
XUnless \fB%C\fP is used, tilde expansion is performed first.
X.TP
X.B ! %h %!
XCurrent history event number
X.TP
X.B %M
XThe full machine hostname.
X.TP
X.B %m
XThe hostname up to the first '.'.
XMay be followed by a digit to specify
Xhow many components of the hostname are desired.
X.TP
X.B %S (%s)
XStart (stop) standout mode.
X.TP
X.B %U (%u)
XStart (stop) underline mode.
X.TP
X.B %B (%b)
XStart (stop) boldface mode.
X.TP
X.B %t
X.TP
X.B %@
XCurrent time of day, in 12-hour, am/pm format.
X.TP
X.B %T
XCurrent time of day, in 24-hour format.
X.TP
X.B %*
XCurrent time of day in 24-hour format, with seconds.
X.TP
X.B %n
X\fB$USERNAME\fP.
X.TP
X.B %w
XThe date in day\-dd format.
X.TP
X.B %W
XThe date in mm/dd/yy format.
X.TP
X.B %D
XThe date in yy\-mm\-dd format.
X.TP
X.B %l
XThe line (tty) the user is logged in on.
X.TP
X.B %?
XThe return code of the last command executed just before the prompt.
X.TP
X.B %#
XA '#' if the shell is running as root, a '%' if not.
X.TP
X\fB%{\fP...\fB%}\fP
XInclude a string as a literal escape sequence.
XThe string within the braces should not change the cursor
Xposition.
X.RE
X.PD
X.PP
X.PD 0
X.TP
X.B PROMPT2
XThe secondary prompt, printed when the shell needs more information
Xto complete a command.
XRecognizes the same escape sequences as \fB$PROMPT\fP.
XThe default is "> ".
X.TP
X.B PROMPT3
XSelection prompt used within a \fBselect\fP loop.
XRecognizes the same escape sequences as \fB$PROMPT\fP.
XThe default is "?# ".
X.TP
X.B PROMPT4
XThe execution trace prompt. Default is "+ ".
X.TP
X.B PS1
X.TP
X.B PS2
X.TP
X.B PS3
X.TP
X.B PS4
XSame as \fBPROMPT\fP, \fBPROMPT2\fP, \fBPROMPT3\fP, and \fBPROMPT4\fP,
Xrespectively.
X.TP
X.B prompt
XSame as \fBPROMPT\fP.
X.TP
X.B 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%s\fP expands to the string which presumably needs spelling
Xcorrection, and \fB%r\fP expands to the proposed correction.
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.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 (VARCMDS)
XAn array (colon-separated list)
Xof command names which take parameter names
Xas arguments, and which therefore should allow parameter
Xcompletion.
X.TP
X.B watch (WATCH)
XAn array (colon-separated list) of login/logout events to report.
XIf it contains the single word "all", then all login/logout events
Xare reported.
XAn entry in this list may consist of a username,
Xan `@' followed by a remote hostname,
Xand a `%' followed by a line (tty).
XAny or all of these components may be present in an entry;
Xif a login/logout event matches all of them,
Xit is reported.
X.TP
X.B WATCHFMT
XThe format of login/logout reports if the \fBwatch\fP parameter is set.
XDefault is "%n has %a %l from %m."
XRecognizes the following escape sequences:
X.PD


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

X.B %n
XThe name of the user that logged in/out.
X.TP
X.B %a
XThe observed action, i.e. "logged on" or "logged off".
X.TP
X.B %l
XThe line (tty) the user is logged in on.
X.TP
X.B %M
XThe full hostname of the remote host.
X.TP
X.B %m
XThe hostname up to the first ".". If only the
Xip address is available or the utmp field contains
Xthe name of an X-windows display, the whole name is printed.
X.TP
X.B %S (%s)
XStart (stop) standout mode.
X.TP
X.B %U (%u)
XStart (stop) underline mode.
X.TP
X.B %B (%b)
XStart (stop) boldface mode.
X.TP
X.B %t
X.TP
X.B %@
XThe time, in 12-hour, am/pm format.
X.TP
X.B %T
XThe time, in 24-hour format.
X.TP
X.B %w
XThe date in day\-dd format.
X.TP
X.B %W
XThe date in mm/dd/yy format.
X.TP
X.B %D
XThe date in yy\-mm\-dd format.
X.RE
X.PD
X.PP
X.PD 0
X.TP
X.B WORDCHARS
XA list of nonalphanumeric characters considered part of a word
Xby the line editor.
X.TP
X.B ZDOTDIR
XThe directory to search for shell startup files (.zshrc, etc),
Xif not \fB$HOME\fP.
X.PD
X.RE
X.PP
X.SH OPTIONS
XThe following options may be set upon invocation of the shell,
Xor with the \fBset\fP or \fBsetopt\fP builtins:
X.RS
X.PD 0
X.TP
X\fBALLEXPORT\fP (\-\fBa\fP)
XAll parameters subsequently defined are automatically exported.
X.TP
X\fBAUTO_CD\fP (\-\fBJ\fP)
XIf a command is not in the hash table, and there exists an
Xexecutable directory by that name, perform the \fBcd\fP
Xcommand to that directory.
X.TP
X\fBAUTOLIST\fP (\-\fB9\fP)
XAutomatically list choices on an ambiguous completion.
X.TP
X\fBAUTOMENU\fP
XAutomatically use menu completion if the \fPTAB\fP
Xkey is pressed repeatedly.
X.TP
X\fBAUTO_PUSHD\fP (\-\fBN\fP)
XMake \fBcd\fP act like \fBpushd\fP.
X.TP
X\fBAUTO_RESUME\fP (\-\fBW\fP)
XTreat single word simple commands without redirection
Xas candidates for resumption of an existing job.
X.TP
X\fBBGNICE\fP (\-\fB6\fP)
XRun all background jobs at a lower priority. This option
Xis set by default.
X.TP
X\fBCDABLEVARS\fP (\-\fBT\fP)
XIf the argument to a \fBcd\fP command is not a directory,
Xbut a parameter exists by the same name whose value
Xbegins with a /, try to change to the directory
Xspecified by the parameter's value.
X.TP
X\fBCHASELINKS\fP (\-\fBw\fP)
XResolve symbolic links to their true values.
X.TP
X\fBCORRECT\fP (\-\fB0\fP)
XTry to correct the spelling of commands.
X.TP
X\fBCORRECT_ALL\fP (\-\fBO\fP)
XTry to correct the spelling of all arguments in a line.
X.TP
X\fBCSH_JUNKIE_LOOPS\fP
XAllow loop bodies to take the form
X"\fIlist\fP; \fBend\fP" instead of
X"\fBdo\fP \fIlist\fP; \fBdone\fP".
X.TP
X\fBCSH_JUNKIE_QUOTES\fP
XComplain if a quoted expression runs off the end of a line;
Xprevent quoted expressions from containing unescaped newlines.
X.TP
X\fBCSH_NULL_GLOB\fP
XIf a pattern for filename generation has no matches,
Xdelete the pattern from the argument list;
Xdo not report an error unless all the patterns
Xin a command have no matches.
XOverrides \fBNULLGLOB\fP.
X.TP
X\fBERREXIT\fP (\-\fBe\fP)
XIf a command has a non-zero exit status, execute the \fBERR\fP
Xtrap, if set, and exit.
X.TP
X\fBEXTENDED_GLOB\fP
XTreat the # and ^ characters as part of patterns for filename
Xgeneration, etc.
X.TP
X\fBGLOB_COMPLETE\fP
XLike \fBMENU_COMPLETE\fP, except that the current word
Xis expanded using normal shell expansion instead of completion.
XIf no matches are found, a * is added to the end of the word, and expansion
Xis attempted again.
X.TP
X\fBGLOB_DOTS\fP (\-\fB4\fP)
XDo not require a leading . in a filename to be matched explicitly.
X.TP
X\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\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_CLOBBER\fP (\-\fBV\fP)
XDon't print a carriage return just before printing
Xa prompt in the line editor.
X.TP
X\fBNO_RCS\fP (\-\fBf\fP)
XDo not source the .zshenv, .zshrc, .zlogin, .zlogout, or .zprofile files.
X.TP
X\fBNO_SHORT_LOOPS\fP
XDisallow the short forms of \fBfor\fP, \fBselect\fP,
X\fBif\fP, and \fBfunction\fP constructs.
X.TP
X\fBNOTIFY\fP (\-\fB5\fP)
XReport the status of background jobs immediately, rather than
Xwaiting until just before printing a prompt.
X.TP
X\fBNOUNSET\fP (\-\fBu\fP)
XTreat unset parameters as an error when substituting.
X.TP
X\fBNULLGLOB\fP (\-\fBG\fP)
XIf a pattern for filename generation has no matches,
Xdelete the pattern from the argument list instead
Xof reporting an error. Overrides \fBNONOMATCH\fP.
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_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 *".
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 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.
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\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 ] [ \-\fBnlr\fP ] [ \fIold\fP=\fInew\fP ... ] [ \fIfirst\fP [ \fIlast\fP ] ]
X.TP
X\fBfc\fP \-\fBRW\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.
X.RS
X.PP
X\fBfc\fP \-\fBR\fP reads the history from the given file,
Xand \fBfc\fP \-\fBW\fP writes the history out to the given file.
X.RE
X.TP
X.PD 0
X\fBfg\fP [ \fIjob\fP ... ]
X.TP
X\fIjob\fP ...
X.PD
XBring the specified \fIjob\fPs to the foreground.
XIf no \fIjob\fP is specified, use the current job.
X.TP
X\fBfunctions\fP [ \(+-\fBtu\fP ] [ \fIname\fP ... ]
XEquivalent to \fBtypeset\fP \-\fBf\fP.
X.TP
X\fBgetln\fP \fIname\fP ...
XRead the top value from the buffer stack and put it in
Xthe shell parameter \fIname\fP. Equivalent to
X\fBread\fP \-\fBzr\fP.
X.TP
X\fBgetopts\fP \fIoptstring\fP \fIname\fP [ \fIarg\fP ... ]
XChecks \fBarg\fP for legal options. If \fIarg\fP is omitted,
Xuse the positional parameters. A valid option argument
Xbegins with a + or a \-. An argument not beginning with
Xa + or a \-, or the argument \-\-, ends the options.
X\fIoptstring\fP contains the letters that \fBgetopts\fP
Xrecognizes. If a letter is followed by a `:', that option
Xis expected to have an argument. The options can be
Xseparated from the argument by blanks.
X.RS
X.PP
XEach time it is invoked, \fBgetopts\fP places the option letter it finds
Xin the shell parameter \fIname\fP, prepended with a + when
X\fIarg\fP begins with a +. The index of the next \fIarg\fP
Xis stored in \fBOPTIND\fP. The option argument, if any,
Xis stored in \fBOPTARG\fP.
X.PP
XA leading : in \fIoptstring\fP causes \fBgetopts\fP to store the
Xletter of the invalid option in \fBOPTARG\fP, and to set \fIname\fP
Xto `?' for an unknown option and to `:' when a required option
Xis missing. Otherwise, \fBgetopts\fP prints an error
Xmessage. The exit status is nonzero when there are no more options.
X.RE
X.TP
X\fBhash\fP \fIname\fP \fIpath\fP
XPuts \fIname\fP in the command hash table, associating it with
Xthe pathname \fIpath\fP. Whenever \fIname\fP is used as a command
Xargument, the shell will try to execute the file given by \fIpath\fP.
X.TP
X\fBhistory\fP [ \-\fBnr\fP ] [ \fIfirst\fP [ \fIlast\fP ] ]
XSame as \fBfc\fP \-\fBl\fP.
X.TP
X\fBinteger\fP
XSame as \fBtypeset\fP \-\fBi\fP.
X.TP
X\fBjobs\fP [ \-\fBlp\fP ] [ \fIjob\fP ... ]
XLists information about each given job, or all jobs
Xif \fIjob\fP is omitted. The \-\fBl\fP flag lists process
Xids, and the \-\fBp\fP flag lists process groups.
X.TP
X.PD 0
X\fBkill\fP [ \-\fIsig\fP ] \fIjob\fP ...
X.TP
X\fBkill\fP \-\fBl\fP
X.PD
XSends either SIGTERM or the specified signal to the given
Xjobs or processes.
XSignals are given by number or by names
X(with the prefix "SIG" removed).
XIf the signal being sent is not KILL or CONT, then the job
Xwill be sent a CONT signal if it is stopped.
XThe argument \fIjob\fP can be the process id of a job
Xnot in the job list.
XIn the second form, \fBkill\fP \-\fBl\fP, the signal names
Xare listed.
X.TP
X\fBlet\fP \fIarg\fP ...
XEvaluate each \fIarg\fP as an arithmetic expression.
XSee \fBARITHMETIC EVALUATION\fP above for a description
Xof arithmetic expressions. The exit status is 0 if the
Xvalue of the last expression is nonzero, and 1 otherwise.
X.TP
X.PD 0
X\fBlimit\fP [ \-\fBh\fP ] [ \fIresource\fP [ \fIlimit\fP ] ] ...
X.TP
X\fBlimit\fP \-\fBs\fP
X.PD
XLimit the resource consumption of children of the current shell.
XIf \fIlimit\fP is not specified, print the current limit placed
Xon \fIresource\fP; otherwise
Xset the limit to the specified value. If the \-\fBh\fP flag
Xis given, use hard limits instead of soft limits.
XIf no \fIresource\fP is given, print all limits.
X.RS
X.PP
X\fIresource\fP is one of:
X.PP
X.PD 0
X.TP
X.B cputime
XMaximum CPU seconds per process.
X.TP
X.B filesize
XLargest single file allowed.
X.TP
X.B datasize
XMaximum data size (including stack) for each process.
X.TP
X.B stacksize
XMaximum stack size for each process.
X.TP
X.B coredumpsize
XMaximum size of a core dump.
X.TP
X.B resident
XMaximum resident set size.
X.TP
X.B descriptors
XMaximum value for a file descriptor.
X.PD
X.PP
X\fIlimit\fP is a number, with an optional scaling factor, as follows:
X.PP
X.PD 0
X.TP
X\fIn\fPh
Xhours.
X.TP
X\fIn\fPk
Xkilobytes.
XThis is the default for all but cputime.
X.TP
X\fIn\fPm
Xmegabytes or minutes.
X.TP
X\fImm\fP:\fBss\fP
Xminutes and seconds.
X.PD
X.RE
X.TP
X\fBlocal\fP
XSame as \fBtypeset\fP.
X.TP
X\fBlog\fP
XList all users currently logged in who are affected by
Xthe current setting of the \fBwatch\fP parameter.
X.TP
X\fBlogout\fP
XExit the shell, if this is a login shell.
X.TP
X\fBpopd\fP [ \(+-\fIn\fP ]
XRemoves entries from the directory stack. With no arguments,
Xremoves the top directory from the stack, and performs a \fBcd\fP
Xto the new top directory. With an argument of the form +\fIn\fP,
Xremove the \fIn\fPth entry counting from the left of the list
Xshown by the \fBdirs\fP command, starting with zero, and change
Xto that directory. With an argument of the form \-\fIn\fP,
Xremove the \fIn\fPth entry counting from the right.
XIf the \fBPUSHD_MINUS\fP option is set, the meanings of +
Xand \- in this context are swapped.
X.TP
X\fBprint\fP [ \-\fBRnrslz0DP\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\-\fB0\fP
Xprint the arguments separated and terminated by nulls.
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 [ \-\fBrz\fP ] [ \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.
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
XRescan the command path, rebuilding the hash table of commands.
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


SHAR_EOF
true || echo 'restore of zsh2.1/man/man1/zsh.1 failed'
fi

echo 'End of zsh2.1.0 part 3'
echo 'File zsh2.1/man/man1/zsh.1 is continued in part 4'
echo 4 > _shar_seq_.tmp

Paul Falstad

unread,
Oct 24, 1991, 3:07:55 PM10/24/91
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 24, Issue 4
Archive-name: zsh2.1/part04

Environment: BSD
Supersedes: zsh2.00: Volume 18, Issue 84-98

#!/bin/sh
# this is zshar.04 (part 4 of zsh2.1.0)


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

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

if test "$Scheck" != 4; then


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

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

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\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
Xundefined. 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 \fIjob\fPs. If \fIjob\fP is not given
Xthen all currently active child processes are waited for.
XThe exit status from this command is that of the process waited for.
X.TP
X\fBwhence\fP [ \-\fBpv\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.
X.TP
X\fBwhich\fP
XSame as \fBwhence\fP.
X.RE
X.SH INVOCATION
XIf the \fBNO_RCS\fP option is unset, commands are read
Xfrom $ZDOTDIR/.zshenv first.
X(If \fBZDOTDIR\fP is unset, \fBHOME\fP is used instead).
XThen, if the shell is interactive and
Xthe \fBNO_RCS\fP option is unset, commands are read
Xfrom /etc/zshrc and $ZDOTDIR/.zshrc, in that order, if either file
Xexists.
XIf the first character of argument zero passed to the shell
Xis \-, then the shell is assumed to be a login shell, and commands
Xare read from /etc/zprofile and $ZDOTDIR/.zprofile before .zshrc is read,
Xthen /etc/zlogin and $ZDOTDIR/.zlogin after .zshrc is read.
XIf the \fBNO_RCS\fP option is set, only /etc/zshrc
X/etc/zlogin, and /etc/zprofile may be read.
XIf the \-\fBs\fP flag is not present and an argument is given,
Xthe first argument is taken to be the pathname of a script to
Xexecute. The remaining arguments are assigned to the positional
Xparameters. The following flags are interpreted by the shell
Xwhen invoked:
X.TP
X.PD 0
X\-\fBc\fP \fIstring\fP
XRead commands from \fIstring\fP.


X.TP
X\-\fBs\fP

XRead command from the standard input.
X.TP
X\-\fBi\fP
XIf this flag is present or the shell input and output
Xare attached to a terminal, this shell is interactive.
X.PD
X.SH "SEE ALSO"
Xsh(1),
Xcsh(1),
Xtcsh(1),
Xitcsh(1),
Xrc(1),
Xbash(1),
Xash(1),
Xksh(1),
Xclam(1).
X.SH FILES
X$ZDOTDIR/.zshenv
X.br
X$ZDOTDIR/.zshrc
X.br
X$ZDOTDIR/.zlogin
X.br
X$ZDOTDIR/.zlogout
X.br
X$ZDOTDIR/.zprofile
X.br
X/tmp/zsh*
X.br
X/etc/zprofile
X.br
X/etc/zshrc
X.br
X/etc/zlogin
X.SH AUTHOR
XPaul Falstad (pfal...@phoenix.princeton.edu)
X.SH "UNDOCUMENTED FEATURES"
XNone known, but many suspected.
XPlease mail the author if you find any.
SHAR_EOF
echo 'File zsh2.1/man/man1/zsh.1 is complete' &&
chmod 0644 zsh2.1/man/man1/zsh.1 ||


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

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.1/src/buildzsh (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/src/buildzsh' &&
X#! /bin/sh
Xecho
Xecho 'Building config.h...' | tr -d '\012'
Xexec >config.h
Xcat <<'foo'
X/* this file is created automatically by buildzsh */
X
X/* define this if you are sysvish */
Xfoo
Xif test -f /usr/include/sys/resource.h
Xthen echo '/* #define SYSV */'
Xelse echo '#define SYSV'
Xfi
Xecho
Xif grep TCGETS /usr/include/sys/termios.h >/dev/null 2>&1
Xthen echo '#define TERMIOS
X/* #define TTY_NEEDS_DRAINING */
X/* #define CLOBBERS_TYPEAHEAD */'
Xelse
Xif grep sgttyb /usr/include/sys/ioctl.h >/dev/null 2>&1
Xthen echo '/* #define TERMIO */'
Xelse echo '#define TERMIO'
Xfi
Xecho '#define TTY_NEEDS_DRAINING
X#define CLOBBERS_TYPEAHEAD'
Xfi
Xecho
Xecho '/* define this if you have a host field in utmp */'
Xif grep ut_host /usr/include/utmp.h >/dev/null
Xthen echo '#define UTMP_HOST'
Xelse echo '/* #define UTMP_HOST */'
Xfi
Xecho
Xecho '/* define this if you have WAITPID */'
X# this next line should read "sed 's/_^H//g'"
X# there should be a _(backspace) there
Xif man 2 wait 2>/dev/null | sed 's/_ //g' | grep waitpid >/dev/null
Xthen echo '#define WAITPID'
Xelse echo '/* #define WAITPID */'
Xfi
Xecho
Xecho '/* define this if you have SELECT */'
Xif grep FD_SET /usr/include/sys/types.h >/dev/null
Xthen echo '#define HAS_SELECT'
Xelse echo '/* #define HAS_SELECT */'
Xfi
Xecho
Xecho '/* define this if your signal handlers return void */'
Xif grep SIG_DFL /usr/include/signal.h /usr/include/sys/signal.h |
X grep void >/dev/null
Xthen echo '#define SIGVOID'
Xelse echo '/* #define SIGVOID */'
Xfi
Xcat <<'foo'
X#ifdef sgi
X#undef SIGVOID
X#endif
Xfoo
Xecho
Xecho '/* define this if signal handlers need to be reset each time */'
Xif grep SIGTSTP /usr/include/signal.h /usr/include/sys/signal.h >/dev/null
Xthen echo '/* #define RESETHANDNEEDED */'
Xelse echo '#define RESETHANDNEEDED'
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'
X( tcsh -fc 'echo $HOSTTYPE' || arch || echo unknown ) 2>/dev/null |
X tr -d '\012'
Xecho '"'
Xecho
Xecho '/* the default editor for the fc builtin */'
Xecho '#define DEFFCEDIT "vi"'
Xecho
Xif grep UTMP_FILE /usr/include/utmp.h >/dev/null
Xthen :
Xelse
Xecho '/* the path of wtmp */'
Xecho '#define WTMP_FILE "' | tr -d '\012'
Xif test -f /etc/wtmp
Xthen echo /etc/wtmp
Xelif test -f /usr/etc/wtmp
Xthen echo /usr/etc/wtmp
Xelif test -f /var/adm/wtmp
Xthen echo /var/adm/wtmp
Xelif test -f /usr/adm/wtmp
Xthen echo /usr/adm/wtmp
Xelse echo /dev/null
Xfi | tr -d '\012'
Xecho '"
X
X/* the path of utmp */
X#define UTMP_FILE "/etc/utmp"
X'
Xfi
Xcat <<'foo'
X/* default prefix for temporary files */
X#define DEFTMPPREFIX "/tmp/zsh"
X
X/* define if you prefer "suspended" to "stopped" */
X#define USE_SUSPENDED
X
X/* the file to source whenever zsh is run; if undefined, don't source
X anything */
X#define GLOBALZSHRC "/etc/zshrc"
X
X/* the file to source whenever zsh is run as a login shell; if
X undefined, don't source anything */
X#define GLOBALZLOGIN "/etc/zlogin"
X
X/* the file to source whenever zsh is run as a login shell, before
X zshrc is read; if undefined, don't source anything */
X#define GLOBALZPROFILE "/etc/zprofile"
X
X/* the default HISTSIZE */
X#define DEFAULT_HISTSIZE 128
X
X/* define if you like interactive comments */
X/*#define INTERACTIVE_COMMENTS*/
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
X/* if your compiler doesn't like void *, change this to char *
X and ignore all the warnings.
X*/
X
Xtypedef void *vptr;
X
X#define JOB_CONTROL
Xfoo
Xexec 1>&2
Xecho done
Xecho 'Building signals.h...' | tr -d '\012'
Xecho `csh -fc 'kill -l'` | tr ' ' '\012' >signals.h
Xlct=`wc -l < signals.h`
Xcp signals.h signams.h
X(
Xecho '/* this file is created automatically by buildzsh */
X/* if all this is wrong, blame csh ;-) */
X
X#define SIGCOUNT '"$lct"'
X
X#ifdef GLOBALS
X
Xchar *sigmsg[SIGCOUNT+2] = {
X "done",'
Xsed -e 's/^/SIG/' -e '/SIGHUP/s//hangup/
X/SIGINT/s//interrupt/
X/SIGQUIT/s//quit/
X/SIGILL/s//illegal instruction/
X/SIGTRAP/s//trace trap/
X/SIGIOT/s//IOT instruction/
X/SIGABRT/s//abort/
X/SIGEMT/s//EMT instruction/
X/SIGFPE/s//floating point exception/
X/SIGKILL/s//killed/
X/SIGBUS/s//bus error/
X/SIGSEGV/s//segmentation fault/
X/SIGSYS/s//bad system call/
X/SIGPIPE/s//broken pipe/
X/SIGTERM/s//terminated/
X/SIGPWR/s//power fail/
X/SIGVTALRM/s//virtual time alarm/
X/SIGCONT/s//continued/
X/SIGXCPU/s//cpu limit exceeded/
X/SIGXFSZ/s//filesize limit exceeded/' -e 's/.*/ "&",/' signals.h
Xecho ' NULL
X};
X
Xchar *sigs[SIGCOUNT+4] = {
X "EXIT",' ) >sigtmp.h
Xmv sigtmp.h signals.h
Xif grep SIGSTOP signals.h >/dev/null
Xthen ed signals.h <<'foo' >/dev/null 2>&1
X/SIGSTOP/c
X#ifdef USE_SUSPENDED
X "suspended (signal)",
X#else
X "stopped (signal)",
X#endif
X.
X/SIGTSTP/c
X#ifdef USE_SUSPENDED
X "suspended",
X#else
X "stopped",
X#endif
X.
X/SIGTTIN/c
X#ifdef USE_SUSPENDED
X "suspended (tty input)",
X#else
X "stopped (tty input)",
X#endif
X.
X/SIGTTOU/c
X#ifdef USE_SUSPENDED
X "suspended (tty output)",
X#else
X "stopped (tty output)",
X#endif
X.
Xw
Xq
Xfoo
Xfi
X(sed 's/.*/ "&",/' signams.h
Xecho ' "ERR",
X "DEBUG",
X NULL
X};
X
X#else
X
Xextern char *sigs[SIGCOUNT+4],*sigmsg[SIGCOUNT+2];
X
X#endif') >>signals.h
Xrm signams.h
Xecho done
Xecho 'Building Makefile...' | tr -d '\012'
Xexec >Makefile
Xcat <<'foo'
X#! /bin/make -f
X#
X# Makefile - rather obvious isn't it
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# zsh is distributed in the hope that it will be useful, but
X# WITHOUT ANY WARRANTY. No author or distributor accepts
X# responsibility to anyone for the consequences of using it or for
X# whether it serves any particular purpose or works at all, unless he
X# says so in writing. Refer to the GNU General Public License
X# for full details.
X#
X# Everyone is granted permission to copy, modify and redistribute
X# zsh, but only under the conditions described in the GNU General Public
X# License. A copy of this license is supposed to have been given to you
X# along with zsh so you can know your rights and responsibilities.
X# It should be in a file named COPYING.
X#
X# Among other things, the copyright notice and this notice must be
X# preserved on all copies.
X#
X
XOBJS=builtin.o cond.o exec.o glob.o hist.o init.o jobs.o lex.o loop.o \
Xmath.o mem.o params.o parse.o subst.o table.o text.o utils.o watch.o \
Xzle_bindings.o zle_hist.o zle_main.o zle_misc.o zle_move.o zle_refresh.o \
Xzle_tricky.o zle_utils.o zle_vi.o zle_word.o
X
XBINDIR=/usr/local/bin
XMANDIR=/usr/local/man/man1
X
X# debugging flags
X#CFLAGS=-g -Wreturn-type -Wunused -Wpointer-arith -DQDEBUG
X#CC=gcc -traditional
X
XCC=cc
Xfoo
Xif test -f /usr/include/ndir.h -a ! -f /usr/lib/libBSD.a
Xthen echo 'CFLAGS= -O -Aa'
Xelse echo 'CFLAGS= -O'
Xfi
Xif test -f /usr/lib/libbsd.a
Xthen
Xif grep '^\+' /etc/passwd >/dev/null
Xthen echo 'LIBS= -lcurses -lbsd -lc_s'
Xelse echo 'LIBS= -lcurses -lbsd'
Xfi
Xelif test -f /usr/lib/libcposix.a
Xthen echo 'LIBS= -lcposix -ltermcap'
Xelif test -f /usr/lib/libBSD.a
Xthen echo 'LIBS= -ltermcap -lBSD'
Xelif test -f /usr/lib/libtermcap.a
Xthen echo 'LIBS= -ltermcap'
Xelse echo 'LIBS= -lcurses'
Xfi
Xcat <<'foo'
X
XZSHPATH=zsh
X
X.c.o:
X $(CC) $(CFLAGS) -c $<
X
Xall: $(ZSHPATH)
X
X$(ZSHPATH): $(OBJS)
X $(CC) -o $(ZSHPATH) $(OBJS) $(LIBS) $(LFLAGS)
X
Xtags: /tmp
X ctags *.[cy]
X
X# I hate this next line
X$(OBJS): config.h zsh.h zle.h signals.h ztype.h funcs.h
X
Xclean:
X rm -f *.o zsh core
X
Xcleanall:
X rm -f *.o zsh core Makefile signals.h config.h
X
Xinstall: zsh
X install -s -m 755 zsh $(BINDIR)
X install -m 444 ../man/man1/zsh.1 $(MANDIR)
Xfoo
Xexec 1>&2
Xcat <<'foo'
Xdone
X
XYou may want to look at the files I just created (config.h, Makefile,
Xand signals.h) to make sure they are correct. Or you may just want
Xto go ahead and try running make now to see what happens.
X
Xfoo
Xecho 'Shall I execute make now?' | tr -d '\012'
Xread reply
Xecho
Xcase "$reply" in
X[yY]*) exec make ;;
Xesac
X
SHAR_EOF
chmod 0755 zsh2.1/src/buildzsh ||
echo 'restore of zsh2.1/src/buildzsh failed'
Wc_c="`wc -c < 'zsh2.1/src/buildzsh'`"
test 8053 -eq "$Wc_c" ||
echo 'zsh2.1/src/buildzsh: original size 8053, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/src/builtin.c ==============
if test -f 'zsh2.1/src/builtin.c' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/src/builtin.c (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.1/src/builtin.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/src/builtin.c' &&
X/*
X
X builtin.c - builtin commands
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 zsh is distributed in the hope that it will be useful, but
X WITHOUT ANY WARRANTY. No author or distributor accepts
X responsibility to anyone for the consequences of using it or for
X whether it serves any particular purpose or works at all, unless he
X says so in writing. Refer to the GNU General Public License
X for full details.
X
X Everyone is granted permission to copy, modify and redistribute
X zsh, but only under the conditions described in the GNU General Public
X License. A copy of this license is supposed to have been given to you
X along with zsh so you can know your rights and responsibilities.
X It should be in a file named COPYING.
X
X Among other things, the copyright notice and this notice must be
X preserved on all copies.
X
X*/
X
X#include "zsh.h"
X#include <sys/errno.h>
X#include <sys/times.h>
X
X#define makecond() allocnode(N_COND)
X
X/* builtin flags */
X
X#define BINF_PLUSOPTS 1 /* +xyz legal */
X#define BINF_R 2 /* this is r (fc -e -) */
X#define BINF_PRINTOPTS 4
X#define BINF_SETOPTS 8
X#define BINF_FCOPTS 16
X#define BINF_TYPEOPT 32
X#define BINF_TYPEOPTS (BINF_TYPEOPT|BINF_PLUSOPTS)
X#define BINF_ECHOPTS 64
X
X/* builtin funcs */
X
X#define BIN_TYPESET 0
X#define BIN_BG 1
X#define BIN_FG 2
X#define BIN_JOBS 3
X#define BIN_WAIT 4
X#define BIN_DISOWN 5
X#define BIN_BREAK 6
X#define BIN_CONTINUE 7
X#define BIN_EXIT 8
X#define BIN_RETURN 9
X#define BIN_SHIFT 10
X#define BIN_CD 11
X#define BIN_POPD 12
X#define BIN_PUSHD 13
X#define BIN_PRINT 14
X#define BIN_EVAL 15
X#define BIN_SCHED 16
X#define BIN_FC 17
X#define BIN_PUSHLINE 18
X#define BIN_LOGOUT 19
X#define BIN_BUILTIN 20
X#define BIN_TEST 21
X#define BIN_BRACKET 22
X
Xstruct bincmd {
X char *name;
X int (*handlerfunc) DCLPROTO((char *,char **,char *,int));
X int minargs; /* min # of args */
X int maxargs; /* max # of args, or -1 for no limit */
X int flags; /* BINF_flags (see above) */
X int funcid; /* xbins (see above) for overloaded handlerfuncs */
X char *optstr; /* string of legal options */
X char *defopts; /* options set by default for overloaded handlerfuncs */
X };
X
X/* structure for foo=bar assignments */
X
Xstruct asgment {
X struct asgment *next;
X char *name,*value;
X };
X
Xstatic char *auxdata;
Xstatic int auxlen;
Xstatic int showflag = 0,showflag2 = 0;
X
Xstruct bincmd builtins[] = {
X "[",bin_test,0,-1,0,BIN_BRACKET,NULL,NULL,
X ".",bin_dot,1,-1,0,0,NULL,NULL,
X ":",bin_colon,0,-1,0,0,NULL,NULL,
X "alias",bin_alias,0,-1,0,0,"ga",NULL,
X "autoload",bin_typeset,0,-1,BINF_TYPEOPTS,0,"tx","fu",
X "bg",bin_fg,0,-1,0,BIN_BG,NULL,NULL,
X "bindkey",bin_bindkey,0,-1,0,0,"asvemdrl",NULL,
X "break",bin_break,0,1,0,BIN_BREAK,NULL,NULL,
X "builtin",NULL,0,0,0,BIN_BUILTIN,NULL,NULL,
X "bye",bin_break,0,1,0,BIN_EXIT,NULL,NULL,
X "cd",bin_cd,0,2,0,BIN_CD,NULL,NULL,
X "chdir",bin_cd,0,2,0,BIN_CD,NULL,NULL,
X "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_unhash,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,"nlreRW",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,"nr","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,"RDPnrslz0-",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,"rz",NULL,
X "readonly",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfiltux","r",
X "rehash",bin_rehash,0,0,0,0,NULL,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,"0123456789ABCDEFGHIJKLMNOPQRSTUWXYZaefghijklnosuvwxy",NULL,
X "setopt",bin_setopt,0,-1,BINF_PLUSOPTS,0,"0123456789BCDEFGHIJKLMNOPQRSTUWXYZaefghijklmnosuvwxy",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 "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,"p","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,"0123456789BCDEFGHIJKLMNOPQRSTUWXYZaefghijklmnosuvwxy",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,"pv",NULL,
X "which",bin_whence,0,-1,0,0,"pv",NULL,
X NULL,NULL,0,0,0,0,NULL,NULL
X };
X
X/* print options */
X
Xstatic void prtopt()
X{
Xstruct option *opp;
X
X if (isset(KSHOPTIONPRINT)) {
X printf("Current option settings\n");
X for (opp = optns; opp->name; opp++)
X printf("%-20s%s\n", opp->name,
X (opts[opp->id] == OPT_SET) ? "on" : "off");
X } else
X for (opp = optns; opp->name; opp++)
X if (opts[opp->id] == OPT_SET)
X puts(opp->name);
X}
X
X/* add builtins to the command hash table */
X
Xvoid addbuiltins() /**/
X{
Xstruct cmdnam *c;
Xstruct bincmd *b;
Xint t0;
X
X for (t0 = 0, b = builtins; b->name; b++,t0++)
X {
X c = (Cmdnam) zcalloc(sizeof *c);
X c->type = BUILTIN;
X c->u.binnum = t0;
X addhperm(b->name,c,cmdnamtab,freecmdnam);
X }
X}
X
X/* enable */
X
Xint bin_enable(name,argv,ops,whocares) /**/
Xchar *name;char **argv;char *ops;int whocares;
X{
Xstruct cmdnam *c;
Xstruct bincmd *b;
Xint t0,ret = 0;
X
X for (; *argv; argv++)
X {
X for (t0 = 0, b = builtins; b->name; b++,t0++)
X if (!strcmp(*argv,b->name))
X break;
X if (!b->name)
X {
X zerrnam(name,"no such builtin: %s",*argv,0);
X ret = 1;
X }
X else
X {
X c = (Cmdnam) zcalloc(sizeof *c);
X c->type = BUILTIN;
X c->u.binnum = t0;
X addhperm(b->name,c,cmdnamtab,freecmdnam);
X }
X }
X return ret;
X}
X
X/* :, true */
X
Xint bin_colon(name,argv,ops,whocares) /**/
Xchar *name;char **argv;char *ops;int whocares;
X{
X return 0;
X}
X
X/* break, bye, continue, exit, logout, return, shift */
X
Xint bin_break(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xint num = -1;
X
X if (*argv)
X num = matheval(*argv);
X if ((func == BIN_BREAK || func == BIN_CONTINUE) && !loops)
X {
X if (func == BIN_CONTINUE)
X zerrnam(name,"not in loop",NULL,0);
X return 1;
X }
X switch (func)
X {
X case BIN_CONTINUE:
X contflag = 1;
X case BIN_BREAK:
X breaks = (num == -1) ? 1 : num;
X break;
X case BIN_LOGOUT:
X if (!islogin)
X {
X zerrnam(name,"not login shell",NULL,0);
X return 1;
X }
X case BIN_EXIT:
X zexit((num == -1) ? lastval : num);
X break;
X case BIN_RETURN:
X retflag = 1;
X return lastval = (num == -1) ? lastval : num;
X case BIN_SHIFT:
X {
X char **s;
X
X if (num == -1)
X num = 1;
X if (num > arrlen(pparams))
X num = arrlen(pparams);
X permalloc();
X s = arrdup(pparams+num);
X heapalloc();
X freearray(pparams);
X pparams = s;
X break;
X }
X }
X return 0;
X}
X
X/* bg, disown, fg, jobs, wait */
X
Xint bin_fg(name,argv,ops,func) /**/
Xchar *name;char **argv;char *ops;int func;
X{
Xint job,lng,firstjob = -1,retval = 0;
X
X if (ops['Z']) { if (*argv) strcpy(hackzero,*argv); return 0; }
X lng = (ops['l']) ? 1 : (ops['p']) ? 2 : 0;
X if ((func == BIN_FG || func == BIN_BG) && !jobbing)
X {
X zerrnam(name,"no job control in this shell.",NULL,0);
X return 1;
X }
X if (!(jobtab[curjob].stat & STAT_INUSE))
X {
X curjob = prevjob; setprevjob();
X if (!(jobtab[curjob].stat & STAT_INUSE))
X curjob = prevjob; setprevjob();
X }
X if (func == BIN_JOBS)
X stopmsg = 2;
X if (!*argv)
X if (func == BIN_FG || func == BIN_BG)
X {
X if (curjob == -1 || curjob == thisjob)
X {
X zerrnam(name,"no current job",NULL,0);
X return 1;
X }
X firstjob = curjob;
X }
X else if (func == BIN_JOBS)
X {
X for (job = 0; job != MAXJOB; job++)
X if (job != thisjob && jobtab[job].stat)
X printjob(job+jobtab,lng);
X return 0;
X }
X else
X {
X for (job = 0; job != MAXJOB; job++)
X if (job != thisjob && jobtab[job].stat)
X waitjob(job);
X return lastval;
X }
X for (; (firstjob != -1) || *argv; ( void ) (*argv && argv++))
X {
X int stopped,ocj = thisjob;
X
X 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].cwd,cwd))
X {
X printf("(pwd : ");
X printdir(jobtab[job].cwd);
X printf(")\n");
X }
X fflush(stdout);
X attachtty(jobtab[job].gleader);
X }
X if (stopped)
X kill(-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(cwd);
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 {
X checkjobs();
X if (stopmsg)
X {
X stopmsg = 2;
X return 1;
X }
X }
X else
X killrunjobs();
X savehistfile(getsparam("HISTFILE"),0);
X if (islogin && unset(NORCS))
X sourcehome(".zlogout");
X if (sigtrapped[SIGEXIT])
X dotrap(SIGEXIT);
X exit(val); return 0;
X}
X
X/* identify an option name */
X
Xint optlookup(s) /**/
Xchar *s;
X{
Xchar *t;
Xstruct option *o;
X
X t = s = strdup(s);
X while (*t)
X if (*t == '_')
X chuck(t);
X else
X {
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 {
X if (!isun)
X prtopt();
X return 0;
X }
X for (opp = optns; opp->name; opp++)
X if (ops[opp->id] == 1+isun)
X opts[opp->id] = OPT_SET;
X else if (ops[opp->id] == 2-isun)
X opts[opp->id] = OPT_UNSET;
X while (*args)
X {
X c = optlookup(*args++);
X if (c != -1)
X {
X if (c == INTERACTIVE || c == MONITOR)
X zerrnam(nam,"can't change that option",NULL,0);
X else
X opts[c] = (isun) ? OPT_UNSET : OPT_SET;
X }
X else
X {
X zerrnam(nam,"no such option: %s",args[-1],0);
X return 1;
X }
X }
X return 0;
X}
X
X/* execute func on each member of the hash table ht */
X
Xvoid listhtable(ht,func) /**/
XHashtab ht;HFunc func;
X{
Xint t0;
Xstruct hashnode *hn;
X
X for (t0 = ht->hsize-1; t0 >= 0; t0--)
X for (hn = ht->nodes[t0]; hn; hn = hn->next)
X func(hn->nam,hn->dat);
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 {
X printf("%s ()\n",s);
X return;
X }
X t = gettext((vptr) (cc->u.list),1);
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 (*s >= 32 && *s <= 126)
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,v = ops['v'];
Xchar *cnam;
X
X for (; *argv; argv++)
X {
X if (!ops['p'] && (a = (Alias) gethnode(*argv,aliastab)) && a->cmd)
X {
X if (a->cmd < 0)
X printf((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("%s is an alias for %s\n",*argv,a->text);
X else
X printf("%s is a global alias for %s\n",*argv,a->text);
X retval = 0;
X }
X else if (!ops['p'] && (chn = (Cmdnam) gethnode(*argv,cmdnamtab)) &&
X (chn->type == SHFUNC || chn->type == BUILTIN))
X {
X if (chn->type == SHFUNC)
X printf((v) ? "%s is a function\n" : "%s\n",*argv);
X else
X printf((v) ? "%s is a shell builtin\n" : "%s\n",*argv);
X retval = 0;
X }
X else if (!(cnam = findcmd(*argv)))
X {
X if (v)
X printf("%s not found\n",*argv);
X retval = 1;
X }
X else
X {
X if (v)
X printf("%s is %s\n",*argv,cnam);
X else
X puts(cnam);
X retval = 0;
X }
X }
X return retval;
X}
X
X/* cd, chdir, pushd, popd */
X
Xint bin_cd(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
Xchar *dest;
X
X if (func == BIN_CD && isset(AUTOPUSHD))
X func = BIN_PUSHD;
X dest = cd_get_dest(nam,argv,ops,func);
X if (!dest) return 1;
X dest = cd_do_chdir(nam,dest);
X if (!dest) return 1;
X cd_new_pwd(func,dest);
X return 0;
X}
X
Xchar *cd_get_dest(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
Xchar *dest;
X
X if (!argv[0])
X if (func == BIN_CD || (func == BIN_PUSHD && isset(PUSHDTOHOME)
X || !full(dirstack)))
X dest = ztrdup(home);
X else
X dest = getnode(dirstack);
X else if (!argv[1]) {
X Lknode n;
X int dd;
X
X if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '-' : '+')) {
X dd = atoi(argv[0]+1)-1;
X if (dd < 0) {
X zerrnam(nam,"bad directory specification",NULL,0);
X return NULL;
X }
X for (n = firstnode(dirstack); n && dd; dd--, incnode(n));
X if (!n) {
X zerrnam(nam,"no such entry in dir stack",NULL,0);
X return NULL;
X }
X dest = remnode(dirstack,n);
X } else if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '+' : '-')) {
X dd = atoi(argv[0]+1);
X for (n = lastnode(dirstack); n != (Lknode) dirstack && dd;
X dd--, n = prevnode(n));
X if (n == (Lknode) dirstack) {
X zerrnam(nam,"no such entry in dir stack",NULL,0);
X return NULL;
X }
X dest = remnode(dirstack,n);
X } else
X dest = ztrdup(strcmp(argv[0],"-") ? argv[0] : oldpwd);
X } else {
X char *u;
X int len1,len2,len3;
X
X if (!(u = ztrstr(cwd,argv[0]))) {
X zerrnam(nam,"string not in pwd: %s",argv[1],0);
X return NULL;
X }
X len1 = strlen(argv[0]);
X len2 = strlen(argv[1]);
X len3 = u-cwd;
X dest = zalloc(len3+len2+strlen(u+len1)+1);
X strncpy(dest,cwd,len3);
X strcpy(dest+len3,argv[1]);
X strcat(dest,u+len1);
X }
X return dest;
X}
X
Xchar *cd_do_chdir(nam,dest) /**/
Xchar *nam; char *dest;
X{
Xstatic char buf[MAXPATHLEN], buf2[MAXPATHLEN];
Xstruct stat sbuf, tbuf;
Xint origerr, val, t0;
X
X if (*dest == '/') {
X convertwd(dest,buf);
X free(dest);
X val = chdir(buf);
X if (val == -1) {
X zerrnam(nam,"%e: %s",dest,errno);
X free(dest);
X return NULL;
X }
X return buf;
X }
X for (t0 = -1;; t0++) {
X if (t0 == -1) {
X sprintf(buf2,"%s/%s",cwd,dest);
X strcpy(buf,dest);
X } else {
X if (!cdpath[t0]) break;
X sprintf(buf2,"%s/%s",cdpath[t0],dest);
X if (!strncmp(buf2,"../",3))
X sprintf(buf2,"%s/%s/%s",cwd,cdpath[t0],dest);
X }
X convertwd(buf2,buf);
X val = chdir(dest);
X if (t0 == -1) origerr = errno;
X if (val != -1) {
X if (stat(buf,&sbuf) == -1)
X if (errno == ENOENT) continue;
X else break;
X if (stat(".",&tbuf) == -1) break;
X if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
X break;
X chdir(buf);
X break;
X } else {
X val = chdir(buf);
X if (val != -1) break;
X }
X }
X if (t0 > -1 && !cdpath[t0]) {
X char *s;
X if (isset(CDABLEVARS) &&
X (s = getsparam(dest)) && *s == '/' && chdir(s) != -1)
X strcpy(buf,s);
X else {
X zerrnam(nam,"%e: %s",dest,origerr);
X free(dest);
X return NULL;
X }
X }
X free(dest);
X if (t0 > -1) {
X printdir(buf);
X putchar('\n');
X }
X return buf;
X}
X
Xvoid cd_new_pwd(func,s) /**/
Xint func; char *s;
X{
XParam pm;
XList l;
X
X oldpwd = cwd;
X if (isset(CHASELINKS))
X cwd = findcwd(s);
X else
X cwd = ztrdup(s);
X if ((pm = gethnode("PWD", paramtab)) &&
X (pm->flags & PMFLAG_x) && pm->env)
X pm->env = replenv(pm->env,cwd);
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 pushnode(dirstack,oldpwd);
X heapalloc();
X }
X if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE))
X pdstack();
X if (l = getshfunc("chpwd"))
X newrunlist(l);
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) /**/
Xchar *s; char *t;
X{
Xchar *u,*start;
X
X *t++ = '/';
X start = t;
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 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_PREDOT;
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 bin_kill(nam,argv,ops,func) /**/
Xchar *nam;char **argv;char *ops;int func;
X{
Xint sig = SIGTERM;
X
X if (*argv && **argv == '-')
X {
X if (idigit((*argv)[1]))
X sig = atoi(*argv+1);
X else
X {
X if ((*argv)[1] == 'l' && (*argv)[2] == '\0')
X {
X printf("%s",sigs[1]);
X for (sig = 2; sig != SIGCOUNT; sig++)
X printf(" %s",sigs[sig]);
X putchar('\n');
X return 0;
X }
X for (sig = 0; sig != SIGCOUNT; sig++)
X if (!strcmp(sigs[sig],*argv+1))
X break;
X if (sig == SIGCOUNT)
X {
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 while (*argv)
X {
X if (**argv == '%')
X {
X int p = getjob(*argv,"kill");
X
X if (p == -1)
X return 1;
X if (killjb(jobtab+p,sig) == -1)
X {
X zerrnam("kill","kill failed: %e",NULL,errno);
X return 1;
X }
X if (jobtab[p].stat & STAT_STOPPED)
X {
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 }
X else
X if (kill(atoi(*argv),sig) == -1)
X {
X zerrnam("kill","kill failed: %e",NULL,errno);
X return 1;
X }
X argv++;
SHAR_EOF
true || echo 'restore of zsh2.1/src/builtin.c failed'
fi
echo 'End of zsh2.1.0 part 4'
echo 'File zsh2.1/src/builtin.c is continued in part 5'
echo 5 > _shar_seq_.tmp

Paul Falstad

unread,
Oct 24, 1991, 3:08:20 PM10/24/91
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 24, Issue 5
Archive-name: zsh2.1/part05

Environment: BSD
Supersedes: zsh2.00: Volume 18, Issue 84-98

#!/bin/sh
# this is zshar.05 (part 5 of zsh2.1.0)


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

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


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

if test "$Scheck" != 5; then


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

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


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

X }
X return 0;
X}
X

Xstatic char *recs[] = {
X "cputime","filesize","datasize","stacksize","coredumpsize",
X "resident","descriptors"
X };
X
Xint bin_limit(nam,argv,ops,func) /**/


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

X#ifndef RLIM_INFINITY
X zerrnam(nam,"not available on this system",NULL,0);
X return 1;
X#else
Xchar *s;
Xint hard = ops['h'],t0,lim;
Xlong val;
X
X if (ops['s'])
X {
X if (*argv)
X zerrnam(nam,"arguments after -s ignored",NULL,0);
X for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
X if (setrlimit(t0,limits+t0) < 0)
X zerrnam(nam,"setrlimit failed: %e",NULL,errno);
X return 0;
X }
X if (!*argv)
X {
X showlimits(hard,-1);
X return 0;
X }
X while (s = *argv++)
X {
X for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++)
X if (!strncmp(recs[t0],s,strlen(s)))
X {
X if (lim != -1)
X lim = -2;
X else
X lim = t0;
X }
X if (lim < 0)
X {
X zerrnam("limit",
X (lim == -2) ? "ambiguous resource specification: %s"
X : "no such resource: %s",s,0);
X return 1;
X }
X if (!(s = *argv++))
X {
X showlimits(hard,lim);
X return 0;
X }
X if (!lim)
X {
X val = zstrtol(s,&s,10);
X if (*s)
X if ((*s == 'h' || *s == 'H') && !s[1])
X val *= 3600L;
X else if ((*s == 'm' || *s == 'M') && !s[1])
X val *= 60L;
X else if (*s == ':')
X val = val*60+zstrtol(s+1,&s,10);
X else
X {
X zerrnam("limit","unknown scaling factor: %s",s,0);


X return 1;
X }
X }

X#ifdef RLIMIT_NOFILE
X else if (lim == RLIMIT_NOFILE)
X val = zstrtol(s,&s,10);
X#endif
X else
X {
X val = zstrtol(s,&s,10);
X if (!*s || ((*s == 'k' || *s == 'K') && !s[1]))
X val *= 1024L;
X else if ((*s == 'M' || *s == 'm') && !s[1])
X val *= 1024L*1024;
X else
X {
X zerrnam("limit","unknown scaling factor: %s",s,0);


X return 1;
X }
X }

X if (hard)
X if (val > limits[lim].rlim_max && geteuid())
X {
X zerrnam("limit","can't raise hard limits",NULL,0);
X return 1;
X }
X else
X {
X limits[lim].rlim_max = val;
X if (limits[lim].rlim_max < limits[lim].rlim_cur)
X limits[lim].rlim_cur = limits[lim].rlim_max;
X }
X else
X if (val > limits[lim].rlim_max)
X {
X zerrnam("limit","limit exceeds hard limit",NULL,0);
X return 1;
X }
X else
X limits[lim].rlim_cur = val;
X }
X return 0;
X#endif
X}
X
Xint bin_unlimit(nam,argv,ops,func) /**/


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

X#ifndef RLIM_INFINITY
X zerrnam(nam,"not available on this system",NULL,0);
X return 1;
X#else
Xint hard = ops['h'],t0,lim;
X
X if (hard && geteuid())
X {
X zerrnam(nam,"can't remove hard limits",NULL,0);
X return 1;
X }
X if (!*argv)
X {
X for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
X {
X if (hard)
X limits[t0].rlim_max = RLIM_INFINITY;
X else
X limits[t0].rlim_cur = limits[t0].rlim_max;


X }
X return 0;
X }

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

X for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++)
X if (!strncmp(recs[t0],*argv,strlen(*argv)))
X {
X if (lim != -1)
X lim = -2;
X else
X lim = t0;
X }
X if (lim < 0)
X {
X zerrnam(nam,
X (lim == -2) ? "ambiguous resource specification: %s"
X : "no such resource: %s",*argv,0);
X return 1;
X }
X if (hard)
X limits[lim].rlim_max = RLIM_INFINITY;
X else
X limits[lim].rlim_cur = limits[lim].rlim_max;
X }
X return 0;
X#endif
X}
X
Xvoid showlimits(hard,lim) /**/
Xint hard;int lim;
X{
Xint t0;
Xlong val;
X
X#ifdef RLIM_INFINITY
X for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
X if (t0 == lim || lim == -1)
X {
X printf("%-16s",recs[t0]);
X val = (hard) ? limits[t0].rlim_max : limits[t0].rlim_cur;
X if (val == RLIM_INFINITY)
X printf("unlimited\n");
X else if (!t0)
X printf("%d:%02d:%02d\n",(int) (val/3600),
X (int) (val/60) % 60,(int) (val % 60));
X#ifdef RLIMIT_NOFILE
X else if (t0 == RLIMIT_NOFILE)
X printf("%d\n",(int) val);
X#endif
X else if (val >= 1024L*1024L)
X printf("%ldMb\n",val/(1024L*1024L));
X else
X printf("%ldKb\n",val/1024L);
X }
X#endif
X}
X
Xint bin_sched(nam,argv,ops,func) /**/


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

Xchar *s = *argv++;
Xtime_t t;
Xlong h,m;
Xstruct tm *tm;
Xstruct schedcmd *sch,*sch2,*schl;
Xint t0;
X
X if (s && *s == '-')
X {
X t0 = atoi(s+1);
X
X if (!t0)
X {
X zerrnam("sched","usage for delete: sched -<item#>.",NULL,0);
X return 1;
X }
X for (schl = (struct schedcmd *) &schedcmds, sch = schedcmds, t0--;
X sch && t0; sch = (schl = sch)->next, t0--);
X if (!sch)
X {
X zerrnam("sched","not that many entries",NULL,0);
X return 1;
X }
X schl->next = sch->next;
X free(sch->cmd);
X free(sch);
X return 0;
X }
X if (!s)
X {
X char tbuf[40];
X
X for (t0 = 1, sch = schedcmds; sch; sch = sch->next,t0++)
X {
X t = sch->time;
X tm = localtime(&t);
X ztrftime(tbuf,20,"%a %b %e %k:%M:%S",tm);
X printf("%3d %s %s\n",t0,tbuf,sch->cmd);


X }
X return 0;
X }

X else if (!*argv)
X {
X zerrnam("sched","not enough arguments",NULL,0);
X return 1;
X }
X if (*s == '+')
X {
X h = zstrtol(s+1,&s,10);
X if (*s != ':')
X {
X zerrnam("sched","bad time specifier",NULL,0);
X return 1;
X }
X m = zstrtol(s+1,&s,10);
X if (*s)
X {
X zerrnam("sched","bad time specifier",NULL,0);
X return 1;
X }
X t = time(NULL)+h*3600+m*60;
X }
X else
X {
X h = zstrtol(s,&s,10);
X if (*s != ':')
X {
X zerrnam("sched","bad time specifier",NULL,0);
X return 1;
X }
X m = zstrtol(s+1,&s,10);
X if (*s && *s != 'a' && *s != 'p')
X {
X zerrnam("sched","bad time specifier",NULL,0);
X return 1;
X }
X t = time(NULL);
X tm = localtime(&t);
X t -= tm->tm_sec+tm->tm_min*60+tm->tm_hour*3600;
X if (*s == 'p')
X h += 12;
X t += h*3600+m*60;
X if (t < time(NULL))
X t += 3600*24;
X }
X sch = zcalloc(sizeof *sch);
X sch->time = t;
X sch->cmd = 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 = 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,first,last,subs) /**/
XFILE *f;int n;int r;int first;int last;struct asgment *subs;
X{
Xint done = 0,ct;
XLknode node;
Xchar *s;
X
X if (!subs)
X done = 1;
X last -= first;
X first -= firsthist;
X if (r)
X first += last;
X for (node = firstnode(histlist),ct = first; ct && node;
X incnode(node), ct--);
X first += firsthist;
X while (last-- >= 0)
X {
X if (!node)
X {
X zerrnam("fc","no such event: %d",NULL,first);
X return 1;
X }
X s = makehstr(getdata(node));
X done |= fcsubs(&s,subs);
X if (n)
X fprintf(f,"%5d ",first);
X if (f == stdout)
X {
X niceprintf(s,f);


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

X fprintf(f,"%s\n",s);
X node = (r) ? prevnode(node) : nextnode(node);
X (r) ? first-- : first++;
X }
X if (f != stdout)
X fclose(f);
X if (!done)
X {
X zerrnam("fc","no substitutions performed",NULL,0);
X return 1;
X }


X return 0;
X}
X

Xint fcedit(ename,fn) /**/
Xchar *ename;char *fn;
X{
X if (!strcmp(ename,"-"))
X return 1;
X return !zyztem(ename,fn);
X}
X
X/* fc, history, r */
X
Xint bin_fc(nam,argv,ops,func) /**/


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

Xint first = -1,last = -1,retval,minflag = 0;
Xchar *s;
Xstruct asgment *asgf = NULL,*asgl = NULL;
X
X if (!interact)
X {
X zerrnam(nam,"not interactive shell",NULL,0);
X return 1;
X }
X if (!(ops['l'] && unset(HISTNOSTORE)))
X remhist();
X if (ops['R'])
X {
X readhistfile(*argv ? *argv : getsparam("HISTFILE"),1);
X return 0;
X }
X if (ops['W'])
X {
X savehistfile(*argv ? *argv : getsparam("HISTFILE"),1);
X return 0;
X }
X while (*argv && equalsplit(*argv,&s))
X {
X struct asgment *a = (struct asgment *) alloc(sizeof *a);
X
X if (!asgf)
X asgf = asgl = a;
X else
X {
X asgl->next = a;
X asgl = a;
X }
X a->name = *argv;
X a->value = s;
X argv++;
X }
X if (*argv)
X {
X minflag = **argv == '-';
X first = fcgetcomm(*argv);
X if (first == -1)
X return 1;
X argv++;
X }
X if (*argv)
X {
X last = fcgetcomm(*argv);
X if (last == -1)
X return 1;
X argv++;
X }
X if (*argv)
X {
X zerrnam("fc","too many arguments",NULL,0);
X return 1;
X }
X if (first == -1)
X {
X first = (ops['l']) ? curhist-16 : curhist;
X if (last == -1)
X last = (ops['l']) ? curhist : first;
X }
X if (first < firsthist)
X first = firsthist;
X if (last == -1)
X last = (minflag) ? curhist : first;
X if (ops['l'])
X retval = fclist(stdout,!ops['n'],ops['r'],first,last,asgf);
X else
X {
X FILE *out;
X char *fil = gettemp();
X
X out = fopen(fil,"w");
X if (!out)
X zerrnam("fc","can't open temp file: %e",NULL,errno);
X else
X {
X retval = 1;
X if (!fclist(out,0,ops['r'],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 {
X zerrnam(name,"can't suspend login shell",NULL,0);
X return 1;
X }
X if (jobbing)
X signal(SIGTSTP,SIG_DFL);
X kill(0,SIGTSTP);
X if (jobbing)
X signal(SIGTSTP,SIG_IGN);


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 && !(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 {
X on &= PMFLAG_t|PMFLAG_u;
X off &= PMFLAG_t|PMFLAG_u;
X showflag = (ops['f'] == 1);
X if (ops['@'] && (off || (on & ~(PMFLAG_u|PMFLAG_t))))
X {
X zerrnam(name,"invalid option(s)",NULL,0);
X return 1;
X }
X showflag2 = 0;
X if (!*argv)
X {
X showflag2 = off|on;
X listhtable(cmdnamtab,(HFunc) pshfunc);
X }
X else for (; *argv; argv++)
X {
X Cmdnam cc;
X
X if ((cc = (Cmdnam) gethnode(*argv,cmdnamtab)) && cc->type == SHFUNC)
X if (on)
X cc->flags |= on;
X else
X pshfunc(*argv,cc);
X else if (on & PMFLAG_u)
X {
X cc = (Cmdnam) zcalloc(sizeof *cc);
X cc->type = SHFUNC;
X cc->flags = on;
X addhnode(ztrdup(*argv),cc,cmdnamtab,freecmdnam);
X }
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 if (!*argv)
X {
X showflag = on|off;
X showflag2 = roff;
X listhtable(paramtab,(HFunc) printparam);
X }
X else while (asg = getasg(*argv++))
X {
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 {
X if (!on && !roff && !asg->value)
X {
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 {
X if (pm->flags & PMFLAG_x)
X {
X if (!pm->env)
X pm->env = addenv(asg->name,
X (asg->value) ? asg->value : getsparam(asg->name));
X }
X else if (pm->env)
X delenv(pm->env);
X if (asg->value)
X setsparam(asg->name,ztrdup(asg->value));


X }
X }
X else
X {

X if (locallist && !(on & PMFLAG_x))
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/* print s with escape sequences */
X
Xint escputs(s) /**/
Xchar *s;
X{
Xint nnl = 0;
X
X for (; *s; s++)
X if (*s == '\\' && s[1])
X switch (*++s)
X {
X case 'b': putchar('\b'); break;
X case 'c': nnl = 1; break;
X case 'e': putchar('\033'); break;
X case 'f': putchar('\f'); break;
X case 'n': putchar('\n'); break;
X case 'r': putchar('\r'); break;
X case 't': putchar('\t'); break;
X case 'v': putchar('\v'); break;
X case '\\': putchar('\\'); break;
X case '0': putchar(zstrtol(s,&s,8)); s--; break;
X default: putchar('\\'); putchar(*s); break;
X }
X else
X putchar(*s);
X return nnl;
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;
X
X if (ops['z'])
X {
X permalloc();
X pushnode(bufstack,spacejoin(args));
X heapalloc();
X return 0;
X }
X if (ops['s'])
X {
X permalloc();
X addnode(histlist,join(args,HISTSPACE));
X addnode(lithistlist,join(args,' '));
X heapalloc();
X curhist++;
X return 0;
X }
X if (ops['R'])
X ops['r'] = 1;
X for (; *args; args++)
X {
X if (ops['D'])
X printdir(*args);
X else if (ops['P'])
X {
X int junk;
X fputs(putprompt(*args,&junk),stdout);
X }
X else if (ops['r'])
X fputs(*args,stdout);
X else
X nnl |= escputs(*args);
X if (args[1])
X putchar(ops['l'] ? '\n' : ops['0'] ? '\0' : ' ');
X }
X if (!(ops['n'] || nnl))
X putchar(ops['0'] ? '\0' : '\n');


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(cwd);
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

X/* disable, unfunction, unhash */
X
Xint bin_unhash(name,argv,ops,func) /**/


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

XCmdnam chn;


X
X while (*argv)
X {

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_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;
X
Xint zread() /**/
X{
Xchar cc;
X
X if (zbuf)
X return *zbuf++;
X if (read(0,&cc,1) != 1)
X return EOF;
X return cc;
X}
X
Xint bin_read(name,args,ops,func) /**/
Xchar *name;char **args;char *ops;int func;
X{
Xchar *reply,*pmpt;
Xint bsiz,c,gotnl = 0;
Xchar *buf,*bptr;
X
X attachtty((jobtab[thisjob].gleader) ? jobtab[thisjob].gleader : mypgrp);
X if (*args)
X reply = *args++;
X else
X reply = "REPLY";
X if (ops['z'])
X zbuf = (full(bufstack)) ? (char *) getnode(bufstack) : ztrdup("");
X else
X zbuf = NULL;
X if (isatty(0))
X {
X for (pmpt = reply; *pmpt && *pmpt != '?'; pmpt++);
X if (*pmpt++)
X {
X write(2,pmpt,strlen(pmpt));
X pmpt[-1] = '\0';
X }
X }
X while (*args)
X {
X buf = bptr = zalloc(bsiz = 64);
Xredo:
X for(;;)
X {
X if (gotnl)
X break;
X c = zread();
X if (!ops['r'] && c == '\n' && bptr != buf && bptr[-1] == '\\')
X {
X bptr--;
X continue;
X }
X if (c == EOF || iblank(c))
X break;
X *bptr++ = c;
X if (bptr == buf+bsiz)
X {
X buf = realloc(buf,bsiz *= 2);
X bptr = buf+(bsiz/2);
X }
X }
X if (c == EOF)
X return 1;
X if (c == '\n')
X gotnl = 1;
X if (bptr == buf)
X goto redo;
X *bptr = '\0';
X setsparam(reply,buf);
X reply = *args++;
X }
X buf = bptr = zalloc(bsiz = 64);
X if (!gotnl)


X for (;;)
X {

X c = zread();
X if (!ops['r'] && c == '\n' && bptr != buf && bptr[-1] == '\\')
X {
X bptr--;
X continue;
X }
X if (c == EOF || c == '\n')
X break;
X *bptr++ = c;
X if (bptr == buf+bsiz)
X {
X buf = realloc(buf,bsiz *= 2);
X bptr = buf+(bsiz/2);
X }
X }
X *bptr = '\0';
X if (c == EOF)
X return 1;
X setsparam(reply,buf);


X return 0;
X}
X

Xint bin_vared(name,args,ops,func) /**/
Xchar *name;char **args;char *ops;int func;
X{
Xchar *s,*t;
Xstruct param *pm;
X
X if (!(s = getsparam(args[0])))
X {
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 = zleread("> ",NULL,2);
X if (!t || errflag)
X return 1;
X if (t[strlen(t)-1] == '\n')
X t[strlen(t)-1] = '\0';
X pm = gethnode(args[0],paramtab);
X if (pmtype(pm) == PMFLAG_A)
X setaparam(args[0],spacesplit(t));
X else
X setsparam(args[0],t);


X return 0;
X}
X

X#define fset(X) (flags & X)
X
X/* execute a builtin handler function after parsing the arguments */
X
Xint execbin(args,cnode) /**/
XLklist args;Cmdnam cnode;
X{
Xstruct bincmd *b;
Xchar ops[128],*arg,*pp,*name,**argv,**oargv,*optstr;
Xint t0,flags,sense,argc = 0,op;
XLknode n;
X
X auxdata = NULL;
X auxlen = 0;
X for (t0 = 0; t0 != 128; t0++)
X ops[t0] = 0;
X name = ugetnode(args);
X b = builtins+cnode->u.binnum;
X
X/* the 'builtin' builtin is handled specially */
X
X if (b->funcid == BIN_BUILTIN)
X {
X if (!(name = ugetnode(args)))
X {
X zerrnam("builtin","command name expected",NULL,0);
X return 1;
X }


X for (t0 = 0, b = builtins; b->name; b++,t0++)

X if (!strcmp(name,b->name))


X break;
X if (!b->name)
X {

X zerrnam("builtin","no such builtin: %s",name,0);


X return 1;
X }
X }

X flags = b->flags;
X arg = ugetnode(args);
X optstr = b->optstr;
X if (flags & BINF_ECHOPTS && arg && strcmp(arg,"-n"))
X optstr = NULL;
X if (optstr)
X while (arg &&
X ((sense = *arg == '-') || fset(BINF_PLUSOPTS) && *arg == '+') &&
X (fset(BINF_PLUSOPTS) || !atoi(arg)))
X {
X pp = arg;
X if (arg[1] == '-')
X arg++;
X if (!arg[1])
X {
X ops['-'] = 1;
X if (!sense)
X ops['+'] = 1;
X }
X else
X ops['@'] = 1;
X op = -1;
X while (*++arg)
X if (strchr(b->optstr,op = *arg))
X ops[*arg] = (sense) ? 1 : 2;
X else
X break;
X if (*arg)
X {
X zerr("bad option: %c",NULL,*arg);
X return 1;
X }
X arg = ugetnode(args);
X if (fset(BINF_SETOPTS) && op == 'o')
X {
X int c;
X
X if (!arg)
X prtopt();
X else
X {
X c = optlookup(arg);
X if (c == -1)
X {
X zerr("bad option: %s",arg,0);
X return 1;
X }
X else
X {
X ops[c] = ops['o'];
X arg = ugetnode(args);
X }
X }
X }
X if ((fset(BINF_PRINTOPTS) && ops['R']) || ops['-'])
X break;
X if (fset(BINF_SETOPTS) && ops['A'])
X {
X auxdata = arg;
X arg = ugetnode(args);
X break;
X }
X if (fset(BINF_FCOPTS) && op == 'e')
X {
X auxdata = arg;
X arg = ugetnode(args);
X }
X if (fset(BINF_TYPEOPT) && (op == 'L' || op == 'R' ||
X op == 'Z' || op == 'i') && arg && idigit(*arg))
X {
X auxlen = atoi(arg);
X arg = ugetnode(args);
X }
X }
X if (fset(BINF_R))
X auxdata = "-";
X if (pp = b->defopts)
X while (*pp)
X ops[*pp++] = 1;
X if (arg)
X {
X argc = 1;
X n = firstnode(args);
X while (n)
X argc++,incnode(n);
X }
X oargv = argv = (char **) ncalloc(sizeof(char **) * (argc+1));
X if (*argv++ = arg)
X while (*argv++ = ugetnode(args));
X argv = oargv;
X if (errflag)
X return 1;
X if (argc < b->minargs || (argc > b->maxargs && b->maxargs != -1)) {
X zerrnam(name,(argc < b->minargs)
X ? "not enough arguments" : "too many arguments",NULL,0);
X return 1;
X }
X if (isset(XTRACE)) {
X char **pp = argv;
X fprintf(stderr,"%s%s",(prompt4) ? prompt4 : "",name);
X while (*pp) fprintf(stderr," %s",*pp++);
X fputc('\n',stderr);
X fflush(stderr);
X }
X return (*(b->handlerfunc))(name,argv,ops,b->funcid);
X}
X
Xstruct asgment *getasg(s) /**/
Xchar *s;
X{
Xstatic struct asgment asg;
X
X if (!s)
X return NULL;
X if (*s == '=')
X {
X zerr("bad assignment",NULL,0);
X return NULL;
X }
X asg.name = s;
X for (; *s && *s != '='; s++);
X if (*s)
X {
X *s = '\0';
X asg.value = s+1;
X }
X else
X asg.value = NULL;
X return &asg;
X}
X
X/* ., source */
X
Xint bin_dot(name,argv,ops,func) /**/


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

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


X return ret;
X}
X

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


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

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


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

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


X opts[opp->id] = OPT_SET;

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


X opts[opp->id] = OPT_UNSET;

X if (!*argv && !ops['-'])
X return 0;
X permalloc();
X x = arrdup(argv);
X heapalloc();
X if (ops['A'])
X setaparam(auxdata,x);
X else
X {
X freearray(pparams);
X permalloc();
X pparams = x;
X heapalloc();


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 optbuf[0] = '+'; optbuf[1] = optbuf[2] = '\0';
X if (optarg)
X free(optarg);
X optarg = ztrdup("");
X setsparam(var,ztrdup(""));
X if (*optstr == ':')
X {
X quiet = 1;
X optstr++;
X }
X if (optind >= arrlen(args))
X return 1;
X str = args[optind];
X if (*str != '+' && *str != '-' || optcind >= strlen(str) ||
X !strcmp("--",str))
X {
X if (*str == '+' || *str == '-')
X optind++;
X optcind = 0;
X return 1;
X }
X if (!optcind)
X optcind = 1;
X *opch = str[optcind++];
X if (!args[optind][optcind])
X {
X optind++;
X optcind = 0;
X }
X for (; *optstr; optstr++)
X if (*opch == *optstr)
X break;
X if (!*optstr)
X {
X if (quiet)
X {
X optarg = ztrdup(opch);
X setsparam(var,ztrdup("?"));
X return 0;
X }
X zerr("bad option: %c",NULL,*opch);
X return 1;
X }
X setsparam(var,ztrdup(opch-(*str == '+')));
X if (optstr[1] == ':')
X {
X if (!args[optind])
X {
X if (quiet)
X {
X optarg = ztrdup(opch);
X setsparam(var,ztrdup(":"));
X return 0;
X }
X zerr("argument expected after %c option",NULL,*opch);
X return 1;
X }
X free(optarg);
X optarg = ztrdup(args[optind-1]+optcind);
X optind++;
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 {
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 {
X char *s = gettext((vptr) sigfuncs[t0],1);
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 {
X int t0;
X
X argv++;
X if (*argv)
X for (t0 = 0; t0 != VSIGCOUNT; t0++)
X unsettrap(t0);
X else
X while (*argv)
X unsettrap(getsignum(*argv++));
X return 0;
X }
X arg = *argv++;
X if (!*arg)
X l = NULL;
X else if (!(l = parselstring(arg)))
X {
X zerrnam(name,"couldn't parse trap command",NULL,0);
X popheap();
X return 1;
X }


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

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


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

Xint res,hard;
X
X#ifndef RLIM_INFINITY
X zerrnam(name,"not available on this system",NULL,0);
X return 1;
X#else
X hard = ops['H'];
X if (ops['a'] || !ops['@'])
X res = -1;
X else if (ops['t'])
X res = RLIMIT_CPU;
X else if (ops['f'])
X res = RLIMIT_FSIZE;
X else if (ops['d'])
X res = RLIMIT_DATA;
X else if (ops['s'])
X res = RLIMIT_STACK;
X else if (ops['c'])
X res = RLIMIT_CORE;
X#ifdef RLIMIT_RSS
X else if (ops['m'])
X res = RLIMIT_RSS;
X#endif
X#ifdef RLIMIT_NOFILE
X else if (ops['n'])
X res = RLIMIT_NOFILE;
X#endif
X else
X {
X zerrnam(name,"no such limit",NULL,0);
X return 1;
X }
X if (res == -1)
X if (*argv)
X {
X zerrnam(name,"no arguments required after -a",NULL,0);
X return 1;
X }
X else
X {
X int t0;
X
X for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
X printulimit(t0,hard);
X return 0;
X }
X if (!*argv)
X printulimit(res,hard);
X else if (strcmp(*argv,"unlimited"))
X {
X long t0;
X
X t0 = atol(*argv);
X switch(res)
X {
X case RLIMIT_FSIZE: case RLIMIT_CORE: t0 *= 512; break;
X case RLIMIT_DATA: case RLIMIT_STACK:
X#ifdef RLIMIT_RSS
X case RLIMIT_RSS:
X#endif
X t0 *= 1024; break;
X }
X if (hard)
X {
X if (t0 > limits[res].rlim_max && geteuid())
X {
X zerrnam(name,"can't raise hard limits",NULL,0);
X return 1;
X }
X limits[res].rlim_max = t0;
X }
X else
X {
X if (t0 > limits[res].rlim_max)
X {
X if (geteuid())
X {
X zerrnam(name,"value exceeds hard limit",NULL,0);
X return 1;
X }
X limits[res].rlim_max = limits[res].rlim_cur = t0;
X }
X else
X limits[res].rlim_cur = t0;


X }
X }
X else
X {

X if (hard)
X {
X if (geteuid())
X {
X zerrnam(name,"can't remove hard limits",NULL,0);
X return 1;
X }
X limits[res].rlim_max = RLIM_INFINITY;
X }
X else
X limits[res].rlim_cur = limits[res].rlim_max;
X }
X return 0;
X#endif
X}
X
Xint putraw(c) /**/
Xint c;
X{
X putchar(c);


X return 0;
X}
X

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


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

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


X }
X return 0;
X}
X

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


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

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


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

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


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

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

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

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 '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 'L': return(S_ISLNK(dolstat(c->left)));
X case 'O': return((st = getstat(c->left)) && st->st_uid == geteuid());
X case 'G': return((st = getstat(c->left)) && st->st_gid == getegid());
X case 't': return isatty(matheval(c->left));
X case COND_EQ: return matheval(c->left) == matheval(c->right);
X case COND_NE: return matheval(c->left) != matheval(c->right);
X case COND_LT: return matheval(c->left) < matheval(c->right);
X case COND_GT: return matheval(c->left) > matheval(c->right);
X case COND_LE: return matheval(c->left) <= matheval(c->right);
X case COND_GE: return matheval(c->left) >= matheval(c->right);
X case COND_NT: case COND_OT:
X {
X time_t a;
X if (!(st = getstat(c->left)))
X return 0;
X a = st->st_mtime;
X if (!(st = getstat(c->right)))
X return 0;
X return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
X }
X case COND_EF:
X {
X dev_t d;
X ino_t i;
X
X if (!(st = getstat(c->left)))
X return 0;
X d = st->st_dev;
X i = st->st_ino;
X if (!(st = getstat(c->right)))
X return 0;
X return d == st->st_dev && i == st->st_ino;
X }
X default: zerr("bad cond structure",NULL,0);


X }
X return 0;
X}
X

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


X return 0;
X}
X

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

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

X#ifdef __hpux
X#include <ndir.h>
X#else
X#include <sys/dir.h>
X#endif
X
X#define execerr() { if (forked) exit(1); \
X closemnodes(mfds); errflag = 1; return; }
X
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 {
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 {
X execlist(l);
X popheap();
X }
X}
X
X/* duplicate a list and run it */
X
Xvoid newrunlist(l) /**/
XList l;
X{
X List a = (List) dupstruct(l); runlist(a);
X}
X
X/* fork and set limits */
X
Xint phork() /**/
X{
Xint pid = fork(),t0;
X
X if (pid == -1)
X {
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
Xvoid zexecve(pth,argv,ee,b1,b2) /**/
Xchar *pth;char **argv;int *ee;char *b1;char *b2;
X{
Xint eno;
Xchar buf[MAXPATHLEN*2];
Xchar **eep;
X
X for (eep = environ; *eep; eep++)
X if (**eep == '_' && (*eep)[1] == '=')
X break;
X buf[0] = '_';
X buf[1] = '=';
X if (*pth == '/')
X strcpy(buf+2,pth);
X else
X sprintf(buf+2,"%s/%s",cwd,pth);
X if (!*eep)
X eep[1] = NULL;
X *eep = buf;
X execve(pth,argv,environ);
X if ((eno = errno) == ENOEXEC)
X {
X char buf[POUNDBANGLIMIT+1],*ptr,*ptr2,*argv0;
X int fd,ct,t0;
X
X if ((fd = open(pth,O_RDONLY)) >= 0)
X {
X argv0 = *argv;
X *argv = pth;
X ct = read(fd,buf,POUNDBANGLIMIT);
X close(fd);
X if (ct > 0)
X {
X if (buf[0] == '#')
X if (buf[1] == '!')
X {
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 {
X *ptr = '\0';
X argv[-2] = ptr2;
X argv[-1] = ptr+1;
X execve(ptr2,argv-2,environ);
X }
X else
X {
X argv[-1] = ptr2;
X execve(ptr2,argv-1,environ);


X }
X }
X else
X {

X argv[-1] = "sh";
X execve("/bin/sh",argv-1,environ);
X }
X else
X {
X for (t0 = 0; t0 != ct; t0++)
X if (!buf[t0])
X break;
X if (t0 == ct)
X {
X argv[-1] = "sh";
X execve("/bin/sh",argv-1,environ);
X }
X }
X }
X else
X eno = errno;
X *argv = argv0;
X }
X else
X eno = errno;
X }
X if (ee && eno != ENOENT)
X {
X *ee = eno;
X strcpy(b1,b2);
X }
X}
X
X#define MAXCMDLEN (MAXPATHLEN*4)
X
X/* execute an external command */
X
Xvoid execute(args,dash) /**/
XLklist args;int dash;
X{
Xchar **argv,*arg0;
Xchar *z,*s,buf[MAXCMDLEN],buf2[MAXCMDLEN];
XCmdnam cn;
Xint tl,ee = 0;
X
X if (!full(args)) {
X zerr("no command");
X _exit(1);
X }
X cn = (Cmdnam) gethnode(peekfirst(args),cmdnamtab);
X if (cn && cn->type == DISABLED)
X cn = NULL;
X if (s = zgetenv("STTY"))
X zyztem("stty",s);
X arg0 = peekfirst(args);
X if (z = zgetenv("ARGV0"))
X {
X setdata(firstnode(args),ztrdup(z));
X delenv(z-6);
X }
X else if (dash)
X {
X sprintf(buf2,"-%s",arg0);
X setdata(firstnode(args),ztrdup(buf2));
X }
X argv = makecline(args);
X fixsigs();
X if (cn && ISEXCMD(cn->type))
X {
X if (cn->type == EXCMD_POSTDOT)
X zexecve(arg0,argv,&ee,buf2,buf);
X zexecve(cn->u.nam,argv,&ee,buf2,buf);
X }
X for (s = arg0; *s; s++)
X if (*s == '/')
X {
X zexecve(arg0,argv,NULL,NULL,NULL);
X if (arg0 == s || unset(PATHDIRS))
X {
X zerr("%e: %s",arg0,errno);
X _exit(1);
X }
X break;
X }
X for (; *path; path++)
X if ((*path)[0] == '.' && !(*path)[1])
X zexecve(arg0,argv,&ee,buf2,buf);
X else
X {
X tl = strlen(*path);
X strcpy(buf,*path);
X buf[tl] = '/';
X if (strlen(arg0)+strlen(buf)+1 >= MAXCMDLEN)
X {
X zerr("command too long: %s",arg0,0);
X _exit(1);
X }
X strcpy(buf+tl+1,arg0);
X zexecve(buf,argv,&ee,buf2,buf);
X }
X if (ee)
X {
X zerr("%e: %s",arg0,ee);
X _exit(1);
X }
X zerr("command not found: %s",arg0,0);
X _exit(1);
X}
X
X#define try(X) { if (!access(X,X_OK)) return ztrdup(X); }
X
X/* get the pathname of a command */
X
Xchar *findcmd(arg0) /**/
Xchar *arg0;
X{
Xchar *s,buf[MAXPATHLEN];
Xint tl;
Xstruct cmdnam *cn = (Cmdnam) gethnode(arg0,cmdnamtab);
Xchar **pp = path;
X
X if (cn && cn->type == DISABLED)
X cn = NULL;
X if (cn && ISEXCMD(cn->type))
X {
X if (cn->type == EXCMD_POSTDOT)
X {
X strcpy(buf,"./");
X strcat(buf,arg0);
X try(buf);
X }
X try(cn->u.nam);
X }
X for (s = arg0; *s; s++)
X if (*s == '/')
X {
X try(arg0);
X if (s == arg0 || unset(PATHDIRS))
X goto failed;
X break;
X }
X for (; *pp; pp++)
X if (**pp == '.')
X {
X strcpy(buf,"./");
X strcat(buf,arg0);
X try(buf);
X }
X else
X {
X tl = strlen(*pp);
X strcpy(buf,*pp);
X buf[tl] = '/';
X strcpy(buf+tl+1,arg0);
X try(buf);
X }
Xfailed:


X return NULL;
X}
X

Xvoid execlist(list) /**/
XList list;
X{
X if (breaks)
X return;
X simplifyright(list);
X switch(list->type)
X {
X case SYNC:
X case ASYNC:
X execlist2(list->left,list->type,!list->right);
X if (sigtrapped[SIGDEBUG])
X dotrap(SIGDEBUG);
X if (sigtrapped[SIGERR] && lastval)
X dotrap(SIGERR);
X if (list->right && !retflag)
X execlist(list->right);


X break;
X }
X}
X

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


X break;
X }
X}
X

Xint execpline(l,how,last1) /**/
XSublist l;int how;int last1;
X{
Xint ipipe[2],opipe[2];
X
X ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0;
SHAR_EOF
true || echo 'restore of zsh2.1/src/exec.c failed'
fi
echo 'End of zsh2.1.0 part 5'
echo 'File zsh2.1/src/exec.c is continued in part 6'
echo 6 > _shar_seq_.tmp

Paul Falstad

unread,
Oct 24, 1991, 3:08:40 PM10/24/91
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 24, Issue 6
Archive-name: zsh2.1/part06

Environment: BSD
Supersedes: zsh2.00: Volume 18, Issue 84-98

#!/bin/sh
# this is zshar.06 (part 6 of zsh2.1.0)


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

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


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

if test "$Scheck" != 6; then


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

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


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

X blockchld();
X if ((thisjob = getfreejob()) == -1)
X return 1;
X initjob();
X if (how == TIMED)
X {
X jobtab[thisjob].stat |= STAT_TIMED;
X how = SYNC;
X }
X if (l->flags & PFLAG_COPROC)
X {
X how = ASYNC;
X mpipe(ipipe);
X mpipe(opipe);
X if (coprocin)
X {
X close(coprocin);
X close(coprocout);
X }
X coprocin = ipipe[0];
X coprocout = opipe[1];
X }
X execpline2(l->left,how,opipe[0],ipipe[1],last1);
X if (how == ASYNC)
X {
X spawnjob();
X unblockchld();


X return 1;
X }
X else
X {

X waitjobs();
X unblockchld();
X if (l->flags & PFLAG_NOT)
X 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 {
X execcmd(pline->left,input,output,how==ASYNC,last1);
X pline->left = NULL;
X }
X else
X {
X mpipe(pipes);
X
X /* if we are doing "foo | bar" where foo is a current
X shell command, do foo in the current shell and do
X the rest of the pipeline in a subshell. */
X
X if (pline->left->type >= CURSH && how == SYNC)
X {
X if (!(pid = fork()))
X {
X close(pipes[1]);
X entersubsh(how==ASYNC);
X exiting = 1;
X execpline2(pline->right,ASYNC,pipes[0],output,1);
X _exit(lastval);
X }
X else if (pid == -1)


X zerr("fork failed: %e",NULL,errno);

X else
X {
X char *s,*text;
X
X close(pipes[0]);
X text = s = gettext((vptr) pline->right,0);
X addproc(pid,text)->lastfg = 1;
X pline->right = NULL;
X }
X }
X
X /* otherwise just do the pipeline normally. */
X
X execcmd(pline->left,input,pipes[1],how==ASYNC,0);
X pline->left = NULL;
X close(pipes[1]);
X if (pline->right)
X {
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 {
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 {
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 }
X else
X {
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 {
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 {
X next = nextnode(node);
X if (!*(char *) getdata(node))
X uremnode(l,node);
X else
X untokenize(getdata(node));
X }
X}
X
Xvoid untokenize(s) /**/
Xchar *s;
X{


X for (; *s; s++)

X if (itok(*s))
X if (*s == Nularg)
X chuck(s--);
X else
X *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)
X return 0;
X if (stat(f->name,&buf) == -1)
X 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 {
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 {
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 {
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 }
X else
X {
X if (mfds[fd1]->rflag != rflag)
X {
X zerr("file mode mismatch on fd %d",NULL,fd1);
X return;
X }
X if (mfds[fd1]->ct == 1) /* split the stream */
X {
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 }
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 {
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 {
X vl = newlist();
X addnode(vl,v->str);
X }
X else
X vl = v->arr;
X prefork(vl);
X if (errflag)
X return;
X postfork(vl,1);
X if (errflag)
X return;
X if (v->type == PMFLAG_s && (!full(vl) || !nextnode(firstnode(vl))))
X {
X Param pm;
X char *val;
X
X if (!full(vl))
X pm = setsparam(v->name,val = ztrdup(""));
X else
X {
X untokenize(peekfirst(vl));
X pm = setsparam(v->name,val = ztrdup(ugetnode(vl)));
X }
X if (export && !(pm->flags & PMFLAG_x))
X addenv(v->name,val);
X continue;
X }
X ptr = arr = (char **) zalloc(sizeof(char **)*(countnodes(vl)+1));
X while (full(vl))
X {
X *ptr = ztrdup(ugetnode(vl));
X untokenize(*ptr++);
X }
X *ptr = NULL;
X setaparam(v->name,arr);
X }
X}
X
Xvoid execcmd(cmd,input,output,bkg,last1) /**/
XCmd cmd;int input;int output;int bkg;int last1;
X{
Xint type;
Xlong pid = 0;
XLklist args = cmd->args;
Xint save[10],t0;
Xstruct redir *fn;
Xstruct multio *mfds[10];
Xint fil,forked = 0,iscursh = 0,nullexec = 0;
XCmdnam chn = NULL;
Xchar *text;
X
X for (t0 = 0; t0 != 10; t0++)
X {
X save[t0] = 0;
X mfds[t0] = NULL;
X }
X if ((type = cmd->type) == SIMPLE && !full(args))
X if (full(cmd->redir))
X if (cmd->flags & CFLAG_EXEC)
X nullexec = 1;
X else if (!*nullcmd)
X {
X zerr("redirection with no command",NULL,0);
X errflag = lastval = 1;
X return;
X }
X else
X addnode(args,strdup(nullcmd));
X else
X {
X addvars(cmd->vars,0);
X return;
X }
X if (full(args) && *(char *) peekfirst(args) == '%')
X {
X insnode(args,(Lknode) args,strdup((bkg) ? "bg" : "fg"));
X bkg = 0;
X }
X if (isset(AUTORESUME) && !bkg && !full(cmd->redir) && full(args) &&
X !input && type == SIMPLE && !nextnode(firstnode(args)) &&
X findjobnam(peekfirst(args)) != -1)
X pushnode(args,strdup("fg"));
X if (unset(RMSTARSILENT) && interact && isset(SHINSTDIN) &&
X type == SIMPLE && full(args) && nextnode(firstnode(args)) &&
X !strcmp(peekfirst(args),"rm"))
X {
X char *s = getdata(nextnode(firstnode(args)));
X
X if (s[0] == Star && !s[1])
X checkrmall();
X }
X if (jobbing) /* get the text associated with this command */
X {
X char *s;
X s = text = gettext((vptr) cmd,0);
X }
X else
X text = NULL;
X prefork(args); /* do prefork substitutions */
X if (errflag)
X {
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 (full(args) && !(cmd->flags & CFLAG_COMMAND))
X chn = (Cmdnam) gethnode(peekfirst(args),cmdnamtab);
X if (type == SIMPLE && !pathsuppress && !chn && isset(AUTOCD) &&
X full(args) && !full(cmd->redir) &&
X !nextnode(firstnode(args)) && cancd(peekfirst(args)))
X {
X pushnode(args,strdup("cd"));
X chn = (Cmdnam) gethnode("cd",cmdnamtab);
X }
X
X /* this is nonzero if cmd is a current shell procedure */
X
X iscursh = (type >= CURSH) || (type == SIMPLE && chn &&
X (chn->type == BUILTIN || chn->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 (chn && (chn->type == BUILTIN || chn->type == SHFUNC) && output))
X {
X int synch[2];
X
X pipe(synch);
X pid = (last1 && execok()) ? 0 : phork();


X if (pid == -1)
X {

X close(synch[0]);
X close(synch[1]);
X return;
X }
X if (pid)
X {
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 ( void ) addproc(pid,text);
X return;
X }
X close(synch[0]);
X entersubsh(bkg);
X close(synch[1]);
X forked = 1;
X }
X if (bkg && isset(BGNICE)) /* stupid */
X nice(5);
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 {
X if (fn->fd2 == -1)
X execerr();
X addfd(forked,save,mfds,fn->fd1,fn->fd2,0);
X }
X else if (fn->type == OUTPIPE)
X {
X if (fn->fd2 == -1)
X execerr();
X addfd(forked,save,mfds,fn->fd1,fn->fd2,1);
X }
X else
X {
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 (fn->type == HERESTR)
X {
X fil = getherestr(fn);
X if (fil == -1)
X {
X if (errno != EINTR)
X zerr("%e",NULL,errno);
X execerr();
X }
X addfd(forked,save,mfds,fn->fd1,fil,0);
X }
X else if (fn->type == READ)
X {
X fil = open(fn->name,O_RDONLY);
X if (fil == -1)
X {
X if (errno != EINTR)
X zerr("%e: %s",fn->name,errno);
X execerr();
X }
X addfd(forked,save,mfds,fn->fd1,fil,0);
X }
X else if (fn->type == CLOSE)
X {
X if (!forked && fn->fd1 < 10)
X save[fn->fd1] = movefd(fn->fd1);
X closemn(mfds,fn->fd1);
X close(fn->fd1);
X }
X else if (fn->type == MERGE || fn->type == MERGEOUT)
X {
X fil = dup(fn->fd2);
X if (mfds[fn->fd1])
X redup(fil,fn->fd1);
X else
X addfd(forked,save,mfds,fn->fd1,fil,fn->type == MERGEOUT);
X }
X else
X {
X if (fn->type >= APP)
X fil = open(fn->name,isset(NOCLOBBER) ?
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 {
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 /* perform postfork substitutions */
X /* you put this here so that ls *.sdfoij >& /dev/null works, remember? */
X postfork(args,!(cmd->flags & CFLAG_NOGLOB));
X if (errflag)
X {
X lastval = 1;
X goto err;
X }
X
X /* we are done with redirection. close the mnodes, spawning
X tee/cat processes as necessary. */
X for (t0 = 0; t0 != 10; t0++)
X closemn(mfds,t0);
X
X if (nullexec)
X return;
X if (unset(NOEXEC))
X if (type >= ZCTIME)
X {
X static int (*func[]) DCLPROTO((Cmd)) = {
X exectime,execcursh,execfuncdef,execfor,execwhile,
X execrepeat,execif,execcase,execselect,execcond };
X
X fixcline(args);
X lastval = (func[type-ZCTIME])(cmd);
X }
X else if (iscursh) /* builtin or shell function */
X {
X if (cmd->vars)
X addvars(cmd->vars,0);
X fixcline(args);
X if (chn && chn->type == SHFUNC)
X execshfunc(cmd,chn);
X else
X {
X lastval = execbin(args,chn);
X if (isset(PRINTEXITVALUE) && lastval)
X zerr("exit %d",NULL,lastval);
X fflush(stdout);
X if (ferror(stdout))
X {
X zerr("write error: %e",NULL,errno);
X clearerr(stdout);


X }
X }
X }
X else

X {
X if (cmd->vars)
X addvars(cmd->vars,1);
X if (type == SIMPLE)
X {
X closem();
X execute(args,cmd->flags & CFLAG_DASH);
X }
X else /* ( ... ) */
X execlist(cmd->u.list);
X }
Xerr:
X if (forked)
X _exit(lastval);
X fixfds(save);
X}
X
X/* restore fds after redirecting a builtin */
X
Xvoid fixfds(save) /**/
Xint *save;
X{
Xint t0;
X
X for (t0 = 0; t0 != 10; t0++)
X if (save[t0])
X redup(save[t0],t0);
X}
X
Xvoid entersubsh(bkg) /**/
Xint bkg;
X{
X if (!jobbing)
X {
X if (bkg && isatty(0))
X {
X close(0);
X if (open("/dev/null",O_RDWR))
X {
X zerr("can't open /dev/null: %e",NULL,errno);
X _exit(1);
X }
X }
X }
X else if (!jobtab[thisjob].gleader)
X {
X jobtab[thisjob].gleader = getpid();
X setpgrp(0L,jobtab[thisjob].gleader);
X if (!bkg)
X attachtty(jobtab[thisjob].gleader);
X }
X else
X setpgrp(0L,jobtab[thisjob].gleader);
X subsh = 1;
X if (SHTTY != -1)
X {
X close(SHTTY);
X SHTTY = -1;
X }
X if (jobbing)
X {
X signal(SIGTTOU,SIG_DFL);
X signal(SIGTTIN,SIG_DFL);
X signal(SIGTSTP,SIG_DFL);
X signal(SIGPIPE,SIG_DFL);
X }
X if (interact)
X {
X signal(SIGTERM,SIG_DFL);
X if (sigtrapped[SIGINT])
X signal(SIGINT,SIG_IGN);
X }
X if (!sigtrapped[SIGQUIT])
X signal(SIGQUIT,SIG_DFL);
X opts[MONITOR] = OPT_UNSET;
X clearjobtab();
X}
X
X/* close all internal shell fds */
X
Xvoid closem() /**/
X{
Xint t0;
X
X for (t0 = 10; t0 != NOFILE; t0++)
X close(t0);
X}
X
X/* convert here document into a here string */
X
Xchar *gethere(str,typ) /**/
Xchar *str;int typ;
X{
Xchar pbuf[256];
Xint qt = 0,siz = 0,l,strip = 0;
Xchar *s,*t,*bptr;
X
X for (s = str; *s; s++)
X if (*s == Nularg)
X qt = 1;
X untokenize(str);
X if (typ == HEREDOCDASH)
X {
X strip = 1;
X while (*str == '\t')
X str++;
X }
X t = ztrdup("");
X for(;;)
X {
X char *u,*v;
X
X if (!fgets(pbuf,256,bshin))
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 {
X s++;
X if (!*s)
X break;
X }
X s = strdup(t);
X free(t);
X return s;
X}
X
X/* open here string fd */
X
Xint getherestr(fn) /**/
Xstruct redir *fn;
X{
XLklist fake;
Xchar *s = gettemp(),*t;
Xint fd;
X
X fake = newlist();
X addnode(fake,fn->name);
X prefork(fake);
X if (!errflag)
X postfork(fake,1);
X if (errflag)
X return -1;
X if ((fd = open(s,O_CREAT|O_WRONLY,0600)) == -1)
X return -1;
X while (t = ugetnode(fake))
X {
X untokenize(t);
X write(fd,t,strlen(t));
X if (full(fake))
X write(fd," ",1);
X }
X write(fd,"\n",1);
X close(fd);
X fd = open(s,O_RDONLY);
X unlink(s);
X return fd;
X}
X
Xvoid catproc(mn) /**/
Xstruct multio *mn;
X{
Xint len,t0;
Xchar *buf;
X
X if (phork())
X {
X for (t0 = 0; t0 != mn->ct; t0++)
X close(mn->fds[t0]);
X close(mn->pipe);
X return;
X }
X closeallelse(mn);
X buf = zalloc(4096);
X for (t0 = 0; t0 != mn->ct; t0++)
X while (len = read(mn->fds[t0],buf,4096))
X write(mn->pipe,buf,len);
X _exit(0);
X}
X
Xvoid teeproc(mn) /**/
Xstruct multio *mn;
X{
Xint len,t0;
Xchar *buf;
X
X if (phork())
X {
X for (t0 = 0; t0 != mn->ct; t0++)
X close(mn->fds[t0]);
X close(mn->pipe);
X return;
X }
X buf = zalloc(4096);
X closeallelse(mn);
X while ((len = read(mn->pipe,buf,4096)) > 0)
X for (t0 = 0; t0 != mn->ct; t0++)
X write(mn->fds[t0],buf,len);
X _exit(0);
X}
X
Xvoid closeallelse(mn) /**/
Xstruct multio *mn;
X{
Xint t0,t1;
X
X for (t0 = 0; t0 != NOFILE; t0++)
X if (mn->pipe != t0)
X {
X for (t1 = 0; t1 != mn->ct; t1++)
X if (mn->fds[t1] == t0)
X break;
X if (t1 == mn->ct)
X close(t0);
X }
X}
X
Xlong int zstrtol(s,t,base) /**/
Xchar *s;char **t;int base;


X{
Xint ret = 0;
X

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


X return ret;
X}
X

X/* $(...) */
X
XLklist getoutput(cmd,qt) /**/
Xchar *cmd;int qt;
X{
XList list;
Xint pipes[2];
X
X if (*cmd == '<')
X {
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 {
X zerr("%e: %s",cmd+1,errno);
X return NULL;
X }
X return readoutput(stream,qt);
X }
X if (!(list = parselstring(cmd)))
X return NULL;
X mpipe(pipes);
X if (phork())
X {
X popheap();
X close(pipes[1]);
X /* chldsuspend(); */
X return readoutput(pipes[0],qt);
X }
X subsh = 1;
X close(pipes[0]);
X redup(pipes[1],1);
X entersubsh(0);
X signal(SIGTSTP,SIG_IGN);
X exiting = 1;
X execlist(list);
X close(1);
X exit(0); return NULL;
X}
X
X/* read output of command substitution */
X
XLklist readoutput(in,qt) /**/
Xint in;int qt;
X{
XLklist ret;
Xchar *buf,*ptr;
Xint bsiz,c,cnt = 0;
XFILE *fin;
X
X fin = fdopen(in,"r");
X ret = newlist();
X ptr = buf = zalloc(bsiz = 256);
X while ((c = fgetc(fin)) != EOF)
X if (!qt && isep(c))
X {
X if (cnt)


X {
X *ptr = '\0';

X addnode(ret,ztrdup(buf));
X cnt = 0;
X ptr = buf;


X }
X }
X else
X {

X *ptr++ = c;
X if (++cnt == bsiz)
X {
X char *pp = zalloc(bsiz *= 2);
X
X memcpy(pp,buf,cnt);
X free(buf);
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)
X addnode(ret,ztrdup(buf));
X free(buf);
X fclose(fin);


X return ret;
X}
X

X/* =(...) */
X
Xchar *getoutputfile(cmd) /**/
Xchar *cmd;
X{
X#ifdef WAITPID
Xint pid;
X#endif
Xchar *nam = gettemp(),*str;
Xint tfil;
XList list;
X
X if (thisjob == -1)
X return NULL;
X for (str = cmd; *str && *str != Outpar; str++);
X if (!*str)
X zerr("oops.",NULL,0);
X *str = '\0';
X if (!(list = parselstring(cmd)))
X return NULL;
X permalloc();
X if (!jobtab[thisjob].filelist)
X jobtab[thisjob].filelist = newlist();
X addnode(jobtab[thisjob].filelist,ztrdup(nam));
X heapalloc();
X#ifdef WAITPID
X if (pid = phork())
X {
X popheap();
X waitpid(pid,NULL,WUNTRACED);
X return nam;
X }
X#else
X if (waitfork())
X return nam;
X#endif
X subsh = 1;
X close(1);
X entersubsh(0);
X tfil = creat(nam,0666);
X exiting = 1;
X execlist(list);
X close(1);
X exit(0); return NULL;
X}
X
X/* get a temporary named pipe */
X
Xchar *namedpipe() /**/
X{
Xchar *tnam = gettemp();
X
X mknod(tnam,0010666,0);
X return tnam;
X}
X
X/* <(...) */
X
Xchar *getoutproc(cmd) /**/
Xchar *cmd;
X{
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 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 fd = open(pnam,O_WRONLY);
X if (fd == -1)
X {
X zerr("can't open %s: %e",pnam,errno);
X _exit(0);
X }
X redup(fd,1);
X fd = open("/dev/null",O_RDONLY);
X redup(fd,0);
X exiting = 1;
X execlist(list);
X close(1);
X _exit(0); return NULL;
X}
X
X/* >(...) */
X
Xchar *getinproc(cmd) /**/
Xchar *cmd;
X{
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 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 fd = open(pnam,O_RDONLY);
X redup(fd,0);
X exiting = 1;
X execlist(list);
X _exit(0); return NULL;
X}
X
X/* > >(...) (does not use named pipes) */
X
Xint getinpipe(cmd) /**/
Xchar *cmd;
X{
XList list;
Xint pipes[2];
Xchar *str = cmd;
X
X for (str = cmd; *str && *str != Outpar; str++);
X if (!*str)
X zerr("oops.",NULL,0);
X *str = '\0';
X if (!(list = parselstring(cmd+2)))
X return -1;
X mpipe(pipes);
X if (phork())
X {
X popheap();
X close(pipes[1]);
X return pipes[0];
X }
X close(pipes[0]);
X entersubsh(1);
X redup(pipes[1],1);
X exiting = 1;
X execlist(list);
X _exit(0); return 0;
X}
X
X/* < <(...) */
X
Xint getoutpipe(cmd) /**/
Xchar *cmd;
X{
XList list;
Xint pipes[2];
Xchar *str;
X
X for (str = cmd; *str && *str != Outpar; str++);
X if (!*str)
X zerr("oops.",NULL,0);
X *str = '\0';
X if (!(list = parselstring(cmd+2)))
X return -1;
X strinend();
X mpipe(pipes);
X if (phork())
X {
X popheap();
X close(pipes[0]);
X return pipes[1];
X }
X close(pipes[1]);
X entersubsh(1);
X redup(pipes[0],0);
X exiting = 1;
X execlist(list);
X _exit(0); return 0;
X}
X
X/* run a list, saving the current job num */
X
Xvoid runlist(l) /**/
XList l;
X{
Xint cj = thisjob;
X
X execlist(l);
X thisjob = cj;
X}
X
Xchar *gettemp() /**/
X{
X return mktemp(dyncat(tmpprefix,"XXXXXX"));
X}
X
X/* my getwd; all the other ones I tried confused the SIGCHLD handler */
X
Xchar *zgetwd() /**/
X{
Xstatic char buf0[MAXPATHLEN];
Xchar buf3[MAXPATHLEN],*buf2 = buf0+1;
Xstruct stat sbuf;
Xstruct direct *de;
XDIR *dir;
Xino_t ino = -1;
Xdev_t dev = -1;
X
X holdintr();
X buf2[0] = '\0';
X buf0[0] = '/';
X for(;;)
X {
X if (stat(".",&sbuf) < 0)
X {
X chdir(buf0);
X noholdintr();
X return ztrdup(".");
X }
X ino = sbuf.st_ino;
X dev = sbuf.st_dev;
X if (stat("..",&sbuf) < 0)
X {
X chdir(buf0);
X noholdintr();
X return ztrdup(".");
X }
X if (sbuf.st_ino == ino && sbuf.st_dev == dev)
X {
X chdir(buf0);
X noholdintr();
X return ztrdup(buf0);
X }
X dir = opendir("..");
X if (!dir)
X {
X chdir(buf0);
X noholdintr();
X return ztrdup(".");
X }
X chdir("..");
X readdir(dir); readdir(dir);
X while (de = readdir(dir))
X if (de->d_ino == ino)
X {
X lstat(de->d_name,&sbuf);
X if (sbuf.st_dev == dev)
X goto match;
X }
X rewinddir(dir);
X readdir(dir); readdir(dir);
X while (de = readdir(dir))
X {
X lstat(de->d_name,&sbuf);
X if (sbuf.st_dev == dev)
X goto match;
X }
X noholdintr();
X closedir(dir);
X return ztrdup(".");
Xmatch:
X strcpy(buf3,de->d_name);
X if (*buf2)
X strcat(buf3,"/");
X strcat(buf3,buf2);
X strcpy(buf2,buf3);
X closedir(dir);
X }
X}
X
X/* open pipes with fds >= 10 */
X
Xvoid mpipe(pp) /**/
Xint *pp;
X{
X pipe(pp);
X pp[0] = movefd(pp[0]);
X pp[1] = movefd(pp[1]);
X}
X
X/* do process substitution with redirection */
X
Xvoid spawnpipes(l) /**/
XLklist l;
X{
XLknode n = firstnode(l);
XRedir f;
X
X for (; n; incnode(n))
X {
X f = (Redir) getdata(n);
X if (f->type == OUTPIPE)
X {
X char *str = f->name;
X f->fd2 = getoutpipe(str);
X }
X if (f->type == INPIPE)
X {
X char *str = f->name;
X f->fd2 = getinpipe(str);
X }
X }
X}
X
X/* perform time ... command */
X
Xint exectime(cmd) /**/
XCmd cmd;
X{
Xint jb = thisjob;
X
X execpline(cmd->u.pline,TIMED,0);
X thisjob = jb;


X return lastval;
X}
X

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


X cc->type = SHFUNC;

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


X }
X heapalloc();
X return 0;
X}
X

X/* evaluate a [[ ... ]] */
X
Xint execcond(cmd) /**/
XCmd cmd;
X{
X return !evalcond(cmd->u.cond);
X}
X
Xvoid execshfunc(cmd,cn) /**/
XCmd cmd;Cmdnam cn;
X{
Xchar **tab,**x,*oargv0;
Xint oxtr = opts[XTRACE],flags,xexittr;
XList l;
XLklist olist;
Xchar *s;
XList xexitfn;
X
X if (errflag)
X return;
X l = cn->u.list;
X if (!l)
X {
X char *nam;
X
X if (!(l = getfpfunc(nam = peekfirst(cmd->args))))
X {
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 flags = cn->flags;
X xexittr = sigtrapped[SIGEXIT];
X xexitfn = sigfuncs[SIGEXIT];
X tab = pparams;
X oargv0 = argzero;
X optind = 0;
X if (flags & PMFLAG_t)
X opts[XTRACE] = OPT_SET;
X pparams = x = (char **) zcalloc(((sizeof *x)*(1+countnodes(cmd->args))));
X argzero = ztrdup(ugetnode(cmd->args));
X while (*x = ugetnode(cmd->args))
X *x = ztrdup(*x), x++;
X permalloc();
X olist = locallist;
X locallist = newlist();
X heapalloc();
X newrunlist(l);
X while (s = getnode(locallist))
X unsetparam(s);
X free(locallist);
X locallist = olist;
X retflag = 0;


X cmd->u.list = NULL;

X freearray(pparams);
X free(argzero);
X argzero = oargv0;
X pparams = tab;
X if (sigfuncs[SIGEXIT] && sigfuncs[SIGEXIT] != xexitfn)
X {
X dotrap(SIGEXIT);
X freestruct(sigfuncs[SIGEXIT]);
X }
X sigtrapped[SIGEXIT] = xexittr;
X sigfuncs[SIGEXIT] = xexitfn;
X opts[XTRACE] = oxtr;
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{
X if (*s != '/')
X {
X char sbuf[MAXPATHLEN],**cp;
X
X if (cancd2(s))
X return 1;
X if (access(s,X_OK) == 0)
X return 0;
X for (cp = cdpath; *cp; cp++)
X {
X sprintf(sbuf,"%s/%s",*cp,s);
X if (cancd2(sbuf))


X return 1;
X }
X return 0;
X }

X return cancd2(s);
X}
X
Xint cancd2(s)
Xchar *s;
X{
Xstruct stat buf;
X
X return !(access(s,X_OK) || stat(s,&buf) || !S_ISDIR(buf.st_mode));
X}
X
SHAR_EOF
echo 'File zsh2.1/src/exec.c is complete' &&
chmod 0644 zsh2.1/src/exec.c ||


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

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

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

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

X#ifdef SYSV
X#define direct dirent
X#else
X#include <sys/dir.h>
X#endif
X#endif
X#include <sys/errno.h>
X
X#define exists(X) (access(X,0) == 0)
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] */
X
X/* max # of qualifiers */
X
X#define QUALCT 16
X
Xstatic int (*qualfuncs[QUALCT])DCLPROTO((struct stat *,long));
Xstatic long qualdata[QUALCT];
Xstatic int qualsense[QUALCT];
Xstatic int qualct;
X
X/* pathname component in filename patterns */
X
Xstruct complist {
X Complist next;
X Comp comp;
X int closure; /* 1 if this is a (foo/)# */
X };
Xstruct comp {
X Comp left,right,next;
X char *str;
X int closure,last;
X };
X
Xvoid glob(list,np) /**/
XLklist list;Lknode *np;
X{
XLknode node = prevnode(*np);
XLknode next = nextnode(*np);
Xint sl; /* length of the pattern */
Xchar *ostr; /* the pattern before the parser chops it up */
XComplist q; /* pattern after parsing */
Xchar *str = getdata(*np); /* the pattern */
X
X sl = strlen(str);
X ostr = strdup(str);
X uremnode(list,*np);
X qualct = 0;
X if (str[sl-1] == Outpar) /* check for qualifiers */
X {
X char *s;
X int sense = 0;
X long data;
X int (*func) DCLPROTO((struct stat *,long));
X
X for (s = str+sl-2; s != str; s--)
X if (*s == Bar || *s == Outpar || *s == Inpar)
X break;
X if (*s == Inpar)
X {
X *s++ = '\0';
X func = NULL;
X while (*s != Outpar)
X {
X func = NULL;
X if (idigit(*s))
X {
X func = qualflags;
X data = 0;
X while (idigit(*s))
X data = data*010+(*s++-'0');
X }
X else switch (*s++)
X {
X case 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 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 default: zerr("unknown file attribute",NULL,0); return;
X }
X if (func)
X {
X if (qualct == QUALCT-1)
X {
X zerr("too many qualifiers",NULL,0);
X return;
X }
X qualfuncs[qualct] = func;
X qualsense[qualct] = sense;
X qualdata[qualct] = data;
X qualct++;
X }
X if (errflag)
X return;
X }
X }
X }
X else if (str[sl-1] == '/') /* foo/ == foo(/) */
X {
X str[sl-1] = '\0';
X qualfuncs[0] = qualmode;
X qualdata[0] = S_IFDIR;
X qualsense[0] = 0;
X qualct = 1;
X }
X qualfuncs[qualct] = NULL;
X if (*str == '/') /* pattern has absolute path */
X {
X str++;
X pathbuf[0] = '/';
X pathbuf[pathpos = 1] = '\0';
X }
X else /* pattern is relative to cwd */
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 (unset(NULLGLOB))
X if (isset(CSHNULLGLOB)) {
X badcshglob |= 1;
X } else if (unset(NONOMATCH)) {
X zerr("no matches found: %s",ostr,0);
X free(matchbuf);
X return;
X } else {
X *matchptr++ = strdup(ostr);
X matchct = 1;
X }
X qsort(&matchbuf[0],matchct,sizeof(char *),notstrcmp);
X matchptr = matchbuf;
X while (matchct--) /* insert matches in the arg list */
X insnode(list,node,*matchptr++);
X free(matchbuf);
X *np = (next) ? prevnode(next) : lastnode(list);
X}
X
X/* get number after qualifier */
X
Xlong qgetnum(s) /**/
Xchar **s;
X{
Xlong v = 0;
X
X if (!idigit(**s))
X {
X zerr("number expected",NULL,0);
X return 0;
X }
X while (idigit(**s))
X v = v*10+*(*s)++-'0';
X return v;
X}
X
Xint notstrcmp(a,b) /**/
Xchar **a;char **b;
X{
Xchar *c = *b,*d = *a;
Xint x1,x2;
X
X for (; *c == *d && *c; c++,d++);
X x1 = atoi(c); x2 = atoi(d);
X if (x1==x2)
X return ((int) (unsigned char) *c-(int) (unsigned char) *d);
X return x1-x2;
X}
X
Xint forstrcmp(a,b) /**/
Xchar **a;char **b;
X{
Xchar *c = *b,*d = *a;
X
X for (; *c == *d && *c; c++,d++);
X return ((int) (unsigned char) *d-(int) (unsigned char) *c);
X}
X
X/* add a match to the list */
X
Xvoid insert(s) /**/
Xchar *s;
X{
Xstruct stat buf;
X
X if (isset(MARKDIRS) && !lstat(s,&buf) && S_ISDIR(buf.st_mode)) /* grrr */
X {
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 }
X *matchptr++ = s;
X if (++matchct == matchsz)
X {
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[1] && (*str == Inbrack || *str == Outbrack))
X return 0;
X if (str[0] == '%')
X return 0;
X for (; *str; str++)
X if (str[0] == Star && str[1] == Star &&
X str[2] == Star && str[3] == Star && str[4] == '/')
X return 1;
X else if (*str == Pound || *str == Hat || *str == Star ||
X *str == Bar || *str == Inbrack || *str == Inang ||
X *str == Quest)
X 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 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)
X return 0;
X if (full(fake) && !nextnode(firstnode(fake)))
X {
X fn->name = peekfirst(fake);
X untokenize(fn->name);
X }
X else
X while (nam = ugetnode(fake))
X {
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;
X
X for (; *str != Inbrace; str++);
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,unset(GLOBDOTS)))
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
X {
X if (qualct) /* do the (X) (^X) stuff */
X {
X int (**fptr)DCLPROTO((struct stat *,long)) = qualfuncs;
X int *sptr = qualsense;
X long *lptr = qualdata;
X struct stat buf;
X
X if (lstat(getfullpath(fn),&buf) == -1)
X {
X if (errno != ENOENT && errno != EINTR)
X {
X zerr("%e: %s",fn,errno);
X errflag = 0;
X }
X continue;
X }
X while (*fptr)
X if (!(!!((*fptr++)(&buf,*lptr++)) ^ *sptr++))
X {
X fptr = NULL;
X break;
X }
X if (!fptr)
X continue;
X }
X insert(dyncat(pathbuf,fn));
X }
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 {
X char *saves = pptr;
X int savei = first;
X
X if (doesmatch(c->next))
X return 1;
X pptr = saves;
X first = savei;
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;
SHAR_EOF
true || echo 'restore of zsh2.1/src/glob.c failed'
fi
echo 'End of zsh2.1.0 part 6'
echo 'File zsh2.1/src/glob.c is continued in part 7'
echo 7 > _shar_seq_.tmp

Paul Falstad

unread,
Oct 24, 1991, 3:09:01 PM10/24/91
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 24, Issue 7
Archive-name: zsh2.1/part07

Environment: BSD
Supersedes: zsh2.00: Volume 18, Issue 84-98

#!/bin/sh
# this is zshar.07 (part 7 of zsh2.1.0)


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

# file zsh2.1/src/glob.c continued


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

if test "$Scheck" != 7; then


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

echo 'x - still skipping zsh2.1/src/glob.c'
else
echo 'x - continuing file zsh2.1/src/glob.c'


sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.1/src/glob.c' &&

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{
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] == Star && pptr[3] == Star &&
X pptr[4] == '/')
X {
X pptr[0] = Inpar;
X pptr[1] = Star;
X pptr[2] = '/';
X pptr[3] = Outpar;
X pptr[4] = Pound; /* "####/" -> "( * /)#" */
X }
X if (*pptr == Inpar)
X {
X char *str;
X int pars = 1;
X
X for (str = pptr+1; *str && pars; str++)
X if (*str == Inpar)
X pars++;
X else if (*str == Outpar)
X pars--;
X if (str[0] != Pound || str[-1] != Outpar || str[-2] != '/')
X goto kludge;
X pptr++;
X if (!(c1 = parsecompsw()))
X return NULL;
X if (pptr[0] == '/' && pptr[1] == Outpar && pptr[2] == Pound)
X {
X int pdflag = 0;
X
X pptr += 3;
X if (*pptr == Pound)
X {
X pdflag = 1;
X pptr++;
X }
X p1 = (Complist) alloc(sizeof *p1);
X p1->comp = c1;
X p1->closure = 1+pdflag;
X p1->next = parsecomplist();
X return (p1->comp) ? p1 : NULL;


X }
X }
X else
X {

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


X return NULL;
X}
X

XComp parsecomp() /**/
X{
XComp c = (Comp) alloc(sizeof *c),c1,c2;
Xchar *s = c->str = alloc(MAXPATHLEN*2),*ls = NULL;
X
X c->next = tail;
X
X while (*pptr && (mode || *pptr != '/') && *pptr != Bar &&
X *pptr != Outpar)
X {
X if (*pptr == Hat)
X {
X *s++ = Hat;
X *s++ = '\0';
X pptr++;
X if (!(c->next = parsecomp()))
X return NULL;
X return c;
X }
X if (*pptr == Star && pptr[1] && (mode || pptr[1] != '/'))


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

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


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

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


X if (*s == Nularg)

X chuck(s);
X else
X s++;
X if (!*t && nl)
X {
X t[0] = Nularg;
X t[1] = '\0';
X }
X}
X
X/* qualifier functions */
X
Xint qualdev(buf,dv) /**/
Xstruct stat *buf;long dv;
X{
X return buf->st_dev == dv;
X}
X
Xint qualnlink(buf,ct) /**/
Xstruct stat *buf;long ct;
X{
X return buf->st_nlink == ct;
X}
X
Xint qualuid(buf,uid) /**/
Xstruct stat *buf;long uid;
X{
X return buf->st_uid == uid;
X}
X
Xint qualgid(buf,gid) /**/
Xstruct stat *buf;long gid;
X{
X return buf->st_gid == gid;
X}
X
Xint qualisdev(buf,junk) /**/
Xstruct stat *buf;long junk;
X{
X junk = buf->st_mode & S_IFMT;
X return junk == S_IFBLK || junk == S_IFCHR;
X}
X
Xint qualmode(buf,mod) /**/
Xstruct stat *buf;long mod;
X{
X return (buf->st_mode & S_IFMT) == mod;
X}
X
Xint qualflags(buf,mod) /**/
Xstruct stat *buf;long mod;
X{
X return buf->st_mode & mod;
X}
X
Xint qualiscom(buf,mod) /**/
Xstruct stat *buf;long mod;
X{
X return (buf->st_mode & (S_IFMT|S_IEXEC)) == (S_IFREG|S_IEXEC);
X}
X
SHAR_EOF
echo 'File zsh2.1/src/glob.c is complete' &&
chmod 0644 zsh2.1/src/glob.c ||


echo 'restore of zsh2.1/src/glob.c failed'

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

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

Xstatic int lastc;
X
X/* add a character to the current history word */
X
Xvoid hwaddc(c) /**/
Xint c;
X{
X if (hlastw && hline && (!(errflag || lexstop) || c == HISTSPACE))
X {
X *hptr++ = c;
X if (hptr-hline >= hlinesz)
X {
X int ll,flag = 0;
X
X ll = hptr-hlastw;
X if (full(histlist) && getdata(lastnode(histlist)) == hline)
X flag = 1;
X hline = realloc(hline,hlinesz *= 4);
X if (flag)
X setdata(lastnode(histlist),hline);
X hptr = hline+(hlinesz/4);
X hlastw = hptr-ll;
X }
X }
X}
X
X#define habort() { errflag = lexstop = 1; return ' '; }
X
X/* get a character after performing history substitution */
X
Xint hgetc() /**/
X{
Xint c,ev,farg,larg,argc,marg = -1,cflag = 0,bflag = 0;
Xchar buf[256],*ptr;
Xchar *sline,*eline;
X
Xtailrec:
X c = hgetch();
X if (stophist || alstackind)
X {
X hwaddc(c);
X return c;
X }
X if (isfirstch && c == hatchar)
X {
X isfirstch = 0;
X hungetch(hatchar);
X hungets(":s");
X c = bangchar;
X goto hatskip;
X }
X if (c != ' ')
X isfirstch = 0;
X if (c == '\\')
X {
X int g = hgetch();
X
X if (g != bangchar)
X hungetch(g);
X else
X {
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]) && !idigit(c)) break;


X }
X *ptr++ = c;

X if (c == '#' || c == bangchar)
X {
X c = hgetch();
X break;
X }
X c = hgetch();


X }
X *ptr = 0;

X if (!*buf)
X ev = defev;
X else if (t0 = atoi(buf))
X ev = (t0 < 0) ? curhist+t0 : t0;
X else if (*buf == bangchar)
X ev = curhist-1;
X else if (*buf == '#')
X ev = curhist;
X else if ((ev = hcomsearch(buf)) == -1)
X {
X zerr("event not found: %s",buf,0);
X while (c != '\n' && !lexstop)
X c = hgetch();
X habort();
X }
X }
X
X /* get the event */
X
X if (!(eline = getevent(defev = ev)))
X habort();
X
X /* extract the relevant arguments */
X
X argc = getargc(eline);
X if (c == ':')
X {
X cflag = 1;
X c = hgetch();
X }
X if (c == '*')
X {
X farg = 1;
X larg = argc;
X cflag = 0;
X }
X else
X {
X hungetch(c);
X larg = farg = getargspec(argc,marg);
X if (larg == -2)
X habort();
X if (farg != -1)
X cflag = 0;
X c = hgetch();
X if (c == '*')
X {
X cflag = 0;
X larg = argc;
X }
X else if (c == '-')
X {
X cflag = 0;
X larg = getargspec(argc,marg);
X if (larg == -2)
X habort();
X if (larg == -1)
X larg = argc-1;
X }
X else
X hungetch(c);
X }
X if (farg == -1)
X farg = 0;
X if (larg == -1)
X larg = argc;
X if (!(sline = getargs(eline,farg,larg)))
X habort();
X
X /* do the modifiers */


X
X for(;;)
X {

X c = (cflag) ? ':' : hgetch();
X cflag = 0;
X if (c == ':')
X {
X int gbal = 0;
X
X if ((c = hgetch()) == 'g')
X {
X gbal = 1;
X c = hgetch();
X }
X switch(c)
X {
X case 'p':
X histdone = HISTFLAG_DONE|HISTFLAG_NOEXEC;
X break;
X case 'h':
X if (!remtpath(&sline))
X {
X herrflush();
X zerr("modifier failed: h",NULL,0);
X habort();
X }
X break;
X case 'e':
X if (!rembutext(&sline))
X {
X herrflush();
X zerr("modifier failed: e",NULL,0);
X habort();
X }
X break;
X case 'r':
X if (!remtext(&sline))
X {
X herrflush();
X zerr("modifier failed: r",NULL,0);
X habort();
X }
X break;
X case 't':
X if (!remlpaths(&sline))
X {
X herrflush();
X zerr("modifier failed: t",NULL,0);
X habort();
X }
X break;
X case 's':
X {
X int del;
X char *ptr1,*ptr2;
X
X del = hgetch();
X ptr1 = hdynread2(del);
X if (!ptr1)
X habort();
X ptr2 = hdynread2(del);
X if (strlen(ptr1))
X {
X if (hsubl)
X free(hsubl);
X hsubl = ptr1;
X }
X if (hsubr)
X free(hsubr);
X hsubr = ptr2;
X }
X case '&':
X if (hsubl && hsubr)
X subst(&sline,hsubl,hsubr,gbal);
X else
X {
X herrflush();
X zerr("no previous substitution with &",NULL,0);
X habort();
X }
X break;
X case 'q':
X quote(&sline);
X break;
X case 'x':
X quotebreak(&sline);
X break;
X case 'l':
X downcase(&sline);
X break;
X case 'u':
X upcase(&sline);
X break;
X default:
X herrflush();
X zerr("illegal modifier: %c",NULL,c);
X habort();
X break;


X }
X }
X else
X {

X if (c != '}' || !bflag)
X hungetch(c);
X if (c != '}' && bflag)
X {
X zerr("'}' expected",NULL,0);
X habort();
X }
X break;
X }
X }
X
X /* stuff the resulting string in the input queue and start over */
X
X lexstop = 0;
X if (alstackind != MAXAL)
X {
X hungets(HISTMARK);
X alstack[alstackind++] = NULL;
X }
X hungets(sline);
X histdone |= HISTFLAG_DONE;
X if (isset(HISTVERIFY)) {
X histdone |= HISTFLAG_NOEXEC;
X zrecall = 1;
X }
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{
Xchar *line,*pmpt,*pmpt2 = NULL;
Xint plen;
X
Xstart:
X if (inbufct)
X {
X inbufct--;
X if ((lastc = *inbufptr++) == ALPOP)
X {
X Alias ix;
X char *t;
X
X if (!alstackind)
X {
X zerr("alias stack underflow",NULL,0);
X errflag = lexstop = 1;
X return lastc = ' ';
X }
X ix = alstack[--alstackind];
X if (ix)
X {
X ix->inuse = 0;
X t = ix->text;
X if (*t && t[strlen(t)-1] == ' ')
X alstat = ALSTAT_MORE;
X else
X alstat = ALSTAT_JUNK;
X }
X goto start;
X }
X if (itok(lastc))
X goto start;
X return lastc;
X }
X if (strin || errflag)
X {
X lexstop = 1;
X return lastc = ' ';
X }
X if (interact && isset(SHINSTDIN))
X if (!isfirstln)
X pmpt = putprompt(prompt2,&plen);
X else
X {
X int foo;
X
X pmpt = putprompt(prompt,&plen);
X pmpt2 = (rprompt) ? putprompt(rprompt,&foo) : NULL;
X }
X if (!(interact && isset(SHINSTDIN) && SHTTY != -1 && isset(USEZLE)))
X {
X if (interact && isset(SHINSTDIN))
X write(2,pmpt,strlen(pmpt));
X line = fgets(zalloc(256),256,bshin);
X }
X else
X line = zleread(pmpt,pmpt2,plen);
X if (!line)
X {
X lexstop = 1;
X return lastc = ' ';
X }
X if (errflag)
X {
X lexstop = errflag = 1;
X return lastc = ' ';
X }
X if (interact && isset(SHINSTDIN))
X {
X char *s = getdata(lastnode(lithistlist));


X
X if (!*s)
X {

X free(s);
X setdata(lastnode(lithistlist),ztrdup(line));
X }
X else
X {
X char *t = zalloc(strlen(s)+strlen(line)+3);
X
X strcpy(t,s);
X strcat(t,line);
X free(s);
X setdata(lastnode(lithistlist),t);
X }
X }
X if (isfirstln)
X spaceflag = *line == ' ';
X if (isset(VERBOSE))
X {
X fputs(line,stderr);
X fflush(stderr);
X }
X if (line[strlen(line)-1] == '\n')
X {
X lineno++;
X if (interact && isset(SUNKEYBOARDHACK) && isset(SHINSTDIN) &&
X SHTTY != -1 && *line && line[1] && line[strlen(line)-2] == '`')
X {
X int ct;
X 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(line);
X free(line);
X goto start;
X}
X
X/* put a string in the input queue */
X
Xvoid hungets(str) /**/
Xchar *str;
X{
Xint slen = strlen(str);
X
X/* shrink inbuf if it gets too big */
X
X if (!inbufct && inbufsz > 65536)
X {
X free(inbuf);
X inbuf = zalloc(inbufsz = 256);
X inbufptr = inbuf+inbufsz;
X inbufct = 0;
X }
X if (slen+inbufct > inbufsz)
X {
X char *x;
X
X while (slen+inbufct > inbufsz)
X inbufsz *= 4;
X x = zalloc(inbufsz);
X memcpy(x+inbufsz-inbufct,inbufptr,inbufct);
X inbufptr = x+inbufsz-inbufct;
X free(inbuf);
X inbuf = x;
X }
X memcpy(inbufptr -= slen,str,slen);
X inbufct += slen;
X}
X
X/* unget a char and remove it from hline */
X
Xvoid hungetc(c) /**/
Xint c;
X{
X if (lexstop)
X return;
X if (hlastw)
X {
X if (hlastw == hptr)
X zerr("hungetc attempted at buffer start",NULL,0);
X else
X hptr--;
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 = isset(NOBANGHIST);
X lithist = isset(HISTLIT);
X hline = hptr = zalloc(hlinesz = 32);
X if (interact && isset(SHINSTDIN) && !strin) {
X inittty();
X defev = curhist++;
X while (curhist-firsthist >= histsiz) {
X free(getnode(histlist));
X firsthist++;
X }
X while (curhist-firstlithist >= lithistsiz) {
X free(getnode(lithistlist));
X firstlithist++;
X }
X permalloc();
X addnode(histlist,hline);
X addnode(lithistlist,ztrdup(""));
X heapalloc();
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;
X
X if (!hline)
X return 1;
X if (!interact || strin || unset(SHINSTDIN)) {
X free(hline);
X return 1;
X }
X flag = histdone;
X histdone = 0;
X if (hptr < hline+2)
X save = 0;
X else {
X char *s = getdata(lastnode(lithistlist));
X
X if (*s)
X s[strlen(s)-1] = '\0';
X hptr[-1] = '\0';
X if (hptr[-2] == '\n')
X if (hline[1])
X hptr[-3] = '\0';
X else
X save = 0;
X if (!strcmp(hline,"\n") ||
X (isset(HISTIGNOREDUPS) && firstnode(histlist) &&
X nextnode(firstnode(histlist)) &&
X !strcmp(hline,getdata(prevnode(lastnode(histlist))))) ||
X (isset(HISTIGNORESPACE) && spaceflag) )
X save = 0;
X }
X if (flag & HISTFLAG_DONE) {
X char *ptr,*p;
X
X p = ptr = ztrdup(hline);
X for (;*p;p++)
X if (*p == HISTSPACE)
X *p = ' ';
X fprintf(stderr,"%s\n",ptr);
X fflush(stderr);
X free(ptr);
X }
X if (!save) {
X free(hline);
X if (!histremmed) {
X remnode(histlist,lastnode(histlist));
X free(remnode(lithistlist,lastnode(lithistlist)));
X curhist--;
X }
X }
X hline = 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)
X {
X histremmed = 1;
X free(remnode(histlist,lastnode(histlist)));
X free(remnode(lithistlist,lastnode(lithistlist)));
X curhist--;
X }
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 && hline)
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;
XLknode node;
Xchar *s;
X
X if (curhist-firsthist < 1)
X return -1;
X for (t0 = curhist-1,node = prevnode(lastnode(histlist));
X t0 >= firsthist; t0--,node = prevnode(node))
X if (s = ztrstr(getdata(node),str))
X {
X while (s != (char *) getdata(node))
X if (*s-- == HISTSPACE)
X 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;
XLknode node;
X
X if (curhist-firsthist < 1)
X return -1;
X for (t0 = curhist-1,node = prevnode(lastnode(histlist)); t0 >= firsthist;
X t0--,node = prevnode(node))
X if (!strncmp(getdata(node),str,strlen(str)))


X 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 cut += strlen(in);
X off = cut-*strptr;
X *strptr = tricat(*strptr,sptr = convamps(out,in),cut);
X if (gbal) {
X str = (char *) *strptr+off+strlen(sptr);
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{
XLknode node;
X
X ev -= (lithist) ? firstlithist : firsthist;
X if (ev < 0)
X return NULL;
X for (node = firstnode((lithist) ? lithistlist : histlist);
X ev && node; incnode(node), ev--);
X if (!node)
X return NULL;
X return getdata(node);
X}
X
Xchar *getevent(ev) /**/
Xint ev;
X{
XLknode node;
Xint oev = ev;
X
X ev -= firsthist;
X for (node = firstnode(histlist); ev && node; incnode(node), ev--);
X if (!node)
X {
X herrflush();
X zerr("no such event: %d",NULL,oev);
X return NULL;
X }
X return getdata(node);
X}
X
Xint getargc(list) /**/
Xchar *list;
X{
Xint argc = 0;
X
X for (; *list; list++)
X if (*list == HISTSPACE)
X 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 = 1;
X
X for (ptr = *str; *ptr; ptr++,len++)
X if (*ptr == '\'')
X len += 3;
X ptr = *str;
X *str = rptr = zalloc(len);
X for (ptr = *str; *ptr; )
X if (*ptr == '\'')
X {
X *rptr++ = '\''; *rptr++ = '\\'; *rptr++ = '\''; *rptr++ = '\'';
X ptr++;
X }
X else
X *rptr++ = *ptr++;


X return 0;
X}
X

Xint quotebreak(tr) /**/
Xchar **tr;
X{
Xchar *ptr,*rptr,**str = (char **) tr;
Xint len = 1;
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 = zalloc(len);
X for (ptr = *str; *ptr; )
X if (*ptr == '\'')
X {
X *rptr++ = '\''; *rptr++ = '\\'; *rptr++ = '\''; *rptr++ = '\'';
X ptr++;
X }
X else if (inblank(*ptr))
X {
X *rptr++ = '\''; *rptr++ = *ptr++; *rptr++ = '\'';
X }
X else
X *rptr++ = *ptr++;


X return 0;
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) /**/
Xchar *fm;int *lenp;
X{
Xchar *ss,*ttyname DCLPROTO((int)),*bl0;
Xstatic char buf1[256],buf2[256],*buf;
Xchar buf3[MAXPATHLEN];
Xint t0,bracepos = 0;
Xstruct tm *tm = NULL;
Xtime_t timet;
X
X lensb = 0; countp = 1;
X if (!fm)
X {
X *lenp = 0;
X return "";
X }
X /* kludge alert! */
X buf = (buf == buf1) ? buf2 : buf1;
X bp = bl0 = buf;
X if (!columns)
X columns = 80;
X clearerr(stdin);
X for(;*fm;fm++)
X {
X if (bp-buf >= 220)
X break;
X if (*fm == '%')
X switch (*++fm)
X {
X case '~':
X t0 = finddir(cwd);


X if (t0 != -1) {

X *bp++ = '~';
X stradd(usernames[t0]);
X stradd(cwd+strlen(userdirs[t0]));
X break;
X }
X if (!strncmp(cwd,home,t0 = strlen(home)) && t0 > 1) {
X *bp++ = '~';
X stradd(cwd+t0);
X break;
X }
X case 'd': case '/': stradd(cwd); break;
X case 'c': case '.':
X t0 = finddir(cwd);


X if (t0 != -1) {

X sprintf(buf3,"~%s%s",usernames[t0],
X cwd+strlen(userdirs[t0]));
X } else if (!strncmp(cwd,home,t0 = strlen(home)) && t0 > 1) {
X sprintf(buf3,"~%s",cwd+t0);
X } else {
X strcpy(buf3,cwd);
X }
X t0 = 1;
X if (idigit(fm[1])) { t0 = fm[1]-'0'; fm++; }
X for (ss = buf3+strlen(buf3); ss > buf3; ss--)
X if (*ss == '/' && !--t0) {
X ss++;
X break;
X }
X if (*ss == '/' && ss[1]) ss++;
X stradd(ss);
X break;
X case 'C':
X strcpy(buf3,cwd);
X t0 = 1;
X if (idigit(fm[1])) { t0 = fm[1]-'0'; fm++; }
X for (ss = buf3+strlen(buf3); ss > buf3; ss--)
X if (*ss == '/' && !--t0) {
X ss++;
X break;
X }
X if (*ss == '/' && ss[1]) 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 (idigit(fm[1]))
X t0 = (*++fm)-'0';
X else
X t0 = 1;
X for (ss = hostnam; *ss; ss++)
X if (*ss == '.' && !--t0)
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 timet = time(NULL);
X tm = localtime(&timet);
X ztrftime(bp,16,"%y-%m-%d",tm);
X bp += strlen(bp);
X break;
X case 'l':
X if (ss = ttyname(SHTTY))
X stradd((strncmp(ss,"/dev/tty",8) ? ss : ss+8));
X else
X 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 default: *bp++ = '%'; *bp++ = *fm; break;
X }
X else if (*fm == '!')
X {
X sprintf(bp,"%d",curhist);
X bp += strlen(bp);
X }
X else
X {
X if (fm[0] == '\\' && fm[1])
X fm++;
X if ((*bp++ = *fm) == '\n')
X bl0 = bp;
X }
X }
X *lenp = (bp-bl0)-lensb;
X *lenp %= columns;
X if (*lenp == columns-1)
X {
X *lenp = 0;
X *bp++ = ' ';
X }
X *bp = '\0';


X return buf;
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

X/* set cbreak mode, or the equivalent */
X
Xvoid setcbreak() /**/
X{
Xstruct ttyinfo ti;
X
X ti = shttyinfo;
X#ifdef TERMIOS
X ti.termios.c_lflag &= ~ICANON;
X ti.termios.c_cc[VMIN] = 1;
X ti.termios.c_cc[VTIME] = 0;
X#else
X#ifdef TERMIO
X ti.termio.c_lflag &= ~ICANON;
X ti.termio.c_cc[VMIN] = 1;
X ti.termio.c_cc[VTIME] = 0;
X#else
X ti.sgttyb.sg_flags |= CBREAK;
X#endif
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;
Xint arg = pgrp;
X
X if (jobbing)
X#ifndef TIOCSPGRP
X if (SHTTY != -1 && tcsetpgrp(SHTTY,pgrp) == -1 && !ep)
X#else
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
SHAR_EOF
chmod 0644 zsh2.1/src/hist.c ||
echo 'restore of zsh2.1/src/hist.c failed'
Wc_c="`wc -c < 'zsh2.1/src/hist.c'`"
test 24813 -eq "$Wc_c" ||
echo 'zsh2.1/src/hist.c: original size 24813, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/src/init.c ==============
if test -f 'zsh2.1/src/init.c' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/src/init.c (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.1/src/init.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/src/init.c' &&
X/*
X
X init.c - main loop and initialization routines

X#define GLOBALS
X#include "zsh.h"
X#include <pwd.h>
X
Xextern int yydebug;
X
Xvoid main(argc,argv,envp) /**/
Xint argc; char **argv; char **envp;
X{
Xint notect = 0;
X
X environ = envp;
X pathsuppress = 1;
X meminit();
X setflags();
X parseargs(argv);
X setmoreflags();
X setupvals();
X initialize();
X heapalloc();
X runscripts();
X if (interact)
X {
X pathsuppress = 0;
X newcmdnamtab();


X }
X for(;;)
X {

X do
X loop();
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(NULL);
X continue;
X }
X zerrnam("zsh",(!islogin) ? "use 'exit' to exit."
X : "use 'logout' to logout.",NULL,0);
X notect++;
X if (notect == 10)
X zexit(NULL);
X }
X}
X
X/* keep executing lists until EOF found */
X
Xvoid loop() /**/
X{
XList list;
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 }
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 ((opts['t'] == OPT_SET) || (lastval && opts[ERREXIT] == OPT_SET))
X {


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

X exit(lastval);
X }
X }
X popheap();
X}
X
Xvoid setflags() /**/
X{
Xint c;
X
X for (c = 0; c != 32; c++)
X opts[c] = OPT_UNSET;
X for (c = 32; c != 128; c++)
X opts[c] = OPT_INVALID;
X for (c = 'a'; c <= 'z'; c++)
X opts[c] = opts[c-'a'+'A'] = OPT_UNSET;
X for (c = '0'; c <= '9'; c++)
X 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}
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 {
X if (opts[**argv] == OPT_INVALID)
X {
X zerr("bad option: -%c",NULL,**argv);
X exit(1);
X }
X opts[**argv] = action;
X if (bk = **argv == 'b')
X break;
X if (**argv == 'c') /* -c command */
X {
X argv++;
X if (!*argv)
X {
X zerr("string expected after -c",NULL,0);
X exit(1);
X }
X cmd = *argv;
X opts[INTERACTIVE] = OPT_UNSET;
X break;
X }
X else if (**argv == 'o')


X {
X int c;
X

X if (!*++*argv)
X argv++;
X if (!*argv)
X {
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 }
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{
Xint t0;
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 {
X SHTTY = movefd((isatty(0)) ? dup(0) : open("/dev/tty",O_RDWR));
X if (SHTTY == -1)


X opts[MONITOR] = OPT_UNSET;

X else
X {
X#ifdef TIOCSETD
X int ldisc = NTTYDISC;
X ioctl(SHTTY, TIOCSETD, &ldisc);
X#endif
X gettyinfo(&shttyinfo); /* get tty state */
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 }

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 {

X gettyinfo(&shttyinfo);
X savedttyinfo = shttyinfo;
X }
X#endif
X}
X
Xvoid setupvals() /**/
X{
Xstruct passwd *pwd;
Xchar *ptr;
Xstatic long bauds[] = {
X 0,50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,19200,38400
X };
X
X curhist = 0;
X histsiz = 20;
X lithistsiz = 5;
X logcheck = 60;
X dirstacksize = -1;
X listmax = 100;
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(13);
X initxbindtab();
X nullcmd = ztrdup("cat");
X prompt = ztrdup("%m%# ");
X prompt2 = ztrdup("> ");
X prompt3 = ztrdup("?# ");
X prompt4 = ztrdup("+ ");
X sprompt = ztrdup("zsh: correct `%s' to `%r' [nyae]? ");
X ppid = getppid();
X#ifdef TERMIOS
X baud = bauds[shttyinfo.termios.c_cflag & CBAUD];
X#else
X#ifdef TERMIO
X baud = bauds[shttyinfo.termio.c_cflag & CBAUD];
X#else
X baud = bauds[shttyinfo.sgttyb.sg_ospeed];
X#endif
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 (pwd = getpwuid(getuid())) {
X username = ztrdup(pwd->pw_name);
X home = ztrdup(pwd->pw_dir);
X } else {
X username = ztrdup("");
X home = ztrdup("/");
X }
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 if (ispwd(home))
X cwd = ztrdup(home);
X else if ((ptr = zgetenv("PWD")) && ispwd(ptr))
X cwd = ztrdup(ptr);
X else
X cwd = zgetwd();
X oldpwd = ztrdup(cwd);
X hostnam = zalloc(256);
X underscore = ztrdup("");
X gethostname(hostnam,256);
X mypid = getpid();
X cdpath = mkarray(NULL);
X fignore = mkarray(NULL);
X fpath = mkarray(NULL);
X mailpath = mkarray(NULL);
X watch = mkarray(NULL);
X hosts = mkarray(NULL);
X hostcmds = (char **) zcalloc(sizeof(char *)*7);
X hostcmds[0] = ztrdup("telnet"); hostcmds[1] = ztrdup("rlogin");
X hostcmds[2] = ztrdup("ftp"); hostcmds[3] = ztrdup("rup");
X hostcmds[4] = ztrdup("rusers"); hostcmds[5] = ztrdup("rsh");
X optcmds = (char **) zcalloc(sizeof(char *)*3);
X optcmds[0] = ztrdup("setopt"); optcmds[1] = ztrdup("unsetopt");
X bindcmds = (char **) zcalloc(sizeof(char *)*2);
X bindcmds[0] = ztrdup("bindkey");
X varcmds = (char **) zcalloc(sizeof(char *)*5);
X varcmds[0] = ztrdup("export"); varcmds[1] = ztrdup("typeset");
X varcmds[2] = ztrdup("vared"); varcmds[3] = ztrdup("unset");
X userdirs = (char **) zcalloc(sizeof(char *)*2);
X usernames = (char **) zcalloc(sizeof(char *)*2);
X userdirsz = 2;
X userdirct = 0;


X optarg = ztrdup("");

X optind = 0;
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}
X
Xvoid initialize() /**/
X{
Xint t0;
X
X breaks = loops = 0;
X lastmailcheck = time(NULL);
X firsthist = firstlithist = 1;
X histsiz = DEFAULT_HISTSIZE;
X histlist = newlist();
X lithistlist = newlist();
X locallist = NULL;
X dirstack = newlist();
X bufstack = newlist();
X newcmdnamtab();
X inbuf = zalloc(inbufsz = 256);
X inbufptr = inbuf+inbufsz;
X inbufct = 0;
X#ifdef 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 signal(SIGCHLD,handler);
X if (jobbing)
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 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,NULL);
X}
X
Xvoid runscripts() /**/
X{
X if (opts[NORCS] == OPT_SET) {
X#ifdef GLOBALZPROFILE
X source(GLOBALZPROFILE);
X#endif
X#ifdef GLOBALZSHRC
X source(GLOBALZSHRC);
X#endif
X#ifdef GLOBALZLOGIN
X if (islogin) source(GLOBALZLOGIN);
X#endif
X return;
X }
X sourcehome(".zshenv");
X if (opts[NORCS] == OPT_SET)
X return;
X if (interact) {
X if (islogin) {
X sourcehome(".zprofile");
X#ifdef GLOBALZPROFILE
X source(GLOBALZPROFILE);
X#endif
X }
X#ifdef GLOBALZSHRC
X source(GLOBALZSHRC);
X#endif
X sourcehome(".zshrc");
X if (islogin) {
X#ifdef GLOBALZLOGIN
X source(GLOBALZLOGIN);
X#endif
X sourcehome(".zlogin");
X }
X }
X if (interact)
X readhistfile(getsparam("HISTFILE"),0);
X if (opts['c'] == OPT_SET)
X {
X if (SHIN >= 10)
X close(SHIN);
X SHIN = movefd(open("/dev/null",O_RDONLY));
X hungets(cmd);
X strinbeg();
X }
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}
X
Xvoid readhistfile(s,err) /**/
Xchar *s;int err;
X{
Xchar buf[1024];
XFILE *in;
X
X if (!s)
X return;
X if (in = fopen(s,"r"))
X {
X permalloc();
X while (fgets(buf,1024,in))
X {
X int l = strlen(buf);
X char *pt = buf;
X
X if (l && buf[l-1] == '\n')
X buf[l-1] = '\0';
X for (;*pt;pt++)
X if (*pt == ' ')
X *pt = HISTSPACE;
X addnode(histlist,ztrdup(buf));
X addnode(lithistlist,ztrdup(buf));
X curhist++;
X }
X fclose(in);
X lastalloc();
X }
X else if (err)
X zerr("can't read history file",s,0);
X}
X
Xvoid savehistfile(s,err) /**/
Xchar *s;int err;
X{
Xchar *t;
XLknode n;
XLklist l;
XFILE *out;
X
X if (!s || !interact)
X return;
X if (out = fdopen(open(s,O_CREAT|O_WRONLY|O_TRUNC,0600),"w"))
X {
X n = lastnode(l = (isset(HISTLIT) ? lithistlist : histlist));
X if (n == (Lknode) l)
X {
X fclose(out);
X return;
X }
X while (--savehist && prevnode(n) != (Lknode) l)
X n = prevnode(n);


X for (; n; incnode(n))
X {

X for (s = t = getdata(n); *s; s++)
X if (*s == HISTSPACE)
X *s = ' ';
X fputs(t,out);
X fputc('\n',out);
X }
X fclose(out);
X }
X else if (err)
X zerr("can't write history file: %s",s,0);
X}
X
SHAR_EOF
chmod 0644 zsh2.1/src/init.c ||
echo 'restore of zsh2.1/src/init.c failed'
Wc_c="`wc -c < 'zsh2.1/src/init.c'`"
test 12375 -eq "$Wc_c" ||
echo 'zsh2.1/src/init.c: original size 12375, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/src/jobs.c ==============
if test -f 'zsh2.1/src/jobs.c' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/src/jobs.c (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.1/src/jobs.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/src/jobs.c' &&
X/*
X
X jobs.c - job control


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

SHAR_EOF
true || echo 'restore of zsh2.1/src/jobs.c failed'
fi
echo 'End of zsh2.1.0 part 7'
echo 'File zsh2.1/src/jobs.c is continued in part 8'
echo 8 > _shar_seq_.tmp

Paul Falstad

unread,
Oct 24, 1991, 3:09:25 PM10/24/91
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 24, Issue 8
Archive-name: zsh2.1/part08

Environment: BSD
Supersedes: zsh2.00: Volume 18, Issue 84-98

#!/bin/sh
# this is zshar.08 (part 8 of zsh2.1.0)


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

# file zsh2.1/src/jobs.c continued


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

if test "$Scheck" != 8; then


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

echo 'x - still skipping zsh2.1/src/jobs.c'
else
echo 'x - continuing file zsh2.1/src/jobs.c'


sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.1/src/jobs.c' &&
X

X zsh is distributed in the hope that it will be useful, but
X WITHOUT ANY WARRANTY. No author or distributor accepts
X responsibility to anyone for the consequences of using it or for
X whether it serves any particular purpose or works at all, unless he
X says so in writing. Refer to the GNU General Public License
X for full details.
X
X Everyone is granted permission to copy, modify and redistribute
X zsh, but only under the conditions described in the GNU General Public
X License. A copy of this license is supposed to have been given to you
X along with zsh so you can know your rights and responsibilities.
X It should be in a file named COPYING.
X
X Among other things, the copyright notice and this notice must be
X preserved on all copies.
X
X*/
X
X#include "zsh.h"

X#include <sys/errno.h>
X
X/* != 0 means the handler is active */
X
Xstatic int handling = 0;
X
X/* != 0 means the shell is waiting for a job to complete */
X
Xstatic int waiting = 0;
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,code) /**/
Xint sig;int code;
X{
Xlong pid;
Xint statusp;
XJob jn;
Xstruct process *pn;
Xstruct rusage ru;
X
X#ifdef RESETHANDNEEDED
X signal(sig,handler);
X#endif
X if (sig == SIGINT)
X {


X if (sigtrapped[SIGINT])

X dotrap(SIGINT);
X else
X errflag = 1;
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 && !sigtrapped[SIGALRM])
X {
X zerr("timeout",NULL,0);
X exit(1);
X }
X RETURN;


X }
X for (;;)
X {

X#ifdef SYSV
X pid = wait(&statusp);
X#else
X#if defined(RLIM_INFINITY) & ! defined(__hpux)
X pid = wait3(&statusp,WNOHANG|WUNTRACED,&ru);
X#else
X pid = wait3(&statusp,WNOHANG|WUNTRACED,NULL);
X#endif
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 findproc(pid,&jn,&pn); /* find the process of this pid */
X if (jn)
X {
X pn->statusp = statusp;
X handling = 1;
X pn->ru = ru;
X pn->endtime = time(NULL);
X updatestatus(jn);
X handling = 0;
X if (zleactive)
X refresh();
X }
X else if (WIFSTOPPED(SP(statusp)))
X kill(pid,SIGKILL); /* kill stopped untraced children */
X }
X RETURN;
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(SP(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,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(SP(pn->statusp)))
X alldone = 0;
X if (WIFSTOPPED(SP(pn->statusp)))
X somestopped = 1;
X if (!pn->next && jn)
X val = (WIFSIGNALED(SP(pn->statusp))) ?
X 0200 | WTERMSIG(SP(pn->statusp)) : WEXITSTATUS(SP(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 (!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 (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 = -1,sflag = 0,llen,printed = 0;
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(SP(pn->statusp)))
X {
X sig = WTERMSIG(SP(pn->statusp));
X llen = strlen(sigmsg[sig]);
X if (WCOREDUMPED(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(SP(pn->statusp)))
X {
X sig = WSTOPSIG(SP(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) && WEXITSTATUS(SP(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(SP(pn->statusp)))
X if (WEXITSTATUS(SP(pn->statusp)))
X fprintf(stderr,"exit %-4d%*s",WEXITSTATUS(SP(pn->statusp)),
X len-9+2,"");
X else
X fprintf(stderr,"done%*s",len-4+2,"");
X else if (WIFSTOPPED(SP(pn->statusp)))
X fprintf(stderr,"%-*s",len+2,sigmsg[WSTOPSIG(SP(pn->statusp))]);
X else if (WCOREDUMPED(pn->statusp))
X fprintf(stderr,"%s (core dumped)%*s",
X sigmsg[WTERMSIG(SP(pn->statusp))],
X len-14+2-strlen(sigmsg[WTERMSIG(SP(pn->statusp))]),"");
X else
X fprintf(stderr,"%-*s",len+2,sigmsg[WTERMSIG(SP(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 printed = 1;
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->cwd,cwd))
X {
X printf("(pwd now: ");
X printdir(cwd);


X printf(")\n");

X fflush(stdout);
X }
X
X /* delete job if done */
X
X if (jn->stat & STAT_DONE)


X {
X static struct job zero;

X struct process *nx;
X char *s;
X
X if (jn->stat & STAT_TIMED)
X {
X dumptime(jn);
X printed = 1;
X }
X for (pn = jn->procs; pn; pn = nx)
X {
X nx = pn->next;
X if (pn->text)
X free(pn->text);
X free(pn);
X }
X free(jn->cwd);
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].cwd = ztrdup(cwd);
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)
X jobtab[thisjob].gleader = lastpid = pid;
X lastpid = pid;
X process = zcalloc(sizeof *process);
X process->pid = pid;
X process->text = text;
X process->next = NULL;
X process->statusp = SP_RUNNING;
X process->bgtime = time(NULL);
X if (jobtab[thisjob].procs)
X {
X struct process *n;
X
X for (n = jobtab[thisjob].procs; n->next && !n->next->lastfg; n = n->next);
X process->next = n->next;
X n->next = process;
X }
X else
X 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/* wait for a job to finish */
X
Xvoid waitjob(job) /**/
Xint job;
X{
Xstatic struct job zero;
XJob jn;
X
X if (jobtab[job].procs) /* if any forks were done */
X {
X jobtab[job].stat |= STAT_LOCKED;
X waiting = 1;
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 waiting = 0;
X }
X else /* else do what printjob() usually does */


X {
X char *s;
X

X jn = jobtab+job;
X free(jn->cwd);
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{
Xstatic struct job zero;
Xint t0;
X
X for (t0 = 1; t0 != MAXJOB; t0++)
X jobtab[thisjob] = zero;
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 static struct job zero;

X struct job *jn;
X
X jn = jobtab+thisjob;
X free(jn->cwd);
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
Xvoid printtime(real,ru,desc) /**/
Xtime_t real;struct rusage *ru;char *desc;
X{
Xchar *s;
X
X if (!desc)
X desc = "";
X for (s = (timefmt) ? timefmt : DEFTIMEFMT; *s; s++)
X if (*s == '%')
X switch(s++,*s)
X {
X case 'E': fprintf(stderr,"%lds",real); break;
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 case 'X': fprintf(stderr,"%ld",ru->ru_ixrss); break;
X case 'D': fprintf(stderr,"%ld",ru->ru_idrss); break;
X case 'K': fprintf(stderr,"%ld",ru->ru_ixrss+ru->ru_idrss); break;
X case 'M': fprintf(stderr,"%ld",ru->ru_maxrss); break;
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 default: fprintf(stderr,"%%%c",s[-1]); 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 = jn->procs;
X
X if (!jn->procs)
X return;
X for (pn = jn->procs; pn; pn = pn->next)
X printtime(pn->endtime-pn->bgtime,&pn->ru,pn->text);
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 &&
X !(jobtab[t0].stat & STAT_STOPPED))
X {
X kill(-jobtab[t0].gleader,SIGHUP);
X killed++;
X }
X if (killed)
X 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 for (t0 = 1; t0 != MAXJOB; t0++)
X if (t0 != thisjob && jobtab[t0].stat)
X break;
X if (t0 != MAXJOB)
X {
X if (jobtab[t0].stat & STAT_STOPPED)
X {
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 }
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;
X
X if (jobbing)
X return(kill(-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}
X
SHAR_EOF
echo 'File zsh2.1/src/jobs.c is complete' &&
chmod 0644 zsh2.1/src/jobs.c ||


echo 'restore of zsh2.1/src/jobs.c failed'

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.1/src/lex.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/src/lex.c' &&
X/*
X
X lex.c - lexical analysis

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 = hline;
X xhptr = hptr;
X xhlastw = hlastw;
X xhlinesz = hlinesz;
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 hline = 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 isnewlin = (tok == NEWLIN && !inbufct);
X if (tok == SEMI || tok == NEWLIN)
X tok = SEPER;
X}
X
Xvoid ctxtlex() /**/
X{
Xstatic int oldpos,inredir = 0;
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 FOR: case SELECT: case FOREACH: case CASE: incmdpos = 0; break;
X }
X if (IS_REDIROP(tok)) {
X inredir = 2;
X oldpos = incmdpos;
X incmdpos = 0;
X } else if (inredir) {
X if (!--inredir) incmdpos = oldpos;
X else incmdpos = 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[lx1[t0]] = t0;
X for (t0 = 0; lx2[t0]; t0++)
X if (lx2[t0] != 'x')
X lexact2[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--; bsiz--;
X}
X
Xint gettok() /**/
X{
Xint bct = 0,pct = 0,brct = 0;
Xint c,d,intpos = 1;
Xint peekfd = -1,peek;
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 = Qstring;
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 /* changed hgetch to hgetc so comments appear in history */
X stophist = 1;
X while ((c = hgetc()) != '\n' && !lexstop);


X if (c == '\n') {

X hwaddc('\n');
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 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))
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 while ((c = hgetc()) != ']' && !lexstop)
X add(c);
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)
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)
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(c);
X c = hgetc();
X continue;
X case LX2_QUOTE:
X add(Nularg);
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 = Nularg;
X break;
X case LX2_DQUOTE:
X add(Nularg);
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 = Nularg;
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 gotword(s);
X an = gethnode(s,aliastab);
X if (t)
X *t = HISTSPACE;
X if (alstackind != MAXAL && an && !an->inuse)
X if (!(an->cmd && !incmdpos && alstat != ALSTAT_MORE))
X {
X if (an->cmd < 0)
X {
X tok = DO-an->cmd-1;
X return 0;
X }
X else
X {
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] == ' ')
X 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}
X
SHAR_EOF
chmod 0644 zsh2.1/src/lex.c ||
echo 'restore of zsh2.1/src/lex.c failed'
Wc_c="`wc -c < 'zsh2.1/src/lex.c'`"
test 15750 -eq "$Wc_c" ||
echo 'zsh2.1/src/lex.c: original size 15750, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/src/loop.c ==============
if test -f 'zsh2.1/src/loop.c' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/src/loop.c (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

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

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 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;
X
X loops++;
X node = cmd->u.forcmd;
X args = cmd->args;
X if (!full(args))
X return 1;
X exiting = 0;
X pushheap();


X for (;;)
X {

X do
X {
X selectlist(args);
X if (interact && SHTTY != -1 && isset(USEZLE))
X {
X int pl;
X
X str = putprompt(prompt3,&pl);
X str = zleread(str,NULL,pl);
X }
X else
X str = fgets(zalloc(256),256,bshin);
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 thisjob = cj;
X return lastval;
X}
X
Xint execwhile(cmd) /**/
XCmd cmd;
X{
XList list;
Xstruct whilecmd *node;


Xint cj = thisjob;
X

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


X pushheap();
X for(;;)
X {

X list = dupstruct(node->cont);
X execlist(list);
X if (!((lastval == 0) ^ node->cond))
X break;
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 return lastval;
X}
X
Xint execrepeat(cmd) /**/
XCmd cmd;
X{
XList list;
Xint cj = thisjob,count;
X
X loops++;
X exiting = 0;
X if (!full(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 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 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 errflag = 1;
X return 1;
X }
X if (!full(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}
SHAR_EOF
chmod 0644 zsh2.1/src/loop.c ||
echo 'restore of zsh2.1/src/loop.c failed'
Wc_c="`wc -c < 'zsh2.1/src/loop.c'`"
test 4854 -eq "$Wc_c" ||
echo 'zsh2.1/src/loop.c: original size 4854, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.1/src/math.c ==============
if test -f 'zsh2.1/src/math.c' -a X"$1" != X"-c"; then
echo 'x - skipping zsh2.1/src/math.c (File already exists)'


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.1/src/math.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/src/math.c' &&
X/*
X
X math.c - mathematical expression evaluation

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 (ialpha(*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(ialpha(*++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(a<b); break;
X case LEQ: pop2(); pushv(a<=b); break;
X case GRE: pop2(); pushv(a>b); break;
X case GEQ: pop2(); pushv(a>=b); break;
X case DEQ: pop2(); pushv(a==b); break;
X case NEQ: pop2(); pushv(a!=b); break;
X case DAND: pop2(); pushv(a&&b); break;
X case DOR: pop2(); pushv(a||b); break;
X case DXOR: pop2(); pushv(a&&!b||!a&&b); break;
X case QUEST: pop3(); pushv((a)?b:c); break;
X case COLON: break;
X case EQ: pop2lv(); 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(a&&b); break;
X case DOREQ: pop2lv(); set(a||b); break;
X case DXOREQ: pop2lv(); set(a&&!b||!a&&b); break;
X case COMMA: pop2(); pushv(b); break;
X case PREPLUS: stack[sp].val = setvar(stack[sp].lval,
X stack[sp].val+1); break;
SHAR_EOF
true || echo 'restore of zsh2.1/src/math.c failed'
fi
echo 'End of zsh2.1.0 part 8'
echo 'File zsh2.1/src/math.c is continued in part 9'
echo 9 > _shar_seq_.tmp

Paul Falstad

unread,
Oct 24, 1991, 3:09:47 PM10/24/91
to
Submitted-by: pfal...@phoenix.Princeton.EDU (Paul Falstad)
Posting-number: Volume 24, Issue 9
Archive-name: zsh2.1/part09

Environment: BSD
Supersedes: zsh2.00: Volume 18, Issue 84-98

#!/bin/sh
# this is zshar.09 (part 9 of zsh2.1.0)


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

# file zsh2.1/src/math.c continued


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

if test "$Scheck" != 9; then


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

echo 'x - still skipping zsh2.1/src/math.c'
else
echo 'x - continuing file zsh2.1/src/math.c'


sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.1/src/math.c' &&

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
SHAR_EOF
echo 'File zsh2.1/src/math.c is complete' &&
chmod 0644 zsh2.1/src/math.c ||


echo 'restore of zsh2.1/src/math.c failed'

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


rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp

echo 'x - extracting zsh2.1/src/mem.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.1/src/mem.c' &&
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 zsh is distributed in the hope that it will be useful, but
X WITHOUT ANY WARRANTY. No author or distributor accepts
X responsibility to anyone for the consequences of using it or for
X whether it serves any particular purpose or works at all, unless he
X says so in writing. Refer to the GNU General Public License
X for full details.
X
X Everyone is granted permission to copy, modify and redistribute
X zsh, but only under the conditions described in the GNU General Public
X License. A copy of this license is supposed to have been given to you
X along with zsh so you can know your rights and responsibilities.
X It should be in a file named COPYING.
X
X Among other things, the copyright notice and this notice must be
X preserved on all copies.
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 hea