]> Zhao Yanbai Git Server - minix.git/commitdiff
Importing bin/sh 92/2792/2
authorLionel Sambuc <lionel@minix3.org>
Sun, 3 Aug 2014 21:10:41 +0000 (23:10 +0200)
committerGerrit Code Review <gerrit@localhost>
Fri, 29 Aug 2014 16:56:04 +0000 (12:56 -0400)
/etc/profile enables by default tabcompletion, as well as emacs mode,
in order to keep the old MINIX ash behavior.

Note: The shell now refuses to source a script without a relative or
      absolute path.
      This means:
        - '. myscript.sh' fails, while
        - '. ./myscript.sh' succeeds

Change-Id: I0be89b0747bd005e4c05cadb937af86883627dc6

117 files changed:
bin/Makefile
bin/sh/Makefile [new file with mode: 0644]
bin/sh/TOUR [moved from minix/commands/ash/TOUR with 97% similarity]
bin/sh/USD.doc/Makefile [new file with mode: 0644]
bin/sh/USD.doc/Rv7man [new file with mode: 0644]
bin/sh/USD.doc/t.mac [new file with mode: 0644]
bin/sh/USD.doc/t1 [new file with mode: 0644]
bin/sh/USD.doc/t2 [new file with mode: 0644]
bin/sh/USD.doc/t3 [new file with mode: 0644]
bin/sh/USD.doc/t4 [new file with mode: 0644]
bin/sh/alias.c [moved from minix/commands/ash/alias.c with 86% similarity]
bin/sh/alias.h [moved from minix/commands/ash/alias.h with 85% similarity]
bin/sh/arith.y [new file with mode: 0644]
bin/sh/arith_lex.l [moved from minix/commands/ash/arith_lex.l with 50% similarity]
bin/sh/bltin/bltin.h [moved from minix/commands/ash/bltin/bltin.h with 60% similarity]
bin/sh/bltin/echo.1 [new file with mode: 0644]
bin/sh/bltin/echo.c [moved from minix/commands/ash/bltin/echo.c with 69% similarity]
bin/sh/builtins.def [moved from minix/commands/ash/builtins.def with 59% similarity]
bin/sh/cd.c [moved from minix/commands/ash/cd.c with 55% similarity]
bin/sh/cd.h [moved from minix/commands/ash/cd.h with 85% similarity]
bin/sh/error.c [new file with mode: 0644]
bin/sh/error.h [moved from minix/commands/ash/error.h with 70% similarity]
bin/sh/eval.c [moved from minix/commands/ash/eval.c with 58% similarity]
bin/sh/eval.h [moved from minix/commands/ash/eval.h with 82% similarity]
bin/sh/exec.c [moved from minix/commands/ash/exec.c with 57% similarity]
bin/sh/exec.h [moved from minix/commands/ash/exec.h with 61% similarity]
bin/sh/expand.c [moved from minix/commands/ash/expand.c with 77% similarity]
bin/sh/expand.h [moved from minix/commands/ash/expand.h with 87% similarity]
bin/sh/funcs/cmv [moved from minix/commands/ash/funcs/cmv with 86% similarity, mode: 0644]
bin/sh/funcs/dirs [moved from minix/commands/ash/funcs/dirs with 88% similarity, mode: 0644]
bin/sh/funcs/kill [moved from minix/commands/ash/funcs/kill with 86% similarity, mode: 0644]
bin/sh/funcs/login [moved from minix/commands/ash/funcs/login with 85% similarity, mode: 0644]
bin/sh/funcs/newgrp [moved from minix/commands/ash/funcs/newgrp with 85% similarity, mode: 0644]
bin/sh/funcs/popd [moved from minix/commands/ash/funcs/popd with 88% similarity, mode: 0644]
bin/sh/funcs/pushd [moved from minix/commands/ash/funcs/pushd with 88% similarity, mode: 0644]
bin/sh/funcs/suspend [moved from minix/commands/ash/funcs/suspend with 85% similarity, mode: 0644]
bin/sh/histedit.c [moved from minix/commands/ash/histedit.c with 76% similarity]
bin/sh/init.h [moved from minix/commands/ash/init.h with 89% similarity]
bin/sh/input.c [moved from minix/commands/ash/input.c with 80% similarity]
bin/sh/input.h [moved from minix/commands/ash/input.h with 90% similarity]
bin/sh/jobs.c [new file with mode: 0644]
bin/sh/jobs.h [moved from minix/commands/ash/jobs.h with 62% similarity]
bin/sh/machdep.h [moved from minix/commands/ash/machdep.h with 78% similarity]
bin/sh/mail.c [moved from minix/commands/ash/mail.c with 89% similarity]
bin/sh/mail.h [moved from minix/commands/ash/mail.h with 89% similarity]
bin/sh/main.c [moved from minix/commands/ash/main.c with 72% similarity]
bin/sh/main.h [moved from minix/commands/ash/main.h with 87% similarity]
bin/sh/memalloc.c [moved from minix/commands/ash/memalloc.c with 74% similarity]
bin/sh/memalloc.h [moved from minix/commands/ash/memalloc.h with 91% similarity]
bin/sh/miscbltin.c [moved from minix/commands/ash/miscbltin.c with 57% similarity]
bin/sh/miscbltin.h [new file with mode: 0644]
bin/sh/mkbuiltins [moved from minix/commands/ash/mkbuiltins.sh with 57% similarity, mode: 0644]
bin/sh/mkinit.sh [new file with mode: 0755]
bin/sh/mknodes.sh [new file with mode: 0755]
bin/sh/mktokens [moved from minix/commands/ash/mktokens.sh with 75% similarity, mode: 0644]
bin/sh/myhistedit.h [moved from minix/commands/ash/myhistedit.h with 84% similarity]
bin/sh/mystring.c [moved from minix/commands/ash/mystring.c with 90% similarity]
bin/sh/mystring.h [moved from minix/commands/ash/mystring.h with 90% similarity]
bin/sh/nodes.c.pat [moved from minix/commands/ash/nodes.c.pat with 80% similarity]
bin/sh/nodetypes [moved from minix/commands/ash/nodetypes with 94% similarity]
bin/sh/options.c [moved from minix/commands/ash/options.c with 80% similarity]
bin/sh/options.h [moved from minix/commands/ash/options.h with 56% similarity]
bin/sh/output.c [moved from minix/commands/ash/output.c with 76% similarity]
bin/sh/output.h [moved from minix/commands/ash/output.h with 82% similarity]
bin/sh/parser.c [moved from minix/commands/ash/parser.c with 77% similarity]
bin/sh/parser.h [moved from minix/commands/ash/parser.h with 78% similarity]
bin/sh/redir.c [moved from minix/commands/ash/redir.c with 71% similarity]
bin/sh/redir.h [moved from minix/commands/ash/redir.h with 88% similarity]
bin/sh/sh.1 [new file with mode: 0644]
bin/sh/shell.h [moved from minix/commands/ash/shell.h with 66% similarity]
bin/sh/show.c [moved from minix/commands/ash/show.c with 83% similarity]
bin/sh/show.h [moved from minix/commands/ash/show.h with 84% similarity]
bin/sh/syntax.c [new file with mode: 0644]
bin/sh/syntax.h [new file with mode: 0644]
bin/sh/trap.c [new file with mode: 0644]
bin/sh/trap.h [moved from minix/commands/ash/trap.h with 80% similarity]
bin/sh/var.c [moved from minix/commands/ash/var.c with 60% similarity]
bin/sh/var.h [moved from minix/commands/ash/var.h with 75% similarity]
distrib/sets/lists/minix/mi
etc/mtree/NetBSD.dist.base
etc/profile
minix/commands/Makefile
minix/commands/ash/Makefile [deleted file]
minix/commands/ash/arith.y [deleted file]
minix/commands/ash/arith_lex.h [deleted file]
minix/commands/ash/bltin/LICENSE [deleted file]
minix/commands/ash/bltin/Makefile.inc [deleted file]
minix/commands/ash/bltin/binary_op [deleted file]
minix/commands/ash/bltin/catf.c [deleted file]
minix/commands/ash/bltin/error.c [deleted file]
minix/commands/ash/bltin/expr.c [deleted file]
minix/commands/ash/bltin/line.c [deleted file]
minix/commands/ash/bltin/makefile.not [deleted file]
minix/commands/ash/bltin/mkexpr.sh [deleted file]
minix/commands/ash/bltin/myregexp.h [deleted file]
minix/commands/ash/bltin/nlecho.c [deleted file]
minix/commands/ash/bltin/regexp.c [deleted file]
minix/commands/ash/bltin/stalloc.c [deleted file]
minix/commands/ash/bltin/umask.c [deleted file]
minix/commands/ash/bltin/unary_op [deleted file]
minix/commands/ash/builtins [deleted file]
minix/commands/ash/complete.c [deleted file]
minix/commands/ash/complete.h [deleted file]
minix/commands/ash/errmsg.c [deleted file]
minix/commands/ash/errmsg.h [deleted file]
minix/commands/ash/error.c [deleted file]
minix/commands/ash/jobs.c [deleted file]
minix/commands/ash/mkinit.c [deleted file]
minix/commands/ash/mknodes.c [deleted file]
minix/commands/ash/mksignames.c [deleted file]
minix/commands/ash/mksyntax.c [deleted file]
minix/commands/ash/setmode.c [deleted file]
minix/commands/ash/trap.c [deleted file]
minix/drivers/storage/ramdisk/Makefile
minix/man/man1/Makefile
minix/man/man1/ash.1 [deleted file]
minix/tests/testvnd.sh

index 7066ea3b758750135dfdc66dec0a30a7948c90cd..2215fdb5b2b1aede763b1d5603feae3044d0c3c3 100644 (file)
@@ -2,7 +2,7 @@
 #      @(#)Makefile    8.1 (Berkeley) 5/31/93
 
 SUBDIR=        cat chmod cp date df echo ed expr hostname \
-       kill ksh ln ls mkdir mv pax pwd rm rmdir \
+       kill ksh ln ls mkdir mv pax pwd rm rmdir sh \
        sleep stty sync test
 
 .include <bsd.subdir.mk>
diff --git a/bin/sh/Makefile b/bin/sh/Makefile
new file mode 100644 (file)
index 0000000..28890a2
--- /dev/null
@@ -0,0 +1,88 @@
+#      $NetBSD: Makefile,v 1.99 2012/12/02 12:55:27 apb Exp $
+#      @(#)Makefile    8.4 (Berkeley) 5/5/95
+
+.include <bsd.own.mk>
+
+YHEADER=1
+PROG=  sh
+SHSRCS=        alias.c cd.c echo.c error.c eval.c exec.c expand.c \
+       histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
+       mystring.c options.c parser.c redir.c show.c trap.c output.c var.c \
+       test.c kill.c syntax.c
+GENSRCS=arith.c arith_lex.c builtins.c init.c nodes.c
+GENHDRS=arith.h builtins.h nodes.h token.h
+SRCS=  ${SHSRCS} ${GENSRCS}
+
+DPSRCS+=${GENHDRS}
+
+LDADD+=        -ll -ledit -lterminfo
+DPADD+=        ${LIBL} ${LIBEDIT} ${LIBTERMINFO}
+
+LFLAGS=        -8      # 8-bit lex scanner for arithmetic
+
+# Environment for scripts executed during build.
+SCRIPT_ENV= \
+       AWK=${TOOL_AWK:Q} \
+       SED=${TOOL_SED:Q}
+
+# The .depend file can get references to these temporary files
+.OPTIONAL: lex.yy.c y.tab.c
+
+.ifdef CRUNCHEDPROG
+LFLAGS+=-L
+YFLAGS+=-l
+.endif
+
+CPPFLAGS+=-DSHELL -I. -I${.CURDIR}
+#XXX: For testing only.
+#CPPFLAGS+=-DDEBUG=2
+#COPTS+=-g
+#CFLAGS+=-funsigned-char
+#TARGET_CHARFLAG?= -DTARGET_CHAR="unsigned char" -funsigned-char
+
+.ifdef SMALLPROG
+CPPFLAGS+=-DSMALL
+.else
+SRCS+=printf.c
+.endif
+
+.PATH: ${.CURDIR}/bltin ${NETBSDSRCDIR}/bin/test \
+       ${NETBSDSRCDIR}/usr.bin/printf \
+       ${NETBSDSRCDIR}/bin/kill
+
+CLEANFILES+= ${GENSRCS} ${GENHDRS} y.tab.h
+CLEANFILES+= trace
+
+token.h: mktokens
+       ${_MKTARGET_CREATE}
+       ${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC}
+
+.ORDER: builtins.h builtins.c
+builtins.h builtins.c: mkbuiltins shell.h builtins.def
+       ${_MKTARGET_CREATE}
+       ${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC} ${.OBJDIR}
+       [ -f builtins.h ]
+
+init.c: mkinit.sh ${SHSRCS}
+       ${_MKTARGET_CREATE}
+       ${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC}
+
+.ORDER: nodes.h nodes.c
+nodes.c nodes.h: mknodes.sh nodetypes nodes.c.pat
+       ${_MKTARGET_CREATE}
+       ${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC} ${.OBJDIR}
+       [ -f nodes.h ]
+
+.if ${USETOOLS} == "yes"
+NBCOMPATLIB=   -L${TOOLDIR}/lib -lnbcompat
+.endif
+
+.if make(install)
+SUBDIR+=USD.doc
+.endif
+
+COPTS.printf.c = -Wno-format-nonliteral
+COPTS.jobs.c = -Wno-format-nonliteral
+
+.include <bsd.prog.mk>
+.include <bsd.subdir.mk>
similarity index 97%
rename from minix/commands/ash/TOUR
rename to bin/sh/TOUR
index afd0c8dd255639277454272ce3bc8407f08af54f..681f9866daa5b92ba79f02a91277e808048e3f49 100644 (file)
@@ -1,5 +1,5 @@
+#      $NetBSD: TOUR,v 1.10 2008/11/15 17:01:38 snj Exp $
 #      @(#)TOUR        8.1 (Berkeley) 5/31/93
-# $FreeBSD: src/bin/sh/TOUR,v 1.6 1999/08/27 23:15:07 peter Exp $
 
 NOTE -- This is the original TOUR paper distributed with ash and
 does not represent the current state of the shell.  It is provided anyway
@@ -22,7 +22,7 @@ SOURCE CODE GENERATORS:  Files whose names begin with "mk" are
 programs that generate source code.  A complete list of these
 programs is:
 
-        program         intput files        generates
+        program         input files         generates
         -------         ------------        ---------
         mkbuiltins      builtins            builtins.h builtins.c
         mkinit          *.c                 init.c
@@ -91,7 +91,7 @@ INTERRUPTS:  In an interactive shell, an interrupt will cause an
 EXINT exception to return to the main command loop.  (Exception:
 EXINT is not raised if the user traps interrupts using the trap
 command.)  The INTOFF and INTON macros (defined in exception.h)
-provide uninterruptable critical sections.  Between the execution
+provide uninterruptible critical sections.  Between the execution
 of INTOFF and the execution of INTON, interrupt signals will be
 held for later delivery.  INTOFF and INTON can be nested.
 
@@ -110,7 +110,7 @@ string was going to be:
         p = stackptr;
         *p++ = c;       /* repeated as many times as needed */
         stackptr = p;
-The folloing three macros (defined in memalloc.h) perform these
+The following three macros (defined in memalloc.h) perform these
 operations, but grow the stack if you run off the end:
         STARTSTACKSTR(p);
         STPUTC(c, p);   /* repeated as many times as needed */
@@ -232,7 +232,7 @@ control is defined.
 REDIR.C:  Ash allows file descriptors to be redirected and then
 restored without forking off a child process.  This is accom-
 plished by duplicating the original file descriptors.  The redir-
-tab structure records where the file descriptors have be dupli-
+tab structure records where the file descriptors have been dupli-
 cated to.
 
 EXEC.C:  The routine find_command locates a command, and enters
@@ -327,7 +327,7 @@ is called at appropriate points to actually handle the signal.
 When an interrupt is caught and no trap has been set for that
 signal, the routine "onint" in error.c is called.
 
-OUTPUT:  Ash uses it's own output routines.  There are three out-
+OUTPUT:  Ash uses its own output routines.  There are three out-
 put structures allocated.  "Output" represents the standard out-
 put, "errout" the standard error, and "memout" contains output
 which is to be stored in memory.  This last is used when a buil-
@@ -355,6 +355,3 @@ cause the preprocessor can't handle functions with a variable
 number of arguments.  Defining DEBUG also causes the shell to
 generate a core dump if it is sent a quit signal.  The tracing
 code is in show.c.
-
-#
-# $PchId: TOUR,v 1.3 2006/03/31 11:33:46 philip Exp $
diff --git a/bin/sh/USD.doc/Makefile b/bin/sh/USD.doc/Makefile
new file mode 100644 (file)
index 0000000..b12590e
--- /dev/null
@@ -0,0 +1,12 @@
+#      $NetBSD: Makefile,v 1.1 2010/08/22 01:58:16 perry Exp $
+#      @(#)Makefile    8.1 (Berkeley) 8/14/93
+
+DIR=   usd/03.shell
+SRCS=  Rv7man t.mac t1 t2 t3 t4
+MACROS= -ms
+
+paper.ps: ${SRCS}
+       ${TOOL_REFER} -e -p ${SRCS} | \
+           ${TOOL_ROFF_PS} ${MACROS} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/bin/sh/USD.doc/Rv7man b/bin/sh/USD.doc/Rv7man
new file mode 100644 (file)
index 0000000..e5da452
--- /dev/null
@@ -0,0 +1,405 @@
+%A L. P. Deutsch
+%A B. W. Lampson
+%T An online editor
+%J Comm. Assoc. Comp. Mach.
+%V 10
+%N 12
+%D December 1967
+%P 793-799, 803
+%K qed
+
+.[
+%r 17
+%K cstr
+%R Comp. Sci. Tech. Rep. No. 17
+%I Bell Laboratories
+%C Murray Hill, New Jersey
+%A B. W. Kernighan
+%A L. L. Cherry
+%T A System for Typesetting Mathematics
+%d May 1974, revised April 1977
+%J Comm. Assoc. Comp. Mach.
+%K acm cacm
+%V 18
+%P 151-157
+%D March 1975
+.]
+
+%T U\s-2NIX\s0 Time-Sharing System: Document Preparation
+%K unix bstj
+%A B. W. Kernighan
+%A M. E. Lesk
+%A J. F. Ossanna
+%J Bell Sys. Tech. J.
+%V 57
+%N 6
+%P 2115-2135
+%D 1978
+
+%A T. A. Dolotta
+%A J. R. Mashey
+%T An Introduction to the Programmer's Workbench
+%J Proc. 2nd Int. Conf. on Software Engineering
+%D October 13-15, 1976
+%P 164-168
+
+%T U\s-2NIX\s0 Time-Sharing System: The Programmer's Workbench
+%A T. A. Dolotta
+%A R. C. Haight
+%A J. R. Mashey
+%J Bell Sys. Tech. J.
+%V 57
+%N 6
+%P 2177-2200
+%D 1978
+%K unix bstj
+
+%T U\s-2NIX\s0 Time-Sharing System: U\s-2NIX\s0 on a Microprocessor
+%K unix bstj
+%A H. Lycklama
+%J Bell Sys. Tech. J.
+%V 57
+%N 6
+%P 2087-2101
+%D 1978
+
+%T The C Programming Language
+%A B. W. Kernighan
+%A D. M. Ritchie
+%I Prentice-Hall
+%C Englewood Cliffs, New Jersey
+%D 1978
+
+%T Computer Recreations
+%A Aleph-null
+%J Software Practice and Experience
+%V 1
+%N 2
+%D April-June 1971
+%P 201-204
+
+%T U\s-2NIX\s0 Time-Sharing System: The U\s-2NIX\s0 Shell
+%A S. R. Bourne
+%K unix bstj
+%J Bell Sys. Tech. J.
+%V 57
+%N 6
+%P 1971-1990
+%D 1978
+
+%A L. P. Deutsch
+%A B. W. Lampson
+%T \*sSDS\*n 930 time-sharing system preliminary reference manual
+%R Doc. 30.10.10, Project \*sGENIE\*n
+%C Univ. Cal. at Berkeley
+%D April 1965
+
+%A R. J. Feiertag
+%A E. I. Organick
+%T The Multics input-output system
+%J Proc. Third Symposium on Operating Systems Principles
+%D October 18-20, 1971
+%P 35-41
+
+%A D. G. Bobrow
+%A J. D. Burchfiel
+%A D. L. Murphy
+%A R. S. Tomlinson
+%T \*sTENEX\*n, a Paged Time Sharing System for the \*sPDP\*n-10
+%J Comm. Assoc. Comp. Mach.
+%V 15
+%N 3
+%D March 1972
+%K tenex
+%P 135-143
+
+%A R. E. Griswold
+%A D. R. Hanson
+%T An Overview of SL5
+%J SIGPLAN Notices
+%V 12
+%N 4
+%D April 1977
+%P 40-50
+
+%A E. W. Dijkstra
+%T Cooperating Sequential Processes
+%B Programming Languages
+%E F. Genuys
+%I Academic Press
+%C New York
+%D 1968
+%P 43-112
+
+%A J. A. Hawley
+%A W. B. Meyer
+%T M\s-2UNIX\s0, A Multiprocessing Version of U\s-2NIX\s0
+%K munix unix
+%R M.S. Thesis
+%I Naval Postgraduate School
+%C Monterey, Cal.
+%D 1975
+
+%T The U\s-2NIX\s0 Time-Sharing System
+%K unix bstj
+%A D. M. Ritchie
+%A K. Thompson
+%J Bell Sys. Tech. J.
+%V 57
+%N 6
+%P 1905-1929
+%D 1978
+
+%A E. I. Organick
+%T The M\s-2ULTICS\s0 System
+%K multics
+%I M.I.T. Press
+%C Cambridge, Mass.
+%D 1972
+
+%T UNIX for Beginners
+%A B. W. Kernighan
+%D 1978
+
+%T U\s-2NIX\s0 Programmer's Man\&ual
+%A K. Thompson
+%A D. M. Ritchie
+%K unix
+%I Bell Laboratories
+%O Seventh Edition.
+%D 1978
+
+%A K. Thompson
+%T The U\s-2NIX\s0 Command Language
+%B Structured Programming\(emInfotech State of the Art Report
+%I Infotech International Ltd.
+%C Nicholson House, Maidenhead, Berkshire, England
+%D March 1975
+%P 375-384
+%K unix
+%X pwb
+Brief description of shell syntax and semantics, without much
+detail on implementation.
+Much on pipes and convenience of hooking programs together.
+Includes SERMONETTE:
+"Many familiar computing `concepts' are missing from UNIX.
+Files have no records. There are no access methods.
+There are no file types.  These concepts fill a much-needed gap.
+I sincerely hope that when future systems are designed by
+manufacturers the value of some of these ingrained notions is re-examined.
+Like the politician and his `common man', manufacturers have
+their `average user'.
+
+%A J. R. Mashey
+%T PWB/UNIX Shell Tutorial
+%D September 30, 1977
+
+%A D. F. Hartley (Ed.)
+%T The Cambridge Multiple Access System \- Users Reference Manual
+%I University Mathematical Laboratory
+%C Cambridge, England
+%D 1968
+
+%A P. A. Crisman (Ed.)
+%T The Compatible Time-Sharing System
+%I M.I.T. Press
+%K whole ctss book
+%C Cambridge, Mass.
+%D 1965
+
+%T LR Parsing
+%A A. V. Aho
+%A S. C. Johnson
+%J Comp. Surveys
+%V 6
+%N 2
+%P 99-124
+%D June 1974
+
+%T Deterministic Parsing of Ambiguous Grammars
+%A A. V. Aho
+%A S. C. Johnson
+%A J. D. Ullman
+%J Comm. Assoc. Comp. Mach.
+%K acm cacm
+%V 18
+%N 8
+%P 441-452
+%D August 1975
+
+%A A. V. Aho
+%A J. D. Ullman
+%T Principles of Compiler Design
+%I Addison-Wesley
+%C Reading, Mass.
+%D 1977
+
+.[
+%r 65
+%R Comp. Sci. Tech. Rep. No. 65
+%K CSTR
+%A S. C. Johnson
+%T Lint, a C Program Checker
+%D December 1977
+%O updated version TM 78-1273-3
+%D 1978
+.]
+
+%T A Portable Compiler: Theory and Practice
+%A S. C. Johnson
+%J Proc. 5th ACM Symp. on Principles of Programming Languages
+%P 97-104
+%D January 1978
+
+.[
+%r 39
+%K CSTR
+%R Comp. Sci. Tech. Rep. No. 39
+%I Bell Laboratories
+%C Murray Hill, New Jersey
+%A M. E. Lesk
+%T Lex \(em A Lexical Analyzer Generator
+%D October 1975
+.]
+
+.[
+%r 32
+%K CSTR
+%R Comp. Sci. Tech. Rep. No. 32
+%I Bell Laboratories
+%C Murray Hill, New Jersey
+%A S. C. Johnson
+%T Yacc \(em  Yet Another Compiler-Compiler
+%D July 1975
+.]
+
+%T U\s-2NIX\s0 Time-Sharing System: Portability of C Programs and the U\s-2NIX\s0 System
+%K unix bstj
+%A S. C. Johnson
+%A D. M. Ritchie
+%J Bell Sys. Tech. J.
+%V 57
+%N 6
+%P 2021-2048
+%D 1978
+
+%T Typing Documents on UNIX and GCOS:  The -ms Macros for Troff
+%A M. E. Lesk
+%D 1977
+
+%A K. Thompson
+%A D. M. Ritchie
+%T U\s-2NIX\s0 Programmer's Manual
+%K unix
+%I Bell Laboratories
+%O Sixth Edition
+%D May 1975
+
+%T The Network U\s-2NIX\s0 System
+%K unix
+%A G. L. Chesson
+%J Operating Systems Review
+%V 9
+%N 5
+%P 60-66
+%D 1975
+%O Also in \f2Proc. 5th Symp. on Operating Systems Principles.\f1
+
+%T Spider \(em An Experimental Data Communications System
+%Z ctr127
+%A A. G. Fraser
+%J Proc. IEEE Conf. on Communications
+%P 21F
+%O IEEE Cat. No. 74CH0859-9-CSCB.
+%D June 1974
+
+%T A Virtual Channel Network
+%A A. G. Fraser
+%J Datamation
+%P 51-56
+%D February 1975
+
+.[
+%r 41
+%K CSTR
+%R Comp. Sci. Tech. Rep. No. 41
+%I Bell Laboratories
+%C Murray Hill, New Jersey
+%A J. W. Hunt
+%A M. D. McIlroy
+%T An Algorithm for Differential File Comparison
+%D June 1976
+.]
+
+%A F. P. Brooks, Jr.
+%T The Mythical Man-Month
+%I Addison-Wesley
+%C Reading, Mass.
+%D 1975
+%X pwb
+Readable, classic reference on software engineering and
+problems of large projects, from someone with experience in them.
+Required reading for any software engineer, even if conclusions may not
+always be agreed with.
+%br
+"The second is the most dangerous system a man every designs." p.55.
+%br
+"Hence plan to throw one away; you will, anyhow." p.116.
+%br
+"Cosgrove has perceptively pointed out that the programmer delivers
+satisfaction of a user need rather than any tangible product.
+And both the actual need and the user's perception of that need
+will change as programs are built, tested, and used." p.117.
+%br
+"The total cost of maintaining a widely used program is typically 40 percent
+or more of the cost of developing it." p.121.
+%br
+"As shown above, amalgamating prose and program reduces the total
+number of characters to be stored." p.175.
+
+%T A Portable Compiler for the Language C
+%A A. Snyder
+%I Master's Thesis, M.I.T.
+%C Cambridge, Mass.
+%D 1974
+
+%T The C Language Calling Sequence
+%A M. E. Lesk
+%A S. C. Johnson
+%A D. M. Ritchie
+%D 1977
+
+%T Optimal Code Generation for Expression Trees
+%A A. V. Aho
+%A S. C. Johnson
+%D 1975
+%J J. Assoc. Comp. Mach.
+%K acm jacm
+%V 23
+%N 3
+%P 488-501
+%O Also in \f2Proc. ACM Symp. on Theory of Computing,\f1 pp. 207-217, 1975.
+
+%A R. Sethi
+%A J. D. Ullman
+%T The Generation of Optimal Code for Arithmetic Expressions
+%J J. Assoc. Comp. Mach.
+%K acm jacm
+%V 17
+%N 4
+%D October 1970
+%P 715-728
+%O Reprinted as pp. 229-247 in \fICompiler Techniques\fR, ed. B. W. Pollack, Auerbach, Princeton NJ (1972).
+%X pwb
+Optimal approach for straight-line, fixed
+number of regs.
+
+%T Code Generation for Machines with Multiregister
+Operations
+%A A. V. Aho
+%A S. C. Johnson
+%A J. D. Ullman
+%J Proc. 4th ACM Symp. on Principles of Programming Languages
+%P 21-28
+%D January 1977
+
diff --git a/bin/sh/USD.doc/t.mac b/bin/sh/USD.doc/t.mac
new file mode 100644 (file)
index 0000000..9bf65c8
--- /dev/null
@@ -0,0 +1,69 @@
+.\"    $NetBSD: t.mac,v 1.2 2010/08/22 02:19:07 perry Exp $
+.\"
+.\" Copyright (C) Caldera International Inc. 2001-2002.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" Redistributions of source code and documentation must retain the above
+.\" copyright notice, this list of conditions and the following
+.\" disclaimer.
+.\"
+.\" Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\"
+.\" This product includes software developed or owned by Caldera
+.\" International, Inc.  Neither the name of Caldera International, Inc.
+.\" nor the names of other contributors may be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC.  AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"    @(#)t.mac       8.1 (Berkeley) 8/14/93
+.\"
+.ds ZZ \fB.\|.\|.\fP
+.ds ST \v'.3m'\s+2*\s0\v'-.3m'
+.ds DO \h'\w'do 'u'
+.ds Ca \h'\w'case 'u'
+.ds WH \h'\w'while 'u'
+.ds VT \|\fB\(or\fP\|
+.ds TH \h'\w'then 'u'
+.ds DC \*(DO\*(Ca
+.ds AP >\h'-.2m'>
+.ds HE <\h'-.2m'<
+.      \" macros for algol 68c reference manual
+.ds DA 1977 November 1
+.ds md \v'.25m'
+.ds mu \v'-.25m'
+.ds U \*(mu\s-3
+.ds V \s0\*(md
+.ds L \*(md\s-3
+.ds M \s0\*(mu
+.ds S \s-1
+.ds T \s0
+.      \" small 1
+.ds O \*S1\*T
+.ds h \|
+.ds s \|\|
+.      \" ellipsis
+.ds e .\|.\|.
+.      \" subscripts
+.ds 1 \*(md\s-41\s0\*(mu
+.ds 2 \*(md\s-42\s0\*(mu
diff --git a/bin/sh/USD.doc/t1 b/bin/sh/USD.doc/t1
new file mode 100644 (file)
index 0000000..075511f
--- /dev/null
@@ -0,0 +1,553 @@
+.\"    $NetBSD: t1,v 1.3 2010/08/22 02:19:07 perry Exp $
+.\"
+.\" Copyright (C) Caldera International Inc. 2001-2002.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" Redistributions of source code and documentation must retain the above
+.\" copyright notice, this list of conditions and the following
+.\" disclaimer.
+.\"
+.\" Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgment:
+.\"
+.\" This product includes software developed or owned by Caldera
+.\" International, Inc.  Neither the name of Caldera International, Inc.
+.\" nor the names of other contributors may be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC.  AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"    @(#)t1  8.1 (Berkeley) 8/14/93
+.\"
+.EH 'USD:3-%''An Introduction to the UNIX Shell'
+.OH 'An Introduction to the UNIX Shell''USD:3-%'
+.\".RP
+.TL
+An Introduction to the UNIX Shell
+.AU
+S. R. Bourne
+.AI
+Murray Hill, NJ
+.AU
+(Updated for 4.3BSD by Mark Seiden)
+.AU
+(Further updated by Perry E. Metzger)\(dg
+.AB
+.FS
+\(dg This paper was updated in 2010 to reflect most features of modern
+POSIX shells, which all follow the design of S.R. Bourne's original v7
+Unix shell.
+Among these are ash, bash, ksh and others.
+Typically one of these will be installed as /bin/sh on a modern system.
+It does not describe the behavior of the c shell (csh).
+If it's the c shell (csh) you're interested in, a good place to
+begin is William Joy's paper "An Introduction to the C shell" (USD:4).
+.FE
+.LP
+The
+.ul
+shell
+is a command programming language that provides an interface
+to the
+.UX
+operating system.
+Its features include
+control-flow primitives, parameter passing, variables and
+string substitution.
+Constructs such as
+.ul
+while, if then else, case
+and
+.ul
+for
+are available.
+Two-way communication is possible between the
+.ul
+shell
+and commands.
+String-valued parameters, typically file names or flags, may be
+passed to a command.
+A return code is set by commands that may be used to determine control-flow,
+and the standard output from a command may be used
+as shell input.
+.LP
+The
+.ul
+shell
+can modify the environment
+in which commands run.
+Input and output can be redirected
+to files, and processes that communicate through `pipes'
+can be invoked.
+Commands are found by
+searching directories
+in the file system in a
+sequence that can be defined by the user.
+Commands can be read either from the terminal or from a file,
+which allows command procedures to be
+stored for later use.
+.AE
+.ds ST \v'.3m'\s+2*\s0\v'-.3m'
+.SH
+1.0\ Introduction
+.LP
+The shell is both a command language
+and a programming language
+that provides an interface to the UNIX
+operating system.
+This memorandum describes, with
+examples, the UNIX shell.
+The first section covers most of the
+everyday requirements
+of terminal users.
+Some familiarity with UNIX
+is an advantage when reading this section;
+see, for example,
+"UNIX for beginners".
+.[
+unix beginn kernigh 1978
+.]
+Section 2 describes those features
+of the shell primarily intended
+for use within shell procedures.
+These include the control-flow
+primitives and string-valued variables
+provided by the shell.
+A knowledge of a programming language
+would be a help when reading this section.
+The last section describes the more
+advanced features of the shell.
+References of the form "see \fIpipe\fP (2)"
+are to a section of the UNIX manual.
+.[
+seventh 1978 ritchie thompson
+.]
+.SH
+1.1\ Simple\ commands
+.LP
+Simple commands consist of one or more words
+separated by blanks.
+The first word is the name of the command
+to be executed; any remaining words
+are passed as arguments to the command.
+For example,
+.DS
+       who
+.DE
+is a command that prints the names
+of users logged in.
+The command
+.DS
+       ls \(mil
+.DE
+prints a list of files in the current
+directory.
+The argument \fI\(mil\fP tells \fIls\fP
+to print status information, size and
+the creation date for each file.
+.SH
+1.2\ Input\ output\ redirection
+.LP
+Most commands produce output on the standard output
+that is initially connected to the terminal.
+This output may be sent to a file
+by writing, for example,
+.DS
+       ls \(mil >file
+.DE
+The notation \fI>file\fP
+is interpreted by the shell and is not passed
+as an argument to \fIls.\fP
+If \fIfile\fP does not exist then the
+shell creates it;
+otherwise the original contents of
+\fIfile\fP are replaced with the output
+from \fIls.\fP
+Output may be appended to a file
+using the notation
+.DS
+       ls \(mil \*(APfile
+.DE
+In this case \fIfile\fP is also created if it does not already
+exist.
+.LP
+The standard input of a command may be taken
+from a file instead of the terminal by
+writing, for example,
+.DS
+       wc <file
+.DE
+The command \fIwc\fP reads its standard input
+(in this case redirected from \fIfile\fP)
+and prints the number of characters, words and
+lines found.
+If only the number of lines is required
+then
+.DS
+       wc \(mil <file
+.DE
+could be used.
+.\" I considered adding the following, but have thought better of it
+.\" for now.
+.\" -- Perry Metzger
+.\"
+.\" .LP
+.\" Error messages are typically printed by commands on a different
+.\" channel, called standard error, which may also be redirected using the
+.\" notation 2>\|.
+.\" For example
+.\" .DS
+.\" command some args >out 2>errors
+.\" .DE
+.\" will redirect standard output to the file `out' but standard error
+.\" (and thus all error messages) to `errors'.
+.\" The notation 2>&1 sets standard error pointing to the same
+.\" place as standard out.
+.\" Thus:
+.\" .DS
+.\" command some args 2>&1 >everything
+.\" .DE
+.\" will put both standard out and standard error into the file `everything'.
+.\" See section 3.7 below for more details.
+.SH
+1.3\ Pipelines\ and\ filters
+.LP
+The standard output of one command may be
+connected to the standard input of another
+by writing
+the `pipe' operator,
+indicated by \*(VT,
+as in,
+.DS
+       ls \(mil \*(VT wc
+.DE
+Two commands connected in this way constitute
+a \fIpipeline\fP and
+the overall effect is the same as
+.DS
+       ls \(mil >file; wc <file
+.DE
+except that no \fIfile\fP is used.
+Instead the two \fIprocesses\fP are connected
+by a pipe (see \fIpipe\fP(2)) and are
+run in parallel.
+Pipes are unidirectional and
+synchronization is achieved by
+halting \fIwc\fP when there is
+nothing to read and halting \fIls\fP
+when the pipe is full.
+.LP
+A \fIfilter\fP is a command
+that reads its standard input,
+transforms it in some way,
+and prints the result as output.
+One such filter, \fIgrep,\fP
+selects from its input those lines
+that contain some specified string.
+For example,
+.DS
+       ls \*(VT grep old
+.DE
+prints those lines, if any, of the output
+from \fIls\fP that contain
+the string \fIold.\fP
+Another useful filter is \fIsort\fP.
+For example,
+.DS
+       who \*(VT sort
+.DE
+will print an alphabetically sorted list
+of logged in users.
+.LP
+A pipeline may consist of more than two commands,
+for example,
+.DS
+       ls \*(VT grep old \*(VT wc \(mil
+.DE
+prints the number of file names
+in the current directory containing
+the string \fIold.\fP
+.SH
+1.4\ Background\ commands
+.LP
+To execute a command (or pipeline) the shell normally
+creates the new \fIprocesses\fP
+and waits for them to finish.
+A command may be run without waiting
+for it to finish.
+For example,
+.DS
+       cc pgm.c &
+.DE
+calls the C compiler to compile
+the file \fIpgm.c\|.\fP
+The trailing \fB&\fP is an operator that instructs the shell
+not to wait for the command to finish.
+To help keep track of such a process
+the shell reports its job number (see below) and process
+id following its creation.
+Such a command is said to be running in the \fIbackground\fP.
+By contrast, a command executed without the \fB&\fP is said to be
+running in the \fIforeground\fP.\(dg
+.FS
+\(dg Even after execution, one may move commands from the foreground
+to the background, or temporarily suspend their execution (which is
+known as \fIstopping\fP a command.
+This is described in detail in section 3.10 on \fIJob Control\fB.
+.FE
+.LP
+A list of currently active processes, including ones not associated
+with the current shell, may be obtained using the \fIps\fP(1) command.
+.SH
+1.5\ File\ name\ generation
+.LP
+Many commands accept arguments
+which are file names.
+For example,
+.DS
+       ls \(mil main.c
+.DE
+prints information relating to the file \fImain.c\fP\|.
+.LP
+The shell provides a mechanism
+for generating a list of file names
+that match a pattern.
+For example,
+.DS
+       ls \(mil \*(ST.c
+.DE
+generates, as arguments to \fIls,\fP
+all file names in the current directory that end in \fI.c\|.\fP
+The character \*(ST is a pattern that will match any string
+including the null string.
+In general \fIpatterns\fP are specified
+as follows.
+.RS
+.IP \fB\*(ST\fR 8
+Matches any string of characters
+including the null string.
+.IP \fB?\fR 8
+Matches any single character.
+.IP \fB[\*(ZZ]\fR 8
+Matches any one of the characters
+enclosed.
+A pair of characters separated by a minus will
+match any character lexically between
+the pair.
+.RE
+.LP
+For example,
+.DS
+       [a\(miz]\*(ST
+.DE
+matches all names in the current directory
+beginning with
+one of the letters \fIa\fP through \fIz.\fP
+.DS
+       /usr/fred/test/?
+.DE
+matches all names in the directory
+\fB/usr/fred/test\fP that consist of a single character.
+If no file name is found that matches
+the pattern then the pattern is passed,
+unchanged, as an argument.
+.LP
+This mechanism is useful both to save typing
+and to select names according to some pattern.
+It may also be used to find files.
+For example,
+.DS
+       echo /usr/fred/\*(ST/core
+.DE
+finds and prints the names of all \fIcore\fP files in sub-directories
+of \fB/usr/fred\|.\fP
+(\fIecho\fP is a standard UNIX command that prints
+its arguments, separated by blanks.)
+This last feature can be expensive,
+requiring a scan of all
+sub-directories of \fB/usr/fred\|.\fP
+.LP
+There is one exception to the general
+rules given for patterns.
+The character `\fB.\fP'
+at the start of a file name must be explicitly
+matched.
+.DS
+       echo \*(ST
+.DE
+will therefore echo all file names in the current
+directory not beginning
+with `\fB.\fP'\|.
+.DS
+       echo \fB.\fP\*(ST
+.DE
+will echo all those file names that begin with `\fB.\fP'\|.
+This avoids inadvertent matching
+of the names `\fB.\fP' and `\fB..\fP'
+which mean `the current directory'
+and `the parent directory'
+respectively.
+(Notice that \fIls\fP suppresses
+information for the files `\fB.\fP' and `\fB..\fP'\|.)
+.LP
+Finally, the tilde character, `\fB\(ap\fP', may be used to indicate the
+home directory of a user.
+The `\fB\(ap\fP' at the beginning of a path name followed by a
+non-alphabetic character expands to the current user's home
+directory.
+If the `\fB\(ap\fP' is followed by a login name, it expands to the named
+user's home directory.
+For example:
+.DS
+       ls \(ap
+       cd \(apegbert/
+.DE
+will list the contents of the user's home directory and then change
+to the home directory of the user ``egbert''.
+.SH
+1.6\ Quoting
+.LP
+Characters that have a special meaning
+to the shell, such as \fB< > \*(ST ? \*(VT &\|,\fR
+are called metacharacters.
+A complete list of metacharacters is given
+in appendix B.
+Any character preceded by a \fB\\\fR is \fIquoted\fP
+and loses its special meaning, if any.
+The \fB\\\fP is elided so that
+.DS
+       echo \\?
+.DE
+will echo a single \fB?\|,\fP
+and
+.DS
+       echo \\\\
+.DE
+will echo a single \fB\\\|.\fR
+To allow long strings to be continued over
+more than one line
+the sequence \fB\\newline\fP
+is ignored.
+.LP
+\fB\\\fP is convenient for quoting
+single characters.
+When more than one character needs
+quoting the above mechanism is clumsy and
+error prone.
+A string of characters may be quoted
+by enclosing the string between single quotes.
+For example,
+.DS
+       echo xx\'\*(ST\*(ST\*(ST\*(ST\'xx
+.DE
+will echo
+.DS
+       xx\*(ST\*(ST\*(ST\*(STxx
+.DE
+The quoted string may not contain
+a single quote
+but may contain newlines, which are preserved.
+This quoting mechanism is the most
+simple and is recommended
+for casual use.
+.LP
+A third quoting mechanism using double quotes
+is also available
+that prevents interpretation of some but not all
+metacharacters.
+Discussion of the
+details is deferred
+to section 3.5\|.
+.SH
+1.7\ Prompting
+.LP
+When the shell is used from a terminal it will
+issue a prompt before reading a command.
+By default this prompt is `\fB$\ \fR'\|.
+It may be changed by saying,
+for example,
+.DS
+       \s-1PS1\s0="yesdear$ "
+.DE
+that sets the prompt to be the string \fIyesdear$\|.\fP
+If a newline is typed and further input is needed
+then the shell will issue the prompt `\fB>\ \fR'\|.
+Sometimes this can be caused by mistyping
+a quote mark.
+If it is unexpected then entering the interrupt character
+(typically \s-1CONTROL-C\s0) 
+will return the shell to read another command.
+This prompt may be changed by saying, for example,
+.DS
+       \s-1PS2\s0=more
+.DE
+Entering the interrupt character may also be used to terminate most
+programs running as the current foreground job.
+.LP
+(\s-1PS1\s0 and \s-1PS2\s0 are \fIshell variables\fP, which will be
+described in section 2.4 below.)
+.SH
+1.8\ The\ shell\ and\ login
+.LP
+Following \fIlogin\fP(1)
+the shell is called to read and execute
+commands typed at the terminal.
+If the user's login directory
+contains the file \fB.profile\fP
+then it is assumed to contain commands
+and is read by the shell before reading
+any commands from the terminal.
+.LP
+(Most versions of the shell also specify a file that is read and
+executed on start-up whether or not the shell is invoked by login.
+The \s-1ENV\s0 shell variable, described in section 2.4 below, can be
+used to override the name of this file.
+See the shell manual page for further information.)
+.SH
+1.9\ Summary
+.sp
+.RS
+.IP \(bu
+\fBls\fP
+.br
+Print the names of files in the current directory.
+.IP \(bu
+\fBls >file\fP
+.br
+Put the output from \fIls\fP into \fIfile.\fP
+.IP \(bu
+\fBls \*(VT wc \(mil\fR
+.br
+Print the number of files in the current directory.
+.IP \(bu
+\fBls \*(VT grep old\fR
+.br
+Print those file names containing the string \fIold.\fP
+.IP \(bu
+\fBls \*(VT grep old \*(VT wc \(mil\fR
+.br
+Print the number of files whose name contains the string \fIold.\fP
+.IP \(bu
+\fBcc pgm.c &\fR
+.br
+Run \fIcc\fP in the background.
+.RE
diff --git a/bin/sh/USD.doc/t2 b/bin/sh/USD.doc/t2
new file mode 100644 (file)
index 0000000..d49747e
--- /dev/null
@@ -0,0 +1,971 @@
+.\"    $NetBSD: t2,v 1.3 2010/08/22 02:19:07 perry Exp $
+.\"
+.\" Copyright (C) Caldera International Inc. 2001-2002.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" Redistributions of source code and documentation must retain the above
+.\" copyright notice, this list of conditions and the following
+.\" disclaimer.
+.\"
+.\" Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgment:
+.\"
+.\" This product includes software developed or owned by Caldera
+.\" International, Inc.  Neither the name of Caldera International, Inc.
+.\" nor the names of other contributors may be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC.  AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"    @(#)t2  8.1 (Berkeley) 6/8/93
+.\"
+.SH
+2.0\ Shell\ scripts
+.LP
+The shell may be used to read and execute commands
+contained in a file.
+For example,
+.DS
+       sh file [ args \*(ZZ ]
+.DE
+calls the shell to read commands from \fIfile.\fP
+Such a file is called a \fIshell script.\fP
+Arguments may be supplied with the call
+and are referred to in \fIfile\fP
+using the positional parameters
+\fB$1, $2, \*(ZZ\|.\fR
+.LP
+For example, if the file \fIwg\fP contains
+.DS
+       who \*(VT grep $1
+.DE
+then
+.DS
+       sh wg fred
+.DE
+is equivalent to
+.DS
+       who \*(VT grep fred
+.DE
+.LP
+UNIX files have three independent attributes,
+\fIread,\fP \fIwrite\fP and \fIexecute.\fP
+The UNIX command \fIchmod\fP(1) may be used
+to make a file executable.
+For example,
+.DS
+       chmod +x wg
+.DE
+will ensure that the file \fIwg\fP has execute status.
+Following this, the command
+.DS
+       wg fred
+.DE
+is equivalent to
+.DS
+       sh wg fred
+.DE
+This allows shell scripts and other programs
+to be used interchangeably.
+In either case a new process is created to
+run the command.
+.LP
+The `\fB#\fP' character is used as a comment character by the shell.
+All characters following the `#' on a line are ignored.
+.LP
+A typical modern system has several different shells, some with differing
+command syntax, and it is desirable to specify which one should be
+invoked when an executable script is invoked.
+If the special comment
+.DS
+       #!/\fIpath\fP/\fIto\fP/\fIinterpreter\fP
+.DE
+appears as the first line in a script, it is used to specify the
+absolute pathname of the shell (or other interpreter) that should be
+used to execute the file.
+(Without such a line, \fB/bin/sh\fP is assumed.)
+It is best if a script explicitly states
+what shell it is intended for in this manner.
+.LP
+As well as providing names for the positional
+parameters,
+the number of positional parameters to a script
+is available as \fB$#\|.\fP
+The name of the file being executed
+is available as \fB$0\|.\fP
+.LP
+A special shell parameter \fB$\*(ST\fP
+is used to substitute for all positional parameters
+except \fB$0\|.\fP
+A typical use of this is to provide
+some default arguments,
+as in,
+.DS
+       nroff \(miT450 \(mims $\*(ST
+.DE
+which simply prepends some arguments
+to those already given.
+(The variable \fB$@\fP also expands to ``all positional
+parameters'', but is subtly different when expanded inside quotes.
+See section 3.5, below.)
+.SH
+2.1\ Control\ flow\ -\ for
+.LP
+A frequent use of shell scripts is to loop
+through the arguments (\fB$1, $2, \*(ZZ\fR)
+executing commands once for each argument.
+An example of such a script is
+\fItel\fP that searches the file
+\fB/usr/share/telnos\fR
+that contains lines of the form
+.DS
+       \*(ZZ
+       fred mh0123
+       bert mh0789
+       \*(ZZ
+.DE
+The text of \fItel\fP is
+.DS
+       #!/bin/sh
+
+       for i
+       do
+               grep $i /usr/share/telnos
+       done
+.DE
+The command
+.DS
+       tel fred
+.DE
+prints those lines in \fB/usr/share/telnos\fR
+that contain the string \fIfred\|.\fP
+.DS
+       tel fred bert
+.DE
+prints those lines containing \fIfred\fP
+followed by those for \fIbert.\fP
+.LP
+The \fBfor\fP loop notation is recognized by the shell
+and has the general form
+.DS
+       \fBfor\fR \fIname\fR \fBin\fR \fIw1 w2 \*(ZZ\fR
+       \fBdo\fR \fIcommand-list\fR
+       \fBdone\fR
+.DE
+A \fIcommand-list\fP is a sequence of one or more
+simple commands separated or terminated by a newline or semicolon.
+Furthermore, reserved words
+like \fBdo\fP and \fBdone\fP are only
+recognized following a newline or
+semicolon.
+\fIname\fP is a shell variable that is set
+to the words \fIw1 w2 \*(ZZ\fR in turn each time the \fIcommand-list\fP
+following \fBdo\fP
+is executed.
+If \fBin\fR \fIw1 w2 \*(ZZ\fR
+is omitted then the loop
+is executed once for each positional parameter;
+that is, \fBin\fR \fI$\*(ST\fR is assumed.
+.LP
+Another example of the use of the \fBfor\fP
+loop is the \fIcreate\fP command
+whose text is
+.DS
+       for i do >$i; done
+.DE
+The command
+.DS
+       create alpha beta
+.DE
+ensures that two empty files
+\fIalpha\fP and \fIbeta\fP exist
+and are empty.
+The notation \fI>file\fP may be used on its
+own to create or clear the contents of a file.
+Notice also that a semicolon (or newline) is required before \fBdone.\fP
+.SH
+2.2\ Control\ flow\ -\ case
+.LP
+A multiple way branch is provided for by the
+\fBcase\fP notation.
+For example,
+.DS
+       case $# in
+       \*(Ca1) cat \*(AP$1 ;;
+       \*(Ca2) cat \*(AP$2 <$1 ;;
+       \*(Ca\*(ST)     echo \'usage: append [ from ] to\' ;;
+       esac
+.DE
+is an \fIappend\fP command.
+When called
+with one argument as
+.DS
+       append file
+.DE
+\fB$#\fP is the string \fI1\fP and
+the standard input is copied onto the
+end of \fIfile\fP
+using the \fIcat\fP command.
+.DS
+       append file1 file2
+.DE
+appends the contents of \fIfile1\fP
+onto \fIfile2.\fP
+If the number of arguments supplied to
+\fIappend\fP is other than 1 or 2
+then a message is printed indicating
+proper usage.
+.LP
+The general form of the \fBcase\fP command
+is
+.DS
+       \fBcase \fIword \fBin
+       \*(Ca\fIpattern\|\fB)\ \fIcommand-list\fB\|;;
+       \*(Ca\*(ZZ
+       \fBesac\fR
+.DE
+The shell attempts to match
+\fIword\fR with each \fIpattern,\fR
+in the order in which the patterns
+appear.
+If a match is found the
+associated \fIcommand-list\fP is
+executed and execution
+of the \fBcase\fP is complete.
+Since \*(ST is the pattern that matches any
+string it can be used for the default case.
+.LP
+A word of caution:
+no check is made to ensure that only
+one pattern matches
+the case argument.
+The first match found defines the set of commands
+to be executed.
+In the example below the commands following
+the second \*(ST will never be executed.
+.DS
+       case $# in
+       \*(Ca\*(ST) \*(ZZ ;;
+       \*(Ca\*(ST) \*(ZZ ;;
+       esac
+.DE
+.LP
+Another example of the use of the \fBcase\fP
+construction is to distinguish
+between different forms
+of an argument.
+The following example is a fragment of a \fIcc\fP command.
+.DS
+       for i
+       do case $i in
+       \*(DC\(mi[ocs]) \*(ZZ ;;
+       \*(DC\(mi\*(ST) echo "unknown flag $i" ;;
+       \*(DC\*(ST.c)   /lib/c0 $i \*(ZZ ;;
+       \*(DC\*(ST)     echo "unexpected argument $i" ;;
+       \*(DOesac
+       done
+.DE
+.LP
+To allow the same commands to be associated
+with more than one pattern
+the \fBcase\fP command provides
+for alternative patterns
+separated by a \*(VT\|.
+For example,
+.DS
+       case $i in
+       \*(Ca\(mix\*(VT\(miy)   \*(ZZ
+       esac
+.DE
+is equivalent to
+.DS
+       case $i in
+       \*(Ca\(mi[xy])  \*(ZZ
+       esac
+.DE
+.LP
+The usual quoting conventions apply
+so that
+.DS
+       case $i in
+       \*(Ca\\?)       \*(ZZ
+.DE
+will match the character \fB?\|.\fP
+.SH
+2.3\ Here\ documents
+.LP
+The shell script \fItel\fP
+in section 2.1 uses the file \fB/usr/share/telnos\fR
+to supply the data
+for \fIgrep.\fP
+An alternative is to include this
+data
+within the shell script as a \fIhere\fP document, as in,
+.DS
+       for i
+       do grep $i \*(HE!
+       \*(DO\*(ZZ
+       \*(DOfred mh0123
+       \*(DObert mh0789
+       \*(DO\*(ZZ
+       !
+       done
+.DE
+In this example
+the shell takes the lines between \fB\*(HE!\fR and \fB!\fR
+as the standard input for \fIgrep.\fP
+The string \fB!\fR is arbitrary, the document
+being terminated by a line that consists
+of the string following \*(HE\|.
+.LP
+Parameters are substituted in the document
+before it is made available to \fIgrep\fP
+as illustrated by the following script
+called \fIedg\|.\fP
+.DS
+       ed $3 \*(HE%
+       g/$1/s//$2/g
+       w
+       %
+.DE
+The call
+.DS
+       edg string1 string2 file
+.DE
+is then equivalent to the command
+.DS
+       ed file \*(HE%
+       g/string1/s//string2/g
+       w
+       %
+.DE
+and changes all occurrences of \fIstring1\fP
+in \fIfile\fP to \fIstring2\|.\fP
+Substitution can be prevented using \\
+to quote the special character \fB$\fP
+as in
+.DS
+       ed $3 \*(HE+
+       1,\\$s/$1/$2/g
+       w
+       +
+.DE
+(This version of \fIedg\fP is equivalent to
+the first except that \fIed\fP will print
+a \fB?\fR if there are no occurrences of
+the string \fB$1\|.\fP)
+Substitution within a \fIhere\fP document
+may be prevented entirely by quoting
+the terminating string,
+for example,
+.DS
+       grep $i \*(HE'end'
+       \*(ZZ
+       end
+.DE
+The document is presented
+without modification to \fIgrep.\fP
+If parameter substitution is not required
+in a \fIhere\fP document this latter form
+is more efficient.
+.SH
+2.4\ Shell\ variables\(dg
+.LP
+.FS
+Also known as \fIenvironment variables\fB, see \fIenvironment\fB(7).
+.FE
+The shell
+provides string-valued variables.
+Variable names begin with a letter
+and consist of letters, digits and
+underscores.
+Variables may be given values by writing, for example,
+.DS
+       user=fred\ box=m000\ acct=mh0000
+.DE
+which assigns values to the variables
+\fBuser, box\fP and \fBacct.\fP
+A variable may be set to the null string
+by saying, for example,
+.DS
+       null=
+.DE
+The value of a variable is substituted
+by preceding its name with \fB$\|\fP;
+for example,
+.DS
+       echo $user
+.DE
+will echo \fIfred.\fP
+.LP
+Variables may be used interactively
+to provide abbreviations for frequently
+used strings.
+For example,
+.DS
+       b=/usr/fred/bin
+       mv pgm $b
+.DE
+will move the file \fIpgm\fP
+from the current directory to the directory \fB/usr/fred/bin\|.\fR
+A more general notation is available for parameter
+(or variable)
+substitution, as in,
+.DS
+       echo ${user}
+.DE
+which is equivalent to
+.DS
+       echo $user
+.DE
+and is used when the parameter name is
+followed by a letter or digit.
+For example,
+.DS
+       tmp=/tmp/ps
+       ps a >${tmp}a
+.DE
+will direct the output of \fIps\fR
+to the file \fB/tmp/psa,\fR
+whereas,
+.DS
+       ps a >$tmpa
+.DE
+would cause the value of the variable \fBtmpa\fP
+to be substituted.
+.LP
+Except for \fB$?\fP the following
+are set initially by the shell.
+\fB$?\fP is set after executing each command.
+.RS
+.IP \fB$?\fP 8
+The exit status (return code)
+of the last command executed
+as a decimal string.
+Most commands return a zero exit status
+if they complete successfully,
+otherwise a non-zero exit status is returned.
+Testing the value of return codes is dealt with
+later under \fBif\fP and \fBwhile\fP commands.
+.IP \fB$#\fP 8
+The number of positional parameters
+(in decimal).
+Used, for example, in the \fIappend\fP command
+to check the number of parameters.
+.IP \fB$$\fP 8
+The process number of this shell (in decimal).
+Since process numbers are unique among
+all existing processes, this string is
+frequently used to generate
+unique
+temporary file names.
+For example,
+.DS
+       ps a >/tmp/ps$$
+       \*(ZZ
+       rm /tmp/ps$$
+.DE
+.IP \fB$\|!\fP 8
+The process number of the last process
+run in the background (in decimal).
+.IP \fB$\(mi\fP 8
+The current shell flags, such as
+\fB\(mix\fR and \fB\(miv\|.\fR
+.RE
+.LP
+Some variables have a special meaning to the
+shell and should be avoided for general
+use.
+.RS
+.IP \fB$\s-1MAIL\s0\fP 8
+When used interactively
+the shell looks at the file
+specified by this variable
+before it issues a prompt.
+If the specified file has been modified
+since it
+was last looked at the shell
+prints the message
+\fIyou have mail\fP before prompting
+for the next command.
+This variable is typically set
+in the file \fB.profile,\fP
+in the user's login directory.
+For example,
+.DS
+       \s-1MAIL\s0=/usr/spool/mail/fred
+.DE
+.IP \fB$\s-1HOME\s0\fP 8
+The default argument
+for the \fIcd\fP command.
+The current directory is used to resolve
+file name references that do not begin with
+a \fB/\|,\fR
+and is changed using the \fIcd\fP command.
+For example,
+.DS
+       cd /usr/fred/bin
+.DE
+makes the current directory \fB/usr/fred/bin\|.\fR
+.DS
+       cat wn
+.DE
+will print on the terminal the file \fIwn\fP
+in this directory.
+The command
+\fIcd\fP with no argument
+is equivalent to
+.DS
+       cd $\s-1HOME\s0
+.DE
+This variable is also typically set in the
+the user's login profile.
+.IP \fB$\s-1PWD\s0\fP 8
+The current working directory. Set by the \fIcd\fB command.
+.IP \fB$\s-1PATH\s0\fP 8
+A list of directories that contain commands (the \fIsearch path\fR\|).
+Each time a command is executed by the shell
+a list of directories is searched
+for an executable file.
+.ne 5
+If \fB$\s-1PATH\s0\fP is not set
+then the current directory,
+\fB/bin\fP, and \fB/usr/bin\fP are searched by default.
+.ne 5
+Otherwise \fB$\s-1PATH\s0\fP consists of directory
+names separated by \fB:\|.\fP
+For example,
+.DS
+       \s-1PATH\s0=\fB:\fP/usr/fred/bin\fB:\fP/bin\fB:\fP/usr/bin
+.DE
+specifies that the current directory
+(the null string before the first \fB:\fP\|),
+\fB/usr/fred/bin, /bin \fRand\fP /usr/bin\fR
+are to be searched in that order.
+In this way individual users
+can have their own `private' commands
+that are accessible independently
+of the current directory.
+If the command name contains a \fB/\fR then this directory search
+is not used; a single attempt
+is made to execute the command.
+.IP \fB$\s-1PS1\s0\fP 8
+The primary shell prompt string, by default, `\fB$\ \fR'.
+.IP \fB$\s-1PS2\s0\fP 8
+The shell prompt when further input is needed,
+by default, `\fB>\ \fR'.
+.IP \fB$\s-1IFS\s0\fP 8
+The set of characters used by \fIblank
+interpretation\fR (see section 3.5).
+.IP \fB$\s-1ENV\s0\fP 8
+The shell reads and executes the commands in the file
+specified by this variable when it is initially started.
+Unlike the \fB.profile\fP file, these commands are executed by all
+shells, not just the one started at login.
+(Most versions of the shell specify a filename that is used if
+\s-1ENV\s0 is not explicitly set. See the manual page for your shell.)
+.RE
+.SH
+2.5\ The\ test\ command
+.LP
+The \fItest\fP command, although not part of the shell,
+is intended for use by shell programs.
+For example,
+.DS
+       test \(mif file
+.DE
+returns zero exit status if \fIfile\fP
+exists and non-zero exit status otherwise.
+In general \fItest\fP evaluates a predicate
+and returns the result as its exit status.
+Some of the more frequently used \fItest\fP
+arguments are given here, see \fItest\fP(1)
+for a complete specification.
+.DS
+       test s          true if the argument \fIs\fP is not the null string
+       test \(mif file true if \fIfile\fP exists
+       test \(mir file true if \fIfile\fP is readable
+       test \(miw file true if \fIfile\fP is writable
+       test \(mid file true if \fIfile\fP is a directory
+.DE
+The \fItest\fP command is known as `\fB[\fP' and may be invoked as
+such.
+For aesthetic reasons, the command ignores a close bracket `\fB]\fP' given
+at the end of a command so
+.DS
+       [ -f filename ]
+.DE
+and
+.DS
+       test -f filename
+.DE
+are completely equivalent.
+Typically, the bracket notation is used when \fItest\fP is invoked inside
+shell control constructs.
+.SH
+2.6\ Control\ flow\ -\ while
+.LP
+The actions of
+the \fBfor\fP loop and the \fBcase\fP
+branch are determined by data available to the shell.
+A \fBwhile\fP or \fBuntil\fP loop
+and an \fBif then else\fP branch
+are also provided whose
+actions are determined by the exit status
+returned by commands.
+A \fBwhile\fP loop has the general form
+.DS
+       \fBwhile\fP \fIcommand-list\*1\fP
+       \fBdo\fP \fIcommand-list\*2\fP
+       \fBdone\fP
+.DE
+.LP
+The value tested by the \fBwhile\fP command
+is the exit status of the last simple command
+following \fBwhile.\fP
+Each time round the loop
+\fIcommand-list\*1\fP is executed;
+if a zero exit status is returned then
+\fIcommand-list\*2\fP
+is executed;
+otherwise, the loop terminates.
+For example,
+.DS
+       while [ $1 ]
+       do \*(ZZ
+       \*(DOshift
+       done
+.DE
+is equivalent to
+.DS
+       for i
+       do \*(ZZ
+       done
+.DE
+\fIshift\fP is a shell command that
+renames the positional parameters
+\fB$2, $3, \*(ZZ\fR as \fB$1, $2, \*(ZZ\fR
+and loses \fB$1\|.\fP
+.LP
+Another kind of use for the \fBwhile/until\fP
+loop is to wait until some
+external event occurs and then run
+some commands.
+In an \fBuntil\fP loop
+the termination condition is reversed.
+For example,
+.DS
+       until [ \(mif file ]
+       do sleep 300; done
+       \fIcommands\fP
+.DE
+will loop until \fIfile\fP exists.
+Each time round the loop it waits for
+5 minutes before trying again.
+(Presumably another process
+will eventually create the file.)
+.LP
+The most recent enclosing loop may be exited with the \fBbreak\fP
+command, or the rest of the body skipped and the next iteration begun
+with the \fBcontinue\fP command.
+.LP
+The commands \fItrue\fP(1) and \fIfalse\fP(1) return 0 and non-zero
+exit statuses respectively. They are sometimes of use in control flow,
+e.g.:
+.DS
+       while true
+       do date; sleep 5
+       done
+.DE
+is an infinite loop that prints the date and time every five seconds.
+.SH
+2.7\ Control\ flow\ -\ if
+.LP
+Also available is a
+general conditional branch
+of the form,
+.DS
+       \fBif\fP \fIcommand-list
+       \fBthen \fIcommand-list
+       \fBelse \fIcommand-list
+       \fBfi\fR
+.DE
+that tests the value returned by the last simple command
+following \fBif.\fP
+.LP
+The \fBif\fP command may be used
+in conjunction with the \fItest\fP command
+to test for the existence of a file as in
+.DS
+       if [ \(mif file ]
+       then    \fIprocess file\fP
+       else    \fIdo something else\fP
+       fi
+.DE
+.LP
+An example of the use of \fBif, case\fP
+and \fBfor\fP constructions is given in
+section 2.10\|.
+.LP
+A multiple test \fBif\fP command
+of the form
+.DS
+       if \*(ZZ
+       then    \*(ZZ
+       else    if \*(ZZ
+               then    \*(ZZ
+               else    if \*(ZZ
+                       \*(ZZ
+                       fi
+               fi
+       fi
+.DE
+may be written using an extension of the \fBif\fP
+notation as,
+.DS
+       if \*(ZZ
+       then    \*(ZZ
+       elif    \*(ZZ
+       then    \*(ZZ
+       elif    \*(ZZ
+       \*(ZZ
+       fi
+.DE
+.LP
+The following example is an implementation of the \fItouch\fP command
+which changes the `last modified' time for a list
+of files.
+The command may be used in conjunction
+with \fImake\fP(1) to force recompilation of a list
+of files.
+.DS
+       #!/bin/sh
+
+       flag=
+       for i
+       do case $i in
+       \*(DC\(mic)     flag=N ;;
+       \*(DC\*(ST)     if [ \(mif $i ]
+       \*(DC   then    cp $i junk$$; mv junk$$ $i
+       \*(DC   elif [ $flag ]
+       \*(DC   then    echo file \\'$i\\' does not exist
+       \*(DC   else    >$i
+       \*(DC   fi
+       \*(DO esac
+       done
+.DE
+The \fB\(mic\fP flag is used in this command to
+force subsequent files to be created if they do not already exist.
+Otherwise, if the file does not exist, an error message is printed.
+The shell variable \fIflag\fP
+is set to some non-null string if the \fB\(mic\fP
+argument is encountered.
+The commands
+.DS
+       cp \*(ZZ; mv \*(ZZ
+.DE
+copy the file and then overwrite it with the copy,
+thus causing the last modified date to be updated.
+.LP
+The sequence
+.DS
+       if command1
+       then    command2
+       fi
+.DE
+may be written
+.DS
+       command1 && command2
+.DE
+Conversely,
+.DS
+       command1 \*(VT\*(VT command2
+.DE
+executes \fIcommand2\fP only if \fIcommand1\fP
+fails.
+In each case the value returned
+is that of the last simple command executed.
+.LP
+Placing a `\fB!\fP' in front of a pipeline inverts its exit
+status, almost in the manner of the C operator of the same name.
+Thus:
+.DS
+       if ! [ -d $1 ]
+       then
+               echo $1 is not a directory
+       fi
+.DE
+will print a message only if $1 is not a directory.
+.SH
+2.8\ Command\ grouping
+.LP
+Commands may be grouped in two ways,
+.DS
+       \fB{\fI command-list\fB ; }\fR
+.DE
+and
+.DS
+       \fB(\fI command-list\fB )\fR
+.DE
+.LP
+In the first \fIcommand-list\fP is simply executed.
+The second form executes \fIcommand-list\fP
+as a separate process.
+For example,
+.DS
+       (cd x; rm junk )
+.DE
+executes \fIrm junk\fP in the directory
+\fBx\fP without changing the current
+directory of the invoking shell.
+.LP
+The commands
+.DS
+       cd x; rm junk
+.DE
+have the same effect but leave the invoking
+shell in the directory \fBx.\fP
+.SH
+2.9\ Shell\ Functions
+.LP
+A function may be defined by the syntax
+.DS
+       \fIfuncname\fP() \fB{\fI command-list\fB ; }\fR
+.DE
+Functions are invoked within a script as though they were separate
+commands of the same name.
+While they are executed, the
+positional parameters \fB$1, $2, \*(ZZ\fR are temporarily set to the
+arguments passed to the function. For example:
+.DS
+       count() {
+               echo $2 : $#
+       }
+
+       count a b c
+.DE
+would print `b : 3'.
+.SH
+2.10\ Debugging\ shell\ scripts
+.LP
+The shell provides two tracing mechanisms
+to help when debugging shell scripts.
+The first is invoked within the script
+as
+.DS
+       set \(miv
+.DE
+(\fBv\fP for verbose) and causes lines of the
+script to be printed as they are read.
+It is useful to help isolate syntax errors.
+It may be invoked without modifying the script
+by saying
+.DS
+       sh \(miv \fIscript\fP \*(ZZ
+.DE
+where \fIscript\fP is the name of the shell script.
+This flag may be used in conjunction
+with the \fB\(min\fP flag which prevents
+execution of subsequent commands.
+(Note that saying \fIset \(min\fP at a terminal
+will render the terminal useless
+until an end-of-file is typed.)
+.LP
+The command
+.DS
+       set \(mix
+.DE
+will produce an execution
+trace.
+Following parameter substitution
+each command is printed as it is executed.
+(Try these at the terminal to see
+what effect they have.)
+Both flags may be turned off by saying
+.DS
+       set \(mi
+.DE
+and the current setting of the shell flags is available as \fB$\(mi\|\fR.
+.SH
+2.11\ The\ man\ command
+.LP
+The following is a simple implementation of the \fIman\fP command,
+which is used to display sections of the UNIX manual on your terminal.
+It is called, for example, as
+.DS
+               man sh
+               man \(mit ed
+               man 2 fork
+.DE
+In the first the manual section for \fIsh\fP
+is displayed..
+Since no section is specified, section 1 is used.
+The second example will typeset (\fB\(mit\fP option)
+the manual section for \fIed.\fP
+The last prints the \fIfork\fP manual page
+from section 2, which covers system calls.
+.sp 2
+.DS
+       #!/bin/sh
+
+       cd /usr/share/man
+
+       # "#" is the comment character
+       # default is nroff ($N), section 1 ($s)
+       N=n\ s=1
+
+       for i
+       do case $i in
+.sp .5
+       \*(DC[1\(mi9]\*(ST)     s=$i ;;
+.sp .5
+       \*(DC\(mit)     N=t ;;
+.sp .5
+       \*(DC\(min)     N=n ;;
+.sp .5
+       \*(DC\(mi\*(ST) echo unknown flag \\'$i\\' ;;
+.sp .5
+       \*(DC\*(ST)     if [ \(mif man$s/$i.$s ]
+       \*(DC   then
+       \*(DC           ${N}roff \(miman man$s/$i.$s
+       \*(DC   else    # look through all manual sections
+       \*(DC           found=no
+       \*(DC           for j in 1 2 3 4 5 6 7 8 9
+       \*(DC           do
+       \*(DC           \*(DOif [ \(mif man$j/$i.$j ]
+       \*(DC           \*(DOthen
+       \*(DC           \*(DO\*(THman $j $i
+       \*(DC           \*(DO\*(THfound=yes
+       \*(DC           \*(DO\*(THbreak
+       \*(DC           \*(DOfi
+       \*(DC           done
+       \*(DC           case $found in
+       \*(DC           \*(Cano) echo \\'$i: manual page not found\\'
+       \*(DC           esac
+       \*(DC   fi
+       \*(DOesac
+       done
+.DE
+.ce
+.ft B
+Figure 1. A version of the man command
+.ft R
diff --git a/bin/sh/USD.doc/t3 b/bin/sh/USD.doc/t3
new file mode 100644 (file)
index 0000000..aab53ee
--- /dev/null
@@ -0,0 +1,976 @@
+.\"    $NetBSD: t3,v 1.3 2010/08/22 02:19:07 perry Exp $
+.\"
+.\" Copyright (C) Caldera International Inc. 2001-2002.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" Redistributions of source code and documentation must retain the above
+.\" copyright notice, this list of conditions and the following
+.\" disclaimer.
+.\"
+.\" Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\"
+.\" This product includes software developed or owned by Caldera
+.\" International, Inc.  Neither the name of Caldera International, Inc.
+.\" nor the names of other contributors may be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC.  AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"    @(#)t3  8.1 (Berkeley) 6/8/93
+.\"
+.SH
+3.0\ Keyword\ parameters
+.LP
+Shell variables may be given values
+by assignment
+or when a shell script is invoked.
+An argument to a command of the form
+\fIname=value\fP
+that precedes the command name
+causes \fIvalue\fP
+to be assigned to \fIname\fP
+before execution of the command begins.
+The value of \fIname\fP in the invoking
+shell is not affected.
+For example,
+.DS
+       user=fred\ command
+.DE
+will execute \fIcommand\fP with
+\fBuser\fP set to \fIfred\fP.
+.\" Removed by Perry Metzger because -k is not in POSIX
+.\"
+.\" The \fB\(mik\fR flag causes arguments of the form
+.\" \fIname=value\fP to be interpreted in this way
+.\" anywhere in the argument list.
+.\" Such \fInames\fP are sometimes
+.\" called keyword parameters.
+.\" If any arguments remain they
+.\" are available as positional
+.\" parameters \fB$1, $2, \*(ZZ\|.\fP
+.LP
+The \fIset\fP command
+may also be used to set positional parameters
+from within a script.
+For example,
+.DS
+       set\ \(mi\(mi\ \*(ST
+.DE
+will set \fB$1\fP to the first file name
+in the current directory, \fB$2\fP to the next,
+and so on.
+Note that the first argument, \(mi\(mi, ensures correct treatment
+when the first file name begins with a \(mi\|.
+.LP
+.SH
+3.1\ Parameter\ transmission
+.LP
+When a command is executed both positional parameters
+and shell variables may be set on invocation.
+Variables are also made available implicitly
+to a command
+by specifying in advance that such parameters
+are to be exported from the invoking shell.
+For example,
+.DS
+       export\ user\ box=red
+.DE
+marks the variables \fBuser\fP and \fBbox\fP
+for export (setting \fBbox\fP to ``red'' in the process).
+When a command is invoked
+copies are made of all exportable variables
+(also known as \fIenvironment variables\fP)
+for use within the invoked program.
+Modification of such variables
+within an invoked command does not
+affect the values in the invoking shell.
+It is generally true of
+a shell script or other program
+that it
+cannot modify the state
+of its caller without explicit
+actions on the part of the caller.
+.\" Removed by Perry Metzger because this is confusing to beginners.
+.\"
+.\" (Shared file descriptors are an
+.\" exception to this rule.)
+.LP
+Names whose value is intended to remain
+constant may be declared \fIreadonly\|.\fP
+The form of this command is the same as that of the \fIexport\fP
+command,
+.DS
+       readonly name[=value] \*(ZZ
+.DE
+Subsequent attempts to set readonly variables
+are illegal.
+.SH
+3.2\ Parameter\ substitution
+.LP
+If a shell parameter is not set
+then the null string is substituted for it.
+For example, if the variable \fBd\fP
+is not set
+.DS
+       echo $d
+.DE
+or
+.DS
+       echo ${d}
+.DE
+will echo nothing.
+A default string may be given
+as in
+.DS
+       echo ${d:\(mi\fB.\fR}
+.DE
+which will echo
+the value of the variable \fBd\fP
+if it is set and not null and `\fB.\fP' otherwise.
+The default string is evaluated using the usual
+quoting conventions so that
+.DS
+       echo ${d:\(mi\'\*(ST\'}
+.DE
+will echo \fB\*(ST\fP if the variable \fBd\fP
+is not set or null.
+Similarly
+.DS
+       echo ${d:\(mi$1}
+.DE
+will echo the value of \fBd\fP if it is set and not null
+and the value (if any) of \fB$1\fP otherwise.
+.LP
+The notation ${d:+\fB.\fR} performs the inverse operation. It
+substitutes `\fB.\fP' if \fBd\fP is set or not null, and otherwise
+substitutes null.
+.LP
+A variable may be assigned a default value
+using
+the notation
+.DS
+       echo ${d:=\fB.\fR}
+.DE
+which substitutes the same string as
+.DS
+       echo ${d:\(mi\fB.\fR}
+.DE
+and if \fBd\fP were not previously set or null
+then it will be set to the string `\fB.\fP'\|.
+.LP
+If there is no sensible default then
+the notation
+.DS
+       echo ${d:?\fImessage\fP}
+.DE
+will echo the value of the variable \fBd\fP if it is set and not null,
+otherwise \fImessage\fP is printed by the shell and
+execution of the shell script is abandoned.
+If \fImessage\fP is absent then a standard message
+is printed.
+A shell script that requires some variables
+to be set might start as follows:
+.DS
+       :\ ${user:?}\ ${acct:?}\ ${bin:?}
+       \*(ZZ
+.DE
+Colon (\fB:\fP) is a command
+that is
+built in to the shell and does nothing
+once its arguments have been evaluated.
+If any of the variables \fBuser, acct\fP
+or \fBbin\fP are not set then the shell
+will abandon execution of the script.
+.SH
+3.3\ Command\ substitution
+.LP
+The standard output from a command can be
+substituted in a similar way to parameters.
+The command \fIpwd\fP prints on its standard
+output the name of the current directory.
+For example, if the current directory is
+\fB/usr/fred/bin\fR
+then the commands
+.DS
+       d=$(pwd)
+.DE
+(or the older notation d=\`pwd\`)
+is equivalent to
+.DS
+       d=/usr/fred/bin
+.DE
+.LP
+The entire string inside $(\*(ZZ)\| (or between grave accents \`\*(ZZ\`)
+is taken as the command
+to be executed
+and is replaced with the output from
+the command.
+(The difference between the $(\*(ZZ) and \`\*(ZZ\` notations is that
+the former may be nested, while the latter cannot be.)
+.LP
+The command is written using the usual quoting conventions,
+except that inside \`\*(ZZ\`
+a \fB\`\fR must be escaped using
+a \fB\\\|\fR.
+For example,
+.DS
+       ls $(echo "$HOME")
+.DE
+is equivalent to
+.DS
+       ls $HOME
+.DE
+Command substitution occurs in all contexts
+where parameter substitution occurs (including \fIhere\fP documents) and the
+treatment of the resulting text is the same
+in both cases.
+This mechanism allows string
+processing commands to be used within
+shell scripts.
+An example of such a command is \fIbasename\fP
+which removes a specified suffix from a string.
+For example,
+.DS
+       basename main\fB.\fPc \fB.\fPc
+.DE
+will print the string \fImain\|.\fP
+Its use is illustrated by the following
+fragment from a \fIcc\fP command.
+.DS
+       case $A in
+       \*(Ca\*(ZZ
+       \*(Ca\*(ST\fB.\fPc)     B=$(basename $A \fB.\fPc)
+       \*(Ca\*(ZZ
+       esac
+.DE
+that sets \fBB\fP to the part of \fB$A\fP
+with the suffix \fB.c\fP stripped.
+.LP
+Here are some composite examples.
+.RS
+.IP \(bu
+.ft B
+for i in \`ls \(mit\`; do \*(ZZ
+.ft R
+.br
+The variable \fBi\fP is set
+to the names of files in time order,
+most recent first.
+.IP \(bu
+.ft B
+set \(mi\(mi\| \`date\`; echo $6 $2 $3, $4
+.ft R
+.br
+will print, e.g.,
+.ft I
+1977 Nov 1, 23:59:59
+.ft R
+.RE
+.SH
+3.4\ Arithmetic\ Expansion
+.LP
+Within a $((\*(ZZ)) construct, integer arithmetic operations are
+evaluated.
+(The $ in front of variable names is optional within $((\*(ZZ)).
+For example:
+.DS
+       x=5; y=1
+       echo $(($x+3*2))
+       echo $((y+=x))
+       echo $y
+.DE
+will print `11', then `6', then `6' again.
+Most of the constructs permitted in C arithmetic operations are
+permitted though some (like `++') are not universally supported \(em
+see the shell manual page for details.
+.SH
+3.5\ Evaluation\ and\ quoting
+.LP
+The shell is a macro processor that
+provides parameter substitution, command substitution and file
+name generation for the arguments to commands.
+This section discusses the order in which
+these evaluations occur and the
+effects of the various quoting mechanisms.
+.LP
+Commands are parsed initially according to the grammar
+given in appendix A.
+Before a command is executed
+the following
+substitutions occur.
+.RS
+.IP \(bu
+parameter substitution, e.g. \fB$user\fP
+.IP \(bu
+command substitution, e.g. \fB$(pwd)\fP or \fB\`pwd\`\fP
+.IP \(bu
+arithmetic expansion, e.g. \fB$(($count+1))\fP
+.RS
+.LP
+Only one evaluation occurs so that if, for example, the value of the variable
+\fBX\fP
+is the string \fI$y\fP
+then
+.DS
+       echo $X
+.DE
+will echo \fI$y\|.\fP
+.RE
+.IP \(bu
+blank interpretation
+.RS
+.LP
+Following the above substitutions
+the resulting characters
+are broken into non-blank words (\fIblank interpretation\fP).
+For this purpose `blanks' are the characters of the string
+\fB$\s-1IFS\s0\fP.
+By default, this string consists of blank, tab and newline.
+The null string
+is not regarded as a word unless it is quoted.
+For example,
+.DS
+       echo \'\'
+.DE
+will pass on the null string as the first argument to \fIecho\fP,
+whereas
+.DS
+       echo $null
+.DE
+will call \fIecho\fR with no arguments
+if the variable \fBnull\fP is not set
+or set to the null string.
+.RE
+.IP \(bu
+file name generation
+.RS
+.LP
+Each word
+is then scanned for the file pattern characters
+\fB\*(ST, ?\fR and \fB[\*(ZZ]\fR
+and an alphabetical list of file names
+is generated to replace the word.
+Each such file name is a separate argument.
+.RE
+.RE
+.LP
+The evaluations just described also occur
+in the list of words associated with a \fBfor\fP
+loop.
+Only substitution occurs
+in the \fIword\fP used
+for a \fBcase\fP branch.
+.LP
+As well as the quoting mechanisms described
+earlier using \fB\\\fR and \fB\'\*(ZZ\'\fR
+a third quoting mechanism is provided using double quotes.
+Within double quotes parameter and command substitution
+occurs but file name generation and the interpretation
+of blanks does not.
+The following characters
+have a special meaning within double quotes
+and may be quoted using \fB\\\|.\fP
+.DS
+       \fB$    \fPparameter substitution
+       \fB$()\fP       command substitution
+       \fB\`\fP        command substitution
+       \fB"\fP ends the quoted string
+       \fB\e\fP        quotes the special characters \fB$ \` " \e\fP
+.DE
+For example,
+.DS
+       echo "$x"
+.DE
+will pass the value of the variable \fBx\fP as a
+single argument to \fIecho.\fP
+Similarly,
+.DS
+       echo "$\*(ST"
+.DE
+will pass the positional parameters as a single
+argument and is equivalent to
+.DS
+       echo "$1 $2 \*(ZZ"
+.DE
+The notation \fB$@\fP
+is the same as \fB$\*(ST\fR
+except when it is quoted.
+.DS
+       echo "$@"
+.DE
+will pass the positional parameters, unevaluated, to \fIecho\fR
+and is equivalent to
+.DS
+       echo "$1" "$2" \*(ZZ
+.DE
+.LP
+The following table gives, for each quoting mechanism,
+the shell metacharacters that are evaluated.
+.DS
+.ce
+.ft I
+metacharacter
+.ft
+.in 1.5i
+       \e      $       *       \`      "       \'
+\'     n       n       n       n       n       t
+\`     y       n       n       t       n       n
+"      y       y       n       y       t       n
+
+       t       terminator
+       y       interpreted
+       n       not interpreted
+
+.in
+.ft B
+.ce
+Figure 2. Quoting mechanisms
+.ft
+.DE
+.LP
+In cases where more than one evaluation of a string
+is required the built-in command \fIeval\fP
+may be used.
+For example,
+if the variable \fBX\fP has the value
+\fI$y\fP, and if \fBy\fP has the value \fIpqr\fP
+then
+.DS
+       eval echo $X
+.DE
+will echo the string \fIpqr\|.\fP
+.LP
+In general the \fIeval\fP command
+evaluates its arguments (as do all commands)
+and treats the result as input to the shell.
+The input is read and the resulting command(s)
+executed.
+For example,
+.DS
+       wg=\'eval who\*(VTgrep\'
+       $wg fred
+.DE
+is equivalent to
+.DS
+       who\*(VTgrep fred
+.DE
+In this example,
+\fIeval\fP is required
+since there is no interpretation
+of metacharacters, such as \fB\*(VT\|\fR, following
+substitution.
+.SH
+3.6\ Error\ handling
+.LP
+The treatment of errors detected by
+the shell depends on the type of error
+and on whether the shell is being
+used interactively.
+An interactive shell is one whose
+input and output are connected
+to a terminal.
+.\" Removed by Perry Metzger, obsolete and excess detail
+.\"
+.\" (as determined by
+.\" \fIgtty\fP (2)).
+A shell invoked with the \fB\(mii\fP
+flag is also interactive.
+.LP
+Execution of a command (see also 3.7) may fail
+for any of the following reasons.
+.IP \(bu
+Input output redirection may fail.
+For example, if a file does not exist
+or cannot be created.
+.IP \(bu
+The command itself does not exist
+or cannot be executed.
+.IP \(bu
+The command terminates abnormally,
+for example, with a "bus error"
+or "memory fault".
+See Figure 2 below for a complete list
+of UNIX signals.
+.IP \(bu
+The command terminates normally
+but returns a non-zero exit status.
+.LP
+In all of these cases the shell
+will go on to execute the next command.
+Except for the last case an error
+message will be printed by the shell.
+All remaining errors cause the shell
+to exit from a script.
+An interactive shell will return
+to read another command from the terminal.
+Such errors include the following.
+.IP \(bu
+Syntax errors.
+e.g., if \*(ZZ then \*(ZZ done
+.IP \(bu
+A signal such as interrupt.
+The shell waits for the current
+command, if any, to finish execution and
+then either exits or returns to the terminal.
+.IP \(bu
+Failure of any of the built-in commands
+such as \fIcd.\fP
+.LP
+The shell flag \fB\(mie\fP
+causes the shell to terminate
+if any error is detected.
+.DS
+1      hangup
+2      interrupt
+3*     quit
+4*     illegal instruction
+5*     trace trap
+6*     IOT instruction
+7*     EMT instruction
+8*     floating point exception
+9      kill (cannot be caught or ignored)
+10*    bus error
+11*    segmentation violation
+12*    bad argument to system call
+13     write on a pipe with no one to read it
+14     alarm clock
+15     software termination (from \fIkill\fP (1))
+
+.DE
+.ft B
+.ce
+Figure 3. UNIX signals\(dg
+.ft
+.FS
+\(dg Additional signals have been added in modern Unix.
+See \fIsigvec\fP(2) or \fIsignal\fP(3) for an up-to-date list.
+.FE
+Those signals marked with an asterisk
+produce a core dump
+if not caught.
+However,
+the shell itself ignores quit which is the only
+external signal that can cause a dump.
+The signals in this list of potential interest
+to shell programs are 1, 2, 3, 14 and 15.
+.SH
+3.7\ Fault\ handling
+.LP
+shell scripts normally terminate
+when an interrupt is received from the
+terminal.
+The \fItrap\fP command is used
+if some cleaning up is required, such
+as removing temporary files.
+For example,
+.DS
+       trap\ \'rm\ /tmp/ps$$; exit\'\ 2
+.DE
+sets a trap for signal 2 (terminal
+interrupt), and if this signal is received
+will execute the commands
+.DS
+       rm /tmp/ps$$; exit
+.DE
+\fIexit\fP is
+another built-in command
+that terminates execution of a shell script.
+The \fIexit\fP is required; otherwise,
+after the trap has been taken,
+the shell will resume executing
+the script
+at the place where it was interrupted.
+.LP
+UNIX signals can be handled in one of three ways.
+They can be ignored, in which case
+the signal is never sent to the process.
+They can be caught, in which case the process
+must decide what action to take when the
+signal is received.
+Lastly, they can be left to cause
+termination of the process without
+it having to take any further action.
+If a signal is being ignored
+on entry to the shell script, for example,
+by invoking it in the background (see 3.7) then \fItrap\fP
+commands (and the signal) are ignored.
+.LP
+The use of \fItrap\fP is illustrated
+by this modified version of the \fItouch\fP
+command (Figure 4).
+The cleanup action is to remove the file \fBjunk$$\fR\|.
+.DS
+       #!/bin/sh
+
+       flag=
+       trap\ \'rm\ \(mif\ junk$$;\ exit\'\ 1 2 3 15
+       for i
+       do\ case\ $i\ in
+       \*(DC\(mic)     flag=N ;;
+       \*(DC\*(ST)     if\ test\ \(mif\ $i
+       \*(DC   then    cp\ $i\ junk$$;\ mv\ junk$$ $i
+       \*(DC   elif\ test\ $flag
+       \*(DC   then    echo\ file\ \\'$i\\'\ does\ not\ exist
+       \*(DC   else    >$i
+       \*(DC   fi
+       \*(DOesac
+       done
+.DE
+.sp
+.ft B
+.ce
+Figure 4. The touch command
+.ft
+.sp
+The \fItrap\fP command
+appears before the creation
+of the temporary file;
+otherwise it would be
+possible for the process
+to die without removing
+the file.
+.LP
+Since there is no signal 0 in UNIX
+it is used by the shell to indicate the
+commands to be executed on exit from the
+shell script.
+.LP
+A script may, itself, elect to
+ignore signals by specifying the null
+string as the argument to trap.
+The following fragment is taken from the
+\fInohup\fP command.
+.DS
+       trap \'\' 1 2 3 15
+.DE
+which causes \fIhangup, interrupt, quit \fRand\fI kill\fR
+to be ignored both by the
+script and by invoked commands.
+.LP
+Traps may be reset by saying
+.DS
+       trap 2 3
+.DE
+which resets the traps for signals 2 and 3 to their default values.
+A list of the current values of traps may be obtained
+by writing
+.DS
+       trap
+.DE
+.LP
+The script \fIscan\fP (Figure 5) is an example
+of the use of \fItrap\fP where there is no exit
+in the trap command.
+\fIscan\fP takes each directory
+in the current directory, prompts
+with its name, and then executes
+commands typed at the terminal
+until an end of file or an interrupt is received.
+Interrupts are ignored while executing
+the requested commands but cause
+termination when \fIscan\fP is
+waiting for input.
+.DS
+       d=\`pwd\`
+       for\ i\ in\ \*(ST
+       do\ if\ test\ \(mid\ $d/$i
+       \*(DOthen\ cd\ $d/$i
+       \*(DO\*(THwhile\ echo\ "$i:"
+       \*(DO\*(TH\*(WHtrap\ exit\ 2
+       \*(DO\*(TH\*(WHread\ x
+       \*(DO\*(THdo\ trap\ :\ 2;\ eval\ $x;\ done
+       \*(DOfi
+       done
+.DE
+.sp
+.ft B
+.ce
+Figure 5. The scan command
+.ft
+.sp
+\fIread x\fR is a built-in command that reads one line from the
+standard input
+and places the result in the variable \fBx\|.\fP
+It returns a non-zero exit status if either
+an end-of-file is read or an interrupt
+is received.
+.SH
+3.8\ Command\ execution
+.LP
+To run a command (other than a built-in) the shell first creates
+a new process using the system call \fIfork.\fP
+The execution environment for the command
+includes input, output and the states of signals, and
+is established in the child process
+before the command is executed.
+The built-in command \fIexec\fP
+is used in the rare cases when no fork
+is required
+and simply replaces the shell with a new command.
+For example, a simple version of the \fInohup\fP
+command looks like
+.DS
+       trap \\'\\' 1 2 3 15
+       exec $\*(ST
+.DE
+The \fItrap\fP turns off the signals specified
+so that they are ignored by subsequently created commands
+and \fIexec\fP replaces the shell by the command
+specified.
+.LP
+Most forms of input output redirection have already been
+described.
+In the following \fIword\fP is only subject
+to parameter and command substitution.
+No file name generation or blank interpretation
+takes place so that, for example,
+.DS
+               echo \*(ZZ >\*(ST.c
+.DE
+will write its output into a file whose name is \fB\*(ST.c\|.\fP
+Input output specifications are evaluated left to right
+as they appear in the command.
+.IP >\ \fIword\fP 12
+The standard output (file descriptor 1)
+is sent to the file \fIword\fP which is
+created if it does not already exist.
+.IP \*(AP\ \fIword\fP 12
+The standard output is sent to file \fIword.\fP
+If the file exists then output is appended
+(by seeking to the end);
+otherwise the file is created.
+.IP <\ \fIword\fP 12
+The standard input (file descriptor 0)
+is taken from the file \fIword.\fP
+.IP \*(HE\ \fIword\fP 12
+The standard input is taken from the lines
+of shell input that follow up to but not
+including a line consisting only of \fIword.\fP
+If \fIword\fP is quoted then no interpretation
+of the document occurs.
+If \fIword\fP is not quoted
+then parameter and command substitution
+occur and \fB\\\fP is used to quote
+the characters \fB\\\fP \fB$\fP \fB\`\fP and the first character
+of \fIword.\fP
+In the latter case \fB\\newline\fP is ignored (c.f. quoted strings).
+.IP >&\ \fIdigit\fP 12
+The file descriptor \fIdigit\fP is duplicated using the system
+call \fIdup\fP (2)
+and the result is used as the standard output.
+.IP <&\ \fIdigit\fP 12
+The standard input is duplicated from file descriptor \fIdigit.\fP
+.IP <&\(mi 12
+The standard input is closed.
+.IP >&\(mi 12
+The standard output is closed.
+.LP
+Any of the above may be preceded by a digit in which
+case the file descriptor created is that specified by the digit
+instead of the default 0 or 1.
+For example,
+.DS
+       \*(ZZ 2>file
+.DE
+runs a command with message output (file descriptor 2)
+directed to \fIfile.\fP
+.DS
+       \*(ZZ 2>&1
+.DE
+runs a command with its standard output and message output
+merged.
+(Strictly speaking file descriptor 2 is created
+by duplicating file descriptor 1 but the effect is usually to
+merge the two streams.)
+.\" Removed by Perry Metzger, most of this is now obsolete
+.\"
+.\" .LP
+.\" The environment for a command run in the background such as
+.\" .DS
+.\"    list \*(ST.c \*(VT lpr &
+.\" .DE
+.\" is modified in two ways.
+.\" Firstly, the default standard input
+.\" for such a command is the empty file \fB/dev/null\|.\fR
+.\" This prevents two processes (the shell and the command),
+.\" which are running in parallel, from trying to
+.\" read the same input.
+.\" Chaos would ensue
+.\" if this were not the case.
+.\" For example,
+.\" .DS
+.\"    ed file &
+.\" .DE
+.\" would allow both the editor and the shell
+.\" to read from the same input at the same time.
+.\" .LP
+.\" The other modification to the environment of a background
+.\" command is to turn off the QUIT and INTERRUPT signals
+.\" so that they are ignored by the command.
+.\" This allows these signals to be used
+.\" at the terminal without causing background
+.\" commands to terminate.
+.\" For this reason the UNIX convention
+.\" for a signal is that if it is set to 1
+.\" (ignored) then it is never changed
+.\" even for a short time.
+.\" Note that the shell command \fItrap\fP
+.\" has no effect for an ignored signal.
+.SH
+3.9\ Invoking\ the\ shell
+.LP
+The following flags are interpreted by the shell
+when it is invoked.
+If the first character of argument zero is a minus,
+then commands are read from the file \fB.profile\|.\fP
+.IP \fB\(mic\fP\ \fIstring\fP
+.br
+If the \fB\(mic\fP flag is present then
+commands are read from \fIstring\|.\fP
+.IP \fB\(mis\fP
+If the \fB\(mis\fP flag is present or if no
+arguments remain
+then commands are read from the standard input.
+Shell output is written to
+file descriptor 2.
+.IP \fB\(mii\fP
+If the \fB\(mii\fP flag is present or
+if the shell input and output are attached to a terminal (as told by \fIgtty\fP)
+then this shell is \fIinteractive.\fP
+In this case TERMINATE is ignored (so that \fBkill 0\fP
+does not kill an interactive shell) and INTERRUPT is caught and ignored
+(so that \fBwait\fP is interruptable).
+In all cases QUIT is ignored by the shell.
+.SH
+3.10\ Job\ Control
+.LP
+When a command or pipeline (also known as a \fIjob\fP) is running in
+the foreground, entering the stop character (typically
+\s-1CONTROL-Z\s0 but user settable with the \fIstty\fP(1) command)
+will usually cause the job to stop.
+.LP
+The jobs associated with the current shell may be listed by entering
+the \fIjobs\fP command.
+Each job has an associated \fIjob number\fP.
+Jobs that are stopped may be continued by entering
+.DS
+       bg %\fIjobnumber\fP
+.DE
+and jobs may be moved to the foreground by entering
+.DS
+       fg %\fIjobnumber\fP
+.DE
+If there is a sole job with a particular name (say only one instance
+of \fIcc\fP running), \fIfg\fP and \fIbg\fP may also use name of the
+command in place of the number, as in:
+.DS
+       bg %cc
+.DE
+If no `\fB%\fP' clause is entered, most recently stopped job
+(indicated with a `+' by the \fIjobs\fP command) will be assumed.
+See the manual page for the shell for more details.
+.SH
+3.11\ Aliases
+.LP
+The \fIalias\fP command creates a so-called shell alias, which is an
+abbreviation that macro-expands at run time into some other command.
+For example:
+.DS
+       alias ls="ls -F"
+.DE
+would cause the command sequence \fBls -F\fP to be executed whenever
+the user types \fBls\fP into the shell.
+Note that if the user types \fBls -a\fP, the shell will in fact
+execute \fBls -F -a\fP.
+The command \fBalias\fP on its own prints out all current aliases.
+The \fIunalias\fP command, as in:
+.DS
+       unalias ls
+.DE
+will remove an existing alias.
+Aliases can shadow pre-existing commands, as in the example above.
+They are typically used to override the interactive behavior of
+commands in small ways, for example to always invoke some program with
+a favorite option, and are almost never found in scripts.
+.SH
+3.12\ Command\ Line\ Editing\ and\ Recall
+.LP
+When working interactively with the shell, it is often tedious to
+retype previously entered commands, especially if they are complicated.
+The shell therefore maintains a so-called \fIhistory\fP, which is
+stored in the file specified by the \fB\s-1HISTFILE\s0\fP environment
+variable if it is set.
+Users may view, edit, and re-enter previous lines of input using
+a small subset of the commands of the \fIvi\fP(1) or
+\fIemacs\fP(1)\(dg editors.
+.FS
+Technically, vi command editing is standardized by POSIX while emacs
+is not.
+However, all modern shells support both styles.
+.FE
+Emacs style editing may be selected by entering
+.DS
+       set -o emacs
+.DE
+and vi style editing may be selected with
+.DS
+       set -o vi
+.DE
+The details of how command line editing works are beyond the scope of
+this document.
+See the shell manual page for details.
+.SH
+Acknowledgements
+.LP
+The design of the shell is
+based in part on the original UNIX shell
+.[
+unix command language thompson
+.]
+and the PWB/UNIX shell,
+.[
+pwb shell mashey unix
+.]
+some
+features having been taken from both.
+Similarities also exist with the
+command interpreters
+of the Cambridge Multiple Access System
+.[
+cambridge multiple access system hartley
+.]
+and of CTSS.
+.[
+ctss
+.]
+.LP
+I would like to thank Dennis Ritchie
+and John Mashey for many
+discussions during the design of the shell.
+I am also grateful to the members of the Computing Science Research Center
+and to Joe Maranzano for their
+comments on drafts of this document.
+.SH
+.[
+$LIST$
+.]
diff --git a/bin/sh/USD.doc/t4 b/bin/sh/USD.doc/t4
new file mode 100644 (file)
index 0000000..7719d6c
--- /dev/null
@@ -0,0 +1,180 @@
+.\"    $NetBSD: t4,v 1.3 2010/08/22 02:19:07 perry Exp $
+.\"
+.\" Copyright (C) Caldera International Inc. 2001-2002.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are
+.\" met:
+.\"
+.\" Redistributions of source code and documentation must retain the above
+.\" copyright notice, this list of conditions and the following
+.\" disclaimer.
+.\"
+.\" Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\"
+.\" This product includes software developed or owned by Caldera
+.\" International, Inc.  Neither the name of Caldera International, Inc.
+.\" nor the names of other contributors may be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC.  AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED.  IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\"    @(#)t4  8.1 (Berkeley) 8/14/93
+.\"
+.bp
+.SH
+Appendix\ A\ -\ Grammar
+.LP
+Note: This grammar needs updating, it is obsolete.
+.LP
+.LD
+\fIitem:               word
+               input-output
+               name = value
+.sp 0.7
+simple-command: item
+               simple-command item
+.sp 0.7
+command:       simple-command
+               \fB( \fIcommand-list \fB)
+               \fB{ \fIcommand-list \fB}
+               \fBfor \fIname \fBdo \fIcommand-list \fBdone
+               \fBfor \fIname \fBin \fIword \*(ZZ \fBdo \fIcommand-list \fBdone
+               \fBwhile \fIcommand-list \fBdo \fIcommand-list \fBdone
+               \fBuntil \fIcommand-list \fBdo \fIcommand-list \fBdone
+               \fBcase \fIword \fBin \fIcase-part \*(ZZ \fBesac
+               \fBif \fIcommand-list \fBthen \fIcommand-list \fIelse-part \fBfi
+.sp 0.7
+\fIpipeline:   command
+               pipeline \fB\*(VT\fI command
+.sp 0.7
+andor: pipeline
+               andor \fB&&\fI pipeline
+               andor \fB\*(VT\*(VT\fI pipeline
+.sp 0.7
+command-list:  andor
+               command-list \fB;\fI
+               command-list \fB&\fI
+               command-list \fB;\fI andor
+               command-list \fB&\fI andor
+.sp 0.7
+input-output:  \fB> \fIfile
+               \fB< \fIfile
+               \fB\*(AP \fIword
+               \fB\*(HE \fIword
+.sp 0.7
+file:          word
+               \fB&\fI digit
+               \fB&\fI \(mi
+.sp 0.7
+case-part:     pattern\fB ) \fIcommand-list\fB ;;
+.sp 0.7
+\fIpattern:    word
+               pattern \fB\*(VT\fI word
+.sp 0.7
+\fIelse-part:  \fBelif \fIcommand-list\fB then\fI command-list else-part\fP
+               \fBelse \fIcommand-list\fI
+               empty
+.sp 0.7
+empty:
+.sp 0.7
+word:          \fRa sequence of non-blank characters\fI
+.sp 0.7
+name:          \fRa sequence of letters, digits or underscores starting with a letter\fI
+.sp 0.7
+digit:         \fB0 1 2 3 4 5 6 7 8 9\fP
+.DE
+.LP
+.bp
+.SH
+Appendix\ B\ -\ Meta-characters\ and\ Reserved\ Words
+.LP
+a) syntactic
+.RS
+.IP \fB\*(VT\fR 6
+pipe symbol
+.IP \fB&&\fR 6
+`andf' symbol
+.IP \fB\*(VT\*(VT\fR 6
+`orf' symbol
+.IP \fB;\fP 8
+command separator
+.IP \fB;;\fP 8
+case delimiter
+.IP \fB&\fP 8
+background commands
+.IP \fB(\ )\fP 8
+command grouping
+.IP \fB<\fP 8
+input redirection
+.IP \fB\*(HE\fP 8
+input from a here document
+.IP \fB>\fP 8
+output creation
+.IP \fB\*(AP\fP 8
+output append
+.sp 2
+.RE
+.LP
+b) patterns
+.RS
+.IP \fB\*(ST\fP 8
+match any character(s) including none
+.IP \fB?\fP 8
+match any single character
+.IP \fB[...]\fP 8
+match any of the enclosed characters
+.sp 2
+.RE
+.LP
+c) substitution
+.RS
+.IP \fB${...}\fP 8
+substitute shell variable
+.IP \fB$(...)\fP 8
+substitute command output
+.IP \fB\`...\`\fP 8
+substitute command output
+.IP \fB$((...))\fP 8
+substitute arithmetic expression
+.sp 2
+.RE
+.LP
+d) quoting
+.RS
+.IP \fB\e\fP 8
+quote the next character
+.IP \fB\'...\'\fP 8
+quote the enclosed characters except for \'
+.IP \fB"\&..."\fP 8
+quote the enclosed characters except
+for \fB$ \` \e "\fP
+.sp 2
+.RE
+.LP
+e) reserved words
+.DS
+.ft B
+if then else elif fi
+case in esac
+for while until do done
+! {  }
+.ft
+.DE
similarity index 86%
rename from minix/commands/ash/alias.c
rename to bin/sh/alias.c
index e584ebcf3ab1e4b76698837e75d6b27c1e14404f..8b638c6ff2fae156bd4858f9cbc6e7493f17385d 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: alias.c,v 1.14 2011/06/18 21:18:46 christos Exp $      */
+
 /*-
  * Copyright (c) 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)alias.c    8.3 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: alias.c,v 1.14 2011/06/18 21:18:46 christos Exp $");
 #endif
 #endif /* not lint */
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/alias.c,v 1.18 2004/04/06 20:06:51 markm Exp $");
-*/
 
 #include <stdlib.h>
 #include "shell.h"
@@ -49,18 +50,20 @@ __FBSDID("$FreeBSD: src/bin/sh/alias.c,v 1.18 2004/04/06 20:06:51 markm Exp $");
 #include "mystring.h"
 #include "alias.h"
 #include "options.h"   /* XXX for argptr (should remove?) */
+#include "builtins.h"
+#include "var.h"
 
 #define ATABSIZE 39
 
-STATIC struct alias *atab[ATABSIZE];
+struct alias *atab[ATABSIZE];
 
-STATIC void setalias(const char *, const char *);
-STATIC int unalias(const char *);
-STATIC struct alias **hashalias(const char *);
+STATIC void setalias(char *, char *);
+STATIC int unalias(char *);
+STATIC struct alias **hashalias(char *);
 
 STATIC
 void
-setalias(const char *name, const char *val)
+setalias(char *name, char *val)
 {
        struct alias *ap, **app;
 
@@ -78,6 +81,7 @@ setalias(const char *name, const char *val)
        INTOFF;
        ap = ckmalloc(sizeof (struct alias));
        ap->name = savestr(name);
+       ap->flag = 0;
        /*
         * XXX - HACK: in order that the parser will not finish reading the
         * alias value off the input before processing the next alias, we
@@ -87,7 +91,7 @@ setalias(const char *name, const char *val)
         * expanding an alias, the value of the alias is pushed back on the
         * input as a string and a pointer to the alias is stored with the
         * string.  The alias is marked as being in use.  When the input
-        * routine finishes reading the string, it marks the alias not
+        * routine finishes reading the string, it markes the alias not
         * in use.  The problem is synchronization with the parser.  Since
         * it reads ahead, the alias is marked not in use before the
         * resulting token(s) is next checked for further alias sub.  The
@@ -106,14 +110,13 @@ setalias(const char *name, const char *val)
        ap->val[len+1] = '\0';
        }
 #endif
-       ap->flag = 0;
        ap->next = *app;
        *app = ap;
        INTON;
 }
 
 STATIC int
-unalias(const char *name)
+unalias(char *name)
 {
        struct alias *ap, **app;
 
@@ -146,7 +149,8 @@ unalias(const char *name)
 }
 
 #ifdef mkinit
-INCLUDE "alias.h"
+MKINIT void rmaliases(void);
+
 SHELLPROC {
        rmaliases();
 }
@@ -174,7 +178,7 @@ rmaliases(void)
 }
 
 struct alias *
-lookupalias(const char *name, int check)
+lookupalias(char *name, int check)
 {
        struct alias *ap = *hashalias(name);
 
@@ -189,6 +193,17 @@ lookupalias(const char *name, int check)
        return (NULL);
 }
 
+char *
+get_alias_text(char *name)
+{
+       struct alias *ap;
+
+       ap = lookupalias(name, 0);
+       if (ap == NULL)
+               return NULL;
+       return ap->val;
+}
+
 /*
  * TODO - sort output
  */
@@ -206,23 +221,23 @@ aliascmd(int argc, char **argv)
                        for (ap = atab[i]; ap; ap = ap->next) {
                                if (*ap->name != '\0') {
                                        out1fmt("alias %s=", ap->name);
-                                       out1qstr(ap->val);
+                                       print_quoted(ap->val);
                                        out1c('\n');
                                }
                        }
                return (0);
        }
        while ((n = *++argv) != NULL) {
-               if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
+               if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
                        if ((ap = lookupalias(n, 0)) == NULL) {
                                outfmt(out2, "alias: %s not found\n", n);
                                ret = 1;
                        } else {
                                out1fmt("alias %s=", n);
-                               out1qstr(ap->val);
+                               print_quoted(ap->val);
                                out1c('\n');
                        }
-               else {
+               else {
                        *v++ = '\0';
                        setalias(n, v);
                }
@@ -232,7 +247,7 @@ aliascmd(int argc, char **argv)
 }
 
 int
-unaliascmd(int argc __unused, char **argv __unused)
+unaliascmd(int argc, char **argv)
 {
        int i;
 
@@ -249,7 +264,7 @@ unaliascmd(int argc __unused, char **argv __unused)
 }
 
 STATIC struct alias **
-hashalias(const char *p)
+hashalias(char *p)
 {
        unsigned int hashval;
 
@@ -258,7 +273,3 @@ hashalias(const char *p)
                hashval+= *p++;
        return &atab[hashval % ATABSIZE];
 }
-
-/*
- * $PchId: alias.c,v 1.5 2006/05/22 12:41:12 philip Exp $
- */
similarity index 85%
rename from minix/commands/ash/alias.h
rename to bin/sh/alias.h
index 5b4fb8faeae34ced5be0fd7e222efe5896b4c521..2f14dd713178640c9e764e07e1392c712085059e 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: alias.h,v 1.7 2011/06/18 21:18:46 christos Exp $       */
+
 /*-
  * Copyright (c) 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -30,7 +32,6 @@
  * SUCH DAMAGE.
  *
  *     @(#)alias.h     8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/alias.h,v 1.8 2004/04/06 20:06:51 markm Exp $
  */
 
 #define ALIASINUSE     1
@@ -42,11 +43,6 @@ struct alias {
        int flag;
 };
 
-struct alias *lookupalias(const char *, int);
-int aliascmd(int, char **);
-int unaliascmd(int, char **);
+struct alias *lookupalias(char *, int);
+char *get_alias_text(char *);
 void rmaliases(void);
-
-/*
- * $PchId: alias.h,v 1.4 2006/03/31 11:30:54 philip Exp $
- */
diff --git a/bin/sh/arith.y b/bin/sh/arith.y
new file mode 100644 (file)
index 0000000..4fbfa18
--- /dev/null
@@ -0,0 +1,206 @@
+%{
+/*     $NetBSD: arith.y,v 1.22 2012/03/20 18:42:29 matt Exp $  */
+
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)arith.y    8.3 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: arith.y,v 1.22 2012/03/20 18:42:29 matt Exp $");
+#endif
+#endif /* not lint */
+
+#include <stdlib.h>
+#include "expand.h"
+#include "builtins.h"
+#include "shell.h"
+#include "error.h"
+#include "output.h"
+#include "memalloc.h"
+
+typedef intmax_t YYSTYPE;
+#define YYSTYPE YYSTYPE
+
+intmax_t arith_result;
+const char *arith_buf, *arith_startbuf;
+
+__dead static void yyerror(const char *);
+#ifdef TESTARITH
+int main(int , char *[]);
+int error(char *);
+#endif
+
+%}
+%token ARITH_NUM ARITH_LPAREN ARITH_RPAREN
+
+%left ARITH_OR
+%left ARITH_AND
+%left ARITH_BOR
+%left ARITH_BXOR
+%left ARITH_BAND
+%left ARITH_EQ ARITH_NE
+%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
+%left ARITH_LSHIFT ARITH_RSHIFT
+%left ARITH_ADD ARITH_SUB
+%left ARITH_MUL ARITH_DIV ARITH_REM
+%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
+%%
+
+exp:   expr {
+                       /*
+                        * yyparse() returns int, so we have to save
+                        * the desired result elsewhere.
+                        */
+                       arith_result = $1;
+               }
+       ;
+
+
+expr:  ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; }
+       | expr ARITH_OR expr    { $$ = $1 ? $1 : $3 ? $3 : 0; }
+       | expr ARITH_AND expr   { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; }
+       | expr ARITH_BOR expr   { $$ = $1 | $3; }
+       | expr ARITH_BXOR expr  { $$ = $1 ^ $3; }
+       | expr ARITH_BAND expr  { $$ = $1 & $3; }
+       | expr ARITH_EQ expr    { $$ = $1 == $3; }
+       | expr ARITH_GT expr    { $$ = $1 > $3; }
+       | expr ARITH_GE expr    { $$ = $1 >= $3; }
+       | expr ARITH_LT expr    { $$ = $1 < $3; }
+       | expr ARITH_LE expr    { $$ = $1 <= $3; }
+       | expr ARITH_NE expr    { $$ = $1 != $3; }
+       | expr ARITH_LSHIFT expr { $$ = $1 << $3; }
+       | expr ARITH_RSHIFT expr { $$ = $1 >> $3; }
+       | expr ARITH_ADD expr   { $$ = $1 + $3; }
+       | expr ARITH_SUB expr   { $$ = $1 - $3; }
+       | expr ARITH_MUL expr   { $$ = $1 * $3; }
+       | expr ARITH_DIV expr   {
+                       if ($3 == 0)
+                               yyerror("division by zero");
+                       $$ = $1 / $3;
+                       }
+       | expr ARITH_REM expr   {
+                       if ($3 == 0)
+                               yyerror("division by zero");
+                       $$ = $1 % $3;
+                       }
+       | ARITH_NOT expr        { $$ = !($2); }
+       | ARITH_BNOT expr       { $$ = ~($2); }
+       | ARITH_SUB expr %prec ARITH_UNARYMINUS { $$ = -($2); }
+       | ARITH_ADD expr %prec ARITH_UNARYPLUS { $$ = $2; }
+       | ARITH_NUM
+       ;
+%%
+intmax_t
+arith(const char *s)
+{
+       intmax_t result;
+
+       arith_buf = arith_startbuf = s;
+
+       INTOFF;
+       (void) yyparse();
+       result = arith_result;
+       arith_lex_reset();      /* reprime lex */
+       INTON;
+
+       return (result);
+}
+
+
+/*
+ *  The exp(1) builtin.
+ */
+int
+expcmd(int argc, char **argv)
+{
+       const char *p;
+       char *concat;
+       char **ap;
+       intmax_t i;
+
+       if (argc > 1) {
+               p = argv[1];
+               if (argc > 2) {
+                       /*
+                        * concatenate arguments
+                        */
+                       STARTSTACKSTR(concat);
+                       ap = argv + 2;
+                       for (;;) {
+                               while (*p)
+                                       STPUTC(*p++, concat);
+                               if ((p = *ap++) == NULL)
+                                       break;
+                               STPUTC(' ', concat);
+                       }
+                       STPUTC('\0', concat);
+                       p = grabstackstr(concat);
+               }
+       } else
+               p = "";
+
+       (void)arith(p);
+       i = arith_result;
+
+       out1fmt("%"PRIdMAX"\n", i);
+       return (! i);
+}
+
+/*************************/
+#ifdef TEST_ARITH
+#include <stdio.h>
+main(argc, argv)
+       char *argv[];
+{
+       printf("%"PRIdMAX"\n", exp(argv[1]));
+}
+error(s)
+       char *s;
+{
+       fprintf(stderr, "exp: %s\n", s);
+       exit(1);
+}
+#endif
+
+static void
+yyerror(const char *s)
+{
+
+       yyerrok;
+       yyclearin;
+       arith_lex_reset();      /* reprime lex */
+       error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
+       /* NOTREACHED */
+}
similarity index 50%
rename from minix/commands/ash/arith_lex.l
rename to bin/sh/arith_lex.l
index 57d71e966f465b3a7d09f4fae967f83e300c0a57..6f7a933abf0c78938103654b6b76b2aacc6b398f 100644 (file)
@@ -1,4 +1,6 @@
 %{
+/*     $NetBSD: arith_lex.l,v 1.16 2012/03/20 18:42:29 matt Exp $      */
+
 /*-
  * Copyright (c) 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -14,7 +16,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
-#if 0
+#include <sys/cdefs.h>
 #ifndef lint
+#if 0
 static char sccsid[] = "@(#)arith_lex.l        8.3 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: arith_lex.l,v 1.16 2012/03/20 18:42:29 matt Exp $");
 #endif
 #endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/arith_lex.l,v 1.22 2004/04/06 20:06:51 markm Exp $");
-*/
 
-#include <string.h>
-
-#include "shell.h"
+#include <unistd.h>
 #include "arith.h"
 #include "error.h"
-#include "memalloc.h"
+#include "expand.h"
 #include "var.h"
 
-extern char *arith_buf, *arith_startbuf;
+extern intmax_t yylval;
+extern const char *arith_buf, *arith_startbuf;
 #undef YY_INPUT
 #define YY_INPUT(buf,result,max) \
        result = (*buf = *arith_buf++) ? 1 : YY_NULL;
-#define YY_NO_UNPUT
 %}
 
+%option nounput noinput
+
 %%
 [ \t\n]        { ; }
-
-0x[a-fA-F0-9]+ {
-                       yylval.l_value = strtoarith_t(yytext, NULL, 16);
-                       return ARITH_NUM;
-               }
-
-0[0-7]+                {
-                       yylval.l_value = strtoarith_t(yytext, NULL, 8);
-                       return ARITH_NUM;
-               }
-
-[0-9]+         {
-                       yylval.l_value = strtoarith_t(yytext, NULL, 10);
-                       return ARITH_NUM;
-               }
-
-[A-Za-z][A-Za-z0-9_]*  {
-                       /*
-                        * If variable doesn't exist, we should initialize
-                        * it to zero.
-                        */
-                       char *temp;
-                       if (lookupvar(yytext) == NULL)
-                               setvarsafe(yytext, "0", 0);
-                       temp = (char *)ckmalloc(strlen(yytext) + 1);
-                       yylval.s_value = strcpy(temp, yytext);
-
-                       return ARITH_VAR;
-               }
-
-"("            {       return ARITH_LPAREN;    }
-")"            {       return ARITH_RPAREN;    }
-"||"           {       return ARITH_OR;        }
-"&&"           {       return ARITH_AND;       }
-"|"            {       return ARITH_BOR;       }
-"^"            {       return ARITH_BXOR;      }
-"&"            {       return ARITH_BAND;      }
-"=="           {       return ARITH_EQ;        }
-"!="           {       return ARITH_NE;        }
-">"            {       return ARITH_GT;        }
-">="           {       return ARITH_GE;        }
-"<"            {       return ARITH_LT;        }
-"<="           {       return ARITH_LE;        }
-"<<"           {       return ARITH_LSHIFT;    }
-">>"           {       return ARITH_RSHIFT;    }
-"*"            {       return ARITH_MUL;       }
-"/"            {       return ARITH_DIV;       }
-"%"            {       return ARITH_REM;       }
-"+"            {       return ARITH_ADD;       }
-"-"            {       return ARITH_SUB;       }
-"~"            {       return ARITH_BNOT;      }
-"!"            {       return ARITH_NOT;       }
-"="            {       return ARITH_ASSIGN;    }
-"+="           {       return ARITH_ADDASSIGN; }
-"-="           {       return ARITH_SUBASSIGN; }
-"*="           {       return ARITH_MULASSIGN; }
-"/="           {       return ARITH_DIVASSIGN; }
-"%="           {       return ARITH_REMASSIGN; }
-">>="          {       return ARITH_RSHASSIGN; }
-"<<="          {       return ARITH_LSHASSIGN; }
-"&="           {       return ARITH_BANDASSIGN; }
-"^="           {       return ARITH_BXORASSIGN; }
-"|="           {       return ARITH_BORASSIGN; }
-.              {
-                       error("arith: syntax error: \"%s\"\n", arith_startbuf);
+0x[0-9a-fA-F]+ { yylval = strtoimax(yytext, 0, 0); return(ARITH_NUM); }
+0[0-7]*                { yylval = strtoimax(yytext, 0, 0); return(ARITH_NUM); }
+[1-9][0-9]*    { yylval = strtoimax(yytext, 0, 0); return(ARITH_NUM); }
+[A-Za-z_][A-Za-z_0-9]* { char *v = lookupvar(yytext);
+                       if (v) {
+                               yylval = strtoimax(v, &v, 0);
+                               if (*v == 0)
+                                       return ARITH_NUM;
+                       }
+                       error("arith: syntax error: \"%s\"", arith_startbuf);
                }
+"("    { return(ARITH_LPAREN); }
+")"    { return(ARITH_RPAREN); }
+"||"   { return(ARITH_OR); }
+"&&"   { return(ARITH_AND); }
+"|"    { return(ARITH_BOR); }
+"^"    { return(ARITH_BXOR); }
+"&"    { return(ARITH_BAND); }
+"=="   { return(ARITH_EQ); }
+"!="   { return(ARITH_NE); }
+">"    { return(ARITH_GT); }
+">="   { return(ARITH_GE); }
+"<"    { return(ARITH_LT); }
+"<="   { return(ARITH_LE); }
+"<<"   { return(ARITH_LSHIFT); }
+">>"   { return(ARITH_RSHIFT); }
+"*"    { return(ARITH_MUL); }
+"/"    { return(ARITH_DIV); }
+"%"    { return(ARITH_REM); }
+"+"    { return(ARITH_ADD); }
+"-"    { return(ARITH_SUB); }
+"~"    { return(ARITH_BNOT); }
+"!"    { return(ARITH_NOT); }
+.      { error("arith: syntax error: \"%s\"", arith_startbuf); }
 %%
 
 void
-arith_lex_reset(void)
-{
+arith_lex_reset(void) {
+#ifdef YY_NEW_FILE
        YY_NEW_FILE;
+#endif
 }
similarity index 60%
rename from minix/commands/ash/bltin/bltin.h
rename to bin/sh/bltin/bltin.h
index 4dc41fac6f9df0364b6c7f87735d3b19ac489f2b..5cd90f5ac3b1636a1e4ce4ee2ab4b48c40c5ba91 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: bltin.h,v 1.13 2008/10/12 01:40:37 dholland Exp $      */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)bltin.h     8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/bltin/bltin.h,v 1.13 2004/04/06 20:06:53 markm Exp $
+ *     @(#)bltin.h     8.1 (Berkeley) 5/31/93
  */
 
 /*
  * This file is included by programs which are optionally built into the
- * shell.  If SHELL is defined, we try to map the standard UNIX library
- * routines to ash routines using defines.
+ * shell.
+ *
+ * We always define SHELL_BUILTIN, to allow other included headers to
+ * hide some of their symbols if appropriate.
+ *
+ * If SHELL is defined, we try to map the standard UNIX library routines
+ * to ash routines using defines.
  */
 
+#define SHELL_BUILTIN
 #include "../shell.h"
 #include "../mystring.h"
 #ifdef SHELL
-#include "builtins.h"
 #include "../output.h"
+#include "../error.h"
 #undef stdout
-#define stdout out1
 #undef stderr
-#define stderr out2
-#define printf out1fmt
 #undef putc
-#define putc(c, file)  outc(c, file)
 #undef putchar
-#define putchar(c)     out1c(c)
-#define fprintf outfmt
-#define fputs outstr
-#define fflush flushout
+#undef fileno
+#undef ferror
+#define FILE struct output
+#define stdout out1
+#define stderr out2
+#define _RETURN_INT(x) ((x), 0) /* map from void foo() to int bar() */
+#define fprintf(...)   _RETURN_INT(outfmt(__VA_ARGS__))
+#define printf(...)    _RETURN_INT(out1fmt(__VA_ARGS__))
+#define putc(c, file)  _RETURN_INT(outc(c, file))
+#define putchar(c)     _RETURN_INT(out1c(c))
+#define fputs(...)     _RETURN_INT(outstr(__VA_ARGS__))
+#define fflush(f)      _RETURN_INT(flushout(f))
+#define fileno(f) ((f)->fd)
+#define ferror(f) ((f)->flags & OUTPUT_ERR)
 #define INITARGS(argv)
-#define warnx1(a, b, c) {                              \
-       char buf[64];                                   \
-       (void)snprintf(buf, sizeof(buf), a);            \
-       error("%s", buf);                               \
-}
-#define warnx2(a, b, c) {                              \
-       char buf[64];                                   \
-       (void)snprintf(buf, sizeof(buf), a, b);         \
-       error("%s", buf);                               \
-}
-#define warnx3(a, b, c) {                              \
-       char buf[64];                                   \
-       (void)snprintf(buf, sizeof(buf), a, b, c);      \
-       error("%s", buf);                               \
-}
+#define        err sh_err
+#define        verr sh_verr
+#define        errx sh_errx
+#define        verrx sh_verrx
+#define        warn sh_warn
+#define        vwarn sh_vwarn
+#define        warnx sh_warnx
+#define        vwarnx sh_vwarnx
+#define exit sh_exit
+#define setprogname(s)
+#define getprogname() commandname
+#define setlocate(l,s) 0
+
+#define getenv(p) bltinlookup((p),0)
 
-#else
+#else /* ! SHELL */
 #undef NULL
 #include <stdio.h>
 #undef main
 #define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
-#endif
+#endif /* ! SHELL */
 
 pointer stalloc(int);
-void error(const char *, ...);
 
+int echocmd(int, char **);
 
-extern char *commandname;
 
-/*
- * $PchId: bltin.h,v 1.4 2006/03/29 11:39:00 philip Exp $
- */
+extern const char *commandname;
diff --git a/bin/sh/bltin/echo.1 b/bin/sh/bltin/echo.1
new file mode 100644 (file)
index 0000000..7e71fa3
--- /dev/null
@@ -0,0 +1,109 @@
+.\"    $NetBSD: echo.1,v 1.13 2003/08/07 09:05:40 agc Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Kenneth Almquist.
+.\" Copyright 1989 by Kenneth Almquist
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    @(#)echo.1      8.1 (Berkeley) 5/31/93
+.\"
+.Dd May 31, 1993
+.Dt ECHO 1
+.Os
+.Sh NAME
+.Nm echo
+.Nd produce message in a shell script
+.Sh SYNOPSIS
+.Nm
+.Op Fl n | Fl e
+.Ar args ...
+.Sh DESCRIPTION
+.Nm
+prints its arguments on the standard output, separated by spaces.
+Unless the
+.Fl n
+option is present, a newline is output following the arguments.
+The
+.Fl e
+option causes
+.Nm
+to treat the escape sequences specially, as described in the following
+paragraph.
+The
+.Fl e
+option is the default, and is provided solely for compatibility with
+other systems.
+Only one of the options
+.Fl n
+and
+.Fl e
+may be given.
+.Pp
+If any of the following sequences of characters is encountered during
+output, the sequence is not output.  Instead, the specified action is
+performed:
+.Bl -tag -width indent
+.It Li \eb
+A backspace character is output.
+.It Li \ec
+Subsequent output is suppressed.  This is normally used at the end of the
+last argument to suppress the trailing newline that
+.Nm
+would otherwise output.
+.It Li \ef
+Output a form feed.
+.It Li \en
+Output a newline character.
+.It Li \er
+Output a carriage return.
+.It Li \et
+Output a (horizontal) tab character.
+.It Li \ev
+Output a vertical tab.
+.It Li \e0 Ns Ar digits
+Output the character whose value is given by zero to three digits.
+If there are zero digits, a nul character is output.
+.It Li \e\e
+Output a backslash.
+.El
+.Sh HINTS
+Remember that backslash is special to the shell and needs to be escaped.
+To output a message to standard error, say
+.Pp
+.D1  echo message \*[Gt]\*[Am]2
+.Sh BUGS
+The octal character escape mechanism
+.Pq Li \e0 Ns Ar digits
+differs from the
+C language mechanism.
+.Pp
+There is no way to force
+.Nm
+to treat its arguments literally, rather than interpreting them as
+options and escape sequences.
similarity index 69%
rename from minix/commands/ash/bltin/echo.c
rename to bin/sh/bltin/echo.c
index 72bb60e52f029d5035c41215ad9ce5cd0ff129e3..440e01bcd58d02919c73e1e7c0f3b7169c482b76 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: echo.c,v 1.14 2008/10/12 01:40:37 dholland Exp $       */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)echo.c      8.2 (Berkeley) 5/4/95
+ *     @(#)echo.c      8.1 (Berkeley) 5/31/93
  */
 
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/bltin/echo.c,v 1.14 2004/04/06 20:06:53 markm Exp $");
-*/
-
 /*
  * Echo command.
+ *
+ * echo is steeped in tradition - several of them!
+ * netbsd has supported 'echo [-n | -e] args' in spite of -e not being
+ * documented anywhere.
+ * Posix requires that -n be supported, output from strings containing
+ * \ is implementation defined
+ * The Single Unix Spec requires that \ escapes be treated as if -e
+ * were set, but that -n not be treated as an option.
+ * (ksh supports 'echo [-eEn] args', but not -- so that it is actually
+ * impossible to actually output '-n')
+ *
+ * It is suggested that 'printf "%b" "string"' be used to get \ sequences
+ * expanded.  printf is now a builtin of netbsd's sh and csh.
  */
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: echo.c,v 1.14 2008/10/12 01:40:37 dholland Exp $");
+
+#define main echocmd
+
 #include "bltin.h"
 
 int
-echocmd(argc, argv)
-       int argc;
-       char **argv;
+main(int argc, char **argv)
 {
        char **ap;
        char *p;
        char c;
        int count;
        int nflag = 0;
-#ifdef __minix
        int eflag = 0;
-#endif
 
        ap = argv;
        if (argc)
                ap++;
+
        if ((p = *ap) != NULL) {
-#ifdef __minix
-               if (equal(p, "--")) {
-                       ap++;
-               }
-#endif
                if (equal(p, "-n")) {
-                       nflag++;
+                       nflag = 1;
                        ap++;
                } else if (equal(p, "-e")) {
-#ifdef __minix
-                       eflag++;
-#endif
+                       eflag = 1;
                        ap++;
                }
        }
+
        while ((p = *ap++) != NULL) {
                while ((c = *p++) != '\0') {
                        if (c == '\\' && eflag) {
                                switch (*p++) {
-                               case 'a':  c = '\a';  break;
+                               case 'a':  c = '\a';  break;    /* bell */
                                case 'b':  c = '\b';  break;
                                case 'c':  return 0;            /* exit */
-                               case 'e':  c = '\033';  break;
+                               case 'e':  c =  033;  break;    /* escape */
                                case 'f':  c = '\f';  break;
                                case 'n':  c = '\n';  break;
                                case 'r':  c = '\r';  break;
@@ -97,6 +103,7 @@ echocmd(argc, argv)
                                                c = (c << 3) + (*p++ - '0');
                                        break;
                                default:
+                                       /* Output the '/' and char following */
                                        p--;
                                        break;
                                }
@@ -108,9 +115,8 @@ echocmd(argc, argv)
        }
        if (! nflag)
                putchar('\n');
+       fflush(stdout);
+       if (ferror(stdout))
+               return 1;
        return 0;
 }
-
-/*
- * $PchId: echo.c,v 1.5 2006/05/23 12:05:56 philip Exp $
- */
similarity index 59%
rename from minix/commands/ash/builtins.def
rename to bin/sh/builtins.def
index b55ba83eb5e4147edbef7660fbcfb0ddef95e468..1f09d43060004995e915a7b871fa2d2662112ebe 100644 (file)
@@ -1,4 +1,5 @@
 #!/bin/sh -
+#      $NetBSD: builtins.def,v 1.22 2012/12/31 14:10:15 dsl Exp $
 #
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
@@ -14,7 +15,7 @@
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
-# 4. Neither the name of the University nor the names of its contributors
+# 3. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
 #
 # SUCH DAMAGE.
 #
 #      @(#)builtins.def        8.4 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/builtins.def,v 1.14 2004/04/06 20:06:51 markm Exp $
 
 #
 # This file lists all the builtin commands.  The first column is the name
-# of a C routine.  The -j flag, if present, specifies that this command
-# is to be excluded from systems without job control, and the -h flag,
-# if present specifies that this command is to be excluded from systems
-# based on the NO_HISTORY compile-time symbol.  The rest of the line
-# specifies the command name or names used to run the command.  The entry
-# for bltincmd, which is run when the user does not specify a command, must
-# come first.
-#
-# NOTE: bltincmd must come first!
+# of a C routine.
+# The -j flag specifies that this command is to be excluded from systems
+# without job control.
+# The -h flag specifies that this command is to be excluded from systems
+# based on the SMALL compile-time symbol.
+# The -s flag specifies that this is a posix 'special builtin' command.
+# The -u flag specifies that this is a posix 'standard utility'.
+# The rest of the line specifies the command name or names used to run
+# the command.
 
-bltincmd       builtin
-commandcmd     command
-#if JOBS
-bgcmd -j       bg
-#endif
-breakcmd       break continue
-#catfcmd       catf
-cdcmd          cd chdir
-dotcmd         .
+bltincmd       -u command
+bgcmd -j       -u bg
+breakcmd       -s break -s continue
+cdcmd          -u cd chdir
+dotcmd         -s .
 echocmd                echo
-evalcmd                eval
-execcmd                exec
-exitcmd                exit
+evalcmd                -s eval
+execcmd                -s exec
+exitcmd                -s exit
 expcmd         exp let
-exportcmd      export readonly
-exprcmd                expr test [
-falsecmd       false
-histcmd -h     fc
-#if JOBS
-fgcmd -j       fg
-#endif
-getoptscmd     getopts
+exportcmd      -s export -s readonly
+falsecmd       -u false
+histcmd -h     -u fc
+inputrc                inputrc
+fgcmd -j       -u fg
+fgcmd_percent -j       -u %
+getoptscmd     -u getopts
 hashcmd                hash
 jobidcmd       jobid
-jobscmd                jobs
+jobscmd                -u jobs
 localcmd       local
 #ifndef SMALL
-#printfcmd     printf
+printfcmd      printf
 #endif
-pwdcmd         pwd
-readcmd                read
-returncmd      return
-setcmd         set
+pwdcmd         -u pwd
+readcmd                -u read
+returncmd      -s return
+setcmd         -s set
 setvarcmd      setvar
-shiftcmd       shift
-trapcmd                trap
-truecmd                : true
+shiftcmd       -s shift
+timescmd       -s times
+trapcmd                -s trap
+truecmd                -s : -u true
 typecmd                type
-umaskcmd       umask
-unaliascmd     unalias
-unsetcmd       unset
-waitcmd                wait
-aliascmd       alias
+umaskcmd       -u umask
+unaliascmd     -u unalias
+unsetcmd       -s unset
+waitcmd                -u wait
+aliascmd       -u alias
 ulimitcmd      ulimit
-bindcmd                bind
+testcmd                test [
+killcmd                -u kill         # mandated by posix for 'kill %job'
 wordexpcmd     wordexp
+#newgrp                -u newgrp       # optional command in posix
+
+#exprcmd       expr
similarity index 55%
rename from minix/commands/ash/cd.c
rename to bin/sh/cd.c
index 8513128ed54ebdc62357f4bfb66607e852f1efe7..8295708252bd8632cdb2738c13ebdd23acffc302 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: cd.c,v 1.44 2011/08/31 16:24:54 plunky Exp $   */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)cd.c       8.2 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: cd.c,v 1.44 2011/08/31 16:24:54 plunky Exp $");
 #endif
 #endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
-*/
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -46,7 +47,6 @@ __FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
-#include <limits.h>
 
 /*
  * The cd and pwd commands.
@@ -57,68 +57,74 @@ __FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
 #include "nodes.h"     /* for jobs.h */
 #include "jobs.h"
 #include "options.h"
+#include "builtins.h"
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
 #include "exec.h"
 #include "redir.h"
 #include "mystring.h"
-#include "builtins.h"
 #include "show.h"
 #include "cd.h"
 
-STATIC int cdlogical(const char *);
-STATIC int cdphysical(const char *);
-STATIC int docd(const char *, int, int);
+STATIC int docd(const char *, int);
 STATIC char *getcomponent(void);
-STATIC int updatepwd(const char *);
+STATIC void updatepwd(const char *);
+STATIC void find_curdir(int noerror);
 
-STATIC char *curdir = NULL;    /* current working directory */
-STATIC char *prevdir;          /* previous working directory */
+char *curdir = NULL;           /* current working directory */
+char *prevdir;                 /* previous working directory */
 STATIC char *cdcomppath;
 
 int
 cdcmd(int argc, char **argv)
 {
-       char *dest;
-       char *path;
-       char *p;
+       const char *dest;
+       const char *path, *p;
+       char *d;
        struct stat statb;
-       int ch, phys, print = 0;
-
-       optreset = 1; optind = 1; opterr = 0; /* initialize getopt */
-       phys = Pflag;
-       while ((ch = getopt(argc, argv, "LP")) != -1) {
-               switch (ch) {
-               case 'L':
-                       phys = 0;
-                       break;
-               case 'P':
-                       phys = 1;
-                       break;
-               default:
-                       error("unknown option: -%c", optopt);
-                       break;
+       int print = cdprint;    /* set -cdprint to enable */
+
+       while (nextopt("P") != '\0')
+               ;
+
+       /*
+        * Try (quite hard) to have 'curdir' defined, nothing has set
+        * it on entry to the shell, but we want 'cd fred; cd -' to work.
+        */
+       getpwd(1);
+       dest = *argptr;
+       if (dest == NULL) {
+               dest = bltinlookup("HOME", 1);
+               if (dest == NULL)
+                       error("HOME not set");
+       } else {
+               if (argptr[1]) {
+                       /* Do 'ksh' style substitution */
+                       if (!curdir)
+                               error("PWD not set");
+                       p = strstr(curdir, dest);
+                       if (!p)
+                               error("bad substitution");
+                       d = stalloc(strlen(curdir) + strlen(argptr[1]) + 1);
+                       memcpy(d, curdir, p - curdir);
+                       strcpy(d + (p - curdir), argptr[1]);
+                       strcat(d, p + strlen(dest));
+                       dest = d;
+                       print = 1;
                }
        }
-       argc -= optind;
-       argv += optind;
-
-       if (argc > 1)
-               error("too many arguments");
 
-       if ((dest = *argv) == NULL && (dest = bltinlookup("HOME", 1)) == NULL)
-               error("HOME not set");
-       if (*dest == '\0')
-               dest = ".";
        if (dest[0] == '-' && dest[1] == '\0') {
                dest = prevdir ? prevdir : curdir;
-               if (dest)
-                       print = 1;
-               else
-                       dest = ".";
+               print = 1;
        }
-       if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
+       if (*dest == '\0')
+               dest = ".";
+       p = dest;
+       if (*p == '.' && *++p == '.')
+           p++;
+       if (*p == 0 || *p == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
                path = nullstr;
        while ((p = padvance(&path, dest)) != NULL) {
                if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
@@ -127,41 +133,27 @@ cdcmd(int argc, char **argv)
                                 * XXX - rethink
                                 */
                                if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
-                                       p += 2;
-                               print = strcmp(p, dest);
+                                       print = strcmp(p + 2, dest);
+                               else
+                                       print = strcmp(p, dest);
                        }
-                       if (docd(p, print, phys) >= 0)
+                       if (docd(p, print) >= 0)
                                return 0;
+
                }
        }
        error("can't cd to %s", dest);
-       /*NOTREACHED*/
-       return 0;
+       /* NOTREACHED */
 }
 
 
 /*
- * Actually change the directory.  In an interactive shell, print the
+ * Actually do the chdir.  In an interactive shell, print the
  * directory name if "print" is nonzero.
  */
-STATIC int
-docd(const char *dest, int print, int phys)
-{
-
-       TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, phys));
-
-       /* If logical cd fails, fall back to physical. */
-       if ((phys || cdlogical(dest) < 0) && cdphysical(dest) < 0)
-               return (-1);
-
-       if (print && iflag && curdir)
-               out1fmt("%s\n", curdir);
-
-       return 0;
-}
 
 STATIC int
-cdlogical(const char *dest)
+docd(const char *dest, int print)
 {
        char *p;
        char *q;
@@ -170,6 +162,8 @@ cdlogical(const char *dest)
        int first;
        int badstat;
 
+       TRACE(("docd(\"%s\", %d) called\n", dest, print));
+
        /*
         *  Check each component of the path. If we find a symlink or
         *  something we can't stat, clear curdir to force a getcwd()
@@ -196,38 +190,32 @@ cdlogical(const char *dest)
                if (equal(component, ".."))
                        continue;
                STACKSTRNUL(p);
-               if (lstat(stackblock(), &statb) < 0) {
+               if ((lstat(stackblock(), &statb) < 0)
+                   || (S_ISLNK(statb.st_mode)))  {
+                       /* print = 1; */
                        badstat = 1;
                        break;
                }
        }
 
        INTOFF;
-       if (updatepwd(badstat ? NULL : dest) < 0 || chdir(curdir) < 0) {
+       if (chdir(dest) < 0) {
                INTON;
-               return (-1);
+               return -1;
        }
+       updatepwd(badstat ? NULL : dest);
        INTON;
-       return (0);
+       if (print && iflag == 1 && curdir)
+               out1fmt("%s\n", curdir);
+       return 0;
 }
 
-STATIC int
-cdphysical(const char *dest)
-{
-
-       INTOFF;
-       if (chdir(dest) < 0 || updatepwd(NULL) < 0) {
-               INTON;
-               return (-1);
-       }
-       INTON;
-       return (0);
-}
 
 /*
  * Get the next component of the path name pointed to by cdcomppath.
  * This routine overwrites the string pointed to by cdcomppath.
  */
+
 STATIC char *
 getcomponent(void)
 {
@@ -249,12 +237,14 @@ getcomponent(void)
 }
 
 
+
 /*
  * Update curdir (the name of the current directory) in response to a
  * cd command.  We also call hashcd to let the routines in exec.c know
  * that the current directory has changed.
  */
-STATIC int
+
+STATIC void
 updatepwd(const char *dir)
 {
        char *new;
@@ -273,14 +263,14 @@ updatepwd(const char *dir)
                INTOFF;
                prevdir = curdir;
                curdir = NULL;
-               if (getpwd() == NULL) {
-                       INTON;
-                       return (-1);
-               }
-               setvar("PWD", curdir, VEXPORT);
-               setvar("OLDPWD", prevdir, VEXPORT);
+               getpwd(1);
                INTON;
-               return (0);
+               if (curdir) {
+                       setvar("OLDPWD", prevdir, VEXPORT);
+                       setvar("PWD", curdir, VEXPORT);
+               } else
+                       unsetvar("PWD", 0);
+               return;
        }
        cdcomppath = stalloc(strlen(dir) + 1);
        scopy(dir, cdcomppath);
@@ -309,82 +299,166 @@ updatepwd(const char *dir)
                ckfree(prevdir);
        prevdir = curdir;
        curdir = savestr(stackblock());
-       setvar("PWD", curdir, VEXPORT);
        setvar("OLDPWD", prevdir, VEXPORT);
+       setvar("PWD", curdir, VEXPORT);
        INTON;
-
-       return (0);
 }
 
+/*
+ * Posix says the default should be 'pwd -L' (as below), however
+ * the 'cd' command (above) does something much nearer to the
+ * posix 'cd -P' (not the posix default of 'cd -L').
+ * If 'cd' is changed to support -P/L then the default here
+ * needs to be revisited if the historic behaviour is to be kept.
+ */
+
 int
 pwdcmd(int argc, char **argv)
 {
-       char buf[PATH_MAX];
-       int ch, phys;
-
-       optreset = 1; optind = 1; opterr = 0; /* initialize getopt */
-       phys = Pflag;
-       while ((ch = getopt(argc, argv, "LP")) != -1) {
-               switch (ch) {
-               case 'L':
-                       phys = 0;
-                       break;
-               case 'P':
-                       phys = 1;
-                       break;
-               default:
-                       error("unknown option: -%c", optopt);
-                       break;
-               }
-       }
-       argc -= optind;
-       argv += optind;
+       int i;
+       char opt = 'L';
 
-       if (argc != 0)
-               error("too many arguments");
+       while ((i = nextopt("LP")) != '\0')
+               opt = i;
+       if (*argptr)
+               error("unexpected argument");
 
-       if (!phys && getpwd()) {
-               out1str(curdir);
-               out1c('\n');
-       } else {
-               if (getcwd(buf, sizeof(buf)) == NULL)
-                       error(".: %s", strerror(errno));
-               out1str(buf);
-               out1c('\n');
-       }
+       if (opt == 'L')
+               getpwd(0);
+       else
+               find_curdir(0);
 
+       setvar("OLDPWD", prevdir, VEXPORT);
+       setvar("PWD", curdir, VEXPORT);
+       out1str(curdir);
+       out1c('\n');
        return 0;
 }
 
+
+
+void
+initpwd(void)
+{
+       getpwd(1);
+       if (curdir)
+               setvar("PWD", curdir, VEXPORT);
+       else
+               sh_warnx("Cannot determine current working directory");
+}
+
+#define MAXPWD 256
+
 /*
  * Find out what the current directory is. If we already know the current
  * directory, this routine returns immediately.
  */
-char *
-getpwd(void)
+void
+getpwd(int noerror)
 {
-       char buf[PATH_MAX];
+       char *pwd;
+       struct stat stdot, stpwd;
+       static int first = 1;
 
        if (curdir)
-               return curdir;
-       if (getcwd(buf, sizeof(buf)) == NULL) {
-               char *pwd = getenv("PWD");
-               struct stat stdot, stpwd;
+               return;
 
+       if (first) {
+               first = 0;
+               pwd = getenv("PWD");
                if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
                    stat(pwd, &stpwd) != -1 &&
                    stdot.st_dev == stpwd.st_dev &&
                    stdot.st_ino == stpwd.st_ino) {
                        curdir = savestr(pwd);
-                       return curdir;
+                       return;
                }
-               return NULL;
        }
-       curdir = savestr(buf);
 
-       return curdir;
+       find_curdir(noerror);
+
+       return;
 }
 
-/*
- * $PchId: cd.c,v 1.6 2006/05/22 12:42:03 philip Exp $
- */
+STATIC void
+find_curdir(int noerror)
+{
+       int i;
+       char *pwd;
+
+       /*
+        * Things are a bit complicated here; we could have just used
+        * getcwd, but traditionally getcwd is implemented using popen
+        * to /bin/pwd. This creates a problem for us, since we cannot
+        * keep track of the job if it is being ran behind our backs.
+        * So we re-implement getcwd(), and we suppress interrupts
+        * throughout the process. This is not completely safe, since
+        * the user can still break out of it by killing the pwd program.
+        * We still try to use getcwd for systems that we know have a
+        * c implementation of getcwd, that does not open a pipe to
+        * /bin/pwd.
+        */
+#if defined(__NetBSD__) || defined(__SVR4) || defined(__minix)
+
+       for (i = MAXPWD;; i *= 2) {
+               pwd = stalloc(i);
+               if (getcwd(pwd, i) != NULL) {
+                       curdir = savestr(pwd);
+                       return;
+               }
+               stunalloc(pwd);
+               if (errno == ERANGE)
+                       continue;
+               if (!noerror)
+                       error("getcwd() failed: %s", strerror(errno));
+               return;
+       }
+#else
+       {
+               char *p;
+               int status;
+               struct job *jp;
+               int pip[2];
+
+               pwd = stalloc(MAXPWD);
+               INTOFF;
+               if (pipe(pip) < 0)
+                       error("Pipe call failed");
+               jp = makejob(NULL, 1);
+               if (forkshell(jp, NULL, FORK_NOJOB) == 0) {
+                       (void) close(pip[0]);
+                       if (pip[1] != 1) {
+                               close(1);
+                               copyfd(pip[1], 1, 1);
+                               close(pip[1]);
+                       }
+                       (void) execl("/bin/pwd", "pwd", (char *)0);
+                       error("Cannot exec /bin/pwd");
+               }
+               (void) close(pip[1]);
+               pip[1] = -1;
+               p = pwd;
+               while ((i = read(pip[0], p, pwd + MAXPWD - p)) > 0
+                    || (i == -1 && errno == EINTR)) {
+                       if (i > 0)
+                               p += i;
+               }
+               (void) close(pip[0]);
+               pip[0] = -1;
+               status = waitforjob(jp);
+               if (status != 0)
+                       error((char *)0);
+               if (i < 0 || p == pwd || p[-1] != '\n') {
+                       if (noerror) {
+                               INTON;
+                               return;
+                       }
+                       error("pwd command failed");
+               }
+               p[-1] = '\0';
+               INTON;
+               curdir = savestr(pwd);
+               return;
+       }
+#endif
+}
similarity index 85%
rename from minix/commands/ash/cd.h
rename to bin/sh/cd.h
index f4546f206bfb100dfaab2ec41a9914f69e3cbcc4..7600955da60c892c165ae3f3bceecf9d3267b0bd 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: cd.h,v 1.6 2011/06/18 21:18:46 christos Exp $  */
+
 /*-
  * Copyright (c) 1995
  *     The Regents of the University of California.  All rights reserved.
@@ -10,7 +12,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/bin/sh/cd.h,v 1.7 2004/04/06 20:06:51 markm Exp $
  */
 
-char   *getpwd(void);
-int     cdcmd (int, char **);
-int     pwdcmd(int, char **);
-
-/*
- * $PchId: cd.h,v 1.3 2006/03/31 09:59:04 philip Exp $
- */
+void   initpwd(void);
+void   getpwd(int);
diff --git a/bin/sh/error.c b/bin/sh/error.c
new file mode 100644 (file)
index 0000000..2ac98b6
--- /dev/null
@@ -0,0 +1,370 @@
+/*     $NetBSD: error.c,v 1.38 2012/03/15 02:02:20 joerg Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)error.c    8.2 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: error.c,v 1.38 2012/03/15 02:02:20 joerg Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * Errors and exceptions.
+ */
+
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "shell.h"
+#include "eval.h" /* for commandname */
+#include "main.h"
+#include "options.h"
+#include "output.h"
+#include "error.h"
+#include "show.h"
+
+
+/*
+ * Code to handle exceptions in C.
+ */
+
+struct jmploc *handler;
+int exception;
+volatile int suppressint;
+volatile int intpending;
+
+
+static void exverror(int, const char *, va_list) __dead;
+
+/*
+ * Called to raise an exception.  Since C doesn't include exceptions, we
+ * just do a longjmp to the exception handler.  The type of exception is
+ * stored in the global variable "exception".
+ */
+
+void
+exraise(int e)
+{
+       if (handler == NULL)
+               abort();
+       exception = e;
+       longjmp(handler->loc, 1);
+}
+
+
+/*
+ * Called from trap.c when a SIGINT is received.  (If the user specifies
+ * that SIGINT is to be trapped or ignored using the trap builtin, then
+ * this routine is not called.)  Suppressint is nonzero when interrupts
+ * are held using the INTOFF macro.  The call to _exit is necessary because
+ * there is a short period after a fork before the signal handlers are
+ * set to the appropriate value for the child.  (The test for iflag is
+ * just defensive programming.)
+ */
+
+void
+onint(void)
+{
+       sigset_t nsigset;
+
+       if (suppressint) {
+               intpending = 1;
+               return;
+       }
+       intpending = 0;
+       sigemptyset(&nsigset);
+       sigprocmask(SIG_SETMASK, &nsigset, NULL);
+       if (rootshell && iflag)
+               exraise(EXINT);
+       else {
+               signal(SIGINT, SIG_DFL);
+               raise(SIGINT);
+       }
+       /* NOTREACHED */
+}
+
+static __printflike(2, 0) void
+exvwarning(int sv_errno, const char *msg, va_list ap)
+{
+       /* Partially emulate line buffered output so that:
+        *      printf '%d\n' 1 a 2
+        * and
+        *      printf '%d %d %d\n' 1 a 2
+        * both generate sensible text when stdout and stderr are merged.
+        */
+       if (output.nextc != output.buf && output.nextc[-1] == '\n')
+               flushout(&output);
+       if (commandname)
+               outfmt(&errout, "%s: ", commandname);
+       else
+               outfmt(&errout, "%s: ", getprogname());
+       if (msg != NULL) {
+               doformat(&errout, msg, ap);
+               if (sv_errno >= 0)
+                       outfmt(&errout, ": ");
+       }
+       if (sv_errno >= 0)
+               outfmt(&errout, "%s", strerror(sv_errno));
+       out2c('\n');
+       flushout(&errout);
+}
+
+/*
+ * Exverror is called to raise the error exception.  If the second argument
+ * is not NULL then error prints an error message using printf style
+ * formatting.  It then raises the error exception.
+ */
+static __printflike(2, 0) void
+exverror(int cond, const char *msg, va_list ap)
+{
+       CLEAR_PENDING_INT;
+       INTOFF;
+
+#ifdef DEBUG
+       if (msg) {
+               TRACE(("exverror(%d, \"", cond));
+               TRACEV((msg, ap));
+               TRACE(("\") pid=%d\n", getpid()));
+       } else
+               TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
+#endif
+       if (msg)
+               exvwarning(-1, msg, ap);
+
+       flushall();
+       exraise(cond);
+       /* NOTREACHED */
+}
+
+
+void
+error(const char *msg, ...)
+{
+       va_list ap;
+
+       va_start(ap, msg);
+       exverror(EXERROR, msg, ap);
+       /* NOTREACHED */
+       va_end(ap);
+}
+
+
+void
+exerror(int cond, const char *msg, ...)
+{
+       va_list ap;
+
+       va_start(ap, msg);
+       exverror(cond, msg, ap);
+       /* NOTREACHED */
+       va_end(ap);
+}
+
+/*
+ * error/warning routines for external builtins
+ */
+
+void
+sh_exit(int rval)
+{
+       exerrno = rval & 255;
+       exraise(EXEXEC);
+}
+
+void
+sh_err(int status, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       exvwarning(errno, fmt, ap);
+       va_end(ap);
+       sh_exit(status);
+}
+
+void
+sh_verr(int status, const char *fmt, va_list ap)
+{
+       exvwarning(errno, fmt, ap);
+       sh_exit(status);
+}
+
+void
+sh_errx(int status, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       exvwarning(-1, fmt, ap);
+       va_end(ap);
+       sh_exit(status);
+}
+
+void
+sh_verrx(int status, const char *fmt, va_list ap)
+{
+       exvwarning(-1, fmt, ap);
+       sh_exit(status);
+}
+
+void
+sh_warn(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       exvwarning(errno, fmt, ap);
+       va_end(ap);
+}
+
+void
+sh_vwarn(const char *fmt, va_list ap)
+{
+       exvwarning(errno, fmt, ap);
+}
+
+void
+sh_warnx(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       exvwarning(-1, fmt, ap);
+       va_end(ap);
+}
+
+void
+sh_vwarnx(const char *fmt, va_list ap)
+{
+       exvwarning(-1, fmt, ap);
+}
+
+
+/*
+ * Table of error messages.
+ */
+
+struct errname {
+       short errcode;          /* error number */
+       short action;           /* operation which encountered the error */
+       const char *msg;        /* text describing the error */
+};
+
+
+#define ALL (E_OPEN|E_CREAT|E_EXEC)
+
+STATIC const struct errname errormsg[] = {
+       { EINTR,        ALL,    "interrupted" },
+       { EACCES,       ALL,    "permission denied" },
+       { EIO,          ALL,    "I/O error" },
+       { EEXIST,       ALL,    "file exists" },
+       { ENOENT,       E_OPEN, "no such file" },
+       { ENOENT,       E_CREAT,"directory nonexistent" },
+       { ENOENT,       E_EXEC, "not found" },
+       { ENOTDIR,      E_OPEN, "no such file" },
+       { ENOTDIR,      E_CREAT,"directory nonexistent" },
+       { ENOTDIR,      E_EXEC, "not found" },
+       { EISDIR,       ALL,    "is a directory" },
+#ifdef EMFILE
+       { EMFILE,       ALL,    "too many open files" },
+#endif
+       { ENFILE,       ALL,    "file table overflow" },
+       { ENOSPC,       ALL,    "file system full" },
+#ifdef EDQUOT
+       { EDQUOT,       ALL,    "disk quota exceeded" },
+#endif
+#ifdef ENOSR
+       { ENOSR,        ALL,    "no streams resources" },
+#endif
+       { ENXIO,        ALL,    "no such device or address" },
+       { EROFS,        ALL,    "read-only file system" },
+       { ETXTBSY,      ALL,    "text busy" },
+#ifdef EAGAIN
+       { EAGAIN,       E_EXEC, "not enough memory" },
+#endif
+       { ENOMEM,       ALL,    "not enough memory" },
+#ifdef ENOLINK
+       { ENOLINK,      ALL,    "remote access failed" },
+#endif
+#ifdef EMULTIHOP
+       { EMULTIHOP,    ALL,    "remote access failed" },
+#endif
+#ifdef ECOMM
+       { ECOMM,        ALL,    "remote access failed" },
+#endif
+#ifdef ESTALE
+       { ESTALE,       ALL,    "remote access failed" },
+#endif
+#ifdef ETIMEDOUT
+       { ETIMEDOUT,    ALL,    "remote access failed" },
+#endif
+#ifdef ELOOP
+       { ELOOP,        ALL,    "symbolic link loop" },
+#endif
+#ifdef ENAMETOOLONG
+       { ENAMETOOLONG, ALL,    "file name too long" },
+#endif
+       { E2BIG,        E_EXEC, "argument list too long" },
+#ifdef ELIBACC
+       { ELIBACC,      E_EXEC, "shared library missing" },
+#endif
+       { 0,            0,      NULL },
+};
+
+
+/*
+ * Return a string describing an error.  The returned string may be a
+ * pointer to a static buffer that will be overwritten on the next call.
+ * Action describes the operation that got the error.
+ */
+
+const char *
+errmsg(int e, int action)
+{
+       struct errname const *ep;
+       static char buf[12];
+
+       for (ep = errormsg ; ep->errcode ; ep++) {
+               if (ep->errcode == e && (ep->action & action) != 0)
+                       return ep->msg;
+       }
+       fmtstr(buf, sizeof buf, "error %d", e);
+       return buf;
+}
similarity index 70%
rename from minix/commands/ash/error.h
rename to bin/sh/error.h
index 6597d9038db7e71f9968622c4637ffed7177a187..b4121b8da0c19494e0faf4aa69263384c594a357 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: error.h,v 1.19 2012/03/15 02:02:20 joerg Exp $ */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)error.h     8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/error.h,v 1.17 2004/04/06 20:06:51 markm Exp $
  */
 
+#include <stdarg.h>
+
+/*
+ * Types of operations (passed to the errmsg routine).
+ */
+
+#define E_OPEN 01      /* opening a file */
+#define E_CREAT 02     /* creating a file */
+#define E_EXEC 04      /* executing a program */
+
+
 /*
  * We enclose jmp_buf in a structure so that we can declare pointers to
  * jump locations.  The global variable handler contains the location to
  * jump to when an exception occurs, and the global variable exception
- * contains a code identifying the exception.  To implement nested
+ * contains a code identifying the exeception.  To implement nested
  * exception handlers, the user should save the value of handler on entry
  * to an inner scope, set handler to point to a jmploc structure for the
  * inner scope, and restore handler on exit from the scope.
  */
 
 #include <setjmp.h>
-#include <signal.h>
 
 struct jmploc {
        jmp_buf loc;
 };
 
 extern struct jmploc *handler;
-extern volatile sig_atomic_t exception;
+extern int exception;
+extern int exerrno;    /* error for EXEXEC */
 
 /* exceptions */
 #define EXINT 0                /* SIGINT received */
@@ -67,8 +79,8 @@ extern volatile sig_atomic_t exception;
  * more fun than worrying about efficiency and portability. :-))
  */
 
-extern volatile sig_atomic_t suppressint;
-extern volatile sig_atomic_t intpending;
+extern volatile int suppressint;
+extern volatile int intpending;
 
 #define INTOFF suppressint++
 #define INTON { if (--suppressint == 0 && intpending) onint(); }
@@ -76,12 +88,24 @@ extern volatile sig_atomic_t intpending;
 #define CLEAR_PENDING_INT intpending = 0
 #define int_pending() intpending
 
-#define __printf0like(a,b)
-
-void exraise(int);
+#if ! defined(SHELL_BUILTIN)
+void exraise(int) __dead;
 void onint(void);
-void error(const char *, ...) __printf0like(1, 2);
-void exerror(int, const char *, ...) __printf0like(2, 3);
+void error(const char *, ...) __dead __printflike(1, 2);
+void exerror(int, const char *, ...) __dead __printflike(2, 3);
+const char *errmsg(int, int);
+#endif /* ! SHELL_BUILTIN */
+
+void sh_err(int, const char *, ...) __dead __printflike(2, 3);
+void sh_verr(int, const char *, va_list) __dead __printflike(2, 0);
+void sh_errx(int, const char *, ...) __dead __printflike(2, 3);
+void sh_verrx(int, const char *, va_list) __dead __printflike(2, 0);
+void sh_warn(const char *, ...) __printflike(1, 2);
+void sh_vwarn(const char *, va_list) __printflike(1, 0);
+void sh_warnx(const char *, ...) __printflike(1, 2);
+void sh_vwarnx(const char *, va_list) __printflike(1, 0);
+
+void sh_exit(int) __dead;
 
 
 /*
@@ -89,13 +113,7 @@ void exerror(int, const char *, ...) __printf0like(2, 3);
  * so we use _setjmp instead.
  */
 
-#ifdef BSD
-#ifndef __minix
+#if defined(BSD) && !defined(__SVR4)
 #define setjmp(jmploc) _setjmp(jmploc)
 #define longjmp(jmploc, val)   _longjmp(jmploc, val)
 #endif
-#endif
-
-/*
- * $PchId: error.h,v 1.5 2006/04/10 14:36:43 philip Exp $
- */
similarity index 58%
rename from minix/commands/ash/eval.c
rename to bin/sh/eval.c
index 4c1df9c55997f4a64bf1c109443288e4b8bcba46..a22819b52cc6c06a9f24a8d6c97a225dcde50da0 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: eval.c,v 1.107 2013/06/27 23:22:04 yamt Exp $  */
+
 /*-
  * Copyright (c) 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)eval.c     8.9 (Berkeley) 6/8/95";
+#else
+__RCSID("$NetBSD: eval.c,v 1.107 2013/06/27 23:22:04 yamt Exp $");
 #endif
 #endif /* not lint */
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/eval.c,v 1.42 2004/04/06 20:06:51 markm Exp $");
-*/
 
-#ifndef NO_PATHS_H
-#include <paths.h>
-#endif
-#include <signal.h>
+#include <stdbool.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <sys/wait.h> /* For WIFSIGNALED(status) */
+#include <signal.h>
+#include <stdio.h>
 #include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/sysctl.h>
 
 /*
  * Evaluate a command.
@@ -72,33 +78,32 @@ __FBSDID("$FreeBSD: src/bin/sh/eval.c,v 1.42 2004/04/06 20:06:51 markm Exp $");
 #include "error.h"
 #include "show.h"
 #include "mystring.h"
-#if !defined(NO_HISTORY)
+#include "main.h"
+#ifndef SMALL
 #include "myhistedit.h"
 #endif
 
-#ifndef _PATH_STDPATH
-#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin:"
-#endif
 
 /* flags in argument to evaltree */
 #define EV_EXIT 01             /* exit after evaluating tree */
 #define EV_TESTED 02           /* exit status is checked; ignore -e flag */
 #define EV_BACKCMD 04          /* command executing within back quotes */
 
-MKINIT int evalskip;           /* set if we are skipping commands */
+int evalskip;                  /* set if we are skipping commands */
 STATIC int skipcount;          /* number of levels to skip */
 MKINIT int loopnest;           /* current loop nesting level */
 int funcnest;                  /* depth of function calls */
+STATIC int builtin_flags;      /* evalcommand flags for builtins */
 
 
-char *commandname;
+const char *commandname;
 struct strlist *cmdenviron;
 int exitstatus;                        /* exit status of last command */
-int oexitstatus;               /* saved exit status */
+int back_exitstatus;           /* exit status of backquoted command */
 
 
-STATIC void evalloop(union node *);
-STATIC void evalfor(union node *);
+STATIC void evalloop(union node *, int);
+STATIC void evalfor(union node *, int);
 STATIC void evalcase(union node *, int);
 STATIC void evalsubshell(union node *, int);
 STATIC void expredir(union node *);
@@ -125,10 +130,35 @@ SHELLPROC {
 }
 #endif
 
+static int
+sh_pipe(int fds[2])
+{
+       int nfd;
+
+       if (pipe(fds))
+               return -1;
+
+       if (fds[0] < 3) {
+               nfd = fcntl(fds[0], F_DUPFD, 3);
+               if (nfd != -1) {
+                       close(fds[0]);
+                       fds[0] = nfd;
+               }
+       }
+
+       if (fds[1] < 3) {
+               nfd = fcntl(fds[1], F_DUPFD, 3);
+               if (nfd != -1) {
+                       close(fds[1]);
+                       fds[1] = nfd;
+               }
+       }
+       return 0;
+}
 
 
 /*
- * The eval command.
+ * The eval commmand.
  */
 
 int
@@ -153,7 +183,7 @@ evalcmd(int argc, char **argv)
                         STPUTC('\0', concat);
                         p = grabstackstr(concat);
                 }
-                evalstring(p);
+                evalstring(p, builtin_flags & EV_TESTED);
         }
         return exitstatus;
 }
@@ -164,15 +194,16 @@ evalcmd(int argc, char **argv)
  */
 
 void
-evalstring(char *s)
+evalstring(char *s, int flag)
 {
        union node *n;
        struct stackmark smark;
 
        setstackmark(&smark);
        setinputstring(s, 1);
+
        while ((n = parsecmd(0)) != NEOF) {
-               evaltree(n, 0);
+               evaltree(n, flag);
                popstackmark(&smark);
        }
        popfile();
@@ -189,27 +220,30 @@ evalstring(char *s)
 void
 evaltree(union node *n, int flags)
 {
+       bool do_etest;
+
+       do_etest = false;
        if (n == NULL) {
                TRACE(("evaltree(NULL) called\n"));
                exitstatus = 0;
                goto out;
        }
-#if !defined(NO_HISTORY)
+#ifndef SMALL
        displayhist = 1;        /* show history substitutions done with fc */
 #endif
-       TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
+       TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
+           getpid(), n, n->type, flags));
        switch (n->type) {
        case NSEMI:
-               evaltree(n->nbinary.ch1, 0);
+               evaltree(n->nbinary.ch1, flags & EV_TESTED);
                if (evalskip)
                        goto out;
                evaltree(n->nbinary.ch2, flags);
                break;
        case NAND:
                evaltree(n->nbinary.ch1, EV_TESTED);
-               if (evalskip || exitstatus != 0) {
+               if (evalskip || exitstatus != 0)
                        goto out;
-               }
                evaltree(n->nbinary.ch2, flags);
                break;
        case NOR:
@@ -226,6 +260,7 @@ evaltree(union node *n, int flags)
                break;
        case NSUBSHELL:
                evalsubshell(n, flags);
+               do_etest = !(flags & EV_TESTED);
                break;
        case NBACKGND:
                evalsubshell(n, flags);
@@ -244,10 +279,10 @@ evaltree(union node *n, int flags)
        }
        case NWHILE:
        case NUNTIL:
-               evalloop(n);
+               evalloop(n, flags);
                break;
        case NFOR:
-               evalfor(n);
+               evalfor(n, flags);
                break;
        case NCASE:
                evalcase(n, flags);
@@ -260,12 +295,13 @@ evaltree(union node *n, int flags)
                evaltree(n->nnot.com, EV_TESTED);
                exitstatus = !exitstatus;
                break;
-
        case NPIPE:
                evalpipe(n);
+               do_etest = !(flags & EV_TESTED);
                break;
        case NCMD:
-               evalcommand(n, flags, (struct backcmd *)NULL);
+               evalcommand(n, flags, NULL);
+               do_etest = !(flags & EV_TESTED);
                break;
        default:
                out1fmt("Node type = %d\n", n->type);
@@ -275,15 +311,13 @@ evaltree(union node *n, int flags)
 out:
        if (pendingsigs)
                dotrap();
-       if ((flags & EV_EXIT) || (eflag && exitstatus 
-           && !(flags & EV_TESTED) && (n->type == NCMD || 
-           n->type == NSUBSHELL)))
+       if ((flags & EV_EXIT) != 0 || (eflag && exitstatus != 0 && do_etest))
                exitshell(exitstatus);
 }
 
 
 STATIC void
-evalloop(union node *n)
+evalloop(union node *n, int flags)
 {
        int status;
 
@@ -307,7 +341,7 @@ skipping:     if (evalskip == SKIPCONT && --skipcount <= 0) {
                        if (exitstatus == 0)
                                break;
                }
-               evaltree(n->nbinary.ch2, 0);
+               evaltree(n->nbinary.ch2, flags & EV_TESTED);
                status = exitstatus;
                if (evalskip)
                        goto skipping;
@@ -319,28 +353,28 @@ skipping:   if (evalskip == SKIPCONT && --skipcount <= 0) {
 
 
 STATIC void
-evalfor(union node *n)
+evalfor(union node *n, int flags)
 {
        struct arglist arglist;
        union node *argp;
        struct strlist *sp;
        struct stackmark smark;
+       int status = 0;
 
        setstackmark(&smark);
        arglist.lastp = &arglist.list;
        for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
-               oexitstatus = exitstatus;
                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
                if (evalskip)
                        goto out;
        }
        *arglist.lastp = NULL;
 
-       exitstatus = 0;
        loopnest++;
        for (sp = arglist.list ; sp ; sp = sp->next) {
                setvar(n->nfor.var, sp->text, 0);
-               evaltree(n->nfor.body, 0);
+               evaltree(n->nfor.body, flags & EV_TESTED);
+               status = exitstatus;
                if (evalskip) {
                        if (evalskip == SKIPCONT && --skipcount <= 0) {
                                evalskip = 0;
@@ -352,6 +386,7 @@ evalfor(union node *n)
                }
        }
        loopnest--;
+       exitstatus = status;
 out:
        popstackmark(&smark);
 }
@@ -365,22 +400,24 @@ evalcase(union node *n, int flags)
        union node *patp;
        struct arglist arglist;
        struct stackmark smark;
+       int status = 0;
 
        setstackmark(&smark);
        arglist.lastp = &arglist.list;
-       oexitstatus = exitstatus;
        expandarg(n->ncase.expr, &arglist, EXP_TILDE);
        for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
                for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
                        if (casematch(patp, arglist.list->text)) {
                                if (evalskip == 0) {
                                        evaltree(cp->nclist.body, flags);
+                                       status = exitstatus;
                                }
                                goto out;
                        }
                }
        }
 out:
+       exitstatus = status;
        popstackmark(&smark);
 }
 
@@ -397,18 +434,19 @@ evalsubshell(union node *n, int flags)
        int backgnd = (n->type == NBACKGND);
 
        expredir(n->nredir.redirect);
+       INTOFF;
        jp = makejob(n, 1);
-       if (forkshell(jp, n, backgnd) == 0) {
+       if (forkshell(jp, n, backgnd ? FORK_BG : FORK_FG) == 0) {
+               INTON;
                if (backgnd)
                        flags &=~ EV_TESTED;
                redirect(n->nredir.redirect, 0);
-               evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
-       }
-       if (! backgnd) {
-               INTOFF;
-               exitstatus = waitforjob(jp, (int *)NULL);
-               INTON;
+               /* never returns */
+               evaltree(n->nredir.n, flags | EV_EXIT);
        }
+       if (! backgnd)
+               exitstatus = waitforjob(jp);
+       INTON;
 }
 
 
@@ -425,13 +463,12 @@ expredir(union node *n)
        for (redir = n ; redir ; redir = redir->nfile.next) {
                struct arglist fn;
                fn.lastp = &fn.list;
-               oexitstatus = exitstatus;
                switch (redir->type) {
+               case NFROMTO:
                case NFROM:
                case NTO:
-               case NFROMTO:
-               case NAPPEND:
                case NCLOBBER:
+               case NAPPEND:
                        expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
                        redir->nfile.expfname = fn.list->text;
                        break;
@@ -475,22 +512,24 @@ evalpipe(union node *n)
                prehash(lp->n);
                pip[1] = -1;
                if (lp->next) {
-                       if (pipe(pip) < 0) {
-                               close(prevfd);
-                               error("Pipe call failed: %s", strerror(errno));
+                       if (sh_pipe(pip) < 0) {
+                               if (prevfd >= 0)
+                                       close(prevfd);
+                               error("Pipe call failed");
                        }
                }
-               if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
+               if (forkshell(jp, lp->n, n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) {
                        INTON;
                        if (prevfd > 0) {
-                               dup2(prevfd, 0);
+                               close(0);
+                               copyfd(prevfd, 0, 1);
                                close(prevfd);
                        }
                        if (pip[1] >= 0) {
-                               if (!(prevfd >= 0 && pip[0] == 0))
-                                       close(pip[0]);
+                               close(pip[0]);
                                if (pip[1] != 1) {
-                                       dup2(pip[1], 1);
+                                       close(1);
+                                       copyfd(pip[1], 1, 1);
                                        close(pip[1]);
                                }
                        }
@@ -501,13 +540,11 @@ evalpipe(union node *n)
                prevfd = pip[0];
                close(pip[1]);
        }
-       INTON;
        if (n->npipe.backgnd == 0) {
-               INTOFF;
-               exitstatus = waitforjob(jp, (int *)NULL);
+               exitstatus = waitforjob(jp);
                TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
-               INTON;
        }
+       INTON;
 }
 
 
@@ -532,102 +569,185 @@ evalbackcmd(union node *n, struct backcmd *result)
        result->nleft = 0;
        result->jp = NULL;
        if (n == NULL) {
-               exitstatus = 0;
                goto out;
        }
+#ifdef notyet
+       /*
+        * For now we disable executing builtins in the same
+        * context as the shell, because we are not keeping
+        * enough state to recover from changes that are
+        * supposed only to affect subshells. eg. echo "`cd /`"
+        */
        if (n->type == NCMD) {
                exitstatus = oexitstatus;
                evalcommand(n, EV_BACKCMD, result);
-       } else {
-               exitstatus = 0;
-               if (pipe(pip) < 0)
-                       error("Pipe call failed: %s", strerror(errno));
+       } else
+#endif
+       {
+               INTOFF;
+               if (sh_pipe(pip) < 0)
+                       error("Pipe call failed");
                jp = makejob(n, 1);
                if (forkshell(jp, n, FORK_NOJOB) == 0) {
                        FORCEINTON;
                        close(pip[0]);
                        if (pip[1] != 1) {
-                               dup2(pip[1], 1);
+                               close(1);
+                               copyfd(pip[1], 1, 1);
                                close(pip[1]);
                        }
+                       eflag = 0;
                        evaltree(n, EV_EXIT);
+                       /* NOTREACHED */
                }
                close(pip[1]);
                result->fd = pip[0];
                result->jp = jp;
+               INTON;
        }
 out:
        popstackmark(&smark);
-       TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
+       TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
                result->fd, result->buf, result->nleft, result->jp));
 }
 
+static const char *
+syspath(void)
+{
+#if !defined(__minix)
+       static char *sys_path = NULL;
+       static int mib[] = {CTL_USER, USER_CS_PATH};
+#endif /* !defined(__minix) */
+       static char def_path[] = "PATH=/usr/bin:/bin:/usr/sbin:/sbin";
+#if !defined(__minix)
+       size_t len;
+
+       if (sys_path == NULL) {
+               if (sysctl(mib, 2, 0, &len, 0, 0) != -1 &&
+                   (sys_path = ckmalloc(len + 5)) != NULL &&
+                   sysctl(mib, 2, sys_path + 5, &len, 0, 0) != -1) {
+                       memcpy(sys_path, "PATH=", 5);
+               } else {
+                       ckfree(sys_path);
+                       /* something to keep things happy */
+                       sys_path = def_path;
+               }
+       }
+       return sys_path;
+#else
+       /* On Minix no support for CTL_USER. */
+       return def_path;
+#endif /* !defined(__minix) */
+}
+
+static int
+parse_command_args(int argc, char **argv, int *use_syspath)
+{
+       int sv_argc = argc;
+       char *cp, c;
+
+       *use_syspath = 0;
+
+       for (;;) {
+               argv++;
+               if (--argc == 0)
+                       break;
+               cp = *argv;
+               if (*cp++ != '-')
+                       break;
+               if (*cp == '-' && cp[1] == 0) {
+                       argv++;
+                       argc--;
+                       break;
+               }
+               while ((c = *cp++)) {
+                       switch (c) {
+                       case 'p':
+                               *use_syspath = 1;
+                               break;
+                       default:
+                               /* run 'typecmd' for other options */
+                               return 0;
+                       }
+               }
+       }
+       return sv_argc - argc;
+}
 
+int vforked = 0;
+extern char *trap[];
 
 /*
  * Execute a simple command.
  */
 
 STATIC void
-evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
+evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
 {
        struct stackmark smark;
        union node *argp;
        struct arglist arglist;
        struct arglist varlist;
-       char **argv;
-       int argc;
+       volatile int flags = flgs;
+       char ** volatile argv;
+       volatile int argc;
        char **envp;
        int varflag;
        struct strlist *sp;
-       int mode;
+       volatile int mode;
        int pip[2];
        struct cmdentry cmdentry;
-       struct job *jp;
+       struct job * volatile jp;
        struct jmploc jmploc;
-       struct jmploc *volatile savehandler;
-       char *volatile savecmdname;
+       struct jmploc *volatile savehandler = NULL;
+       const char *volatile savecmdname;
        volatile struct shparam saveparam;
        struct localvar *volatile savelocalvars;
        volatile int e;
-       char *lastarg;
-       int realstatus;
-       int do_clearcmdentry;
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &argv;
-       (void) &argc;
-       (void) &lastarg;
-       (void) &flags;
-       (void) &do_clearcmdentry;
-#endif
+       char * volatile lastarg;
+       const char * volatile path = pathval();
+       volatile int temp_path;
 
+       vforked = 0;
        /* First expand the arguments. */
        TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
        setstackmark(&smark);
+       back_exitstatus = 0;
+
        arglist.lastp = &arglist.list;
-       varlist.lastp = &varlist.list;
        varflag = 1;
-       do_clearcmdentry = 0;
-       oexitstatus = exitstatus;
-       exitstatus = 0;
+       /* Expand arguments, ignoring the initial 'name=value' ones */
        for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
                char *p = argp->narg.text;
                if (varflag && is_name(*p)) {
                        do {
                                p++;
                        } while (is_in_name(*p));
-                       if (*p == '=') {
-                               expandarg(argp, &varlist, EXP_VARTILDE);
+                       if (*p == '=')
                                continue;
-                       }
                }
                expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
                varflag = 0;
        }
        *arglist.lastp = NULL;
-       *varlist.lastp = NULL;
+
        expredir(cmd->ncmd.redirect);
+
+       /* Now do the initial 'name=value' ones we skipped above */
+       varlist.lastp = &varlist.list;
+       for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
+               char *p = argp->narg.text;
+               if (!is_name(*p))
+                       break;
+               do
+                       p++;
+               while (is_in_name(*p));
+               if (*p != '=')
+                       break;
+               expandarg(argp, &varlist, EXP_VARTILDE);
+       }
+       *varlist.lastp = NULL;
+
        argc = 0;
        for (sp = arglist.list ; sp ; sp = sp->next)
                argc++;
@@ -645,14 +765,19 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
 
        /* Print the command if xflag is set. */
        if (xflag) {
-               outc('+', &errout);
+               char sep = 0;
+               out2str(ps4val());
                for (sp = varlist.list ; sp ; sp = sp->next) {
-                       outc(' ', &errout);
-                       out2str(sp->text);
+                       if (sep != 0)
+                               outc(sep, &errout);
+                       out2shstr(sp->text);
+                       sep = ' ';
                }
                for (sp = arglist.list ; sp ; sp = sp->next) {
-                       outc(' ', &errout);
-                       out2str(sp->text);
+                       if (sep != 0)
+                               outc(sep, &errout);
+                       out2shstr(sp->text);
+                       sep = ' ';
                }
                outc('\n', &errout);
                flushout(&errout);
@@ -660,90 +785,136 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
 
        /* Now locate the command. */
        if (argc == 0) {
-               cmdentry.cmdtype = CMDBUILTIN;
-               cmdentry.u.index = BLTINCMD;
+               cmdentry.cmdtype = CMDSPLBLTIN;
+               cmdentry.u.bltin = bltincmd;
        } else {
                static const char PATH[] = "PATH=";
-               char *path = pathval();
+               int cmd_flags = DO_ERR;
 
                /*
                 * Modify the command lookup path, if a PATH= assignment
                 * is present
                 */
-               for (sp = varlist.list ; sp ; sp = sp->next)
-                       if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) {
+               for (sp = varlist.list; sp; sp = sp->next)
+                       if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
                                path = sp->text + sizeof(PATH) - 1;
-                               /* 
-                                * On `PATH=... command`, we need to make
-                                * sure that the command isn't using the
-                                * non-updated hash table of the outer PATH
-                                * setting and we need to make sure that 
-                                * the hash table isn't filled with items
-                                * from the temporary setting.
-                                *
-                                * It would be better to forbit using and 
-                                * updating the table while this command
-                                * runs, by the command finding mechanism
-                                * is heavily integrated with hash handling,
-                                * so we just delete the hash before and after
-                                * the command runs. Partly deleting like
-                                * changepatch() does doesn't seem worth the
-                                * bookinging effort, since most such runs add
-                                * directories in front of the new PATH.
-                                */
-                               clearcmdentry(0);
-                               do_clearcmdentry = 1;
+
+               do {
+                       int argsused, use_syspath;
+                       find_command(argv[0], &cmdentry, cmd_flags, path);
+                       if (cmdentry.cmdtype == CMDUNKNOWN) {
+                               exitstatus = 127;
+                               flushout(&errout);
+                               goto out;
                        }
 
-               find_command(argv[0], &cmdentry, 1, path);
-               if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
-                       exitstatus = 127;
-                       flushout(&errout);
-                       return;
-               }
-               /* implement the bltin builtin here */
-               if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
-                       for (;;) {
-                               argv++;
-                               if (--argc == 0)
-                                       break;
-                               if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
-                                       outfmt(&errout, "%s: not found\n", *argv);
-                                       exitstatus = 127;
-                                       flushout(&errout);
-                                       return;
-                               }
-                               if (cmdentry.u.index != BLTINCMD)
-                                       break;
+                       /* implement the 'command' builtin here */
+                       if (cmdentry.cmdtype != CMDBUILTIN ||
+                           cmdentry.u.bltin != bltincmd)
+                               break;
+                       cmd_flags |= DO_NOFUNC;
+                       argsused = parse_command_args(argc, argv, &use_syspath);
+                       if (argsused == 0) {
+                               /* use 'type' builting to display info */
+                               cmdentry.u.bltin = typecmd;
+                               break;
                        }
-               }
+                       argc -= argsused;
+                       argv += argsused;
+                       if (use_syspath)
+                               path = syspath() + 5;
+               } while (argc != 0);
+               if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC)
+                       /* posix mandates that 'command <splbltin>' act as if
+                          <splbltin> was a normal builtin */
+                       cmdentry.cmdtype = CMDBUILTIN;
        }
 
        /* Fork off a child process if necessary. */
-       if (cmd->ncmd.backgnd
-        || (cmdentry.cmdtype == CMDNORMAL
-           && ((flags & EV_EXIT) == 0 || Tflag))
+       if (cmd->ncmd.backgnd || (trap[0] && (flags & EV_EXIT) != 0)
+        || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
         || ((flags & EV_BACKCMD) != 0
-           && (cmdentry.cmdtype != CMDBUILTIN
-                || cmdentry.u.index == CDCMD
-                || cmdentry.u.index == DOTCMD
-                || cmdentry.u.index == EVALCMD))
-        || (cmdentry.cmdtype == CMDBUILTIN &&
-           cmdentry.u.index == COMMANDCMD)) {
+           && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN)
+                || cmdentry.u.bltin == dotcmd
+                || cmdentry.u.bltin == evalcmd))) {
+               INTOFF;
                jp = makejob(cmd, 1);
                mode = cmd->ncmd.backgnd;
                if (flags & EV_BACKCMD) {
                        mode = FORK_NOJOB;
-                       if (pipe(pip) < 0)
-                               error("Pipe call failed: %s", strerror(errno));
+                       if (sh_pipe(pip) < 0)
+                               error("Pipe call failed");
                }
-               if (forkshell(jp, cmd, mode) != 0)
-                       goto parent;    /* at end of routine */
-               if (flags & EV_BACKCMD) {
+#ifdef DO_SHAREDVFORK
+               /* It is essential that if DO_SHAREDVFORK is defined that the
+                * child's address space is actually shared with the parent as
+                * we rely on this.
+                */
+               if (cmdentry.cmdtype == CMDNORMAL) {
+                       pid_t   pid;
+
+                       savelocalvars = localvars;
+                       localvars = NULL;
+                       vforked = 1;
+                       switch (pid = vfork()) {
+                       case -1:
+                               TRACE(("Vfork failed, errno=%d\n", errno));
+                               INTON;
+                               error("Cannot vfork");
+                               break;
+                       case 0:
+                               /* Make sure that exceptions only unwind to
+                                * after the vfork(2)
+                                */
+                               if (setjmp(jmploc.loc)) {
+                                       if (exception == EXSHELLPROC) {
+                                               /* We can't progress with the vfork,
+                                                * so, set vforked = 2 so the parent
+                                                * knows, and _exit();
+                                                */
+                                               vforked = 2;
+                                               _exit(0);
+                                       } else {
+                                               _exit(exerrno);
+                                       }
+                               }
+                               savehandler = handler;
+                               handler = &jmploc;
+                               listmklocal(varlist.list, VEXPORT | VNOFUNC);
+                               forkchild(jp, cmd, mode, vforked);
+                               break;
+                       default:
+                               handler = savehandler;  /* restore from vfork(2) */
+                               poplocalvars();
+                               localvars = savelocalvars;
+                               if (vforked == 2) {
+                                       vforked = 0;
+
+                                       (void)waitpid(pid, NULL, 0);
+                                       /* We need to progress in a normal fork fashion */
+                                       goto normal_fork;
+                               }
+                               vforked = 0;
+                               forkparent(jp, cmd, mode, pid);
+                               goto parent;
+                       }
+               } else {
+normal_fork:
+#endif
+                       if (forkshell(jp, cmd, mode) != 0)
+                               goto parent;    /* at end of routine */
                        FORCEINTON;
+#ifdef DO_SHAREDVFORK
+               }
+#endif
+               if (flags & EV_BACKCMD) {
+                       if (!vforked) {
+                               FORCEINTON;
+                       }
                        close(pip[0]);
                        if (pip[1] != 1) {
-                               dup2(pip[1], 1);
+                               close(1);
+                               copyfd(pip[1], 1, 1);
                                close(pip[1]);
                        }
                }
@@ -752,8 +923,9 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
 
        /* This is the child process if a fork occurred. */
        /* Execute the command. */
-       if (cmdentry.cmdtype == CMDFUNCTION) {
-#if DEBUG
+       switch (cmdentry.cmdtype) {
+       case CMDFUNCTION:
+#ifdef DEBUG
                trputs("Shell function:  ");  trargs(argv);
 #endif
                redirect(cmd->ncmd.redirect, REDIR_PUSH);
@@ -768,9 +940,10 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
                localvars = NULL;
                INTON;
                if (setjmp(jmploc.loc)) {
-                       if (exception == EXSHELLPROC)
-                               freeparam((struct shparam *)&saveparam);
-                       else {
+                       if (exception == EXSHELLPROC) {
+                               freeparam((volatile struct shparam *)
+                                   &saveparam);
+                       } else {
                                freeparam(&shellparam);
                                shellparam = saveparam;
                        }
@@ -781,13 +954,11 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
                }
                savehandler = handler;
                handler = &jmploc;
-               for (sp = varlist.list ; sp ; sp = sp->next)
-                       mklocal(sp->text);
-               funcnest++;
-               if (flags & EV_TESTED)
-                       evaltree(cmdentry.u.func, EV_TESTED);
-               else
-                       evaltree(cmdentry.u.func, 0);
+               listmklocal(varlist.list, VEXPORT);
+               /* stop shell blowing its stack */
+               if (++funcnest > 1000)
+                       error("too many nested function calls");
+               evaltree(cmdentry.u.func, flags & EV_TESTED);
                funcnest--;
                INTOFF;
                poplocalvars();
@@ -803,104 +974,123 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
                }
                if (flags & EV_EXIT)
                        exitshell(exitstatus);
-       } else if (cmdentry.cmdtype == CMDBUILTIN) {
-#if DEBUG
+               break;
+
+       case CMDBUILTIN:
+       case CMDSPLBLTIN:
+#ifdef DEBUG
                trputs("builtin command:  ");  trargs(argv);
 #endif
-               mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
+               mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH;
                if (flags == EV_BACKCMD) {
                        memout.nleft = 0;
                        memout.nextc = memout.buf;
                        memout.bufsize = 64;
                        mode |= REDIR_BACKQ;
                }
-               redirect(cmd->ncmd.redirect, mode);
-               savecmdname = commandname;
-               cmdenviron = varlist.list;
                e = -1;
-               if (setjmp(jmploc.loc)) {
-                       e = exception;
-                       exitstatus = (e == EXINT)? SIGINT+128 : 2;
-                       goto cmddone;
-               }
                savehandler = handler;
+               savecmdname = commandname;
                handler = &jmploc;
-               commandname = argv[0];
-               argptr = argv + 1;
-               optptr = NULL;                  /* initialize nextopt */
-               exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
+               temp_path = 0;
+               if (!setjmp(jmploc.loc)) {
+                       /* We need to ensure the command hash table isn't
+                        * corruped by temporary PATH assignments.
+                        * However we must ensure the 'local' command works!
+                        */
+                       if (path != pathval() && (cmdentry.u.bltin == hashcmd ||
+                           cmdentry.u.bltin == typecmd)) {
+                               savelocalvars = localvars;
+                               localvars = 0;
+                               temp_path = 1;
+                               mklocal(path - 5 /* PATH= */, 0);
+                       }
+                       redirect(cmd->ncmd.redirect, mode);
+
+                       /* exec is a special builtin, but needs this list... */
+                       cmdenviron = varlist.list;
+                       /* we must check 'readonly' flag for all builtins */
+                       listsetvar(varlist.list,
+                               cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET);
+                       commandname = argv[0];
+                       /* initialize nextopt */
+                       argptr = argv + 1;
+                       optptr = NULL;
+                       /* and getopt */
+                       optreset = 1;
+                       optind = 1;
+                       builtin_flags = flags;
+                       exitstatus = cmdentry.u.bltin(argc, argv);
+               } else {
+                       e = exception;
+                       exitstatus = e == EXINT ? SIGINT + 128 :
+                                       e == EXEXEC ? exerrno : 2;
+               }
+               handler = savehandler;
                flushall();
-cmddone:
-               cmdenviron = NULL;
                out1 = &output;
                out2 = &errout;
                freestdout();
+               if (temp_path) {
+                       poplocalvars();
+                       localvars = savelocalvars;
+               }
+               cmdenviron = NULL;
                if (e != EXSHELLPROC) {
                        commandname = savecmdname;
-                       if (flags & EV_EXIT) {
+                       if (flags & EV_EXIT)
                                exitshell(exitstatus);
-                       }
                }
-               handler = savehandler;
                if (e != -1) {
                        if ((e != EXERROR && e != EXEXEC)
-                          || cmdentry.u.index == BLTINCMD
-                          || cmdentry.u.index == DOTCMD
-                          || cmdentry.u.index == EVALCMD
-#ifndef NO_HISTORY
-                          || cmdentry.u.index == HISTCMD
-#endif
-                          || cmdentry.u.index == EXECCMD
-                          || cmdentry.u.index == COMMANDCMD)
+                           || cmdentry.cmdtype == CMDSPLBLTIN)
                                exraise(e);
                        FORCEINTON;
                }
-               if (cmdentry.u.index != EXECCMD)
+               if (cmdentry.u.bltin != execcmd)
                        popredir();
                if (flags == EV_BACKCMD) {
                        backcmd->buf = memout.buf;
                        backcmd->nleft = memout.nextc - memout.buf;
                        memout.buf = NULL;
                }
-       } else {
-#if DEBUG
+               break;
+
+       default:
+#ifdef DEBUG
                trputs("normal command:  ");  trargs(argv);
 #endif
-               clearredir();
-               redirect(cmd->ncmd.redirect, 0);
-               for (sp = varlist.list ; sp ; sp = sp->next)
-                       setvareq(sp->text, VEXPORT|VSTACK);
+               redirect(cmd->ncmd.redirect, vforked ? REDIR_VFORK : 0);
+               if (!vforked)
+                       for (sp = varlist.list ; sp ; sp = sp->next)
+                               setvareq(sp->text, VEXPORT|VSTACK);
                envp = environment();
-               shellexec(argv, envp, pathval(), cmdentry.u.index);
-               /*NOTREACHED*/
+               shellexec(argv, envp, path, cmdentry.u.index, vforked);
+               break;
        }
        goto out;
 
 parent:        /* parent process gets here (if we forked) */
-       if (mode == 0) {        /* argument to fork */
-               INTOFF;
-               exitstatus = waitforjob(jp, &realstatus);
-               INTON;
-               if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) {
-                       evalskip = SKIPBREAK;
-                       skipcount = loopnest;
-               }
-       } else if (mode == 2) {
+       if (mode == FORK_FG) {  /* argument to fork */
+               exitstatus = waitforjob(jp);
+       } else if (mode == FORK_NOJOB) {
                backcmd->fd = pip[0];
                close(pip[1]);
                backcmd->jp = jp;
        }
+       FORCEINTON;
 
 out:
        if (lastarg)
+               /* dsl: I think this is intended to be used to support
+                * '_' in 'vi' command mode during line editing...
+                * However I implemented that within libedit itself.
+                */
                setvar("_", lastarg, 0);
-       if (do_clearcmdentry)
-               clearcmdentry(0);
        popstackmark(&smark);
 }
 
 
-
 /*
  * Search for a command.  This is called before we fork so that the
  * location of the command will be available in the parent as well as
@@ -913,7 +1103,7 @@ prehash(union node *n)
 {
        struct cmdentry entry;
 
-       if (n->type == NCMD && n->ncmd.args)
+       if (n && n->type == NCMD && n->ncmd.args)
                if (goodname(n->ncmd.args->narg.text))
                        find_command(n->ncmd.args->narg.text, &entry, 0,
                                     pathval());
@@ -927,19 +1117,17 @@ prehash(union node *n)
  */
 
 /*
- * No command given, or a bltin command with no arguments.  Set the
- * specified variables.
+ * No command given.
  */
 
 int
-bltincmd(int argc __unused, char **argv __unused)
+bltincmd(int argc, char **argv)
 {
-       listsetvar(cmdenviron);
        /*
         * Preserve exitstatus of a previous possible redirection
         * as POSIX mandates
         */
-       return exitstatus;
+       return back_exitstatus;
 }
 
 
@@ -968,55 +1156,6 @@ breakcmd(int argc, char **argv)
        return 0;
 }
 
-/*
- * The `command' command.
- */
-int
-commandcmd(int argc, char **argv)
-{
-       static char stdpath[] = _PATH_STDPATH;
-       struct jmploc loc, *old;
-       struct strlist *sp;
-       char *path;
-       int ch;
-
-       for (sp = cmdenviron; sp ; sp = sp->next)
-               setvareq(sp->text, VEXPORT|VSTACK);
-       path = pathval();
-
-       optind = optreset = 1;
-       opterr = 0;
-       while ((ch = getopt(argc, argv, "p")) != -1) {
-               switch (ch) {
-               case 'p':
-                       path = stdpath;
-                       break;
-               case '?':
-               default:
-                       error("unknown option: -%c", optopt);
-               }
-       }
-       argc -= optind;
-       argv += optind;
-
-       if (argc != 0) {
-               old = handler;
-               handler = &loc;
-               if (setjmp(handler->loc) == 0)
-                       shellexec(argv, environment(), path, 0);
-               handler = old;
-               if (exception == EXEXEC)
-                       exit(exerrno);
-               exraise(exception);
-       }
-
-       /*
-        * Do nothing successfully if no command was specified;
-        * ksh also does this.
-        */
-       exit(0);
-}
-
 
 /*
  * The return command.
@@ -1025,29 +1164,31 @@ commandcmd(int argc, char **argv)
 int
 returncmd(int argc, char **argv)
 {
-       int ret = argc > 1 ? number(argv[1]) : oexitstatus;
+       int ret = argc > 1 ? number(argv[1]) : exitstatus;
 
        if (funcnest) {
                evalskip = SKIPFUNC;
                skipcount = 1;
-       } else {
-               /* skip the rest of the file */
+               return ret;
+       }
+       else {
+               /* Do what ksh does; skip the rest of the file */
                evalskip = SKIPFILE;
                skipcount = 1;
+               return ret;
        }
-       return ret;
 }
 
 
 int
-falsecmd(int argc __unused, char **argv __unused)
+falsecmd(int argc, char **argv)
 {
        return 1;
 }
 
 
 int
-truecmd(int argc __unused, char **argv __unused)
+truecmd(int argc, char **argv)
 {
        return 0;
 }
@@ -1062,14 +1203,58 @@ execcmd(int argc, char **argv)
                iflag = 0;              /* exit on error */
                mflag = 0;
                optschanged();
-               for (sp = cmdenviron; sp ; sp = sp->next)
+               for (sp = cmdenviron; sp; sp = sp->next)
                        setvareq(sp->text, VEXPORT|VSTACK);
-               shellexec(argv + 1, environment(), pathval(), 0);
-
+               shellexec(argv + 1, environment(), pathval(), 0, 0);
        }
        return 0;
 }
 
-/*
- * $PchId: eval.c,v 1.7 2006/04/10 14:46:14 philip Exp $
- */
+static int
+conv_time(clock_t ticks, char *seconds, size_t l)
+{
+       static clock_t tpm = 0;
+       clock_t mins;
+       int i;
+
+       if (!tpm)
+               tpm = sysconf(_SC_CLK_TCK) * 60;
+
+       mins = ticks / tpm;
+       snprintf(seconds, l, "%.4f", (ticks - mins * tpm) * 60.0 / tpm );
+
+       if (seconds[0] == '6' && seconds[1] == '0') {
+               /* 59.99995 got rounded up... */
+               mins++;
+               strlcpy(seconds, "0.0", l);
+               return mins;
+       }
+
+       /* suppress trailing zeros */
+       i = strlen(seconds) - 1;
+       for (; seconds[i] == '0' && seconds[i - 1] != '.'; i--)
+               seconds[i] = 0;
+       return mins;
+}
+
+int
+timescmd(int argc, char **argv)
+{
+       struct tms tms;
+       int u, s, cu, cs;
+       char us[8], ss[8], cus[8], css[8];
+
+       nextopt("");
+
+       times(&tms);
+
+       u = conv_time(tms.tms_utime, us, sizeof(us));
+       s = conv_time(tms.tms_stime, ss, sizeof(ss));
+       cu = conv_time(tms.tms_cutime, cus, sizeof(cus));
+       cs = conv_time(tms.tms_cstime, css, sizeof(css));
+
+       outfmt(out1, "%dm%ss %dm%ss\n%dm%ss %dm%ss\n",
+               u, us, s, ss, cu, cus, cs, css);
+
+       return 0;
+}
similarity index 82%
rename from minix/commands/ash/eval.h
rename to bin/sh/eval.h
index b8b9415b921ca0c53af2f58af06bde218666a1e9..7c0652af13f71f86bb1dd91105a3fa354f14856d 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: eval.h,v 1.15 2008/02/15 17:26:06 matt Exp $   */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)eval.h      8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/eval.h,v 1.10 2004/04/06 20:06:51 markm Exp $
  */
 
-extern char *commandname;      /* currently executing command */
+extern const char *commandname;        /* currently executing command */
 extern int exitstatus;         /* exit status of last command */
+extern int back_exitstatus;    /* exit status of backquoted command */
 extern struct strlist *cmdenviron;  /* environment for builtin command */
 
 
@@ -45,18 +47,10 @@ struct backcmd {            /* result of evalbackcmd */
        struct job *jp;         /* job structure for command */
 };
 
-int evalcmd(int, char **);
-void evalstring(char *);
+void evalstring(char *, int);
 union node;    /* BLETCH for ansi C */
 void evaltree(union node *, int);
 void evalbackcmd(union node *, struct backcmd *);
-int bltincmd(int, char **);
-int breakcmd(int, char **);
-int returncmd(int, char **);
-int falsecmd(int, char **);
-int truecmd(int, char **);
-int execcmd(int, char **);
-int commandcmd(int, char **);
 
 /* in_function returns nonzero if we are currently evaluating a function */
 #define in_function()  funcnest
@@ -68,7 +62,3 @@ extern int evalskip;
 #define SKIPCONT       2
 #define SKIPFUNC       3
 #define SKIPFILE       4
-
-/*
- * $PchId: eval.h,v 1.3 2006/03/30 15:39:25 philip Exp $
- */
similarity index 57%
rename from minix/commands/ash/exec.c
rename to bin/sh/exec.c
index e6a12e9adf5a71f9df1a5a12ac48ca4fda12f258..739f51b7a07254ca16434dd3ee0be1fc39ef397a 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: exec.c,v 1.45 2013/11/01 16:49:02 christos Exp $       */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)exec.c     8.4 (Berkeley) 6/8/95";
+#else
+__RCSID("$NetBSD: exec.c,v 1.45 2013/11/01 16:49:02 christos Exp $");
 #endif
 #endif /* not lint */
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/exec.c,v 1.24.2.1 2004/09/30 04:41:55 des Exp $");
-*/
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 
 /*
@@ -97,33 +100,38 @@ STATIC int builtinloc = -1;                /* index in path of %builtin, or -1 */
 int exerrno = 0;                       /* Last exec error */
 
 
-STATIC void tryexec(char *, char **, char **);
+STATIC void tryexec(char *, char **, char **, int);
 STATIC void printentry(struct tblentry *, int);
-STATIC struct tblentry *cmdlookup(char *, int);
+STATIC void clearcmdentry(int);
+STATIC struct tblentry *cmdlookup(const char *, int);
 STATIC void delete_cmd_entry(void);
-STATIC void addcmdentry(char *, struct cmdentry *);
 
+#ifndef BSD
+STATIC void execinterp(char **, char **);
+#endif
 
 
+extern const char *const parsekwd[];
+
 /*
  * Exec a program.  Never returns.  If you change this routine, you may
  * have to change the find_command routine as well.
  */
 
 void
-shellexec(char **argv, char **envp, char *path, int index)
+shellexec(char **argv, char **envp, const char *path, int idx, int vforked)
 {
        char *cmdname;
        int e;
 
        if (strchr(argv[0], '/') != NULL) {
-               tryexec(argv[0], argv, envp);
+               tryexec(argv[0], argv, envp, vforked);
                e = errno;
        } else {
                e = ENOENT;
                while ((cmdname = padvance(&path, argv[0])) != NULL) {
-                       if (--index < 0 && pathopt == NULL) {
-                               tryexec(cmdname, argv, envp);
+                       if (--idx < 0 && pathopt == NULL) {
+                               tryexec(cmdname, argv, envp, vforked);
                                if (errno != ENOENT && errno != ENOTDIR)
                                        e = errno;
                        }
@@ -143,31 +151,137 @@ shellexec(char **argv, char **envp, char *path, int index)
                exerrno = 2;
                break;
        }
-       if (e == ENOENT || e == ENOTDIR)
-               exerror(EXEXEC, "%s: not found", argv[0]);
-       exerror(EXEXEC, "%s: %s", argv[0], strerror(e));
+       TRACE(("shellexec failed for %s, errno %d, vforked %d, suppressint %d\n",
+               argv[0], e, vforked, suppressint ));
+       exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
+       /* NOTREACHED */
 }
 
 
 STATIC void
-tryexec(char *cmd, char **argv, char **envp)
+tryexec(char *cmd, char **argv, char **envp, int vforked)
 {
        int e;
+#ifndef BSD
+       char *p;
+#endif
 
+#ifdef SYSV
+       do {
+               execve(cmd, argv, envp);
+       } while (errno == EINTR);
+#else
        execve(cmd, argv, envp);
-
+#endif
        e = errno;
        if (e == ENOEXEC) {
+               if (vforked) {
+                       /* We are currently vfork(2)ed, so raise an
+                        * exception, and evalcommand will try again
+                        * with a normal fork(2).
+                        */
+                       exraise(EXSHELLPROC);
+               }
+#ifdef DEBUG
+               TRACE(("execve(cmd=%s) returned ENOEXEC\n", cmd));
+#endif
                initshellproc();
                setinputfile(cmd, 0);
                commandname = arg0 = savestr(argv[0]);
+#ifndef BSD
+               pgetc(); pungetc();             /* fill up input buffer */
+               p = parsenextc;
+               if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
+                       argv[0] = cmd;
+                       execinterp(argv, envp);
+               }
+#endif
                setparam(argv + 1);
                exraise(EXSHELLPROC);
-               /*NOTREACHED*/
        }
        errno = e;
 }
 
+
+#ifndef BSD
+/*
+ * Execute an interpreter introduced by "#!", for systems where this
+ * feature has not been built into the kernel.  If the interpreter is
+ * the shell, return (effectively ignoring the "#!").  If the execution
+ * of the interpreter fails, exit.
+ *
+ * This code peeks inside the input buffer in order to avoid actually
+ * reading any input.  It would benefit from a rewrite.
+ */
+
+#define NEWARGS 5
+
+STATIC void
+execinterp(char **argv, char **envp)
+{
+       int n;
+       char *inp;
+       char *outp;
+       char c;
+       char *p;
+       char **ap;
+       char *newargs[NEWARGS];
+       int i;
+       char **ap2;
+       char **new;
+
+       n = parsenleft - 2;
+       inp = parsenextc + 2;
+       ap = newargs;
+       for (;;) {
+               while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
+                       inp++;
+               if (n < 0)
+                       goto bad;
+               if ((c = *inp++) == '\n')
+                       break;
+               if (ap == &newargs[NEWARGS])
+bad:             error("Bad #! line");
+               STARTSTACKSTR(outp);
+               do {
+                       STPUTC(c, outp);
+               } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
+               STPUTC('\0', outp);
+               n++, inp--;
+               *ap++ = grabstackstr(outp);
+       }
+       if (ap == newargs + 1) {        /* if no args, maybe no exec is needed */
+               p = newargs[0];
+               for (;;) {
+                       if (equal(p, "sh") || equal(p, "ash")) {
+                               return;
+                       }
+                       while (*p != '/') {
+                               if (*p == '\0')
+                                       goto break2;
+                               p++;
+                       }
+                       p++;
+               }
+break2:;
+       }
+       i = (char *)ap - (char *)newargs;               /* size in bytes */
+       if (i == 0)
+               error("Bad #! line");
+       for (ap2 = argv ; *ap2++ != NULL ; );
+       new = ckmalloc(i + ((char *)ap2 - (char *)argv));
+       ap = newargs, ap2 = new;
+       while ((i -= sizeof (char **)) >= 0)
+               *ap2++ = *ap++;
+       ap = argv;
+       while (*ap2++ = *ap++);
+       shellexec(new, envp, pathval(), 0);
+       /* NOTREACHED */
+}
+#endif
+
+
+
 /*
  * Do a path search.  The variable path (passed by reference) should be
  * set to the start of the path before the first call; padvance will update
@@ -178,13 +292,14 @@ tryexec(char *cmd, char **argv, char **envp)
  * NULL.
  */
 
-char *pathopt;
+const char *pathopt;
 
 char *
-padvance(char **path, char *name)
+padvance(const char **path, const char *name)
 {
-       char *p, *q;
-       char *start;
+       const char *p;
+       char *q;
+       const char *start;
        int len;
 
        if (*path == NULL)
@@ -219,7 +334,7 @@ padvance(char **path, char *name)
 
 
 int
-hashcmd(int argc __unused, char **argv __unused)
+hashcmd(int argc, char **argv)
 {
        struct tblentry **pp;
        struct tblentry *cmdp;
@@ -239,7 +354,7 @@ hashcmd(int argc __unused, char **argv __unused)
        if (*argptr == NULL) {
                for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
                        for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
-                               if (cmdp->cmdtype == CMDNORMAL)
+                               if (verbose || cmdp->cmdtype == CMDNORMAL)
                                        printentry(cmdp, verbose);
                        }
                }
@@ -250,14 +365,12 @@ hashcmd(int argc __unused, char **argv __unused)
                 && (cmdp->cmdtype == CMDNORMAL
                     || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
                        delete_cmd_entry();
-               find_command(name, &entry, 1, pathval());
+               find_command(name, &entry, DO_ERR, pathval());
                if (verbose) {
                        if (entry.cmdtype != CMDUNKNOWN) {      /* if no error msg */
                                cmdp = cmdlookup(name, 0);
                                if (cmdp != NULL)
                                        printentry(cmdp, verbose);
-                               else
-                                       outfmt(&errout, "%s: not found\n", name);
                        }
                        flushall();
                }
@@ -270,34 +383,40 @@ hashcmd(int argc __unused, char **argv __unused)
 STATIC void
 printentry(struct tblentry *cmdp, int verbose)
 {
-       int index;
-       char *path;
+       int idx;
+       const char *path;
        char *name;
 
-       if (cmdp->cmdtype == CMDNORMAL) {
-               index = cmdp->param.index;
+       switch (cmdp->cmdtype) {
+       case CMDNORMAL:
+               idx = cmdp->param.index;
                path = pathval();
                do {
                        name = padvance(&path, cmdp->cmdname);
                        stunalloc(name);
-               } while (--index >= 0);
+               } while (--idx >= 0);
                out1str(name);
-       } else if (cmdp->cmdtype == CMDBUILTIN) {
+               break;
+       case CMDSPLBLTIN:
+               out1fmt("special builtin %s", cmdp->cmdname);
+               break;
+       case CMDBUILTIN:
                out1fmt("builtin %s", cmdp->cmdname);
-       } else if (cmdp->cmdtype == CMDFUNCTION) {
+               break;
+       case CMDFUNCTION:
                out1fmt("function %s", cmdp->cmdname);
                if (verbose) {
+                       struct procstat ps;
                        INTOFF;
-                       name = commandtext(cmdp->param.func);
-                       out1c(' ');
-                       out1str(name);
-                       ckfree(name);
+                       commandtext(&ps, cmdp->param.func);
                        INTON;
+                       out1str("() { ");
+                       out1str(ps.cmd);
+                       out1str("; }");
                }
-#if DEBUG
-       } else {
-               error("internal error: cmdtype %d", cmdp->cmdtype);
-#endif
+               break;
+       default:
+               error("internal error: %s cmdtype %d", cmdp->cmdname, cmdp->cmdtype);
        }
        if (cmdp->rehash)
                out1c('*');
@@ -312,37 +431,79 @@ printentry(struct tblentry *cmdp, int verbose)
  */
 
 void
-find_command(char *name, struct cmdentry *entry, int printerr, char *path)
+find_command(char *name, struct cmdentry *entry, int act, const char *path)
 {
-       struct tblentry *cmdp;
-       int index;
+       struct tblentry *cmdp, loc_cmd;
+       int idx;
        int prev;
        char *fullname;
        struct stat statb;
        int e;
-       int i;
+       int (*bltin)(int,char **);
 
-       /* If name contains a slash, don't use the hash table */
+       /* If name contains a slash, don't use PATH or hash table */
        if (strchr(name, '/') != NULL) {
+               if (act & DO_ABS) {
+                       while (stat(name, &statb) < 0) {
+#ifdef SYSV
+                               if (errno == EINTR)
+                                       continue;
+#endif
+                               if (errno != ENOENT && errno != ENOTDIR)
+                                       e = errno;
+                               entry->cmdtype = CMDUNKNOWN;
+                               entry->u.index = -1;
+                               return;
+                       }
+                       entry->cmdtype = CMDNORMAL;
+                       entry->u.index = -1;
+                       return;
+               }
                entry->cmdtype = CMDNORMAL;
                entry->u.index = 0;
                return;
        }
 
-       /* If name is in the table, and not invalidated by cd, we're done */
-       if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
-               goto success;
+       if (path != pathval())
+               act |= DO_ALTPATH;
 
-       /* If %builtin not in path, check for builtin next */
-       if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
-               INTOFF;
-               cmdp = cmdlookup(name, 1);
-               cmdp->cmdtype = CMDBUILTIN;
-               cmdp->param.index = i;
-               INTON;
-               goto success;
+       if (act & DO_ALTPATH && strstr(path, "%builtin") != NULL)
+               act |= DO_ALTBLTIN;
+
+       /* If name is in the table, check answer will be ok */
+       if ((cmdp = cmdlookup(name, 0)) != NULL) {
+               do {
+                       switch (cmdp->cmdtype) {
+                       case CMDNORMAL:
+                               if (act & DO_ALTPATH) {
+                                       cmdp = NULL;
+                                       continue;
+                               }
+                               break;
+                       case CMDFUNCTION:
+                               if (act & DO_NOFUNC) {
+                                       cmdp = NULL;
+                                       continue;
+                               }
+                               break;
+                       case CMDBUILTIN:
+                               if ((act & DO_ALTBLTIN) || builtinloc >= 0) {
+                                       cmdp = NULL;
+                                       continue;
+                               }
+                               break;
+                       }
+                       /* if not invalidated by cd, we're done */
+                       if (cmdp->rehash == 0)
+                               goto success;
+               } while (0);
        }
 
+       /* If %builtin not in path, check for builtin next */
+       if ((act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc < 0) &&
+           (bltin = find_builtin(name)) != 0)
+               goto builtin_success;
+
        /* We have to search path. */
        prev = -1;              /* where to start */
        if (cmdp) {             /* doing a rehash */
@@ -353,35 +514,35 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
        }
 
        e = ENOENT;
-       index = -1;
+       idx = -1;
 loop:
        while ((fullname = padvance(&path, name)) != NULL) {
                stunalloc(fullname);
-               index++;
+               idx++;
                if (pathopt) {
                        if (prefix("builtin", pathopt)) {
-                               if ((i = find_builtin(name)) < 0)
+                               if ((bltin = find_builtin(name)) == 0)
                                        goto loop;
-                               INTOFF;
-                               cmdp = cmdlookup(name, 1);
-                               cmdp->cmdtype = CMDBUILTIN;
-                               cmdp->param.index = i;
-                               INTON;
-                               goto success;
+                               goto builtin_success;
                        } else if (prefix("func", pathopt)) {
                                /* handled below */
                        } else {
-                               goto loop;      /* ignore unimplemented options */
+                               /* ignore unimplemented options */
+                               goto loop;
                        }
                }
                /* if rehash, don't redo absolute path names */
-               if (fullname[0] == '/' && index <= prev) {
-                       if (index < prev)
+               if (fullname[0] == '/' && idx <= prev) {
+                       if (idx < prev)
                                goto loop;
                        TRACE(("searchexec \"%s\": no change\n", name));
                        goto success;
                }
-               if (stat(fullname, &statb) < 0) {
+               while (stat(fullname, &statb) < 0) {
+#ifdef SYSV
+                       if (errno == EINTR)
+                               continue;
+#endif
                        if (errno != ENOENT && errno != ENOTDIR)
                                e = errno;
                        goto loop;
@@ -390,14 +551,19 @@ loop:
                if (!S_ISREG(statb.st_mode))
                        goto loop;
                if (pathopt) {          /* this is a %func directory */
+                       if (act & DO_NOFUNC)
+                               goto loop;
                        stalloc(strlen(fullname) + 1);
                        readcmdfile(fullname);
-                       if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
+                       if ((cmdp = cmdlookup(name, 0)) == NULL ||
+                           cmdp->cmdtype != CMDFUNCTION)
                                error("%s not defined in %s", name, fullname);
                        stunalloc(fullname);
                        goto success;
                }
 #ifdef notdef
+               /* XXX this code stops root executing stuff, and is buggy
+                  if you need a group from the group list. */
                if (statb.st_uid == geteuid()) {
                        if ((statb.st_mode & 0100) == 0)
                                goto loop;
@@ -411,9 +577,13 @@ loop:
 #endif
                TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
                INTOFF;
-               cmdp = cmdlookup(name, 1);
+               if (act & DO_ALTPATH) {
+                       stalloc(strlen(fullname) + 1);
+                       cmdp = &loc_cmd;
+               } else
+                       cmdp = cmdlookup(name, 1);
                cmdp->cmdtype = CMDNORMAL;
-               cmdp->param.index = index;
+               cmdp->param.index = idx;
                INTON;
                goto success;
        }
@@ -421,19 +591,30 @@ loop:
        /* We failed.  If there was an entry for this command, delete it */
        if (cmdp)
                delete_cmd_entry();
-       if (printerr) {
-               if (e == ENOENT || e == ENOTDIR)
-                       outfmt(out2, "%s: not found\n", name);
-               else
-                       outfmt(out2, "%s: %s\n", name, strerror(e));
-       }
+       if (act & DO_ERR)
+               outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
        entry->cmdtype = CMDUNKNOWN;
        return;
 
+builtin_success:
+       INTOFF;
+       if (act & DO_ALTPATH)
+               cmdp = &loc_cmd;
+       else
+               cmdp = cmdlookup(name, 1);
+       if (cmdp->cmdtype == CMDFUNCTION)
+               /* DO_NOFUNC must have been set */
+               cmdp = &loc_cmd;
+       cmdp->cmdtype = CMDBUILTIN;
+       cmdp->param.bltin = bltin;
+       INTON;
 success:
-       cmdp->rehash = 0;
-       entry->cmdtype = cmdp->cmdtype;
-       entry->u = cmdp->param;
+       if (cmdp) {
+               cmdp->rehash = 0;
+               entry->cmdtype = cmdp->cmdtype;
+               entry->u = cmdp->param;
+       } else
+               entry->cmdtype = CMDUNKNOWN;
 }
 
 
@@ -443,15 +624,48 @@ success:
  */
 
 int
-find_builtin(char *name)
+(*find_builtin(char *name))(int, char **)
 {
        const struct builtincmd *bp;
 
        for (bp = builtincmd ; bp->name ; bp++) {
+               if (*bp->name == *name
+                   && (*name == '%' || equal(bp->name, name)))
+                       return bp->builtin;
+       }
+       return 0;
+}
+
+int
+(*find_splbltin(char *name))(int, char **)
+{
+       const struct builtincmd *bp;
+
+       for (bp = splbltincmd ; bp->name ; bp++) {
                if (*bp->name == *name && equal(bp->name, name))
-                       return bp->code;
+                       return bp->builtin;
+       }
+       return 0;
+}
+
+/*
+ * At shell startup put special builtins into hash table.
+ * ensures they are executed first (see posix).
+ * We stop functions being added with the same name
+ * (as they are impossible to call)
+ */
+
+void
+hash_special_builtins(void)
+{
+       const struct builtincmd *bp;
+       struct tblentry *cmdp;
+
+       for (bp = splbltincmd ; bp->name ; bp++) {
+               cmdp = cmdlookup(bp->name, 1);
+               cmdp->cmdtype = CMDSPLBLTIN;
+               cmdp->param.bltin = bp->builtin;
        }
-       return -1;
 }
 
 
@@ -479,27 +693,28 @@ hashcd(void)
 
 
 /*
+ * Fix command hash table when PATH changed.
  * Called before PATH is changed.  The argument is the new value of PATH;
- * pathval() still returns the old value at this point.  Called with
- * interrupts off.
+ * pathval() still returns the old value at this point.
+ * Called with interrupts off.
  */
 
 void
 changepath(const char *newval)
 {
        const char *old, *new;
-       int index;
+       int idx;
        int firstchange;
        int bltin;
 
        old = pathval();
        new = newval;
        firstchange = 9999;     /* assume no change */
-       index = 0;
+       idx = 0;
        bltin = -1;
        for (;;) {
                if (*old != *new) {
-                       firstchange = index;
+                       firstchange = idx;
                        if ((*old == '\0' && *new == ':')
                         || (*old == ':' && *new == '\0'))
                                firstchange++;
@@ -508,9 +723,9 @@ changepath(const char *newval)
                if (*new == '\0')
                        break;
                if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
-                       bltin = index;
+                       bltin = idx;
                if (*new == ':') {
-                       index++;
+                       idx++;
                }
                new++, old++;
        }
@@ -528,7 +743,7 @@ changepath(const char *newval)
  * PATH which has changed.
  */
 
-void
+STATIC void
 clearcmdentry(int firstchange)
 {
        struct tblentry **tblp;
@@ -559,7 +774,13 @@ clearcmdentry(int firstchange)
  */
 
 #ifdef mkinit
-INCLUDE "exec.h"
+MKINIT void deletefuncs(void);
+MKINIT void hash_special_builtins(void);
+
+INIT {
+       hash_special_builtins();
+}
+
 SHELLPROC {
        deletefuncs();
 }
@@ -598,14 +819,14 @@ deletefuncs(void)
  * entry.
  */
 
-STATIC struct tblentry **lastcmdentry;
+struct tblentry **lastcmdentry;
 
 
 STATIC struct tblentry *
-cmdlookup(char *name, int add)
+cmdlookup(const char *name, int add)
 {
        int hashval;
-       char *p;
+       const char *p;
        struct tblentry *cmdp;
        struct tblentry **pp;
 
@@ -652,23 +873,42 @@ delete_cmd_entry(void)
 
 
 
+#ifdef notdef
+void
+getcmdentry(char *name, struct cmdentry *entry)
+{
+       struct tblentry *cmdp = cmdlookup(name, 0);
+
+       if (cmdp) {
+               entry->u = cmdp->param;
+               entry->cmdtype = cmdp->cmdtype;
+       } else {
+               entry->cmdtype = CMDUNKNOWN;
+               entry->u.index = 0;
+       }
+}
+#endif
+
+
 /*
  * Add a new command entry, replacing any existing command entry for
- * the same name.
+ * the same name - except special builtins.
  */
 
-static void
+STATIC void
 addcmdentry(char *name, struct cmdentry *entry)
 {
        struct tblentry *cmdp;
 
        INTOFF;
        cmdp = cmdlookup(name, 1);
-       if (cmdp->cmdtype == CMDFUNCTION) {
-               freefunc(cmdp->param.func);
+       if (cmdp->cmdtype != CMDSPLBLTIN) {
+               if (cmdp->cmdtype == CMDFUNCTION) {
+                       freefunc(cmdp->param.func);
+               }
+               cmdp->cmdtype = entry->cmdtype;
+               cmdp->param = entry->u;
        }
-       cmdp->cmdtype = entry->cmdtype;
-       cmdp->param = entry->u;
        INTON;
 }
 
@@ -699,16 +939,17 @@ unsetfunc(char *name)
 {
        struct tblentry *cmdp;
 
-       if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
+       if ((cmdp = cmdlookup(name, 0)) != NULL &&
+           cmdp->cmdtype == CMDFUNCTION) {
                freefunc(cmdp->param.func);
                delete_cmd_entry();
-               return (0);
        }
-       return (0);
+       return 0;
 }
 
 /*
  * Locate and print what a word is...
+ * also used for 'command -[v|V]'
  */
 
 int
@@ -716,76 +957,115 @@ typecmd(int argc, char **argv)
 {
        struct cmdentry entry;
        struct tblentry *cmdp;
-       char **pp;
+       const char * const *pp;
        struct alias *ap;
-       int i;
-       int error = 0;
-       extern char *const parsekwd[];
+       int err = 0;
+       char *arg;
+       int c;
+       int V_flag = 0;
+       int v_flag = 0;
+       int p_flag = 0;
+
+       while ((c = nextopt("vVp")) != 0) {
+               switch (c) {
+               case 'v': v_flag = 1; break;
+               case 'V': V_flag = 1; break;
+               case 'p': p_flag = 1; break;
+               }
+       }
+
+       if (p_flag && (v_flag || V_flag))
+               error("cannot specify -p with -v or -V");
 
-       for (i = 1; i < argc; i++) {
-               out1str(argv[i]);
+       while ((arg = *argptr++)) {
+               if (!v_flag)
+                       out1str(arg);
                /* First look at the keywords */
-               for (pp = (char **)parsekwd; *pp; pp++)
-                       if (**pp == *argv[i] && equal(*pp, argv[i]))
+               for (pp = parsekwd; *pp; pp++)
+                       if (**pp == *arg && equal(*pp, arg))
                                break;
 
                if (*pp) {
-                       out1str(" is a shell keyword\n");
+                       if (v_flag)
+                               err = 1;
+                       else
+                               out1str(" is a shell keyword\n");
                        continue;
                }
 
                /* Then look at the aliases */
-               if ((ap = lookupalias(argv[i], 1)) != NULL) {
-                       out1fmt(" is an alias for %s\n", ap->val);
+               if ((ap = lookupalias(arg, 1)) != NULL) {
+                       if (!v_flag)
+                               out1fmt(" is an alias for \n");
+                       out1fmt("%s\n", ap->val);
                        continue;
                }
 
                /* Then check if it is a tracked alias */
-               if ((cmdp = cmdlookup(argv[i], 0)) != NULL) {
+               if ((cmdp = cmdlookup(arg, 0)) != NULL) {
                        entry.cmdtype = cmdp->cmdtype;
                        entry.u = cmdp->param;
-               }
-               else {
+               } else {
                        /* Finally use brute force */
-                       find_command(argv[i], &entry, 0, pathval());
+                       find_command(arg, &entry, DO_ABS, pathval());
                }
 
                switch (entry.cmdtype) {
                case CMDNORMAL: {
-                       if (strchr(argv[i], '/') == NULL) {
-                               char *path = pathval(), *name;
+                       if (strchr(arg, '/') == NULL) {
+                               const char *path = pathval();
+                               char *name;
                                int j = entry.u.index;
                                do {
-                                       name = padvance(&path, argv[i]);
+                                       name = padvance(&path, arg);
                                        stunalloc(name);
                                } while (--j >= 0);
-                               out1fmt(" is%s %s\n",
-                                   cmdp ? " a tracked alias for" : "", name);
+                               if (!v_flag)
+                                       out1fmt(" is%s ",
+                                           cmdp ? " a tracked alias for" : "");
+                               out1fmt("%s\n", name);
                        } else {
-                               if (access(argv[i], X_OK) == 0)
-                                       out1fmt(" is %s\n", argv[i]);
-                               else
-                                       out1fmt(": %s\n", strerror(errno));
+                               if (access(arg, X_OK) == 0) {
+                                       if (!v_flag)
+                                               out1fmt(" is ");
+                                       out1fmt("%s\n", arg);
+                               } else {
+                                       if (!v_flag)
+                                               out1fmt(": %s\n",
+                                                   strerror(errno));
+                                       else
+                                               err = 126;
+                               }
                        }
-                       break;
+                       break;
                }
                case CMDFUNCTION:
-                       out1str(" is a shell function\n");
+                       if (!v_flag)
+                               out1str(" is a shell function\n");
+                       else
+                               out1fmt("%s\n", arg);
                        break;
 
                case CMDBUILTIN:
-                       out1str(" is a shell builtin\n");
+                       if (!v_flag)
+                               out1str(" is a shell builtin\n");
+                       else
+                               out1fmt("%s\n", arg);
+                       break;
+
+               case CMDSPLBLTIN:
+                       if (!v_flag)
+                               out1str(" is a special shell builtin\n");
+                       else
+                               out1fmt("%s\n", arg);
                        break;
 
                default:
-                       out1str(": not found\n");
-                       error |= 127;
+                       if (!v_flag)
+                               out1str(": not found\n");
+                       err = 127;
                        break;
                }
        }
-       return error;
+       return err;
 }
-
-/*
- * $PchId: exec.c,v 1.6 2006/04/10 14:47:03 philip Exp $
- */
similarity index 61%
rename from minix/commands/ash/exec.h
rename to bin/sh/exec.h
index eef4c9533bece435aeec8b5d1528254756ba5708..c0fbd51ba49b6407993d664f782d404383e5148b 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: exec.h,v 1.23 2012/03/15 02:02:20 joerg Exp $  */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)exec.h      8.3 (Berkeley) 6/8/95
- * $FreeBSD: src/bin/sh/exec.h,v 1.12 2004/04/06 20:06:51 markm Exp $
  */
 
 /* values of cmdtype */
-#define CMDUNKNOWN -1          /* no entry in table for command */
-#define CMDNORMAL 0            /* command is an executable program */
-#define CMDBUILTIN 1           /* command is a shell builtin */
-#define CMDFUNCTION 2          /* command is a shell function */
+#define CMDUNKNOWN     -1      /* no entry in table for command */
+#define CMDNORMAL      0       /* command is an executable program */
+#define CMDFUNCTION    1       /* command is a shell function */
+#define CMDBUILTIN     2       /* command is a shell builtin */
+#define CMDSPLBLTIN    3       /* command is a special shell builtin */
 
 
 struct cmdentry {
        int cmdtype;
        union param {
                int index;
+               int (*bltin)(int, char**);
                union node *func;
        } u;
 };
 
 
-extern char *pathopt;          /* set by padvance */
-extern int exerrno;            /* last exec error */
+/* action to find_command() */
+#define DO_ERR         0x01    /* prints errors */
+#define DO_ABS         0x02    /* checks absolute paths */
+#define DO_NOFUNC      0x04    /* don't return shell functions, for command */
+#define DO_ALTPATH     0x08    /* using alternate path */
+#define DO_ALTBLTIN    0x20    /* %builtin in alt. path */
+
+extern const char *pathopt;    /* set by padvance */
 
-void shellexec(char **, char **, char *, int);
-char *padvance(char **, char *);
-int hashcmd(int, char **);
-void find_command(char *, struct cmdentry *, int, char *);
-int find_builtin(char *);
+void shellexec(char **, char **, const char *, int, int) __dead;
+char *padvance(const char **, const char *);
+void find_command(char *, struct cmdentry *, int, const char *);
+int (*find_builtin(char *))(int, char **);
+int (*find_splbltin(char *))(int, char **);
 void hashcd(void);
 void changepath(const char *);
 void deletefuncs(void);
+void getcmdentry(char *, struct cmdentry *);
+void addcmdentry(char *, struct cmdentry *);
 void defun(char *, union node *);
 int unsetfunc(char *);
-int typecmd(int, char **);
-void clearcmdentry(int);
-
-/*
- * $PchId: exec.h,v 1.5 2006/04/10 14:47:34 philip Exp $
- */
+void hash_special_builtins(void);
similarity index 77%
rename from minix/commands/ash/expand.c
rename to bin/sh/expand.c
index 74309c4c93b4b8d1ef7f4c967780cf5b7bdfc5a0..aea3cf190ec7abdd8d89e1ee1f415bcc2a71a7eb 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: expand.c,v 1.90 2013/10/06 21:05:50 ast Exp $  */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)expand.c   8.5 (Berkeley) 5/15/95";
+#else
+__RCSID("$NetBSD: expand.c,v 1.90 2013/10/06 21:05:50 ast Exp $");
 #endif
 #endif /* not lint */
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/expand.c,v 1.46 2004/04/06 20:06:51 markm Exp $");
-*/
 
 #include <sys/types.h>
+#include <sys/time.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <dirent.h>
 #include <unistd.h>
 #include <pwd.h>
-#include <stdlib.h>
 #include <limits.h>
+#include <stdlib.h>
 #include <stdio.h>
-#include <string.h>
 
 /*
  * Routines to expand arguments to commands.  We have to deal with
@@ -65,13 +66,13 @@ __FBSDID("$FreeBSD: src/bin/sh/expand.c,v 1.46 2004/04/06 20:06:51 markm Exp $")
 #include "parser.h"
 #include "jobs.h"
 #include "options.h"
+#include "builtins.h"
 #include "var.h"
 #include "input.h"
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
-#include "arith.h"
 #include "show.h"
 
 /*
@@ -83,15 +84,15 @@ struct ifsregion {
        struct ifsregion *next; /* next region in list */
        int begoff;             /* offset of start of region */
        int endoff;             /* offset of end of region */
-       int nulonly;            /* search for nul bytes only */
+       int inquotes;           /* search for nul bytes only */
 };
 
 
-STATIC char *expdest;                  /* output of current string */
-STATIC struct nodelist *argbackq;      /* list of back quote expressions */
-STATIC struct ifsregion ifsfirst;      /* first struct in list of ifs regions */
-STATIC struct ifsregion *ifslastp;     /* last struct in list */
-STATIC struct arglist exparg;          /* holds expanded arg list */
+char *expdest;                 /* output of current string */
+struct nodelist *argbackq;     /* list of back quote expressions */
+struct ifsregion ifsfirst;     /* first struct in list of ifs regions */
+struct ifsregion *ifslastp;    /* last struct in list */
+struct arglist exparg;         /* holds expanded arg list */
 
 STATIC void argstr(char *, int);
 STATIC char *exptilde(char *, int);
@@ -99,10 +100,11 @@ STATIC void expbackq(union node *, int, int);
 STATIC int subevalvar(char *, char *, int, int, int, int);
 STATIC char *evalvar(char *, int);
 STATIC int varisset(char *, int);
-STATIC void varvalue(char *, int, int);
+STATIC void varvalue(char *, int, int, int);
 STATIC void recordregion(int, int, int);
 STATIC void removerecordregions(int); 
 STATIC void ifsbreakup(char *, struct arglist *);
+STATIC void ifsfree(void);
 STATIC void expandmeta(struct strlist *, int);
 STATIC void expmeta(char *, char *);
 STATIC void addfname(char *);
@@ -110,30 +112,16 @@ STATIC struct strlist *expsort(struct strlist *);
 STATIC struct strlist *msort(struct strlist *, int);
 STATIC int pmatch(char *, char *, int);
 STATIC char *cvtnum(int, char *);
-STATIC int collate_range_cmp(int, int);
-STATIC void expari(int);
-
-STATIC int
-collate_range_cmp(int c1, int c2)
-{
-       static char s1[2], s2[2];
-
-       s1[0] = c1;
-       s2[0] = c2;
-       return (strcoll(s1, s2));
-}
 
 /*
  * Expand shell variables and backquotes inside a here document.
- *     union node *arg         the document
- *     int fd;                 where to write the expanded version
  */
 
 void
 expandhere(union node *arg, int fd)
 {
        herefd = fd;
-       expandarg(arg, (struct arglist *)NULL, 0);
+       expandarg(arg, NULL, 0);
        xwrite(fd, stackblock(), expdest - stackblock());
 }
 
@@ -178,14 +166,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
                *exparg.lastp = sp;
                exparg.lastp = &sp->next;
        }
-       while (ifsfirst.next != NULL) {
-               struct ifsregion *ifsp;
-               INTOFF;
-               ifsp = ifsfirst.next->next;
-               ckfree(ifsfirst.next);
-               ifsfirst.next = ifsp;
-               INTON;
-       }
+       ifsfree();
        *exparg.lastp = NULL;
        if (exparg.list) {
                *arglist->lastp = exparg.list;
@@ -196,31 +177,40 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
 
 
 /*
- * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
- * characters to allow for further processing.  Otherwise treat
- * $@ like $* since no splitting will be performed.
+ * Perform variable and command substitution.
+ * If EXP_FULL is set, output CTLESC characters to allow for further processing.
+ * Otherwise treat $@ like $* since no splitting will be performed.
  */
 
 STATIC void
 argstr(char *p, int flag)
 {
        char c;
-       int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);  /* do CTLESC */
+       int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
        int firsteq = 1;
+       const char *ifs = NULL;
+       int ifs_split = EXP_IFS_SPLIT;
+
+       if (flag & EXP_IFS_SPLIT)
+               ifs = ifsset() ? ifsval() : " \t\n";
 
        if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
                p = exptilde(p, flag);
        for (;;) {
                switch (c = *p++) {
                case '\0':
-               case CTLENDVAR: /* ??? */
-                       goto breakloop;
+               case CTLENDVAR: /* end of expanding yyy in ${xxx-yyy} */
+                       return;
                case CTLQUOTEMARK:
                        /* "$@" syntax adherence hack */
                        if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
                                break;
                        if ((flag & EXP_FULL) != 0)
                                STPUTC(c, expdest);
+                       ifs_split = 0;
+                       break;
+               case CTLQUOTEEND:
+                       ifs_split = EXP_IFS_SPLIT;
                        break;
                case CTLESC:
                        if (quotes)
@@ -229,7 +219,7 @@ argstr(char *p, int flag)
                        STPUTC(c, expdest);
                        break;
                case CTLVAR:
-                       p = evalvar(p, flag);
+                       p = evalvar(p, (flag & ~EXP_IFS_SPLIT) | (flag & ifs_split));
                        break;
                case CTLBACKQ:
                case CTLBACKQ|CTLQUOTE:
@@ -258,9 +248,14 @@ argstr(char *p, int flag)
                        break;
                default:
                        STPUTC(c, expdest);
+                       if (flag & ifs_split && strchr(ifs, c) != NULL) {
+                               /* We need to get the output split here... */
+                               recordregion(expdest - stackblock() - 1,
+                                               expdest - stackblock(), 0);
+                       }
+                       break;
                }
        }
-breakloop:;
 }
 
 STATIC char *
@@ -268,8 +263,8 @@ exptilde(char *p, int flag)
 {
        char c, *startp = p;
        struct passwd *pw;
-       char *home;
-       int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
+       const char *home;
+       int quotes = flag & (EXP_FULL | EXP_CASE);
 
        while ((c = *p) != '\0') {
                switch(c) {
@@ -350,42 +345,44 @@ removerecordregions(int endoff)
                ifslastp->endoff = endoff;
 }
 
+
 /*
  * Expand arithmetic expression.  Backup to start of expression,
  * evaluate, place result in (backed up) result, adjust string position.
  */
-STATIC void
+void
 expari(int flag)
 {
        char *p, *start;
-       int result;
+       intmax_t result;
+       int adjustment;
        int begoff;
-       int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
+       int quotes = flag & (EXP_FULL | EXP_CASE);
        int quoted;
 
+       /*      ifsfree(); */
 
        /*
         * This routine is slightly over-complicated for
         * efficiency.  First we make sure there is
         * enough space for the result, which may be bigger
-        * than the expression if we add exponentiation.  Next we
+        * than the expression if we add exponentation.  Next we
         * scan backwards looking for the start of arithmetic.  If the
         * next previous character is a CTLESC character, then we
         * have to rescan starting from the beginning since CTLESC
         * characters have to be processed left to right.
         */
-#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10
-#error "integers with more than 10 digits are not supported"
-#endif
-       CHECKSTRSPACE(12 - 2, expdest);
+/* SPACE_NEEDED is enough for all digits, plus possible "-", plus 2 (why?) */
+#define SPACE_NEEDED ((sizeof(intmax_t) * CHAR_BIT + 2) / 3 + 1 + 2)
+       CHECKSTRSPACE((int)(SPACE_NEEDED - 2), expdest);
        USTPUTC('\0', expdest);
        start = stackblock();
-       p = expdest - 2;
-       while (p >= start && *p != CTLARI)
+       p = expdest - 1;
+       while (*p != CTLARI && p >= start)
                --p;
-       if (p < start || *p != CTLARI)
+       if (*p != CTLARI)
                error("missing CTLARI (shouldn't happen)");
-       if (p > start && *(p - 1) == CTLESC)
+       if (p > start && *(p-1) == CTLESC)
                for (p = start; *p != CTLARI; p++)
                        if (*p == CTLESC)
                                p++;
@@ -399,13 +396,15 @@ expari(int flag)
        if (quotes)
                rmescapes(p+2);
        result = arith(p+2);
-       fmtstr(p, 12, "%d", result);
+       fmtstr(p, SPACE_NEEDED, "%"PRIdMAX, result);
+
        while (*p++)
                ;
+
        if (quoted == 0)
                recordregion(begoff, p - 1 - start, 0);
-       result = expdest - p + 1;
-       STADJUST(-result, expdest);
+       adjustment = expdest - p + 1;
+       STADJUST(-adjustment, expdest);
 }
 
 
@@ -427,7 +426,7 @@ expbackq(union node *cmd, int quoted, int flag)
        int startloc = dest - stackblock();
        char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
        int saveherefd;
-       int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
+       int quotes = flag & (EXP_FULL | EXP_CASE);
        int nnl;
 
        INTOFF;
@@ -447,7 +446,6 @@ expbackq(union node *cmd, int quoted, int flag)
        p = in.buf;
        lastc = '\0';
        nnl = 0;
-       /* Don't copy trailing newlines */
        for (;;) {
                if (--in.nleft < 0) {
                        if (in.fd < 0)
@@ -461,16 +459,17 @@ expbackq(union node *cmd, int quoted, int flag)
                }
                lastc = *p++;
                if (lastc != '\0') {
-                       if (quotes && syntax[(int)lastc] == CCTL)
-                               STPUTC(CTLESC, dest);
-                       if (lastc == '\n') {
+                       if (lastc == '\n')
                                nnl++;
-                       } else {
+                       else {
+                               CHECKSTRSPACE(nnl + 2, dest);
                                while (nnl > 0) {
                                        nnl--;
-                                       STPUTC('\n', dest);
+                                       USTPUTC('\n', dest);
                                }
-                               STPUTC(lastc, dest);
+                               if (quotes && syntax[(int)lastc] == CCTL)
+                                       USTPUTC(CTLESC, dest);
+                               USTPUTC(lastc, dest);
                        }
                }
        }
@@ -480,12 +479,12 @@ expbackq(union node *cmd, int quoted, int flag)
        if (in.buf)
                ckfree(in.buf);
        if (in.jp)
-               exitstatus = waitforjob(in.jp, (int *)NULL);
+               back_exitstatus = waitforjob(in.jp);
        if (quoted == 0)
                recordregion(startloc, dest - stackblock(), 0);
        TRACE(("evalbackq: size=%d: \"%.*s\"\n",
-               (dest - stackblock()) - startloc,
-               (dest - stackblock()) - startloc,
+               (int)((dest - stackblock()) - startloc),
+               (int)((dest - stackblock()) - startloc),
                stackblock() + startloc));
        expdest = dest;
        INTON;
@@ -494,8 +493,7 @@ expbackq(union node *cmd, int quoted, int flag)
 
 
 STATIC int
-subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
-  int varflags)
+subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags)
 {
        char *startp;
        char *loc = NULL;
@@ -503,10 +501,21 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
        int c = 0;
        int saveherefd = herefd;
        struct nodelist *saveargbackq = argbackq;
-       int amount;
+       int amount, how;
 
        herefd = -1;
-       argstr(p, 0);
+       switch (subtype) {
+       case VSTRIMLEFT:
+       case VSTRIMLEFTMAX:
+       case VSTRIMRIGHT:
+       case VSTRIMRIGHTMAX:
+               how = (varflags & VSQUOTE) ? 0 : EXP_CASE;
+               break;
+       default:
+               how = 0;
+               break;
+       }
+       argstr(p, how);
        STACKSTRNUL(expdest);
        herefd = saveherefd;
        argbackq = saveargbackq;
@@ -520,31 +529,28 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
                amount = startp - expdest;
                STADJUST(amount, expdest);
                varflags &= ~VSNUL;
-               if (c != 0)
-                       *loc = c;
                return 1;
 
        case VSQUESTION:
                if (*p != CTLENDVAR) {
                        outfmt(&errout, "%s\n", startp);
-                       error((char *)NULL);
+                       error(NULL);
                }
-               error("%.*s: parameter %snot set", (int)(p - str - 1),
+               error("%.*s: parameter %snot set",
+                     (int)(p - str - 1),
                      str, (varflags & VSNUL) ? "null or "
                                              : nullstr);
-               return 0;
+               /* NOTREACHED */
 
        case VSTRIMLEFT:
                for (loc = startp; loc < str; loc++) {
                        c = *loc;
                        *loc = '\0';
-                       if (patmatch(str, startp, varflags & VSQUOTE)) {
-                               *loc = c;
+                       if (patmatch(str, startp, varflags & VSQUOTE))
                                goto recordleft;
-                       }
                        *loc = c;
                        if ((varflags & VSQUOTE) && *loc == CTLESC)
-                               loc++;
+                               loc++;
                }
                return 0;
 
@@ -552,10 +558,8 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
                for (loc = str - 1; loc >= startp;) {
                        c = *loc;
                        *loc = '\0';
-                       if (patmatch(str, startp, varflags & VSQUOTE)) {
-                               *loc = c;
+                       if (patmatch(str, startp, varflags & VSQUOTE))
                                goto recordleft;
-                       }
                        *loc = c;
                        loc--;
                        if ((varflags & VSQUOTE) && loc > startp &&
@@ -570,12 +574,9 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
                return 0;
 
        case VSTRIMRIGHT:
-               for (loc = str - 1; loc >= startp;) {
-                       if (patmatch(str, loc, varflags & VSQUOTE)) {
-                               amount = loc - expdest;
-                               STADJUST(amount, expdest);
-                               return 1;
-                       }
+               for (loc = str - 1; loc >= startp;) {
+                       if (patmatch(str, loc, varflags & VSQUOTE))
+                               goto recordright;
                        loc--;
                        if ((varflags & VSQUOTE) && loc > startp &&
                            *(loc - 1) == CTLESC) { 
@@ -590,27 +591,31 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
 
        case VSTRIMRIGHTMAX:
                for (loc = startp; loc < str - 1; loc++) {
-                       if (patmatch(str, loc, varflags & VSQUOTE)) {
-                               amount = loc - expdest;
-                               STADJUST(amount, expdest);
-                               return 1;
-                       }
+                       if (patmatch(str, loc, varflags & VSQUOTE))
+                               goto recordright;
                        if ((varflags & VSQUOTE) && *loc == CTLESC)
-                               loc++;
+                               loc++;
                }
                return 0;
 
-
        default:
                abort();
        }
 
 recordleft:
+       *loc = c;
        amount = ((str - 1) - (loc - startp)) - expdest;
        STADJUST(amount, expdest);
        while (loc != str - 1)
                *startp++ = *loc++;
        return 1;
+
+recordright:
+       amount = loc - expdest;
+       STADJUST(amount, expdest);
+       STPUTC('\0', expdest);
+       STADJUST(-1, expdest);
+       return 1;
 }
 
 
@@ -632,31 +637,37 @@ evalvar(char *p, int flag)
        int special;
        int startloc;
        int varlen;
-       int easy;
-       int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
+       int apply_ifs;
+       int quotes = flag & (EXP_FULL | EXP_CASE);
 
-       varflags = *p++;
+       varflags = (unsigned char)*p++;
        subtype = varflags & VSTYPE;
        var = p;
-       special = 0;
-       if (! is_name(*p))
-               special = 1;
+       special = !is_name(*p);
        p = strchr(p, '=') + 1;
+
 again: /* jump here after setting a variable with ${var=text} */
-       if (special) {
+       if (varflags & VSLINENO) {
+               set = 1;
+               special = 0;
+               val = var;
+               p[-1] = '\0';
+       } else if (special) {
                set = varisset(var, varflags & VSNUL);
                val = NULL;
        } else {
-               val = bltinlookup(var, 1);
+               val = lookupvar(var);
                if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
                        val = NULL;
                        set = 0;
                } else
                        set = 1;
        }
+
        varlen = 0;
        startloc = expdest - stackblock();
-       if (!set && uflag) {
+
+       if (!set && uflag && *var != '@' && *var != '*') {
                switch (subtype) {
                case VSNORMAL:
                case VSTRIMLEFT:
@@ -664,14 +675,16 @@ again: /* jump here after setting a variable with ${var=text} */
                case VSTRIMRIGHT:
                case VSTRIMRIGHTMAX:
                case VSLENGTH:
-                       error("%.*s: parameter not set", (int)(p - var - 1),
-                           var);
+                       error("%.*s: parameter not set",
+                           (int)(p - var - 1), var);
+                       /* NOTREACHED */
                }
        }
+
        if (set && subtype != VSPLUS) {
                /* insert the value of the variable */
                if (special) {
-                       varvalue(var, varflags & VSQUOTE, flag & EXP_FULL);
+                       varvalue(var, varflags & VSQUOTE, subtype, flag);
                        if (subtype == VSLENGTH) {
                                varlen = expdest - stackblock() - startloc;
                                STADJUST(-varlen, expdest);
@@ -683,11 +696,9 @@ again: /* jump here after setting a variable with ${var=text} */
                        if (subtype == VSLENGTH) {
                                for (;*val; val++)
                                        varlen++;
-                       }
-                       else {
+                       } else {
                                while (*val) {
-                                       if (quotes &&
-                                           syntax[(int)*val] == CCTL)
+                                       if (quotes && syntax[(int)*val] == CCTL)
                                                STPUTC(CTLESC, expdest);
                                        STPUTC(*val++, expdest);
                                }
@@ -696,34 +707,45 @@ again: /* jump here after setting a variable with ${var=text} */
                }
        }
 
-       if (subtype == VSPLUS)
-               set = ! set;
-
-       easy = ((varflags & VSQUOTE) == 0 ||
-               (*var == '@' && shellparam.nparam != 1));
 
+       if (flag & EXP_IN_QUOTES)
+               apply_ifs = 0;
+       else if (varflags & VSQUOTE) {
+               if  (*var == '@' && shellparam.nparam != 1)
+                   apply_ifs = 1;
+               else {
+                   /*
+                    * Mark so that we don't apply IFS if we recurse through
+                    * here expanding $bar from "${foo-$bar}".
+                    */
+                   flag |= EXP_IN_QUOTES;
+                   apply_ifs = 0;
+               }
+       } else
+               apply_ifs = 1;
 
        switch (subtype) {
        case VSLENGTH:
                expdest = cvtnum(varlen, expdest);
-               goto record;
+               break;
 
        case VSNORMAL:
-               if (!easy)
-                       break;
-record:
-               recordregion(startloc, expdest - stackblock(),
-                            varflags & VSQUOTE);
                break;
 
        case VSPLUS:
+               set = !set;
+               /* FALLTHROUGH */
        case VSMINUS:
                if (!set) {
-                       argstr(p, flag);
-                       break;
+                       argstr(p, flag | (apply_ifs ? EXP_IFS_SPLIT : 0));
+                       /*
+                        * ${x-a b c} doesn't get split, but removing the
+                        * 'apply_ifs = 0' apparently breaks ${1+"$@"}..
+                        * ${x-'a b' c} should generate 2 args.
+                        */
+                       /* We should have marked stuff already */
+                       apply_ifs = 0;
                }
-               if (easy)
-                       goto record;
                break;
 
        case VSTRIMLEFT:
@@ -745,29 +767,33 @@ record:
                }
                /* Remove any recorded regions beyond start of variable */
                removerecordregions(startloc);
-               goto record;
+               apply_ifs = 1;
+               break;
 
        case VSASSIGN:
        case VSQUESTION:
-               if (!set) {
-                       if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
-                               varflags &= ~VSNUL;
-                               /* 
-                                * Remove any recorded regions beyond 
-                                * start of variable 
-                                */
-                               removerecordregions(startloc);
-                               goto again;
-                       }
+               if (set)
                        break;
+               if (subevalvar(p, var, 0, subtype, startloc, varflags)) {
+                       varflags &= ~VSNUL;
+                       /* 
+                        * Remove any recorded regions beyond 
+                        * start of variable 
+                        */
+                       removerecordregions(startloc);
+                       goto again;
                }
-               if (easy)
-                       goto record;
+               apply_ifs = 0;
                break;
 
        default:
                abort();
        }
+       p[-1] = '=';    /* recover overwritten '=' */
+
+       if (apply_ifs)
+               recordregion(startloc, expdest - stackblock(),
+                            varflags & VSQUOTE);
 
        if (subtype != VSNORMAL) {      /* skip to end of alternative */
                int nesting = 1;
@@ -798,7 +824,6 @@ record:
 STATIC int
 varisset(char *name, int nulok)
 {
-
        if (*name == '!')
                return backgndpid != -1;
        else if (*name == '@' || *name == '*') {
@@ -838,19 +863,18 @@ varisset(char *name, int nulok)
  */
 
 STATIC void
-varvalue(char *name, int quoted, int allow_split)
+varvalue(char *name, int quoted, int subtype, int flag)
 {
        int num;
        char *p;
        int i;
-       extern int oexitstatus;
        char sep;
        char **ap;
        char const *syntax;
 
 #define STRTODEST(p) \
        do {\
-       if (allow_split) { \
+       if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH) { \
                syntax = quoted? DQSYNTAX : BASESYNTAX; \
                while (*p) { \
                        if (syntax[(int)*p] == CCTL) \
@@ -868,7 +892,7 @@ varvalue(char *name, int quoted, int allow_split)
                num = rootpid;
                goto numvar;
        case '?':
-               num = oexitstatus;
+               num = exitstatus;
                goto numvar;
        case '#':
                num = shellparam.nparam;
@@ -879,21 +903,22 @@ numvar:
                expdest = cvtnum(num, expdest);
                break;
        case '-':
-               for (i = 0 ; i < NOPTS ; i++) {
-                       if (optlist[i].val)
+               for (i = 0; optlist[i].name; i++) {
+                       if (optlist[i].val && optlist[i].letter)
                                STPUTC(optlist[i].letter, expdest);
                }
                break;
        case '@':
-               if (allow_split && quoted) {
+               if (flag & EXP_FULL && quoted) {
                        for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
                                STRTODEST(p);
                                if (*ap)
+                                       /* A NUL separates args inside "" */
                                        STPUTC('\0', expdest);
                        }
                        break;
                }
-               /* FALLTHROUGH */
+               /* fall through */
        case '*':
                if (ifsset() != 0)
                        sep = ifsval()[0];
@@ -924,18 +949,24 @@ numvar:
 
 
 /*
- * Record the the fact that we have to scan this region of the
+ * Record the fact that we have to scan this region of the
  * string for IFS characters.
  */
 
 STATIC void
-recordregion(int start, int end, int nulonly)
+recordregion(int start, int end, int inquotes)
 {
        struct ifsregion *ifsp;
 
        if (ifslastp == NULL) {
                ifsp = &ifsfirst;
        } else {
+               if (ifslastp->endoff == start
+                   && ifslastp->inquotes == inquotes) {
+                       /* extend previous area */
+                       ifslastp->endoff = end;
+                       return;
+               }
                ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
                ifslastp->next = ifsp;
        }
@@ -943,7 +974,7 @@ recordregion(int start, int end, int nulonly)
        ifslastp->next = NULL;
        ifslastp->begoff = start;
        ifslastp->endoff = end;
-       ifslastp->nulonly = nulonly;
+       ifslastp->inquotes = inquotes;
 }
 
 
@@ -961,77 +992,89 @@ ifsbreakup(char *string, struct arglist *arglist)
        char *start;
        char *p;
        char *q;
-       char *ifs;
-       int ifsspc;
-       int nulonly;
-
+       const char *ifs;
+       const char *ifsspc;
+       int had_param_ch = 0;
 
        start = string;
-       ifsspc = 0;
-       nulonly = 0;
-       if (ifslastp != NULL) {
-               ifsp = &ifsfirst;
-               do {
-                       p = string + ifsp->begoff;
-                       nulonly = ifsp->nulonly;
-                       ifs = nulonly ? nullstr : 
-                               ( ifsset() ? ifsval() : " \t\n" );
-                       ifsspc = 0;
-                       while (p < string + ifsp->endoff) {
-                               q = p;
-                               if (*p == CTLESC)
+
+       if (ifslastp == NULL) {
+               /* Return entire argument, IFS doesn't apply to any of it */
+               sp = (struct strlist *)stalloc(sizeof *sp);
+               sp->text = start;
+               *arglist->lastp = sp;
+               arglist->lastp = &sp->next;
+               return;
+       }
+
+       ifs = ifsset() ? ifsval() : " \t\n";
+
+       for (ifsp = &ifsfirst; ifsp != NULL; ifsp = ifsp->next) {
+               p = string + ifsp->begoff;
+               while (p < string + ifsp->endoff) {
+                       had_param_ch = 1;
+                       q = p;
+                       if (*p == CTLESC)
+                               p++;
+                       if (ifsp->inquotes) {
+                               /* Only NULs (should be from "$@") end args */
+                               if (*p != 0) {
                                        p++;
-                               if (strchr(ifs, *p)) {
-                                       if (!nulonly)
-                                               ifsspc = (strchr(" \t\n", *p) != NULL);
-                                       /* Ignore IFS whitespace at start */
-                                       if (q == start && ifsspc) {
-                                               p++;
-                                               start = p;
-                                               continue;
-                                       }
-                                       *q = '\0';
-                                       sp = (struct strlist *)stalloc(sizeof *sp);
-                                       sp->text = start;
-                                       *arglist->lastp = sp;
-                                       arglist->lastp = &sp->next;
+                                       continue;
+                               }
+                               ifsspc = NULL;
+                       } else {
+                               if (!strchr(ifs, *p)) {
                                        p++;
-                                       if (!nulonly) {
-                                               for (;;) {
-                                                       if (p >= string + ifsp->endoff) {
-                                                               break;
-                                                       }
-                                                       q = p;
-                                                       if (*p == CTLESC)
-                                                               p++;
-                                                       if (strchr(ifs, *p) == NULL ) {
-                                                               p = q;
-                                                               break;
-                                                       } else if (strchr(" \t\n",*p) == NULL) {
-                                                               if (ifsspc) {
-                                                                       p++;
-                                                                       ifsspc = 0;
-                                                               } else {
-                                                                       p = q;
-                                                                       break;
-                                                               }
-                                                       } else
-                                                               p++;
-                                               }
-                                       }
-                                       start = p;
-                               } else
+                                       continue;
+                               }
+                               had_param_ch = 0;
+                               ifsspc = strchr(" \t\n", *p);
+
+                               /* Ignore IFS whitespace at start */
+                               if (q == start && ifsspc != NULL) {
                                        p++;
+                                       start = p;
+                                       continue;
+                               }
                        }
-               } while ((ifsp = ifsp->next) != NULL);
-               if (*start || (!ifsspc && start > string && 
-                       (nulonly || 1))) {
+
+                       /* Save this argument... */
+                       *q = '\0';
                        sp = (struct strlist *)stalloc(sizeof *sp);
                        sp->text = start;
                        *arglist->lastp = sp;
                        arglist->lastp = &sp->next;
+                       p++;
+
+                       if (ifsspc != NULL) {
+                               /* Ignore further trailing IFS whitespace */
+                               for (; p < string + ifsp->endoff; p++) {
+                                       q = p;
+                                       if (*p == CTLESC)
+                                               p++;
+                                       if (strchr(ifs, *p) == NULL) {
+                                               p = q;
+                                               break;
+                                       }
+                                       if (strchr(" \t\n", *p) == NULL) {
+                                               p++;
+                                               break;
+                                       }
+                               }
+                       }
+                       start = p;
                }
-       } else {
+       }
+
+       /*
+        * Save anything left as an argument.
+        * Traditionally we have treated 'IFS=':'; set -- x$IFS' as
+        * generating 2 arguments, the second of which is empty.
+        * Some recent clarification of the Posix spec say that it
+        * should only generate one....
+        */
+       if (had_param_ch || *start != 0) {
                sp = (struct strlist *)stalloc(sizeof *sp);
                sp->text = start;
                *arglist->lastp = sp;
@@ -1039,6 +1082,21 @@ ifsbreakup(char *string, struct arglist *arglist)
        }
 }
 
+STATIC void
+ifsfree(void)
+{
+       while (ifsfirst.next != NULL) {
+               struct ifsregion *ifsp;
+               INTOFF;
+               ifsp = ifsfirst.next->next;
+               ckfree(ifsfirst.next);
+               ifsfirst.next = ifsp;
+               INTON;
+       }
+       ifslastp = NULL;
+       ifsfirst.next = NULL;
+}
+
 
 
 /*
@@ -1046,11 +1104,11 @@ ifsbreakup(char *string, struct arglist *arglist)
  * should be escapes.  The results are stored in the list exparg.
  */
 
-STATIC char *expdir;
+char *expdir;
 
 
 STATIC void
-expandmeta(struct strlist *str, int flag __unused)
+expandmeta(struct strlist *str, int flag)
 {
        char *p;
        struct strlist **savelastp;
@@ -1107,6 +1165,7 @@ STATIC void
 expmeta(char *enddir, char *name)
 {
        char *p;
+       const char *cp;
        char *q;
        char *start;
        char *endname;
@@ -1124,7 +1183,7 @@ expmeta(char *enddir, char *name)
                        metaflag = 1;
                else if (*p == '[') {
                        q = p + 1;
-                       if (*q == '!' || *q == '^')
+                       if (*q == '!')
                                q++;
                        for (;;) {
                                while (*q == CTLQUOTEMARK)
@@ -1164,7 +1223,7 @@ expmeta(char *enddir, char *name)
                        if (*p == '\0')
                                break;
                }
-               if (metaflag == 0 || stat(expdir, &statb) >= 0)
+               if (metaflag == 0 || lstat(expdir, &statb) >= 0)
                        addfname(expdir);
                return;
        }
@@ -1180,14 +1239,14 @@ expmeta(char *enddir, char *name)
                }
        }
        if (enddir == expdir) {
-               p = ".";
+               cp = ".";
        } else if (enddir == expdir + 1 && *expdir == '/') {
-               p = "/";
+               cp = "/";
        } else {
-               p = expdir;
+               cp = expdir;
                enddir[-1] = '\0';
        }
-       if ((dirp = opendir(p)) == NULL)
+       if ((dirp = opendir(cp)) == NULL)
                return;
        if (enddir != expdir)
                enddir[-1] = '/';
@@ -1213,9 +1272,8 @@ expmeta(char *enddir, char *name)
                                scopy(dp->d_name, enddir);
                                addfname(expdir);
                        } else {
-                               char *q;
-                               for (p = enddir, q = dp->d_name;
-                                    (*p++ = *q++) != '\0';)
+                               for (p = enddir, cp = dp->d_name;
+                                    (*p++ = *cp++) != '\0';)
                                        continue;
                                p[-1] = '/';
                                expmeta(p, endname);
@@ -1380,7 +1438,7 @@ pmatch(char *pattern, char *string, int squoted)
                        char chr;
 
                        endp = p;
-                       if (*endp == '!' || *endp == '^')
+                       if (*endp == '!')
                                endp++;
                        for (;;) {
                                while (*endp == CTLQUOTEMARK)
@@ -1393,7 +1451,7 @@ pmatch(char *pattern, char *string, int squoted)
                                        break;
                        }
                        invert = 0;
-                       if (*p == '!' || *p == '^') {
+                       if (*p == '!') {
                                invert++;
                                p++;
                        }
@@ -1415,9 +1473,7 @@ pmatch(char *pattern, char *string, int squoted)
                                                p++;
                                        if (*p == CTLESC)
                                                p++;
-                                       if (   collate_range_cmp(chr, c) >= 0
-                                           && collate_range_cmp(chr, *p) <= 0
-                                          )
+                                       if (chr >= c && chr <= *p)
                                                found = 1;
                                        p++;
                                } else {
@@ -1532,17 +1588,15 @@ wordexpcmd(int argc, char **argv)
        size_t len;
        int i;
 
-       out1fmt("%08x", argc - 1);
+       out1fmt("%d", argc - 1);
+       out1c('\0');
        for (i = 1, len = 0; i < argc; i++)
                len += strlen(argv[i]);
-       out1fmt("%08x", (int)len);
+       out1fmt("%zu", len);
+       out1c('\0');
        for (i = 1; i < argc; i++) {
                out1str(argv[i]);
                out1c('\0');
        }
-        return (0);
+       return (0);
 }
-
-/*
- * $PchId: expand.c,v 1.6 2006/04/10 14:52:06 philip Exp $
- */
similarity index 87%
rename from minix/commands/ash/expand.h
rename to bin/sh/expand.h
index f53b61c9da7313a6b83ff0cd19e82ad6b9638135..76a012aa977b6479e430e47a03551f41e2ebd414 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: expand.h,v 1.19 2012/12/22 20:15:22 dsl Exp $  */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)expand.h    8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/expand.h,v 1.12 2004/04/06 20:06:51 markm Exp $
  */
 
+#include <inttypes.h>
+
 struct strlist {
        struct strlist *next;
        char *text;
@@ -52,23 +55,19 @@ struct arglist {
 #define        EXP_VARTILDE    0x4     /* expand tildes in an assignment */
 #define        EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
 #define EXP_CASE       0x10    /* keeps quotes around for CASE pattern */
+#define EXP_IFS_SPLIT  0x20    /* need to record arguments for ifs breakup */
+#define EXP_IN_QUOTES  0x40    /* don't set EXP_IFS_SPLIT again */
 
 
 union node;
 void expandhere(union node *, int);
 void expandarg(union node *, struct arglist *, int);
+void expari(int);
 int patmatch(char *, char *, int);
 void rmescapes(char *);
 int casematch(union node *, char *);
-int wordexpcmd(int, char **);
 
 /* From arith.y */
-int arith(char *);
-int arith_assign(char *, arith_t);
-int expcmd(int , char **);
+intmax_t arith(const char *);
 void arith_lex_reset(void);
-
-
-/*
- * $PchId: expand.h,v 1.4 2006/03/30 14:50:52 philip Exp $
- */
+int yylex(void);
old mode 100755 (executable)
new mode 100644 (file)
similarity index 86%
rename from minix/commands/ash/funcs/cmv
rename to bin/sh/funcs/cmv
index 0e701e5..667f846
@@ -1,3 +1,4 @@
+#      $NetBSD: cmv,v 1.7 1995/05/11 21:31:05 christos Exp $
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
 #
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by the University of
+#      California, Berkeley and its contributors.
 # 4. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
@@ -29,7 +34,6 @@
 # SUCH DAMAGE.
 #
 #      @(#)cmv 8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/funcs/cmv,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # Conditional move--don't replace an existing file.
 
@@ -44,6 +48,3 @@ cmv() {
        fi
        /bin/mv "$1" "$2"
 }
-
-#
-# $PchId: cmv,v 1.2 2006/03/29 10:43:18 philip Exp $
old mode 100755 (executable)
new mode 100644 (file)
similarity index 88%
rename from minix/commands/ash/funcs/dirs
rename to bin/sh/funcs/dirs
index 337c709..68bb317
@@ -1,3 +1,4 @@
+#      $NetBSD: dirs,v 1.7 1995/05/11 21:31:08 christos Exp $
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
 #
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by the University of
+#      California, Berkeley and its contributors.
 # 4. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
@@ -29,7 +34,6 @@
 # SUCH DAMAGE.
 #
 #      @(#)dirs        8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/funcs/dirs,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # pushd, popd, and dirs --- written by Chris Bertin
 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
@@ -68,6 +72,3 @@ dirs () {
        echo "`pwd` $DSTACK"
        return 0
 }
-
-#
-# $PchId: dirs,v 1.2 2006/03/29 10:43:18 philip Exp $
old mode 100755 (executable)
new mode 100644 (file)
similarity index 86%
rename from minix/commands/ash/funcs/kill
rename to bin/sh/funcs/kill
index 3c858ca..75b0180
@@ -1,3 +1,4 @@
+#      $NetBSD: kill,v 1.7 1995/05/11 21:31:10 christos Exp $
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
 #
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by the University of
+#      California, Berkeley and its contributors.
 # 4. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
@@ -29,7 +34,6 @@
 # SUCH DAMAGE.
 #
 #      @(#)kill        8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/funcs/kill,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # Convert job names to process ids and then run /bin/kill.
 
@@ -44,6 +48,3 @@ kill() {
        done
        /bin/kill $args
 }
-
-#
-# $PchId: kill,v 1.2 2006/03/29 10:43:18 philip Exp $
old mode 100755 (executable)
new mode 100644 (file)
similarity index 85%
rename from minix/commands/ash/funcs/login
rename to bin/sh/funcs/login
index d4720ed..7ae08b2
@@ -1,3 +1,4 @@
+#      $NetBSD: login,v 1.7 1995/05/11 21:31:11 christos Exp $
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
 #
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by the University of
+#      California, Berkeley and its contributors.
 # 4. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
 # SUCH DAMAGE.
 #
 #      @(#)login       8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/funcs/login,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # replaces the login builtin in the BSD shell
 login () exec login "$@"
-
-#
-# $PchId: login,v 1.2 2006/03/29 10:43:18 philip Exp $
old mode 100755 (executable)
new mode 100644 (file)
similarity index 85%
rename from minix/commands/ash/funcs/newgrp
rename to bin/sh/funcs/newgrp
index c2ab4fd..796a4f1
@@ -1,3 +1,4 @@
+#      $NetBSD: newgrp,v 1.7 1995/05/11 21:31:12 christos Exp $
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
 #
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by the University of
+#      California, Berkeley and its contributors.
 # 4. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
@@ -29,9 +34,5 @@
 # SUCH DAMAGE.
 #
 #      @(#)newgrp      8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/funcs/newgrp,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 newgrp() exec newgrp "$@"
-
-#
-# $PchId: newgrp,v 1.2 2006/03/29 10:43:18 philip Exp $
old mode 100755 (executable)
new mode 100644 (file)
similarity index 88%
rename from minix/commands/ash/funcs/popd
rename to bin/sh/funcs/popd
index a2654e5..b2b65d5
@@ -1,3 +1,4 @@
+#      $NetBSD: popd,v 1.7 1995/05/11 21:31:13 christos Exp $
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
 #
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by the University of
+#      California, Berkeley and its contributors.
 # 4. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
@@ -29,7 +34,6 @@
 # SUCH DAMAGE.
 #
 #      @(#)popd        8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/funcs/popd,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # pushd, popd, and dirs --- written by Chris Bertin
 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
@@ -68,6 +72,3 @@ dirs () {
        echo "`pwd` $DSTACK"
        return 0
 }
-
-#
-# $PchId: popd,v 1.2 2006/03/29 10:43:18 philip Exp $
old mode 100755 (executable)
new mode 100644 (file)
similarity index 88%
rename from minix/commands/ash/funcs/pushd
rename to bin/sh/funcs/pushd
index 799bef4..b393038
@@ -1,3 +1,4 @@
+#      $NetBSD: pushd,v 1.7 1995/05/11 21:31:15 christos Exp $
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
 #
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by the University of
+#      California, Berkeley and its contributors.
 # 4. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
@@ -29,7 +34,6 @@
 # SUCH DAMAGE.
 #
 #      @(#)pushd       8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/funcs/pushd,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 # pushd, popd, and dirs --- written by Chris Bertin
 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
@@ -68,6 +72,3 @@ dirs () {
        echo "`pwd` $DSTACK"
        return 0
 }
-
-#
-# $PchId: pushd,v 1.2 2006/03/29 10:43:18 philip Exp $
old mode 100755 (executable)
new mode 100644 (file)
similarity index 85%
rename from minix/commands/ash/funcs/suspend
rename to bin/sh/funcs/suspend
index 3d354e1..8a4197d
@@ -1,3 +1,4 @@
+#      $NetBSD: suspend,v 1.7 1995/05/11 21:31:17 christos Exp $
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
 #
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+#    must display the following acknowledgement:
+#      This product includes software developed by the University of
+#      California, Berkeley and its contributors.
 # 4. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
 # SUCH DAMAGE.
 #
 #      @(#)suspend     8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/funcs/suspend,v 1.7 2004/04/06 20:06:53 markm Exp $
 
 suspend() {
        local -
        set +j
        kill -TSTP 0
 }
-
-#
-# $PchId: suspend,v 1.2 2006/03/29 10:43:18 philip Exp $
similarity index 76%
rename from minix/commands/ash/histedit.c
rename to bin/sh/histedit.c
index e341c56d83d61900e6101b5da96651b576a5bf39..8a77ebfba9a2414e1daeb01af36a6d4fe38d233e 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: histedit.c,v 1.45 2012/03/20 18:42:29 matt Exp $       */
+
 /*-
  * Copyright (c) 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: histedit.c,v 1.45 2012/03/20 18:42:29 matt Exp $");
 #endif
 #endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
-*/
 
-#include <limits.h>
-#ifndef NO_PATHS_H
+#include <sys/param.h>
 #include <paths.h>
-#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -54,14 +53,13 @@ __FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $
 #include "parser.h"
 #include "var.h"
 #include "options.h"
+#include "builtins.h"
 #include "main.h"
 #include "output.h"
 #include "mystring.h"
-#include "builtins.h"
-#if !defined(NO_HISTORY)
 #include "myhistedit.h"
-#include "complete.h"
 #include "error.h"
+#ifndef SMALL
 #include "eval.h"
 #include "memalloc.h"
 
@@ -71,11 +69,14 @@ __FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $
 History *hist; /* history cookie */
 EditLine *el;  /* editline cookie */
 int displayhist;
-static FILE *el_in, *el_out, *el_err;
+static FILE *el_in, *el_out;
+unsigned char _el_fn_complete(EditLine *, int);
 
-STATIC char *fc_replace(const char *, char *, char *);
-STATIC int not_fcnumber(char *);
-STATIC int str_to_event(char *, int);
+STATIC const char *fc_replace(const char *, char *, char *);
+
+#ifdef DEBUG
+extern FILE *tracefile;
+#endif
 
 /*
  * Set history and editing status.  Called whenever the status may
@@ -84,10 +85,11 @@ STATIC int str_to_event(char *, int);
 void
 histedit(void)
 {
+       FILE *el_err;
 
 #define editing (Eflag || Vflag)
 
-       if (iflag) {
+       if (iflag == 1) {
                if (!hist) {
                        /*
                         * turn history on
@@ -105,20 +107,37 @@ histedit(void)
                        /*
                         * turn editing on
                         */
+                       char *term, *shname;
+
                        INTOFF;
                        if (el_in == NULL)
                                el_in = fdopen(0, "r");
-                       if (el_err == NULL)
-                               el_err = fdopen(1, "w");
                        if (el_out == NULL)
                                el_out = fdopen(2, "w");
-                       if (el_in == NULL || el_err == NULL || el_out == NULL)
+                       if (el_in == NULL || el_out == NULL)
                                goto bad;
-                       el = el_init(arg0, el_in, el_out, el_err);
+                       el_err = el_out;
+#if DEBUG
+                       if (tracefile)
+                               el_err = tracefile;
+#endif
+                       term = lookupvar("TERM");
+                       if (term)
+                               setenv("TERM", term, 1);
+                       else
+                               unsetenv("TERM");
+                       shname = arg0;
+                       if (shname[0] == '-')
+                               shname++;
+                       el = el_init(shname, el_in, el_out, el_err);
                        if (el != NULL) {
                                if (hist)
                                        el_set(el, EL_HIST, history, hist);
                                el_set(el, EL_PROMPT, getprompt);
+                               el_set(el, EL_SIGNAL, 1);
+                               el_set(el, EL_ADDFN, "rl-complete",
+                                   "ReadLine compatible completion function",
+                                   _el_fn_complete);
                        } else {
 bad:
                                out2str("sh: can't initialize editing\n");
@@ -131,27 +150,13 @@ bad:
                        INTON;
                }
                if (el) {
+                       el_source(el, NULL);
                        if (Vflag)
                                el_set(el, EL_EDITOR, "vi");
                        else if (Eflag)
                                el_set(el, EL_EDITOR, "emacs");
-                       el_set(el, EL_ADDFN, "ed-do-complete",
-                               "Complete Argument", complete);
-                       el_set(el, EL_ADDFN, "ed-list-complete",
-                               "List Argument Completions", complete_list);
-                       el_set(el, EL_ADDFN, "ed-maybe-complete",
-                               "Complete Argument Or List Completions",
-                               complete_or_list);
-                       el_set(el, EL_ADDFN, "ed-expand",
-                               "Expand Completions", complete_expand);
-                       el_set(el, EL_BIND, "^I", "ed-maybe-complete", NULL);
-                       el_set(el, EL_BIND, "-a", "=", "ed-list-complete",
-                               NULL);
-                       el_set(el, EL_BIND, "-a", "\\\\", "ed-do-complete",
-                               NULL);
-                       el_set(el, EL_BIND, "-a", "*", "ed-expand",
-                               NULL);
-                       el_source(el, NULL);
+                       el_set(el, EL_BIND, "^I", 
+                           tabcomplete ? "rl-complete" : "ed-insert", NULL);
                }
        } else {
                INTOFF;
@@ -169,8 +174,7 @@ bad:
 
 
 void
-sethistsize(hs)
-       const char *hs;
+sethistsize(const char *hs)
 {
        int histsize;
        HistEvent he;
@@ -180,40 +184,63 @@ sethistsize(hs)
                   (histsize = atoi(hs)) < 0)
                        histsize = 100;
                history(hist, &he, H_SETSIZE, histsize);
+               history(hist, &he, H_SETUNIQUE, 1);
        }
 }
 
+void
+setterm(const char *term)
+{
+       if (el != NULL && term != NULL)
+               if (el_set(el, EL_TERMINAL, term) != 0) {
+                       outfmt(out2, "sh: Can't set terminal type %s\n", term);
+                       outfmt(out2, "sh: Using dumb terminal settings.\n");
+               }
+}
+
+int
+inputrc(int argc, char **argv)
+{
+       if (argc != 2) {
+               out2str("usage: inputrc file\n");
+               return 1;
+       }
+       if (el != NULL) {
+               if (el_source(el, argv[1])) {
+                       out2str("inputrc: failed\n");
+                       return 1;
+               } else
+                       return 0;
+       } else {
+               out2str("sh: inputrc ignored, not editing\n");
+               return 1;
+       }
+}
+
+/*
+ *  This command is provided since POSIX decided to standardize
+ *  the Korn shell fc command.  Oh well...
+ */
 int
 histcmd(int argc, char **argv)
 {
        int ch;
-       char *editor = NULL;
+       const char * volatile editor = NULL;
        HistEvent he;
-       int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
+       int lflg = 0;
+       volatile int nflg = 0, rflg = 0, sflg = 0;
        int i, retval;
-       char *firststr, *laststr;
+       const char *firststr, *laststr;
        int first, last, direction;
-       char *pat = NULL, *repl;
+       char *pat = NULL, *repl;        /* ksh "fc old=new" crap */
        static int active = 0;
        struct jmploc jmploc;
        struct jmploc *volatile savehandler;
-       char editfile[PATH_MAX];
+       char editfile[MAXPATHLEN + 1];
        FILE *efp;
-       int oldhistnum;
 #ifdef __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &editor;
-       (void) &lflg;
-       (void) &nflg;
-       (void) &rflg;
-       (void) &sflg;
-       (void) &firststr;
-       (void) &laststr;
-       (void) &pat;
-       (void) &repl;
-       (void) &efp;
-       (void) &argc;
-       (void) &argv;
+       repl = NULL;    /* XXX gcc4 */
+       efp = NULL;     /* XXX gcc4 */
 #endif
 
        if (hist == NULL)
@@ -223,12 +250,11 @@ histcmd(int argc, char **argv)
                error("missing history argument");
 
        optreset = 1; optind = 1; /* initialize getopt */
-       opterr = 0;
        while (not_fcnumber(argv[optind]) &&
              (ch = getopt(argc, argv, ":e:lnrs")) != -1)
                switch ((char)ch) {
                case 'e':
-                       editor = optarg;
+                       editor = optionarg;
                        break;
                case 'l':
                        lflg = 1;
@@ -244,9 +270,11 @@ histcmd(int argc, char **argv)
                        break;
                case ':':
                        error("option -%c expects argument", optopt);
+                       /* NOTREACHED */
                case '?':
                default:
                        error("unknown option: -%c", optopt);
+                       /* NOTREACHED */
                }
        argc -= optind, argv += optind;
 
@@ -260,6 +288,7 @@ histcmd(int argc, char **argv)
                 * Catch interrupts to reset active counter and
                 * cleanup temp files.
                 */
+               savehandler = handler;
                if (setjmp(jmploc.loc)) {
                        active = 0;
                        if (*editfile)
@@ -267,7 +296,6 @@ histcmd(int argc, char **argv)
                        handler = savehandler;
                        longjmp(handler->loc, 1);
                }
-               savehandler = handler;
                handler = &jmploc;
                if (++active > MAXHISTLOOPS) {
                        active = 0;
@@ -298,6 +326,13 @@ histcmd(int argc, char **argv)
                *repl++ = '\0';
                argc--, argv++;
        }
+
+       /*
+        * If -s is specified, accept only one operand
+        */
+       if (sflg && argc >= 2)
+               error("too many args");
+
        /*
         * determine [first] and [last]
         */
@@ -316,6 +351,7 @@ histcmd(int argc, char **argv)
                break;
        default:
                error("too many args");
+               /* NOTREACHED */
        }
        /*
         * Turn into event numbers.
@@ -341,7 +377,7 @@ histcmd(int argc, char **argv)
        if (editor) {
                int fd;
                INTOFF;         /* easier */
-               sprintf(editfile, "%s/_shXXXXXX", _PATH_TMP);
+               snprintf(editfile, sizeof(editfile), "%s_shXXXXXX", _PATH_TMP);
                if ((fd = mkstemp(editfile)) < 0)
                        error("can't create temporary file %s", editfile);
                if ((efp = fdopen(fd, "w")) == NULL) {
@@ -366,34 +402,29 @@ histcmd(int argc, char **argv)
                                out1fmt("%5d ", he.num);
                        out1str(he.str);
                } else {
-                       char *s = pat ?
-                          fc_replace(he.str, pat, repl) : (char *)he.str;
+                       const char *s = pat ?
+                          fc_replace(he.str, pat, repl) : he.str;
 
                        if (sflg) {
                                if (displayhist) {
                                        out2str(s);
                                }
-                               evalstring(s);
+
+                               evalstring(strcpy(stalloc(strlen(s) + 1), s), 0);
                                if (displayhist && hist) {
                                        /*
                                         *  XXX what about recursive and
                                         *  relative histnums.
                                         */
-                                       oldhistnum = he.num;
                                        history(hist, &he, H_ENTER, s);
-                                       /*
-                                        * XXX H_ENTER moves the internal
-                                        * cursor, set it back to the current
-                                        * entry.
-                                        */
-                                       retval = history(hist, &he,
-                                           H_NEXT_EVENT, oldhistnum);
                                }
+
+                               break;
                        } else
                                fputs(s, efp);
                }
                /*
-                * At end?  (if we were to loose last, we'd sure be
+                * At end?  (if we were to lose last, we'd sure be
                 * messed up).
                 */
                if (he.num == last)
@@ -405,7 +436,7 @@ histcmd(int argc, char **argv)
                fclose(efp);
                editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
                sprintf(editcmd, "%s %s", editor, editfile);
-               evalstring(editcmd);    /* XXX - should use no JC command */
+               evalstring(editcmd, 0); /* XXX - should use no JC command */
                INTON;
                readcmdfile(editfile);  /* XXX - should read back - quick tst */
                unlink(editfile);
@@ -418,7 +449,7 @@ histcmd(int argc, char **argv)
        return 0;
 }
 
-STATIC char *
+STATIC const char *
 fc_replace(const char *s, char *p, char *r)
 {
        char *dest;
@@ -440,21 +471,21 @@ fc_replace(const char *s, char *p, char *r)
        return (dest);
 }
 
-STATIC int
+int
 not_fcnumber(char *s)
 {
        if (s == NULL)
-               return (0);
-       if (*s == '-')
-               s++;
+               return 0;
+        if (*s == '-')
+                s++;
        return (!is_number(s));
 }
 
-STATIC int
-str_to_event(char *str, int last)
+int
+str_to_event(const char *str, int last)
 {
        HistEvent he;
-       char *s = str;
+       const char *s = str;
        int relative = 0;
        int i, retval;
 
@@ -481,7 +512,8 @@ str_to_event(char *str, int last)
                                 * the notion of first and last is
                                 * backwards to that of the history package
                                 */
-                               retval = history(hist, &he, last ? H_FIRST : H_LAST);
+                               retval = history(hist, &he,
+                                               last ? H_FIRST : H_LAST);
                        }
                }
                if (retval == -1)
@@ -497,37 +529,17 @@ str_to_event(char *str, int last)
        }
        return (he.num);
 }
-
-int
-bindcmd(int argc, char **argv)
-{
-
-       if (el == NULL)
-               error("line editing is disabled");
-       return (el_parse(el, argc, argv));
-}
-
 #else
-#include "error.h"
-
 int
 histcmd(int argc, char **argv)
 {
-
        error("not compiled with history support");
-       /*NOTREACHED*/
-       return (0);
+       /* NOTREACHED */
 }
-
 int
-bindcmd(int argc, char **argv)
+inputrc(int argc, char **argv)
 {
-
-       error("not compiled with line editing support");
-       return (0);
+       error("not compiled with history support");
+       /* NOTREACHED */
 }
-#endif /* !NO_HISTORY */
-
-/*
- * $PchId: histedit.c,v 1.6 2006/04/10 14:52:58 philip Exp $
- */
+#endif
similarity index 89%
rename from minix/commands/ash/init.h
rename to bin/sh/init.h
index 0cfb9c4ca7433da74dcaf6e33a551456bac67dcb..60d924e9903f78c7fa9cd3e181aae329a07449e1 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: init.h,v 1.10 2003/08/07 09:05:32 agc Exp $    */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)init.h      8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/init.h,v 1.8 2004/04/06 20:06:51 markm Exp $
  */
 
 void init(void);
 void reset(void);
 void initshellproc(void);
-
-/*
- * $PchId: init.h,v 1.3 2006/03/30 14:31:06 philip Exp $
- */
similarity index 80%
rename from minix/commands/ash/input.c
rename to bin/sh/input.c
index 15fa04ccdd1a571a475ea494db108bb79a12b7b7..50e5cfdaf96b799f8e6c79bf5d641e8c6fe59b61 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: input.c,v 1.46 2013/10/30 08:38:40 mrg Exp $   */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)input.c    8.3 (Berkeley) 6/9/95";
+#else
+__RCSID("$NetBSD: input.c,v 1.46 2013/10/30 08:38:40 mrg Exp $");
 #endif
 #endif /* not lint */
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22 2004/04/06 20:06:51 markm Exp $");
-*/
 
-#include <sys/types.h>
 #include <stdio.h>     /* defines BUFSIZ */
 #include <fcntl.h>
 #include <errno.h>
 #include <unistd.h>
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/stat.h>
 
 /*
  * This file implements the input routines used by the parser.
@@ -64,10 +64,6 @@ __FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22 2004/04/06 20:06:51 markm Exp $");
 #include "alias.h"
 #include "parser.h"
 #include "myhistedit.h"
-#include "redir.h"
-#include "trap.h"
-
-static void popstring(void);
 
 #define EOF_NLEFT -99          /* value of parsenleft when EOF pushed back */
 
@@ -91,7 +87,7 @@ struct parsefile {
        int linno;              /* current line */
        int fd;                 /* file descriptor (or -1 if string) */
        int nleft;              /* number of chars left in this line */
-       int lleft;              /* number of lines left in this buffer */
+       int lleft;              /* number of chars left in this buffer */
        char *nextc;            /* next char in buffer */
        char *buf;              /* input buffer */
        struct strpush *strpush; /* for pushing strings at this level */
@@ -100,27 +96,24 @@ struct parsefile {
 
 
 int plinno = 1;                        /* input line number */
-MKINIT int parsenleft;         /* copy of parsefile->nleft */
+int parsenleft;                        /* copy of parsefile->nleft */
 MKINIT int parselleft;         /* copy of parsefile->lleft */
 char *parsenextc;              /* copy of parsefile->nextc */
 MKINIT struct parsefile basepf;        /* top level input file */
-char basebuf[BUFSIZ];          /* buffer for top level input file */
-STATIC struct parsefile *parsefile = &basepf;  /* current input file */
+MKINIT char basebuf[BUFSIZ];   /* buffer for top level input file */
+struct parsefile *parsefile = &basepf; /* current input file */
 int init_editline = 0;         /* editline library initialized? */
-int whichprompt;               /* -1 == PSE, 1 == PS1, 2 == PS2 */
-
-EditLine *el;                  /* cookie for editline package */
+int whichprompt;               /* 1 == PS1, 2 == PS2 */
 
 STATIC void pushfile(void);
 static int preadfd(void);
 
 #ifdef mkinit
+INCLUDE <stdio.h>
 INCLUDE "input.h"
 INCLUDE "error.h"
 
 INIT {
-       extern char basebuf[];
-
        basepf.nextc = basepf.buf = basebuf;
 }
 
@@ -180,35 +173,40 @@ static int
 preadfd(void)
 {
        int nr;
-       parsenextc = parsefile->buf;
+       char *buf =  parsefile->buf;
+       parsenextc = buf;
 
-#if !defined(NO_HISTORY)
-       if (el != NULL && gotwinch) {
-               gotwinch = 0;
-               el_resize(el);
-       }
-#endif
 retry:
-#ifndef NO_HISTORY
+#ifndef SMALL
        if (parsefile->fd == 0 && el) {
-               const char *rl_cp;
+               static const char *rl_cp;
+               static int el_len;
 
-               rl_cp = el_gets(el, &nr);
                if (rl_cp == NULL)
-                       nr = 0;
+                       rl_cp = el_gets(el, &el_len);
+               if (rl_cp == NULL)
+                       nr = el_len == 0 ? 0 : -1;
                else {
-                       /* XXX - BUFSIZE should redesign so not necessary */
-                       (void) strcpy(parsenextc, rl_cp);
+                       nr = el_len;
+                       if (nr > BUFSIZ - 8)
+                               nr = BUFSIZ - 8;
+                       memcpy(buf, rl_cp, nr);
+                       if (nr != el_len) {
+                               el_len -= nr;
+                               rl_cp += nr;
+                       } else
+                               rl_cp = 0;
                }
+
        } else
 #endif
-               nr = read(parsefile->fd, parsenextc, BUFSIZ - 1);
+               nr = read(parsefile->fd, buf, BUFSIZ - 8);
+
 
        if (nr <= 0) {
                 if (nr < 0) {
                         if (errno == EINTR)
                                 goto retry;
-#ifdef EWOULDBLOCK
                         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
                                 int flags = fcntl(0, F_GETFL, 0);
                                 if (flags >= 0 && flags & O_NONBLOCK) {
@@ -219,7 +217,6 @@ retry:
                                         }
                                 }
                         }
-#endif /* EWOULDBLOCK */
                 }
                 nr = -1;
        }
@@ -232,7 +229,7 @@ retry:
  * 1) If a string was pushed back on the input, pop it;
  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
  *    from a string so we can't refill the buffer, return EOF.
- * 3) If there is more in this buffer, use it else call read to fill it.
+ * 3) If the is more stuff in this buffer, use it else call read to fill it.
  * 4) Process input up to the next newline, deleting nul characters.
  */
 
@@ -241,7 +238,9 @@ preadbuffer(void)
 {
        char *p, *q;
        int more;
+#ifndef SMALL
        int something;
+#endif
        char savec;
 
        if (parsefile->strpush) {
@@ -265,7 +264,9 @@ again:
        q = p = parsenextc;
 
        /* delete nul characters */
+#ifndef SMALL
        something = 0;
+#endif
        for (more = 1; more;) {
                switch (*p) {
                case '\0':
@@ -282,7 +283,9 @@ again:
                        break;
 
                default:
+#ifndef SMALL
                        something = 1;
+#endif
                        break;
                }
 
@@ -300,11 +303,11 @@ check:
        savec = *q;
        *q = '\0';
 
-#if !defined(NO_HISTORY)
+#ifndef SMALL
        if (parsefile->fd == 0 && hist && something) {
                HistEvent he;
                INTOFF;
-               history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
+               history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
                    parsenextc);
                INTON;
        }
@@ -342,7 +345,7 @@ pushstring(char *s, int len, void *ap)
        struct strpush *sp;
 
        INTOFF;
-/*dbgprintf("*** calling pushstring: %s, %d\n", s, len);*/
+/*debugprintf("*** calling pushstring: %s, %d\n", s, len);*/
        if (parsefile->strpush) {
                sp = ckmalloc(sizeof (struct strpush));
                sp->prev = parsefile->strpush;
@@ -360,7 +363,7 @@ pushstring(char *s, int len, void *ap)
        INTON;
 }
 
-static void
+void
 popstring(void)
 {
        struct strpush *sp = parsefile->strpush;
@@ -369,7 +372,7 @@ popstring(void)
        parsenextc = sp->prevstring;
        parsenleft = sp->prevnleft;
        parselleft = sp->prevlleft;
-/*dbgprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
+/*debugprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
        if (sp->ap)
                sp->ap->flag &= ~ALIASINUSE;
        parsefile->strpush = sp->prev;
@@ -384,27 +387,32 @@ popstring(void)
  */
 
 void
-setinputfile(char *fname, int push)
+setinputfile(const char *fname, int push)
 {
+       unsigned char magic[4];
        int fd;
        int fd2;
-       struct stat statbuf;
-       int saved_errno;
 
        INTOFF;
        if ((fd = open(fname, O_RDONLY)) < 0)
-               error("Can't open %s: %s", fname, strerror(errno));
-       if (fstat(fd, &statbuf) < 0) {
-               saved_errno = errno;
-               close(fd);
-               error("Can't stat %s: %s", fname, strerror(saved_errno));
-       }
-       if (!S_ISREG(statbuf.st_mode)) {
-               close(fd);
-               error("Can't open %s: %s", fname, strerror(ENOEXEC));
+               error("Can't open %s", fname);
+
+       /* Since the message "Syntax error: "(" unexpected" is not very
+        * helpful, we check if the file starts with the ELF magic to
+        * avoid that message. The first lseek tries to make sure that
+        * we can later rewind the file.
+        */
+       if (lseek(fd, 0, SEEK_SET) == 0) {
+               if (read(fd, magic, 4) == 4) {
+                       if (memcmp(magic, "\177ELF", 4) == 0)
+                               error("Cannot execute ELF binary %s", fname);
+               }
+               if (lseek(fd, 0, SEEK_SET) != 0)
+                       error("Cannot rewind the file %s", fname);
        }
+
        if (fd < 10) {
-               fd2 = fcntl(fd, F_DUPFD, 10);
+               fd2 = copyfd(fd, 10, 0);
                close(fd);
                if (fd2 < 0)
                        error("Out of file descriptors");
@@ -423,7 +431,7 @@ setinputfile(char *fname, int push)
 void
 setinputfd(int fd, int push)
 {
-       (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
+       (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
        if (push) {
                pushfile();
                parsefile->buf = ckmalloc(BUFSIZ);
@@ -518,18 +526,25 @@ popallfiles(void)
 /*
  * Close the file(s) that the shell is reading commands from.  Called
  * after a fork is done.
+ *
+ * Takes one arg, vfork, which tells it to not modify its global vars
+ * as it is still running in the parent.
+ *
+ * This code is (probably) unnecessary as the 'close on exec' flag is
+ * set and should be enough.  In the vfork case it is definitely wrong
+ * to close the fds as another fork() may be done later to feed data
+ * from a 'here' document into a pipe and we don't want to close the
+ * pipe!
  */
 
 void
-closescript(void)
+closescript(int vforked)
 {
+       if (vforked)
+               return;
        popallfiles();
        if (parsefile->fd > 0) {
                close(parsefile->fd);
                parsefile->fd = 0;
        }
 }
-
-/*
- * $PchId: input.c,v 1.7 2006/05/29 13:09:38 philip Exp $
- */
similarity index 90%
rename from minix/commands/ash/input.h
rename to bin/sh/input.h
index 97267b513c2c4f770a85cd67fad89b98f1112405..a9d3a12b429d1abbe192907068efe9dee54532c8 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: input.h,v 1.15 2003/08/07 09:05:33 agc Exp $   */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -30,7 +32,6 @@
  * SUCH DAMAGE.
  *
  *     @(#)input.h     8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/input.h,v 1.9 2004/04/06 20:06:51 markm Exp $
  */
 
 /* PEOF (the end of file marker) is defined in syntax.h */
@@ -50,15 +51,12 @@ int pgetc(void);
 int preadbuffer(void);
 void pungetc(void);
 void pushstring(char *, int, void *);
-void setinputfile(char *, int);
+void popstring(void);
+void setinputfile(const char *, int);
 void setinputfd(int, int);
 void setinputstring(char *, int);
 void popfile(void);
 void popallfiles(void);
-void closescript(void);
+void closescript(int);
 
 #define pgetc_macro()  (--parsenleft >= 0? *parsenextc++ : preadbuffer())
-
-/*
- * $PchId: input.h,v 1.3 2006/03/30 13:49:37 philip Exp $
- */
diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c
new file mode 100644 (file)
index 0000000..4505b18
--- /dev/null
@@ -0,0 +1,1527 @@
+/*     $NetBSD: jobs.c,v 1.71 2012/12/31 14:10:15 dsl Exp $    */
+
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)jobs.c     8.5 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: jobs.c,v 1.71 2012/12/31 14:10:15 dsl Exp $");
+#endif
+#endif /* not lint */
+
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <paths.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef BSD
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <sys/ioctl.h>
+
+#include "shell.h"
+#if JOBS
+#if OLD_TTY_DRIVER
+#include "sgtty.h"
+#else
+#include <termios.h>
+#endif
+#undef CEOF                    /* syntax.h redefines this */
+#endif
+#include "redir.h"
+#include "show.h"
+#include "main.h"
+#include "parser.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "options.h"
+#include "builtins.h"
+#include "trap.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+
+
+static struct job *jobtab;             /* array of jobs */
+static int njobs;                      /* size of array */
+static int jobs_invalid;               /* set in child */
+MKINIT pid_t backgndpid = -1;  /* pid of last background process */
+#if JOBS
+int initialpgrp;               /* pgrp of shell on invocation */
+static int curjob = -1;                /* current job */
+#endif
+#if JOBS && defined(__minix)
+static int ttyfd = -1;
+#endif /* JOBS && defined(__minix) */
+
+STATIC void restartjob(struct job *);
+STATIC void freejob(struct job *);
+STATIC struct job *getjob(const char *, int);
+STATIC int dowait(int, struct job *);
+#define WBLOCK 1
+#define WNOFREE 2
+STATIC int waitproc(int, struct job *, int *);
+STATIC void cmdtxt(union node *);
+STATIC void cmdlist(union node *, int);
+STATIC void cmdputs(const char *);
+
+#ifdef SYSV
+STATIC int onsigchild(void);
+#endif
+
+#ifdef OLD_TTY_DRIVER
+static pid_t tcgetpgrp(int fd);
+static int tcsetpgrp(int fd, pid_t pgrp);
+
+static pid_t
+tcgetpgrp(int fd)
+{
+       pid_t pgrp;
+       if (ioctl(fd, TIOCGPGRP, (char *)&pgrp) == -1)
+               return -1;
+       else
+               return pgrp;
+}
+
+static int
+tcsetpgrp(int fd, pid_tpgrp)
+{
+       return ioctl(fd, TIOCSPGRP, (char *)&pgrp);
+}
+#endif
+
+/*
+ * Turn job control on and off.
+ *
+ * Note:  This code assumes that the third arg to ioctl is a character
+ * pointer, which is true on Berkeley systems but not System V.  Since
+ * System V doesn't have job control yet, this isn't a problem now.
+ */
+
+MKINIT int jobctl;
+
+#if JOBS /* Minix setjobctl is defined to empty, compilation error */
+void
+setjobctl(int on)
+{
+#ifdef OLD_TTY_DRIVER
+       int ldisc;
+#endif
+
+       if (on == jobctl || rootshell == 0)
+               return;
+       if (on) {
+#if defined(FIOCLEX) || defined(FD_CLOEXEC)
+               int err;
+               int i;
+               if (ttyfd != -1)
+                       close(ttyfd);
+               if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) {
+                       for (i = 0; i < 3; i++) {
+                               if (isatty(i) && (ttyfd = dup(i)) != -1)
+                                       break;
+                       }
+                       if (i == 3)
+                               goto out;
+               }
+               /* Move to a high fd */
+               for (i = 10; i > 2; i--) {
+                       if ((err = fcntl(ttyfd, F_DUPFD, (1 << i) - 1)) != -1)
+                               break;
+               }
+               if (err != -1) {
+                       close(ttyfd);
+                       ttyfd = err;
+               }
+#ifdef FIOCLEX
+               err = ioctl(ttyfd, FIOCLEX, 0);
+#elif FD_CLOEXEC
+               err = fcntl(ttyfd, F_SETFD,
+                   fcntl(ttyfd, F_GETFD, 0) | FD_CLOEXEC);
+#endif
+               if (err == -1) {
+                       close(ttyfd);
+                       ttyfd = -1;
+                       goto out;
+               }
+#else
+               out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control");
+               goto out;
+#endif
+               do { /* while we are in the background */
+                       if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) {
+out:
+                               out2str("sh: can't access tty; job control turned off\n");
+                               mflag = 0;
+                               return;
+                       }
+                       if (initialpgrp == -1)
+                               initialpgrp = getpgrp();
+                       else if (initialpgrp != getpgrp()) {
+                               killpg(0, SIGTTIN);
+                               continue;
+                       }
+               } while (0);
+
+#ifdef OLD_TTY_DRIVER
+               if (ioctl(ttyfd, TIOCGETD, (char *)&ldisc) < 0
+                   || ldisc != NTTYDISC) {
+                       out2str("sh: need new tty driver to run job control; job control turned off\n");
+                       mflag = 0;
+                       return;
+               }
+#endif
+               setsignal(SIGTSTP, 0);
+               setsignal(SIGTTOU, 0);
+               setsignal(SIGTTIN, 0);
+               if (getpgrp() != rootpid && setpgid(0, rootpid) == -1)
+                       error("Cannot set process group (%s) at %d",
+                           strerror(errno), __LINE__);
+               if (tcsetpgrp(ttyfd, rootpid) == -1)
+                       error("Cannot set tty process group (%s) at %d",
+                           strerror(errno), __LINE__);
+       } else { /* turning job control off */
+               if (getpgrp() != initialpgrp && setpgid(0, initialpgrp) == -1)
+                       error("Cannot set process group (%s) at %d",
+                           strerror(errno), __LINE__);
+               if (tcsetpgrp(ttyfd, initialpgrp) == -1)
+                       error("Cannot set tty process group (%s) at %d",
+                           strerror(errno), __LINE__);
+               close(ttyfd);
+               ttyfd = -1;
+               setsignal(SIGTSTP, 0);
+               setsignal(SIGTTOU, 0);
+               setsignal(SIGTTIN, 0);
+       }
+       jobctl = on;
+}
+#endif /* JOBS */
+
+
+#ifdef mkinit
+INCLUDE <stdlib.h>
+
+SHELLPROC {
+       backgndpid = -1;
+#if JOBS
+       jobctl = 0;
+#endif
+}
+
+#endif
+
+
+
+#if JOBS
+static int
+do_fgcmd(const char *arg_ptr)
+{
+       struct job *jp;
+       int i;
+       int status;
+
+       jp = getjob(arg_ptr, 0);
+       if (jp->jobctl == 0)
+               error("job not created under job control");
+       out1fmt("%s", jp->ps[0].cmd);
+       for (i = 1; i < jp->nprocs; i++)
+               out1fmt(" | %s", jp->ps[i].cmd );
+       out1c('\n');
+       flushall();
+
+       for (i = 0; i < jp->nprocs; i++)
+           if (tcsetpgrp(ttyfd, jp->ps[i].pid) != -1)
+                   break;
+
+       if (i >= jp->nprocs) {
+               error("Cannot set tty process group (%s) at %d",
+                   strerror(errno), __LINE__);
+       }
+       restartjob(jp);
+       INTOFF;
+       status = waitforjob(jp);
+       INTON;
+       return status;
+}
+
+int
+fgcmd(int argc, char **argv)
+{
+       nextopt("");
+       return do_fgcmd(*argptr);
+}
+
+int
+fgcmd_percent(int argc, char **argv)
+{
+       nextopt("");
+       return do_fgcmd(*argv);
+}
+
+static void
+set_curjob(struct job *jp, int mode)
+{
+       struct job *jp1, *jp2;
+       int i, ji;
+
+       ji = jp - jobtab;
+
+       /* first remove from list */
+       if (ji == curjob)
+               curjob = jp->prev_job;
+       else {
+               for (i = 0; i < njobs; i++) {
+                       if (jobtab[i].prev_job != ji)
+                               continue;
+                       jobtab[i].prev_job = jp->prev_job;
+                       break;
+               }
+       }
+
+       /* Then re-insert in correct position */
+       switch (mode) {
+       case 0: /* job being deleted */
+               jp->prev_job = -1;
+               break;
+       case 1: /* newly created job or backgrounded job,
+                  put after all stopped jobs. */
+               if (curjob != -1 && jobtab[curjob].state == JOBSTOPPED) {
+                       for (jp1 = jobtab + curjob; ; jp1 = jp2) {
+                               if (jp1->prev_job == -1)
+                                       break;
+                               jp2 = jobtab + jp1->prev_job;
+                               if (jp2->state != JOBSTOPPED)
+                                       break;
+                       }
+                       jp->prev_job = jp1->prev_job;
+                       jp1->prev_job = ji;
+                       break;
+               }
+               /* FALLTHROUGH */
+       case 2: /* newly stopped job - becomes curjob */
+               jp->prev_job = curjob;
+               curjob = ji;
+               break;
+       }
+}
+
+int
+bgcmd(int argc, char **argv)
+{
+       struct job *jp;
+       int i;
+
+       nextopt("");
+       do {
+               jp = getjob(*argptr, 0);
+               if (jp->jobctl == 0)
+                       error("job not created under job control");
+               set_curjob(jp, 1);
+               out1fmt("[%ld] %s", (long)(jp - jobtab + 1), jp->ps[0].cmd);
+               for (i = 1; i < jp->nprocs; i++)
+                       out1fmt(" | %s", jp->ps[i].cmd );
+               out1c('\n');
+               flushall();
+               restartjob(jp);
+       } while (*argptr && *++argptr);
+       return 0;
+}
+
+
+STATIC void
+restartjob(struct job *jp)
+{
+       struct procstat *ps;
+       int i;
+
+       if (jp->state == JOBDONE)
+               return;
+       INTOFF;
+       for (i = 0; i < jp->nprocs; i++)
+               if (killpg(jp->ps[i].pid, SIGCONT) != -1)
+                       break;
+       if (i >= jp->nprocs)
+               error("Cannot continue job (%s)", strerror(errno));
+       for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
+               if (WIFSTOPPED(ps->status)) {
+                       ps->status = -1;
+                       jp->state = JOBRUNNING;
+               }
+       }
+       INTON;
+}
+#else
+/* LSC: For Minix add dummy functions. */
+int
+fgcmd(int argc, char **argv)
+{
+       error("no job control in this shell.");
+       return 1;
+}
+
+int
+fgcmd_percent(int argc, char **argv)
+{
+       error("no job control in this shell.");
+       return 1;
+}
+
+
+int
+bgcmd(int argc, char **argv)
+{
+       error("no job control in this shell.");
+       return 1;
+}
+#endif
+
+static void
+showjob(struct output *out, struct job *jp, int mode)
+{
+       int procno;
+       int st;
+       struct procstat *ps;
+       int col;
+       char s[64];
+
+#if JOBS
+       if (mode & SHOW_PGID) {
+               /* just output process (group) id of pipeline */
+               outfmt(out, "%ld\n", (long)jp->ps->pid);
+               return;
+       }
+#endif
+
+       procno = jp->nprocs;
+       if (!procno)
+               return;
+
+       if (mode & SHOW_PID)
+               mode |= SHOW_MULTILINE;
+
+       if ((procno > 1 && !(mode & SHOW_MULTILINE))
+           || (mode & SHOW_SIGNALLED)) {
+               /* See if we have more than one status to report */
+               ps = jp->ps;
+               st = ps->status;
+               do {
+                       int st1 = ps->status;
+                       if (st1 != st)
+                               /* yes - need multi-line output */
+                               mode |= SHOW_MULTILINE;
+                       if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1))
+                               continue;
+                       if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f)
+                           && st1 != SIGINT && st1 != SIGPIPE))
+                               mode |= SHOW_ISSIG;
+
+               } while (ps++, --procno);
+               procno = jp->nprocs;
+       }
+
+       if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) {
+               if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) {
+                       TRACE(("showjob: freeing job %d\n", jp - jobtab + 1));
+                       freejob(jp);
+               }
+               return;
+       }
+
+       for (ps = jp->ps; --procno >= 0; ps++) {        /* for each process */
+               if (ps == jp->ps)
+                       fmtstr(s, 16, "[%ld] %c ",
+                               (long)(jp - jobtab + 1),
+#if JOBS
+                               jp == jobtab + curjob ? '+' :
+                               curjob != -1 && jp == jobtab +
+                                           jobtab[curjob].prev_job ? '-' :
+#endif
+                               ' ');
+               else
+                       fmtstr(s, 16, "      " );
+               col = strlen(s);
+               if (mode & SHOW_PID) {
+                       fmtstr(s + col, 16, "%ld ", (long)ps->pid);
+                            col += strlen(s + col);
+               }
+               if (ps->status == -1) {
+                       scopy("Running", s + col);
+               } else if (WIFEXITED(ps->status)) {
+                       st = WEXITSTATUS(ps->status);
+                       if (st)
+                               fmtstr(s + col, 16, "Done(%d)", st);
+                       else
+                               fmtstr(s + col, 16, "Done");
+               } else {
+#if JOBS
+                       if (WIFSTOPPED(ps->status)) 
+                               st = WSTOPSIG(ps->status);
+                       else /* WIFSIGNALED(ps->status) */
+#endif
+                               st = WTERMSIG(ps->status);
+                       st &= 0x7f;
+                       if (st < NSIG && sys_siglist[st])
+                               scopyn(sys_siglist[st], s + col, 32);
+                       else
+                               fmtstr(s + col, 16, "Signal %d", st);
+                       if (WCOREDUMP(ps->status)) {
+                               col += strlen(s + col);
+                               scopyn(" (core dumped)", s + col,  64 - col);
+                       }
+               }
+               col += strlen(s + col);
+               outstr(s, out);
+               do {
+                       outc(' ', out);
+                       col++;
+               } while (col < 30);
+               outstr(ps->cmd, out);
+               if (mode & SHOW_MULTILINE) {
+                       if (procno > 0) {
+                               outc(' ', out);
+                               outc('|', out);
+                       }
+               } else {
+                       while (--procno >= 0)
+                               outfmt(out, " | %s", (++ps)->cmd );
+               }
+               outc('\n', out);
+       }
+       flushout(out);
+       jp->changed = 0;
+       if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE))
+               freejob(jp);
+}
+
+
+int
+jobscmd(int argc, char **argv)
+{
+       int mode, m;
+       int sv = jobs_invalid;
+
+       jobs_invalid = 0;
+       mode = 0;
+       while ((m = nextopt("lp")))
+               if (m == 'l')
+                       mode = SHOW_PID;
+               else
+                       mode = SHOW_PGID;
+       if (*argptr)
+               do
+                       showjob(out1, getjob(*argptr,0), mode);
+               while (*++argptr);
+       else
+               showjobs(out1, mode);
+       jobs_invalid = sv;
+       return 0;
+}
+
+
+/*
+ * Print a list of jobs.  If "change" is nonzero, only print jobs whose
+ * statuses have changed since the last call to showjobs.
+ *
+ * If the shell is interrupted in the process of creating a job, the
+ * result may be a job structure containing zero processes.  Such structures
+ * will be freed here.
+ */
+
+void
+showjobs(struct output *out, int mode)
+{
+       int jobno;
+       struct job *jp;
+       int silent = 0, gotpid;
+
+       TRACE(("showjobs(%x) called\n", mode));
+
+       /* If not even one one job changed, there is nothing to do */
+       gotpid = dowait(0, NULL);
+       while (dowait(0, NULL) > 0)
+               continue;
+#if JOBS /* MINIX: #ifdef fails when JOBS = 0 */
+       /*
+        * Check if we are not in our foreground group, and if not
+        * put us in it.
+        */
+       if (mflag && gotpid != -1 && tcgetpgrp(ttyfd) != getpid()) {
+               if (tcsetpgrp(ttyfd, getpid()) == -1)
+                       error("Cannot set tty process group (%s) at %d",
+                           strerror(errno), __LINE__);
+               TRACE(("repaired tty process group\n"));
+               silent = 1;
+       }
+#endif
+       if (jobs_invalid)
+               return;
+
+       for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
+               if (!jp->used)
+                       continue;
+               if (jp->nprocs == 0) {
+                       freejob(jp);
+                       continue;
+               }
+               if ((mode & SHOW_CHANGED) && !jp->changed)
+                       continue;
+               if (silent && jp->changed) {
+                       jp->changed = 0;
+                       continue;
+               }
+               showjob(out, jp, mode);
+       }
+}
+
+/*
+ * Mark a job structure as unused.
+ */
+
+STATIC void
+freejob(struct job *jp)
+{
+       INTOFF;
+       if (jp->ps != &jp->ps0) {
+               ckfree(jp->ps);
+               jp->ps = &jp->ps0;
+       }
+       jp->nprocs = 0;
+       jp->used = 0;
+#if JOBS
+       set_curjob(jp, 0);
+#endif
+       INTON;
+}
+
+
+
+int
+waitcmd(int argc, char **argv)
+{
+       struct job *job;
+       int status, retval;
+       struct job *jp;
+
+       nextopt("");
+
+       if (!*argptr) {
+               /* wait for all jobs */
+               jp = jobtab;
+               if (jobs_invalid)
+                       return 0;
+               for (;;) {
+                       if (jp >= jobtab + njobs) {
+                               /* no running procs */
+                               return 0;
+                       }
+                       if (!jp->used || jp->state != JOBRUNNING) {
+                               jp++;
+                               continue;
+                       }
+                       if (dowait(WBLOCK, NULL) == -1)
+                              return 128 + SIGINT;
+                       jp = jobtab;
+               }
+       }
+
+       retval = 127;           /* XXXGCC: -Wuninitialized */
+       for (; *argptr; argptr++) {
+               job = getjob(*argptr, 1);
+               if (!job) {
+                       retval = 127;
+                       continue;
+               }
+               /* loop until process terminated or stopped */
+               while (job->state == JOBRUNNING) {
+                       if (dowait(WBLOCK|WNOFREE, job) == -1)
+                              return 128 + SIGINT;
+               }
+               status = job->ps[job->nprocs - 1].status;
+               if (WIFEXITED(status))
+                       retval = WEXITSTATUS(status);
+#if JOBS
+               else if (WIFSTOPPED(status))
+                       retval = WSTOPSIG(status) + 128;
+#endif
+               else {
+                       /* XXX: limits number of signals */
+                       retval = WTERMSIG(status) + 128;
+               }
+               if (!iflag)
+                       freejob(job);
+       }
+       return retval;
+}
+
+
+
+int
+jobidcmd(int argc, char **argv)
+{
+       struct job *jp;
+       int i;
+
+       nextopt("");
+       jp = getjob(*argptr, 0);
+       for (i = 0 ; i < jp->nprocs ; ) {
+               out1fmt("%ld", (long)jp->ps[i].pid);
+               out1c(++i < jp->nprocs ? ' ' : '\n');
+       }
+       return 0;
+}
+
+int
+getjobpgrp(const char *name)
+{
+       struct job *jp;
+
+       jp = getjob(name, 1);
+       if (jp == 0)
+               return 0;
+       return -jp->ps[0].pid;
+}
+
+/*
+ * Convert a job name to a job structure.
+ */
+
+STATIC struct job *
+getjob(const char *name, int noerror)
+{
+       int jobno = -1;
+       struct job *jp;
+       int pid;
+       int i;
+       const char *err_msg = "No such job: %s";
+               
+       if (name == NULL) {
+#if JOBS
+               jobno = curjob;
+#endif
+               err_msg = "No current job";
+       } else if (name[0] == '%') {
+               if (is_number(name + 1)) {
+                       jobno = number(name + 1) - 1;
+               } else if (!name[2]) {
+                       switch (name[1]) {
+#if JOBS
+                       case 0:
+                       case '+':
+                       case '%':
+                               jobno = curjob;
+                               err_msg = "No current job";
+                               break;
+                       case '-':
+                               jobno = curjob;
+                               if (jobno != -1)
+                                       jobno = jobtab[jobno].prev_job;
+                               err_msg = "No previous job";
+                               break;
+#endif
+                       default:
+                               goto check_pattern;
+                       }
+               } else {
+                       struct job *found;
+    check_pattern:
+                       found = NULL;
+                       for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
+                               if (!jp->used || jp->nprocs <= 0)
+                                       continue;
+                               if ((name[1] == '?'
+                                       && strstr(jp->ps[0].cmd, name + 2))
+                                   || prefix(name + 1, jp->ps[0].cmd)) {
+                                       if (found) {
+                                               err_msg = "%s: ambiguous";
+                                               found = 0;
+                                               break;
+                                       }
+                                       found = jp;
+                               }
+                       }
+                       if (found)
+                               return found;
+               }
+
+       } else if (is_number(name)) {
+               pid = number(name);
+               for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
+                       if (jp->used && jp->nprocs > 0
+                        && jp->ps[jp->nprocs - 1].pid == pid)
+                               return jp;
+               }
+       }
+
+       if (!jobs_invalid && jobno >= 0 && jobno < njobs) {
+               jp = jobtab + jobno;
+               if (jp->used)
+                       return jp;
+       }
+       if (!noerror)
+               error(err_msg, name);
+       return 0;
+}
+
+
+
+/*
+ * Return a new job structure,
+ */
+
+struct job *
+makejob(union node *node, int nprocs)
+{
+       int i;
+       struct job *jp;
+
+       if (jobs_invalid) {
+               for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) {
+                       if (jp->used)
+                               freejob(jp);
+               }
+               jobs_invalid = 0;
+       }
+
+       for (i = njobs, jp = jobtab ; ; jp++) {
+               if (--i < 0) {
+                       INTOFF;
+                       if (njobs == 0) {
+                               jobtab = ckmalloc(4 * sizeof jobtab[0]);
+                       } else {
+                               jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
+                               memcpy(jp, jobtab, njobs * sizeof jp[0]);
+                               /* Relocate `ps' pointers */
+                               for (i = 0; i < njobs; i++)
+                                       if (jp[i].ps == &jobtab[i].ps0)
+                                               jp[i].ps = &jp[i].ps0;
+                               ckfree(jobtab);
+                               jobtab = jp;
+                       }
+                       jp = jobtab + njobs;
+                       for (i = 4 ; --i >= 0 ; )
+                               jobtab[njobs++].used = 0;
+                       INTON;
+                       break;
+               }
+               if (jp->used == 0)
+                       break;
+       }
+       INTOFF;
+       jp->state = JOBRUNNING;
+       jp->used = 1;
+       jp->changed = 0;
+       jp->nprocs = 0;
+#if JOBS
+       jp->jobctl = jobctl;
+       set_curjob(jp, 1);
+#endif
+       if (nprocs > 1) {
+               jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
+       } else {
+               jp->ps = &jp->ps0;
+       }
+       INTON;
+       TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
+           jp - jobtab + 1));
+       return jp;
+}
+
+
+/*
+ * Fork off a subshell.  If we are doing job control, give the subshell its
+ * own process group.  Jp is a job structure that the job is to be added to.
+ * N is the command that will be evaluated by the child.  Both jp and n may
+ * be NULL.  The mode parameter can be one of the following:
+ *     FORK_FG - Fork off a foreground process.
+ *     FORK_BG - Fork off a background process.
+ *     FORK_NOJOB - Like FORK_FG, but don't give the process its own
+ *                  process group even if job control is on.
+ *
+ * When job control is turned off, background processes have their standard
+ * input redirected to /dev/null (except for the second and later processes
+ * in a pipeline).
+ */
+
+int
+forkshell(struct job *jp, union node *n, int mode)
+{
+       int pid;
+
+       TRACE(("forkshell(%%%d, %p, %d) called\n", jp - jobtab, n, mode));
+       switch ((pid = fork())) {
+       case -1:
+               TRACE(("Fork failed, errno=%d\n", errno));
+               INTON;
+               error("Cannot fork");
+               break;
+       case 0:
+               forkchild(jp, n, mode, 0);
+               return 0;
+       default:
+               return forkparent(jp, n, mode, pid);
+       }
+}
+
+int
+forkparent(struct job *jp, union node *n, int mode, pid_t pid)
+{
+       int pgrp;
+
+       if (rootshell && mode != FORK_NOJOB && mflag) {
+               if (jp == NULL || jp->nprocs == 0)
+                       pgrp = pid;
+               else
+                       pgrp = jp->ps[0].pid;
+#if JOBS /* LSC: not available under MINIX. */
+               /* This can fail because we are doing it in the child also */
+               (void)setpgid(pid, pgrp);
+#endif
+       }
+       if (mode == FORK_BG)
+               backgndpid = pid;               /* set $! */
+       if (jp) {
+               struct procstat *ps = &jp->ps[jp->nprocs++];
+               ps->pid = pid;
+               ps->status = -1;
+               ps->cmd[0] = 0;
+               if (/* iflag && rootshell && */ n)
+                       commandtext(ps, n);
+       }
+       TRACE(("In parent shell:  child = %d\n", pid));
+       return pid;
+}
+
+void
+forkchild(struct job *jp, union node *n, int mode, int vforked)
+{
+       int wasroot;
+#if JOBS /* LSC: for proper compilation with JOBS == 0 */
+       int pgrp;
+#endif
+       const char *devnull = _PATH_DEVNULL;
+       const char *nullerr = "Can't open %s";
+
+       wasroot = rootshell;
+       TRACE(("Child shell %d\n", getpid()));
+       if (!vforked)
+               rootshell = 0;
+
+       closescript(vforked);
+       clear_traps(vforked);
+#if JOBS
+       if (!vforked)
+               jobctl = 0;             /* do job control only in root shell */
+       if (wasroot && mode != FORK_NOJOB && mflag) {
+               if (jp == NULL || jp->nprocs == 0)
+                       pgrp = getpid();
+               else
+                       pgrp = jp->ps[0].pid;
+               /* This can fail because we are doing it in the parent also */
+               (void)setpgid(0, pgrp);
+               if (mode == FORK_FG) {
+                       if (tcsetpgrp(ttyfd, pgrp) == -1)
+                               error("Cannot set tty process group (%s) at %d",
+                                   strerror(errno), __LINE__);
+               }
+               setsignal(SIGTSTP, vforked);
+               setsignal(SIGTTOU, vforked);
+       } else if (mode == FORK_BG) {
+               ignoresig(SIGINT, vforked);
+               ignoresig(SIGQUIT, vforked);
+               if ((jp == NULL || jp->nprocs == 0) &&
+                   ! fd0_redirected_p ()) {
+                       close(0);
+                       if (open(devnull, O_RDONLY) != 0)
+                               error(nullerr, devnull);
+               }
+       }
+#else
+       if (mode == FORK_BG) {
+               ignoresig(SIGINT, vforked);
+               ignoresig(SIGQUIT, vforked);
+               if ((jp == NULL || jp->nprocs == 0) &&
+                   ! fd0_redirected_p ()) {
+                       close(0);
+                       if (open(devnull, O_RDONLY) != 0)
+                               error(nullerr, devnull);
+               }
+       }
+#endif
+       if (wasroot && iflag) {
+               setsignal(SIGINT, vforked);
+               setsignal(SIGQUIT, vforked);
+               setsignal(SIGTERM, vforked);
+       }
+
+       if (!vforked)
+               jobs_invalid = 1;
+}
+
+/*
+ * Wait for job to finish.
+ *
+ * Under job control we have the problem that while a child process is
+ * running interrupts generated by the user are sent to the child but not
+ * to the shell.  This means that an infinite loop started by an inter-
+ * active user may be hard to kill.  With job control turned off, an
+ * interactive user may place an interactive program inside a loop.  If
+ * the interactive program catches interrupts, the user doesn't want
+ * these interrupts to also abort the loop.  The approach we take here
+ * is to have the shell ignore interrupt signals while waiting for a
+ * forground process to terminate, and then send itself an interrupt
+ * signal if the child process was terminated by an interrupt signal.
+ * Unfortunately, some programs want to do a bit of cleanup and then
+ * exit on interrupt; unless these processes terminate themselves by
+ * sending a signal to themselves (instead of calling exit) they will
+ * confuse this approach.
+ */
+
+int
+waitforjob(struct job *jp)
+{
+#if JOBS
+       int mypgrp = getpgrp();
+#endif
+       int status;
+       int st;
+
+       INTOFF;
+       TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
+       while (jp->state == JOBRUNNING) {
+               dowait(WBLOCK, jp);
+       }
+#if JOBS
+       if (jp->jobctl) {
+               if (tcsetpgrp(ttyfd, mypgrp) == -1)
+                       error("Cannot set tty process group (%s) at %d",
+                           strerror(errno), __LINE__);
+       }
+       if (jp->state == JOBSTOPPED && curjob != jp - jobtab)
+               set_curjob(jp, 2);
+#endif
+       status = jp->ps[jp->nprocs - 1].status;
+       /* convert to 8 bits */
+       if (WIFEXITED(status))
+               st = WEXITSTATUS(status);
+#if JOBS
+       else if (WIFSTOPPED(status))
+               st = WSTOPSIG(status) + 128;
+#endif
+       else
+               st = WTERMSIG(status) + 128;
+       TRACE(("waitforjob: job %d, nproc %d, status %x, st %x\n",
+               jp - jobtab + 1, jp->nprocs, status, st ));
+#if JOBS
+       if (jp->jobctl) {
+               /*
+                * This is truly gross.
+                * If we're doing job control, then we did a TIOCSPGRP which
+                * caused us (the shell) to no longer be in the controlling
+                * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
+                * intuit from the subprocess exit status whether a SIGINT
+                * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
+                */
+               if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
+                       raise(SIGINT);
+       }
+#endif
+       if (! JOBS || jp->state == JOBDONE)
+               freejob(jp);
+       INTON;
+       return st;
+}
+
+
+
+/*
+ * Wait for a process to terminate.
+ */
+
+STATIC int
+dowait(int flags, struct job *job)
+{
+       int pid;
+       int status;
+       struct procstat *sp;
+       struct job *jp;
+       struct job *thisjob;
+       int done;
+       int stopped;
+       extern volatile char gotsig[];
+
+       TRACE(("dowait(%x) called\n", flags));
+       do {
+               pid = waitproc(flags & WBLOCK, job, &status);
+               TRACE(("wait returns pid %d, status %d\n", pid, status));
+       } while (pid == -1 && errno == EINTR && gotsig[SIGINT - 1] == 0);
+       if (pid <= 0)
+               return pid;
+       INTOFF;
+       thisjob = NULL;
+       for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
+               if (jp->used) {
+                       done = 1;
+                       stopped = 1;
+                       for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
+                               if (sp->pid == -1)
+                                       continue;
+                               if (sp->pid == pid) {
+                                       TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jp - jobtab + 1, pid, sp->status, status));
+                                       sp->status = status;
+                                       thisjob = jp;
+                               }
+                               if (sp->status == -1)
+                                       stopped = 0;
+                               else if (WIFSTOPPED(sp->status))
+                                       done = 0;
+                       }
+                       if (stopped) {          /* stopped or done */
+                               int state = done ? JOBDONE : JOBSTOPPED;
+                               if (jp->state != state) {
+                                       TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
+                                       jp->state = state;
+#if JOBS
+                                       if (done)
+                                               set_curjob(jp, 0);
+#endif
+                               }
+                       }
+               }
+       }
+
+       if (thisjob && thisjob->state != JOBRUNNING) {
+               int mode = 0;
+               if (!rootshell || !iflag)
+                       mode = SHOW_SIGNALLED;
+               if ((job == thisjob && (flags & WNOFREE) == 0) ||
+                   (job != thisjob && (flags & WNOFREE) != 0))
+                       mode = SHOW_SIGNALLED | SHOW_NO_FREE;
+               if (mode)
+                       showjob(out2, thisjob, mode);
+               else {
+                       TRACE(("Not printing status, rootshell=%d, job=%p\n",
+                               rootshell, job));
+                       thisjob->changed = 1;
+               }
+       }
+
+       INTON;
+       return pid;
+}
+
+
+
+/*
+ * Do a wait system call.  If job control is compiled in, we accept
+ * stopped processes.  If block is zero, we return a value of zero
+ * rather than blocking.
+ *
+ * System V doesn't have a non-blocking wait system call.  It does
+ * have a SIGCLD signal that is sent to a process when one of its
+ * children dies.  The obvious way to use SIGCLD would be to install
+ * a handler for SIGCLD which simply bumped a counter when a SIGCLD
+ * was received, and have waitproc bump another counter when it got
+ * the status of a process.  Waitproc would then know that a wait
+ * system call would not block if the two counters were different.
+ * This approach doesn't work because if a process has children that
+ * have not been waited for, System V will send it a SIGCLD when it
+ * installs a signal handler for SIGCLD.  What this means is that when
+ * a child exits, the shell will be sent SIGCLD signals continuously
+ * until is runs out of stack space, unless it does a wait call before
+ * restoring the signal handler.  The code below takes advantage of
+ * this (mis)feature by installing a signal handler for SIGCLD and
+ * then checking to see whether it was called.  If there are any
+ * children to be waited for, it will be.
+ *
+ * If neither SYSV nor BSD is defined, we don't implement nonblocking
+ * waits at all.  In this case, the user will not be informed when
+ * a background process until the next time she runs a real program
+ * (as opposed to running a builtin command or just typing return),
+ * and the jobs command may give out of date information.
+ */
+
+#ifdef SYSV
+STATIC int gotsigchild;
+
+STATIC int onsigchild() {
+       gotsigchild = 1;
+}
+#endif
+
+
+STATIC int
+waitproc(int block, struct job *jp, int *status)
+{
+#ifdef BSD
+       int flags = 0;
+
+#if JOBS
+       if (jp != NULL && jp->jobctl)
+               flags |= WUNTRACED;
+#endif
+       if (block == 0)
+               flags |= WNOHANG;
+       return waitpid(-1, status, flags);
+#else
+#ifdef SYSV
+       int (*save)();
+
+       if (block == 0) {
+               gotsigchild = 0;
+               save = signal(SIGCLD, onsigchild);
+               signal(SIGCLD, save);
+               if (gotsigchild == 0)
+                       return 0;
+       }
+       return wait(status);
+#else
+       if (block == 0)
+               return 0;
+       return wait(status);
+#endif
+#endif
+}
+
+/*
+ * return 1 if there are stopped jobs, otherwise 0
+ */
+int job_warning = 0;
+int
+stoppedjobs(void)
+{
+       int jobno;
+       struct job *jp;
+
+       if (job_warning || jobs_invalid)
+               return (0);
+       for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
+               if (jp->used == 0)
+                       continue;
+               if (jp->state == JOBSTOPPED) {
+                       out2str("You have stopped jobs.\n");
+                       job_warning = 2;
+                       return (1);
+               }
+       }
+
+       return (0);
+}
+
+/*
+ * Return a string identifying a command (to be printed by the
+ * jobs command).
+ */
+
+STATIC char *cmdnextc;
+STATIC int cmdnleft;
+
+void
+commandtext(struct procstat *ps, union node *n)
+{
+       int len;
+
+       cmdnextc = ps->cmd;
+       if (iflag || mflag || sizeof ps->cmd < 100)
+               len = sizeof(ps->cmd);
+       else
+               len = sizeof(ps->cmd) / 10;
+       cmdnleft = len;
+       cmdtxt(n);
+       if (cmdnleft <= 0) {
+               char *p = ps->cmd + len - 4;
+               p[0] = '.';
+               p[1] = '.';
+               p[2] = '.';
+               p[3] = 0;
+       } else
+               *cmdnextc = '\0';
+       TRACE(("commandtext: ps->cmd %x, end %x, left %d\n\t\"%s\"\n",
+               ps->cmd, cmdnextc, cmdnleft, ps->cmd));
+}
+
+
+STATIC void
+cmdtxt(union node *n)
+{
+       union node *np;
+       struct nodelist *lp;
+       const char *p;
+       int i;
+       char s[2];
+
+       if (n == NULL || cmdnleft <= 0)
+               return;
+       switch (n->type) {
+       case NSEMI:
+               cmdtxt(n->nbinary.ch1);
+               cmdputs("; ");
+               cmdtxt(n->nbinary.ch2);
+               break;
+       case NAND:
+               cmdtxt(n->nbinary.ch1);
+               cmdputs(" && ");
+               cmdtxt(n->nbinary.ch2);
+               break;
+       case NOR:
+               cmdtxt(n->nbinary.ch1);
+               cmdputs(" || ");
+               cmdtxt(n->nbinary.ch2);
+               break;
+       case NPIPE:
+               for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+                       cmdtxt(lp->n);
+                       if (lp->next)
+                               cmdputs(" | ");
+               }
+               break;
+       case NSUBSHELL:
+               cmdputs("(");
+               cmdtxt(n->nredir.n);
+               cmdputs(")");
+               break;
+       case NREDIR:
+       case NBACKGND:
+               cmdtxt(n->nredir.n);
+               break;
+       case NIF:
+               cmdputs("if ");
+               cmdtxt(n->nif.test);
+               cmdputs("; then ");
+               cmdtxt(n->nif.ifpart);
+               if (n->nif.elsepart) {
+                       cmdputs("; else ");
+                       cmdtxt(n->nif.elsepart);
+               }
+               cmdputs("; fi");
+               break;
+       case NWHILE:
+               cmdputs("while ");
+               goto until;
+       case NUNTIL:
+               cmdputs("until ");
+until:
+               cmdtxt(n->nbinary.ch1);
+               cmdputs("; do ");
+               cmdtxt(n->nbinary.ch2);
+               cmdputs("; done");
+               break;
+       case NFOR:
+               cmdputs("for ");
+               cmdputs(n->nfor.var);
+               cmdputs(" in ");
+               cmdlist(n->nfor.args, 1);
+               cmdputs("; do ");
+               cmdtxt(n->nfor.body);
+               cmdputs("; done");
+               break;
+       case NCASE:
+               cmdputs("case ");
+               cmdputs(n->ncase.expr->narg.text);
+               cmdputs(" in ");
+               for (np = n->ncase.cases; np; np = np->nclist.next) {
+                       cmdtxt(np->nclist.pattern);
+                       cmdputs(") ");
+                       cmdtxt(np->nclist.body);
+                       cmdputs(";; ");
+               }
+               cmdputs("esac");
+               break;
+       case NDEFUN:
+               cmdputs(n->narg.text);
+               cmdputs("() { ... }");
+               break;
+       case NCMD:
+               cmdlist(n->ncmd.args, 1);
+               cmdlist(n->ncmd.redirect, 0);
+               break;
+       case NARG:
+               cmdputs(n->narg.text);
+               break;
+       case NTO:
+               p = ">";  i = 1;  goto redir;
+       case NCLOBBER:
+               p = ">|";  i = 1;  goto redir;
+       case NAPPEND:
+               p = ">>";  i = 1;  goto redir;
+       case NTOFD:
+               p = ">&";  i = 1;  goto redir;
+       case NFROM:
+               p = "<";  i = 0;  goto redir;
+       case NFROMFD:
+               p = "<&";  i = 0;  goto redir;
+       case NFROMTO:
+               p = "<>";  i = 0;  goto redir;
+redir:
+               if (n->nfile.fd != i) {
+                       s[0] = n->nfile.fd + '0';
+                       s[1] = '\0';
+                       cmdputs(s);
+               }
+               cmdputs(p);
+               if (n->type == NTOFD || n->type == NFROMFD) {
+                       s[0] = n->ndup.dupfd + '0';
+                       s[1] = '\0';
+                       cmdputs(s);
+               } else {
+                       cmdtxt(n->nfile.fname);
+               }
+               break;
+       case NHERE:
+       case NXHERE:
+               cmdputs("<<...");
+               break;
+       default:
+               cmdputs("???");
+               break;
+       }
+}
+
+STATIC void
+cmdlist(union node *np, int sep)
+{
+       for (; np; np = np->narg.next) {
+               if (!sep)
+                       cmdputs(" ");
+               cmdtxt(np);
+               if (sep && np->narg.next)
+                       cmdputs(" ");
+       }
+}
+
+
+STATIC void
+cmdputs(const char *s)
+{
+       const char *p, *str = 0;
+       char c, cc[2] = " ";
+       char *nextc;
+       int nleft;
+       int subtype = 0;
+       int quoted = 0;
+       static char vstype[16][4] = { "", "}", "-", "+", "?", "=",
+                                       "#", "##", "%", "%%" };
+
+       p = s;
+       nextc = cmdnextc;
+       nleft = cmdnleft;
+       while (nleft > 0 && (c = *p++) != 0) {
+               switch (c) {
+               case CTLESC:
+                       c = *p++;
+                       break;
+               case CTLVAR:
+                       subtype = *p++;
+                       if ((subtype & VSTYPE) == VSLENGTH)
+                               str = "${#";
+                       else
+                               str = "${";
+                       if (!(subtype & VSQUOTE) != !(quoted & 1)) {
+                               quoted ^= 1;
+                               c = '"';
+                       } else
+                               c = *str++;
+                       break;
+               case CTLENDVAR:
+                       if (quoted & 1) {
+                               c = '"';
+                               str = "}";
+                       } else
+                               c = '}';
+                       quoted >>= 1;
+                       subtype = 0;
+                       break;
+               case CTLBACKQ:
+                       c = '$';
+                       str = "(...)";
+                       break;
+               case CTLBACKQ+CTLQUOTE:
+                       c = '"';
+                       str = "$(...)\"";
+                       break;
+               case CTLARI:
+                       c = '$';
+                       str = "((";
+                       break;
+               case CTLENDARI:
+                       c = ')';
+                       str = ")";
+                       break;
+               case CTLQUOTEMARK:
+                       quoted ^= 1;
+                       c = '"';
+                       break;
+               case '=':
+                       if (subtype == 0)
+                               break;
+                       str = vstype[subtype & VSTYPE];
+                       if (subtype & VSNUL)
+                               c = ':';
+                       else
+                               c = *str++;
+                       if (c != '}')
+                               quoted <<= 1;
+                       break;
+               case '\'':
+               case '\\':
+               case '"':
+               case '$':
+                       /* These can only happen inside quotes */
+                       cc[0] = c;
+                       str = cc;
+                       c = '\\';
+                       break;
+               default:
+                       break;
+               }
+               do {
+                       *nextc++ = c;
+               } while (--nleft > 0 && str && (c = *str++));
+               str = 0;
+       }
+       if ((quoted & 1) && nleft) {
+               *nextc++ = '"';
+               nleft--;
+       }
+       cmdnleft = nleft;
+       cmdnextc = nextc;
+}
similarity index 62%
rename from minix/commands/ash/jobs.h
rename to bin/sh/jobs.h
index db436aa8bc48dba46735bc9d275aab3edec52c47..92737361907d7d2731a8723ed0e046fe2ed9e9ce 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: jobs.h,v 1.20 2011/06/18 21:18:46 christos Exp $       */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)jobs.h      8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/jobs.h,v 1.18 2004/04/06 20:06:51 markm Exp $
  */
 
+#include "output.h"
+
 /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
 #define FORK_FG 0
 #define FORK_BG 1
 #define FORK_NOJOB 2
 
-#include <signal.h>            /* for sig_atomic_t */
+/* mode flags for showjob(s) */
+#define        SHOW_PGID       0x01    /* only show pgid - for jobs -p */
+#define        SHOW_MULTILINE  0x02    /* one line per process */
+#define        SHOW_PID        0x04    /* include process pid */
+#define        SHOW_CHANGED    0x08    /* only jobs whose state has changed */
+#define        SHOW_SIGNALLED  0x10    /* only if stopped/exited on signal */
+#define        SHOW_ISSIG      0x20    /* job was signalled */
+#define        SHOW_NO_FREE    0x40    /* do not free job */
+
 
 /*
  * A job structure contains information about a job.  A job is either a
  * latter case, pidlist will be non-NULL, and will point to a -1 terminated
  * array of pids.
  */
+#define        MAXCMDTEXT      200
 
 struct procstat {
-       pid_t pid;              /* process id */
-       int status;             /* status flags (defined above) */
-       char *cmd;              /* text of command being run */
+       pid_t   pid;            /* process id */
+       int     status;         /* last process status from wait() */
+       char    cmd[MAXCMDTEXT];/* text of command being run */
 };
 
-
-/* states */
-#define JOBSTOPPED 1           /* all procs are stopped */
-#define JOBDONE 2              /* all procs are completed */
-
-
 struct job {
        struct procstat ps0;    /* status of process */
        struct procstat *ps;    /* status or processes when more than one */
-       short nprocs;           /* number of processes */
-       pid_t pgrp;             /* process group of this job */
-       char state;             /* true if job is finished */
-       char used;              /* true if this entry is in used */
-       char changed;           /* true if status has changed */
-       char foreground;        /* true if running in the foreground */
+       int     nprocs;         /* number of processes */
+       pid_t   pgrp;           /* process group of this job */
+       char    state;
+#define        JOBRUNNING      0       /* at least one proc running */
+#define        JOBSTOPPED      1       /* all procs are stopped */
+#define        JOBDONE         2       /* all procs are completed */
+       char    used;           /* true if this entry is in used */
+       char    changed;        /* true if status has changed */
 #if JOBS
-       char jobctl;            /* job running under job control */
-       struct job *next;       /* job used after this one */
+       char    jobctl;         /* job running under job control */
+       int     prev_job;       /* previous job index */
 #endif
 };
 
 extern pid_t backgndpid;       /* pid of last background process */
 extern int job_warning;                /* user was warned about stopped jobs */
-extern int in_waitcmd;         /* are we in waitcmd()? */
-extern int in_dowait;          /* are we in dowait()? */
-extern volatile sig_atomic_t breakwaitcmd; /* break wait to process traps? */
 
 void setjobctl(int);
-int fgcmd(int, char **);
-int bgcmd(int, char **);
-int jobscmd(int, char **);
-void showjobs(int, int, int);
-int waitcmd(int, char **);
-int jobidcmd(int, char **);
+void showjobs(struct output *, int);
 struct job *makejob(union node *, int);
-pid_t forkshell(struct job *, union node *, int);
-int waitforjob(struct job *, int *);
+int forkshell(struct job *, union node *, int);
+void forkchild(struct job *, union node *, int, int);
+int forkparent(struct job *, union node *, int, pid_t);
+int waitforjob(struct job *);
 int stoppedjobs(void);
-char *commandtext(union node *);
+void commandtext(struct procstat *, union node *);
+int getjobpgrp(const char *);
 
 #if ! JOBS
 #define setjobctl(on)  /* do nothing */
 #endif
-
-/*
- * $PchId: jobs.h,v 1.4 2006/03/30 12:07:24 philip Exp $
- */
similarity index 78%
rename from minix/commands/ash/machdep.h
rename to bin/sh/machdep.h
index 4de7acd21e03536cabccd0dcf74ec4c3ad5902b9..14e803bf72b103253644311bd8d3d5bcd544235d 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: machdep.h,v 1.11 2003/08/07 09:05:33 agc Exp $ */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * in some way.  The following macro will get this right on many machines.
  */
 
-#ifndef ALIGN
-union align {
-       int i;
-       char *cp;
-};
-
-#define ALIGN(nbytes)  (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
-#endif
-
+#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
 /*
- * $PchId: machdep.h,v 1.2 2001/05/15 16:36:26 philip Exp $
+ * It appears that grabstackstr() will barf with such alignments
+ * because stalloc() will return a string allocated in a new stackblock.
  */
+#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
similarity index 89%
rename from minix/commands/ash/mail.c
rename to bin/sh/mail.c
index 14bc1d91e7e51a87d8d544ba488a8e1300bfde76..4ddd7c0740c2a78664e64e9290337d5687e69ef9 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: mail.c,v 1.16 2003/08/07 09:05:33 agc Exp $    */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)mail.c     8.2 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: mail.c,v 1.16 2003/08/07 09:05:33 agc Exp $");
 #endif
 #endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/mail.c,v 1.13 2004/04/06 20:06:51 markm Exp $");
-*/
 
 /*
  * Routines to check for mail.  (Perhaps make part of main.c?)
  */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
 
 #include "shell.h"
 #include "exec.h"      /* defines padvance() */
@@ -51,9 +55,6 @@ __FBSDID("$FreeBSD: src/bin/sh/mail.c,v 1.13 2004/04/06 20:06:51 markm Exp $");
 #include "memalloc.h"
 #include "error.h"
 #include "mail.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdlib.h>
 
 
 #define MAXMBOXES 10
@@ -74,7 +75,7 @@ void
 chkmail(int silent)
 {
        int i;
-       char *mpath;
+       const char *mpath;
        char *p;
        char *q;
        struct stackmark smark;
@@ -85,7 +86,7 @@ chkmail(int silent)
        if (nmboxes == 0)
                return;
        setstackmark(&smark);
-       mpath = mpathset()? mpathval() : mailval();
+       mpath = mpathset() ? mpathval() : mailval();
        for (i = 0 ; i < nmboxes ; i++) {
                p = padvance(&mpath, nullstr);
                if (p == NULL)
@@ -100,7 +101,7 @@ chkmail(int silent)
                if (stat(p, &statb) < 0)
                        statb.st_mtime = 0;
                if (statb.st_mtime > mailtime[i] && ! silent) {
-                       out2str(pathopt? pathopt : "you have mail");
+                       out2str(pathopt ? pathopt : "you have mail");
                        out2c('\n');
                }
                mailtime[i] = statb.st_mtime;
@@ -108,7 +109,7 @@ chkmail(int silent)
                if (stat(p, &statb) < 0)
                        statb.st_size = 0;
                if (statb.st_size > mailtime[i] && ! silent) {
-                       out2str(pathopt? pathopt : "you have mail");
+                       out2str(pathopt ? pathopt : "you have mail");
                        out2c('\n');
                }
                mailtime[i] = statb.st_size;
@@ -117,7 +118,3 @@ chkmail(int silent)
        nmboxes = i;
        popstackmark(&smark);
 }
-
-/*
- * $PchId: mail.c,v 1.5 2006/05/22 12:02:37 philip Exp $
- */
similarity index 89%
rename from minix/commands/ash/mail.h
rename to bin/sh/mail.h
index 4d67b0ae920ae527959aca1eec1403eafbcd77dc..9ea7c218b89a3d20490555c1481826d7d9c4d1bd 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: mail.h,v 1.10 2003/08/07 09:05:34 agc Exp $    */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)mail.h      8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/mail.h,v 1.8 2004/04/06 20:06:51 markm Exp $
  */
 
 void chkmail(int);
-
-/*
- * $PchId: mail.h,v 1.3 2006/03/30 11:53:44 philip Exp $
- */
similarity index 72%
rename from minix/commands/ash/main.c
rename to bin/sh/main.c
index 262756db4e390d4c37bc53533ab5b2342aee20e8..35082a9553cc1bbc05ffad9d3ae77d8ede6bffd9 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: main.c,v 1.57 2011/06/18 21:18:46 christos Exp $       */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
-static char const copyright[] =
-"@(#) Copyright (c) 1991, 1993\n\
-       The Regents of the University of California.  All rights reserved.\n";
+__COPYRIGHT("@(#) Copyright (c) 1991, 1993\
+ The Regents of the University of California.  All rights reserved.");
 #endif /* not lint */
 
 #ifndef lint
 #if 0
-static char sccsid[] = "@(#)main.c     8.6 (Berkeley) 5/28/95";
+static char sccsid[] = "@(#)main.c     8.7 (Berkeley) 7/19/95";
+#else
+__RCSID("$NetBSD: main.c,v 1.57 2011/06/18 21:18:46 christos Exp $");
 #endif
 #endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/main.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
-*/
 
+#include <errno.h>
 #include <stdio.h>
 #include <signal.h>
 #include <sys/stat.h>
 #include <unistd.h>
-#include <fcntl.h>
+#include <stdlib.h>
 #include <locale.h>
-#include <errno.h>
+#include <fcntl.h>
+
 
 #include "shell.h"
 #include "main.h"
 #include "mail.h"
 #include "options.h"
+#include "builtins.h"
 #include "output.h"
 #include "parser.h"
 #include "nodes.h"
@@ -74,13 +77,20 @@ __FBSDID("$FreeBSD: src/bin/sh/main.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
 #include "mystring.h"
 #include "exec.h"
 #include "cd.h"
-#include "builtins.h"
+
+#define PROFILE 0
 
 int rootpid;
 int rootshell;
+int posix;
+#if PROFILE
+short profile_buf[16384];
+extern int etext();
+#endif
 
-STATIC void read_profile(char *);
+STATIC void read_profile(const char *);
 STATIC char *find_dot_file(char *);
+int main(int, char **);
 
 /*
  * Main routine.  We initialize things, parse the arguments, execute
@@ -91,14 +101,19 @@ STATIC char *find_dot_file(char *);
  */
 
 int
-main(int argc, char *argv[])
+main(int argc, char **argv)
 {
        struct jmploc jmploc;
        struct stackmark smark;
        volatile int state;
        char *shinit;
 
-       (void) setlocale(LC_ALL, "");
+       setlocale(LC_ALL, "");
+
+       posix = getenv("POSIXLY_CORRECT") != NULL;
+#if PROFILE
+       monitor(4, etext, profile_buf, sizeof profile_buf, 50);
+#endif
        state = 0;
        if (setjmp(jmploc.loc)) {
                /*
@@ -127,11 +142,15 @@ main(int argc, char *argv[])
                }
 
                if (exception != EXSHELLPROC) {
-                   if (state == 0 || iflag == 0 || ! rootshell)
-                           exitshell(exitstatus);
+                       if (state == 0 || iflag == 0 || ! rootshell)
+                               exitshell(exitstatus);
                }
                reset();
-               if (exception == EXINT) {
+               if (exception == EXINT
+#if ATTY
+                && (! attyset() || equal(termval(), "emacs"))
+#endif
+                ) {
                        out2c('\n');
                        flushout(&errout);
                }
@@ -147,30 +166,30 @@ main(int argc, char *argv[])
                        goto state4;
        }
        handler = &jmploc;
-#if DEBUG
+#ifdef DEBUG
+#if DEBUG == 2
+       debug = 1;
+#endif
        opentrace();
        trputs("Shell args:  ");  trargs(argv);
 #endif
        rootpid = getpid();
        rootshell = 1;
        init();
+       initpwd();
        setstackmark(&smark);
        procargs(argc, argv);
-       if (getpwd() == NULL && iflag)
-               out2str("sh: cannot determine working directory\n");
        if (argv[0] && argv[0][0] == '-') {
                state = 1;
                read_profile("/etc/profile");
 state1:
                state = 2;
-               if (privileged == 0)
-                       read_profile(".profile");
-               else
-                       read_profile("/etc/suid_profile");
+               read_profile(".profile");
        }
 state2:
        state = 3;
-       if (!privileged && iflag) {
+       if ((iflag || !posix) &&
+           getuid() == geteuid() && getgid() == getegid()) {
                if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
                        state = 3;
                        read_profile(shinit);
@@ -178,16 +197,33 @@ state2:
        }
 state3:
        state = 4;
-       if (minusc) {
-               evalstring(minusc);
+       if (sflag == 0 || minusc) {
+               static int sigs[] =  {
+                   SIGINT, SIGQUIT, SIGHUP, 
+#ifdef SIGTSTP
+                   SIGTSTP,
+#endif
+                   SIGPIPE
+               };
+#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
+               size_t i;
+
+               for (i = 0; i < SIGSSIZE; i++)
+                   setsignal(sigs[i], 0);
        }
+
+       if (minusc)
+               evalstring(minusc, 0);
+
        if (sflag || minusc == NULL) {
 state4:        /* XXX ??? - why isn't this before the "if" statement */
                cmdloop(1);
        }
+#if PROFILE
+       monitor(0);
+#endif
        exitshell(exitstatus);
-       /*NOTREACHED*/
-       return 0;
+       /* NOTREACHED */
 }
 
 
@@ -210,11 +246,11 @@ cmdloop(int top)
                if (pendingsigs)
                        dotrap();
                inter = 0;
-               if (iflag && top) {
-                       inter++;
-                       showjobs(1, 0, 0);
+               if (iflag == 1 && top) {
+                       inter = 1;
+                       showjobs(out2, SHOW_CHANGED);
                        chkmail(0);
-                       flushout(&output);
+                       flushout(&errout);
                }
                n = parsecmd(inter);
                /* showtree(n); DEBUG */
@@ -249,9 +285,11 @@ cmdloop(int top)
  */
 
 STATIC void
-read_profile(char *name)
+read_profile(const char *name)
 {
        int fd;
+       int xflag_set = 0;
+       int vflag_set = 0;
 
        INTOFF;
        if ((fd = open(name, O_RDONLY)) >= 0)
@@ -259,7 +297,20 @@ read_profile(char *name)
        INTON;
        if (fd < 0)
                return;
+       /* -q turns off -x and -v just when executing init files */
+       if (qflag)  {
+           if (xflag)
+                   xflag = 0, xflag_set = 1;
+           if (vflag)
+                   vflag = 0, vflag_set = 1;
+       }
        cmdloop(0);
+       if (qflag)  {
+           if (xflag_set)
+                   xflag = 1;
+           if (vflag_set)
+                   vflag = 1;
+       }
        popfile();
 }
 
@@ -278,7 +329,7 @@ readcmdfile(char *name)
        if ((fd = open(name, O_RDONLY)) >= 0)
                setinputfd(fd, 1);
        else
-               error("Can't open %s: %s", name, strerror(errno));
+               error("Can't open %s", name);
        INTON;
        cmdloop(0);
        popfile();
@@ -295,40 +346,46 @@ readcmdfile(char *name)
 STATIC char *
 find_dot_file(char *basename)
 {
-       static char localname[FILENAME_MAX+1];
        char *fullname;
-       char *path = pathval();
+       const char *path = pathval();
        struct stat statb;
 
        /* don't try this for absolute or relative paths */
-       ifstrchr(basename, '/'))
+       if (strchr(basename, '/'))
                return basename;
 
        while ((fullname = padvance(&path, basename)) != NULL) {
-               strcpy(localname, fullname);
+               if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
+                       /*
+                        * Don't bother freeing here, since it will
+                        * be freed by the caller.
+                        */
+                       return fullname;
+               }
                stunalloc(fullname);
-               if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode))
-                       return localname;
        }
-       return basename;
+
+       /* not found in the PATH */
+       error("%s: not found", basename);
+       /* NOTREACHED */
 }
 
 int
 dotcmd(int argc, char **argv)
 {
-       struct strlist *sp;
        exitstatus = 0;
 
-       for (sp = cmdenviron; sp ; sp = sp->next)
-               setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
-
        if (argc >= 2) {                /* That's what SVR2 does */
-               char *fullname = find_dot_file(argv[1]);
+               char *fullname;
+               struct stackmark smark;
 
+               setstackmark(&smark);
+               fullname = find_dot_file(argv[1]);
                setinputfile(fullname, 1);
                commandname = fullname;
                cmdloop(0);
                popfile();
+               popstackmark(&smark);
        }
        return exitstatus;
 }
@@ -337,19 +394,10 @@ dotcmd(int argc, char **argv)
 int
 exitcmd(int argc, char **argv)
 {
-       extern int oexitstatus;
-
        if (stoppedjobs())
                return 0;
        if (argc > 1)
                exitstatus = number(argv[1]);
-       else
-               exitstatus = oexitstatus;
        exitshell(exitstatus);
-       /*NOTREACHED*/
-       return 0;
+       /* NOTREACHED */
 }
-
-/*
- * $PchId: main.c,v 1.5 2006/05/22 12:03:02 philip Exp $
- */
similarity index 87%
rename from minix/commands/ash/main.h
rename to bin/sh/main.h
index 55ab91b7a1d12b8cc4ea4b9487905526e8ac1aff..9caa218f1fcdcbe424ea59c80c2051cef38804cd 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: main.h,v 1.11 2011/06/18 21:18:46 christos Exp $       */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -30,7 +32,6 @@
  * SUCH DAMAGE.
  *
  *     @(#)main.h      8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/main.h,v 1.8 2004/04/06 20:06:51 markm Exp $
  */
 
 extern int rootpid;    /* pid of main shell */
@@ -38,9 +39,3 @@ extern int rootshell; /* true if we aren't a child of the main shell */
 
 void readcmdfile(char *);
 void cmdloop(int);
-int dotcmd(int, char **);
-int exitcmd(int, char **);
-
-/*
- * $PchId: main.h,v 1.3 2006/03/30 11:43:59 philip Exp $
- */
similarity index 74%
rename from minix/commands/ash/memalloc.c
rename to bin/sh/memalloc.c
index ab4900f461c9d652940c37de36ac2c20102b42a1..a26348e5e2dd97c9f9970a3ecb0e6c96561a0b59 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: memalloc.c,v 1.29 2008/02/15 17:26:06 matt Exp $       */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: memalloc.c,v 1.29 2008/02/15 17:26:06 matt Exp $");
 #endif
 #endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/memalloc.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
-*/
+
+#include <stdlib.h>
+#include <unistd.h>
 
 #include "shell.h"
 #include "output.h"
-#include "machdep.h"
 #include "memalloc.h"
 #include "error.h"
+#include "machdep.h"
 #include "mystring.h"
-#include "expand.h"
-#include <stdlib.h>
-#include <unistd.h>
 
 /*
  * Like malloc, but returns an error when out of space.
  */
 
 pointer
-ckmalloc(int nbytes)
+ckmalloc(size_t nbytes)
 {
        pointer p;
 
-       if ((p = malloc(nbytes)) == NULL)
+       p = malloc(nbytes);
+       if (p == NULL)
                error("Out of space");
        return p;
 }
@@ -72,7 +74,8 @@ ckmalloc(int nbytes)
 pointer
 ckrealloc(pointer p, int nbytes)
 {
-       if ((p = realloc(p, nbytes)) == NULL)
+       p = realloc(p, nbytes);
+       if (p == NULL)
                error("Out of space");
        return p;
 }
@@ -98,56 +101,46 @@ savestr(const char *s)
  * to make this more efficient, and also to avoid all sorts of exception
  * handling code to handle interrupts in the middle of a parse.
  *
- * The size 496 was chosen because with 16-byte alignment the total size
- * for the allocated block is 512.
+ * The size 504 was chosen because the Ultrix malloc handles that size
+ * well.
  */
 
-#define MINSIZE 496            /* minimum size of a block. */
-
+#define MINSIZE 504            /* minimum size of a block */
 
 struct stack_block {
        struct stack_block *prev;
-       /* Data follows */
+       char space[MINSIZE];
 };
-#define SPACE(sp)      ((char*)(sp) + ALIGN(sizeof(struct stack_block)))
 
-STATIC struct stack_block *stackp;
-STATIC struct stackmark *markp;
-char *stacknxt;
-int stacknleft;
+struct stack_block stackbase;
+struct stack_block *stackp = &stackbase;
+struct stackmark *markp;
+char *stacknxt = stackbase.space;
+int stacknleft = MINSIZE;
 int sstrnleft;
 int herefd = -1;
 
-
-static void
-stnewblock(int nbytes)
-{
-       struct stack_block *sp;
-       int allocsize;
-
-       if (nbytes < MINSIZE)
-               nbytes = MINSIZE;
-
-       allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes);
-
-       INTOFF;
-       sp = ckmalloc(allocsize);
-       sp->prev = stackp;
-       stacknxt = SPACE(sp);
-       stacknleft = allocsize - (stacknxt - (char*)sp);
-       stackp = sp;
-       INTON;
-}
-
-
 pointer
 stalloc(int nbytes)
 {
        char *p;
 
-       nbytes = ALIGN(nbytes);
-       if (nbytes > stacknleft)
-               stnewblock(nbytes);
+       nbytes = SHELL_ALIGN(nbytes);
+       if (nbytes > stacknleft) {
+               int blocksize;
+               struct stack_block *sp;
+
+               blocksize = nbytes;
+               if (blocksize < MINSIZE)
+                       blocksize = MINSIZE;
+               INTOFF;
+               sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
+               sp->prev = stackp;
+               stacknxt = sp->space;
+               stacknleft = blocksize;
+               stackp = sp;
+               INTON;
+       }
        p = stacknxt;
        stacknxt += nbytes;
        stacknleft -= nbytes;
@@ -159,7 +152,7 @@ void
 stunalloc(pointer p)
 {
        if (p == NULL) {                /*DEBUG */
-               write(STDERR_FILENO, "stunalloc\n", 10);
+               write(2, "stunalloc\n", 10);
                abort();
        }
        stacknleft += stacknxt - (char *)p;
@@ -210,32 +203,27 @@ popstackmark(struct stackmark *mark)
 void
 growstackblock(void)
 {
-       char *p;
-       int newlen;
-       char *oldspace;
-       int oldlen;
-       struct stack_block *sp;
-       struct stack_block *oldstackp;
-       struct stackmark *xmark;
+       int newlen = SHELL_ALIGN(stacknleft * 2 + 100);
 
-       newlen = (stacknleft == 0) ? MINSIZE : stacknleft * 2 + 100;
-       newlen = ALIGN(newlen);
-       oldspace = stacknxt;
-       oldlen = stacknleft;
+       if (stacknxt == stackp->space && stackp != &stackbase) {
+               struct stack_block *oldstackp;
+               struct stackmark *xmark;
+               struct stack_block *sp;
 
-       if (stackp != NULL && stacknxt == SPACE(stackp)) {
                INTOFF;
                oldstackp = stackp;
-               stackp = oldstackp->prev;
-               sp = ckrealloc((pointer)oldstackp, newlen);
+               sp = stackp;
+               stackp = sp->prev;
+               sp = ckrealloc((pointer)sp,
+                   sizeof(struct stack_block) - MINSIZE + newlen);
                sp->prev = stackp;
                stackp = sp;
-               stacknxt = SPACE(sp);
-               stacknleft = newlen - (stacknxt - (char*)sp);
+               stacknxt = sp->space;
+               stacknleft = newlen;
 
                /*
                 * Stack marks pointing to the start of the old block
-                * must be relocated to point to the new block
+                * must be relocated to point to the new block 
                 */
                xmark = markp;
                while (xmark != NULL && xmark->stackp == oldstackp) {
@@ -246,27 +234,26 @@ growstackblock(void)
                }
                INTON;
        } else {
-               p = stalloc(newlen);
-               if (oldlen != 0)
-                       memcpy(p, oldspace, oldlen);
-               stunalloc(p);
+               char *oldspace = stacknxt;
+               int oldlen = stacknleft;
+               char *p = stalloc(newlen);
+
+               (void)memcpy(p, oldspace, oldlen);
+               stacknxt = p;                   /* free the space */
+               stacknleft += newlen;           /* we just allocated */
        }
 }
 
-
-
 void
 grabstackblock(int len)
 {
-       len = ALIGN(len);
+       len = SHELL_ALIGN(len);
        stacknxt += len;
        stacknleft -= len;
 }
 
-
-
 /*
- * The following routines are somewhat easier to use that the above.
+ * The following routines are somewhat easier to use than the above.
  * The user declares a variable of type STACKSTR, which may be declared
  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
  * the user uses the macro STPUTC to add characters to the string.  In
@@ -283,13 +270,10 @@ grabstackblock(int len)
  * is space for at least one character.
  */
 
-
 char *
 growstackstr(void)
 {
-       int len;
-
-       len = stackblocksize();
+       int len = stackblocksize();
        if (herefd >= 0 && len >= 1024) {
                xwrite(herefd, stackblock(), len);
                sstrnleft = len - 1;
@@ -300,7 +284,6 @@ growstackstr(void)
        return stackblock() + len;
 }
 
-
 /*
  * Called from CHECKSTRSPACE.
  */
@@ -308,24 +291,17 @@ growstackstr(void)
 char *
 makestrspace(void)
 {
-       int len;
-
-       len = stackblocksize() - sstrnleft;
+       int len = stackblocksize() - sstrnleft;
        growstackblock();
        sstrnleft = stackblocksize() - len;
        return stackblock() + len;
 }
 
-
-
 void
 ungrabstackstr(char *s, char *p)
 {
        stacknleft += stacknxt - s;
        stacknxt = s;
        sstrnleft = stacknleft - (p - s);
-}
 
-/*
- * $PchId: memalloc.c,v 1.5 2006/05/22 12:03:26 philip Exp $
- */
+}
similarity index 91%
rename from minix/commands/ash/memalloc.h
rename to bin/sh/memalloc.h
index 68b89a2074fc406248a143e3172fefb59932d2e3..8e5b07615817bb83156cba3e2a2349871a760373 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: memalloc.h,v 1.15 2008/02/15 17:26:06 matt Exp $       */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)memalloc.h  8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/memalloc.h,v 1.9 2004/04/06 20:06:51 markm Exp $
  */
 
 struct stackmark {
        struct stack_block *stackp;
        char *stacknxt;
        int stacknleft;
-        struct stackmark *marknext;
+       struct stackmark *marknext;
 };
 
 
@@ -46,7 +47,7 @@ extern int stacknleft;
 extern int sstrnleft;
 extern int herefd;
 
-pointer ckmalloc(int);
+pointer ckmalloc(size_t);
 pointer ckrealloc(pointer, int);
 char *savestr(const char *);
 pointer stalloc(int);
@@ -74,7 +75,3 @@ void ungrabstackstr(char *, char *);
 #define grabstackstr(p)        stalloc(stackblocksize() - sstrnleft)
 
 #define ckfree(p)      free((pointer)(p))
-
-/*
- * $PchId: memalloc.h,v 1.3 2006/03/30 11:39:41 philip Exp $
- */
similarity index 57%
rename from minix/commands/ash/miscbltin.c
rename to bin/sh/miscbltin.c
index d63b1e27d9849fd0fad581d795271fc325682d3f..b7c1c5ad8cb70c801a55bb9fd11933101cd67655 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: miscbltin.c,v 1.42 2012/06/11 18:28:10 njoly Exp $     */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)miscbltin.c        8.4 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: miscbltin.c,v 1.42 2012/06/11 18:28:10 njoly Exp $");
 #endif
 #endif /* not lint */
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/miscbltin.c,v 1.30 2004/04/06 20:06:51 markm Exp $");
-*/
 
 /*
- * Miscellaneous builtins.
+ * Miscelaneous builtins.
  */
 
-#include <sys/types.h>
+#include <sys/types.h>         /* quad_t */
+#include <sys/param.h>         /* BSD4_4 */
 #include <sys/stat.h>
 #include <sys/time.h>
-#include <sys/select.h>
-#include <time.h>
+#include <sys/resource.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include <ctype.h>
 #include <errno.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <termios.h>
 
 #include "shell.h"
 #include "options.h"
@@ -63,159 +61,148 @@ __FBSDID("$FreeBSD: src/bin/sh/miscbltin.c,v 1.30 2004/04/06 20:06:51 markm Exp
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
-#include "mystring.h"
 #include "builtins.h"
+#include "mystring.h"
+
+#undef rflag
+
 
-#undef eflag
 
 /*
- * The read builtin.  The -r option causes backslashes to be treated like
- * ordinary characters.
+ * The read builtin.
+ * Backslahes escape the next char unless -r is specified.
  *
  * This uses unbuffered input, which may be avoidable in some cases.
+ *
+ * Note that if IFS=' :' then read x y should work so that:
+ * 'a b'       x='a', y='b'
+ * ' a b '     x='a', y='b'
+ * ':b'                x='',  y='b'
+ * ':'         x='',  y=''
+ * '::'                x='',  y=''
+ * ': :'       x='',  y=''
+ * ':::'       x='',  y='::'
+ * ':b c:'     x='',  y='b c:'
  */
 
 int
-readcmd(int argc __unused, char **argv __unused)
+readcmd(int argc, char **argv)
 {
        char **ap;
-       int backslash;
        char c;
        int rflag;
        char *prompt;
-       char *ifs;
+       const char *ifs;
        char *p;
        int startword;
        int status;
        int i;
-       struct timeval tv;
-       char *tvptr;
-#ifndef __minix
-       fd_set ifds;
-       struct termios told, tnew;
-       int tsaved;
-#endif
+       int is_ifs;
+       int saveall = 0;
 
        rflag = 0;
        prompt = NULL;
-       tv.tv_sec = -1;
-       tv.tv_usec = 0;
-       while ((i = nextopt("erp:t:")) != '\0') {
-               switch(i) {
-               case 'p':
-                       prompt = shoptarg;
-                       break;
-               case 'e':
-                       break;
-               case 'r':
+       while ((i = nextopt("p:r")) != '\0') {
+               if (i == 'p')
+                       prompt = optionarg;
+               else
                        rflag = 1;
-                       break;
-               case 't':
-                       tv.tv_sec = strtol(shoptarg, &tvptr, 0);
-                       if (tvptr == shoptarg)
-                               error("timeout value");
-                       switch(*tvptr) {
-                       case 0:
-                       case 's':
-                               break;
-                       case 'h':
-                               tv.tv_sec *= 60;
-                               /* FALLTHROUGH */
-                       case 'm':
-                               tv.tv_sec *= 60;
-                               break;
-                       default:
-                               error("timeout unit");
-                       }
-                       break;
-               }
        }
+
        if (prompt && isatty(0)) {
                out2str(prompt);
                flushall();
        }
+
        if (*(ap = argptr) == NULL)
                error("arg count");
-       if ((ifs = bltinlookup("IFS", 1)) == NULL)
-               ifs = nullstr;
 
-       if (tv.tv_sec >= 0) {
-#ifdef __minix
-               abort();
-#else
-               /*
-                * See if we can disable input processing; this will
-                * not give the desired result if we are in a pipeline
-                * and someone upstream is still in line-by-line mode.
-                */
-               tsaved = 0;
-               if (tcgetattr(0, &told) == 0) {
-                       memcpy(&tnew, &told, sizeof(told));
-                       cfmakeraw(&tnew);
-                       tcsetattr(0, TCSANOW, &tnew);
-                       tsaved = 1;
-               }
-               /*
-                * Wait for something to become available.
-                */
-               FD_ZERO(&ifds);
-               FD_SET(0, &ifds);
-               status = select(1, &ifds, NULL, NULL, &tv);
-               if (tsaved)
-                       tcsetattr(0, TCSANOW, &told);
-               /*
-                * If there's nothing ready, return an error.
-                */
-               if (status <= 0)
-                       return(1);
-#endif
-       }
+       if ((ifs = bltinlookup("IFS", 1)) == NULL)
+               ifs = " \t\n";
 
        status = 0;
-       startword = 1;
-       backslash = 0;
+       startword = 2;
        STARTSTACKSTR(p);
        for (;;) {
-               if (read(STDIN_FILENO, &c, 1) != 1) {
+               if (read(0, &c, 1) != 1) {
                        status = 1;
                        break;
                }
                if (c == '\0')
                        continue;
-               if (backslash) {
-                       backslash = 0;
+               if (c == '\\' && !rflag) {
+                       if (read(0, &c, 1) != 1) {
+                               status = 1;
+                               break;
+                       }
                        if (c != '\n')
                                STPUTC(c, p);
                        continue;
                }
-               if (!rflag && c == '\\') {
-                       backslash++;
-                       continue;
-               }
                if (c == '\n')
                        break;
-               if (startword && *ifs == ' ' && strchr(ifs, c)) {
-                       continue;
-               }
-               startword = 0;
-               if (backslash && c == '\\') {
-                       if (read(STDIN_FILENO, &c, 1) != 1) {
-                               status = 1;
-                               break;
+               if (strchr(ifs, c))
+                       is_ifs = strchr(" \t\n", c) ? 1 : 2;
+               else
+                       is_ifs = 0;
+
+               if (startword != 0) {
+                       if (is_ifs == 1) {
+                               /* Ignore leading IFS whitespace */
+                               if (saveall)
+                                       STPUTC(c, p);
+                               continue;
                        }
+                       if (is_ifs == 2 && startword == 1) {
+                               /* Only one non-whitespace IFS per word */
+                               startword = 2;
+                               if (saveall)
+                                       STPUTC(c, p);
+                               continue;
+                       }
+               }
+
+               if (is_ifs == 0) {
+                       /* append this character to the current variable */
+                       startword = 0;
+                       if (saveall)
+                               /* Not just a spare terminator */
+                               saveall++;
                        STPUTC(c, p);
-               } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
-                       STACKSTRNUL(p);
-                       setvar(*ap, stackblock(), 0);
-                       ap++;
-                       startword = 1;
-                       STARTSTACKSTR(p);
-               } else {
+                       continue;
+               }
+
+               /* end of variable... */
+               startword = is_ifs;
+
+               if (ap[1] == NULL) {
+                       /* Last variable needs all IFS chars */
+                       saveall++;
                        STPUTC(c, p);
+                       continue;
                }
+
+               STACKSTRNUL(p);
+               setvar(*ap, stackblock(), 0);
+               ap++;
+               STARTSTACKSTR(p);
        }
        STACKSTRNUL(p);
+
+       /* Remove trailing IFS chars */
+       for (; stackblock() <= --p; *p = 0) {
+               if (!strchr(ifs, *p))
+                       break;
+               if (strchr(" \t\n", *p))
+                       /* Always remove whitespace */
+                       continue;
+               if (saveall > 1)
+                       /* Don't remove non-whitespace unless it was naked */
+                       break;
+       }
        setvar(*ap, stackblock(), 0);
+
+       /* Set any remaining args to "" */
        while (*++ap != NULL)
                setvar(*ap, nullstr, 0);
        return status;
@@ -224,7 +211,7 @@ readcmd(int argc __unused, char **argv __unused)
 
 
 int
-umaskcmd(int argc __unused, char **argv)
+umaskcmd(int argc, char **argv)
 {
        char *ap;
        int mask;
@@ -276,7 +263,7 @@ umaskcmd(int argc __unused, char **argv)
                        out1fmt("%.4o\n", mask);
                }
        } else {
-               if (isdigit(*ap)) {
+               if (isdigit((unsigned char)*ap)) {
                        mask = 0;
                        do {
                                if (*ap >= '8' || *ap < '0')
@@ -286,44 +273,23 @@ umaskcmd(int argc __unused, char **argv)
                        umask(mask);
                } else {
                        void *set;
-                       if ((set = setmode (ap)) == 0)
-                               error("Illegal number: %s", ap);
 
-                       mask = getmode (set, ~mask & 0777);
+                       INTOFF;
+                       if ((set = setmode(ap)) != 0) {
+                               mask = getmode(set, ~mask & 0777);
+                               ckfree(set);
+                       }
+                       INTON;
+                       if (!set)
+                               error("Cannot set mode `%s' (%s)", ap,
+                                   strerror(errno));
+
                        umask(~mask & 0777);
-                       free(set);
                }
        }
        return 0;
 }
 
-#ifdef __minix
-struct rlimit
-{
-        unsigned long  rlim_cur;       /* current (soft) limit */
-       unsigned long  rlim_max;        /* maximum value for rlim_cur */
-};
-#define RLIM_INFINITY   (((unsigned long)1 << 31) - 1)
-
-int getrlimit (int, struct rlimit *);
-int setrlimit (int, const struct rlimit *);
-
-int getrlimit(resource, rlp)
-int resource;
-struct rlimit *rlp;
-{
-       errno= ENOSYS;
-       return -1;
-}
-int setrlimit(resource, rlp)
-int resource;
-const struct rlimit *rlp;
-{
-       errno= ENOSYS;
-       return -1;
-}
-#endif
-
 /*
  * ulimit builtin
  *
@@ -336,7 +302,7 @@ const struct rlimit *rlp;
 
 struct limits {
        const char *name;
-       const char *units;
+       const char *unit;
        int     cmd;
        int     factor; /* multiply by to get rlim_{cur,max} values */
        char    option;
@@ -344,49 +310,52 @@ struct limits {
 
 static const struct limits limits[] = {
 #ifdef RLIMIT_CPU
-       { "cpu time",           "seconds",      RLIMIT_CPU,        1, 't' },
+       { "time",       "seconds",      RLIMIT_CPU,        1, 't' },
 #endif
 #ifdef RLIMIT_FSIZE
-       { "file size",          "512-blocks",   RLIMIT_FSIZE,    512, 'f' },
+       { "file",       "blocks",       RLIMIT_FSIZE,    512, 'f' },
 #endif
 #ifdef RLIMIT_DATA
-       { "data seg size",      "kbytes",       RLIMIT_DATA,    1024, 'd' },
+       { "data",       "kbytes",       RLIMIT_DATA,    1024, 'd' },
 #endif
 #ifdef RLIMIT_STACK
-       { "stack size",         "kbytes",       RLIMIT_STACK,   1024, 's' },
+       { "stack",      "kbytes",       RLIMIT_STACK,   1024, 's' },
 #endif
 #ifdef  RLIMIT_CORE
-       { "core file size",     "512-blocks",   RLIMIT_CORE,     512, 'c' },
+       { "coredump",   "blocks",       RLIMIT_CORE,     512, 'c' },
 #endif
 #ifdef RLIMIT_RSS
-       { "max memory size",    "kbytes",       RLIMIT_RSS,     1024, 'm' },
+       { "memory",     "kbytes",       RLIMIT_RSS,     1024, 'm' },
 #endif
 #ifdef RLIMIT_MEMLOCK
-       { "locked memory",      "kbytes",       RLIMIT_MEMLOCK, 1024, 'l' },
+       { "locked memory","kbytes",     RLIMIT_MEMLOCK, 1024, 'l' },
+#endif
+#ifdef RLIMIT_NTHR
+       { "thread",     "threads",      RLIMIT_NTHR,       1, 'r' },
 #endif
 #ifdef RLIMIT_NPROC
-       { "max user processes", (char *)0,      RLIMIT_NPROC,      1, 'u' },
+       { "process",    "processes",    RLIMIT_NPROC,      1, 'p' },
 #endif
 #ifdef RLIMIT_NOFILE
-       { "open files",         (char *)0,      RLIMIT_NOFILE,     1, 'n' },
+       { "nofiles",    "descriptors",  RLIMIT_NOFILE,     1, 'n' },
 #endif
 #ifdef RLIMIT_VMEM
-       { "virtual mem size",   "kbytes",       RLIMIT_VMEM,    1024, 'v' },
+       { "vmemory",    "kbytes",       RLIMIT_VMEM,    1024, 'v' },
 #endif
 #ifdef RLIMIT_SWAP
-       { "swap limit",         "kbytes",       RLIMIT_SWAP,    1024, 'w' },
+       { "swap",       "kbytes",       RLIMIT_SWAP,    1024, 'w' },
 #endif
 #ifdef RLIMIT_SBSIZE
-       { "sbsize",             "bytes",        RLIMIT_SBSIZE,     1, 'b' },
+       { "sbsize",     "bytes",        RLIMIT_SBSIZE,     1, 'b' },
 #endif
-       { (char *) 0,           (char *)0,      0,                 0, '\0' }
+       { NULL,         NULL,           0,                 0,  '\0' }
 };
 
 int
-ulimitcmd(int argc __unused, char **argv __unused)
+ulimitcmd(int argc, char **argv)
 {
        int     c;
-       intmax_t val = 0;
+       rlim_t val = 0;
        enum { SOFT = 0x1, HARD = 0x2 }
                        how = SOFT | HARD;
        const struct limits     *l;
@@ -395,7 +364,7 @@ ulimitcmd(int argc __unused, char **argv __unused)
        struct rlimit   limit;
 
        what = 'f';
-       while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0')
+       while ((optc = nextopt("HSabtfdscmlrpnv")) != '\0')
                switch (optc) {
                case 'H':
                        how = HARD;
@@ -424,56 +393,48 @@ ulimitcmd(int argc __unused, char **argv __unused)
                if (strcmp(p, "unlimited") == 0)
                        val = RLIM_INFINITY;
                else {
-                       val = 0;
+                       val = (rlim_t) 0;
 
                        while ((c = *p++) >= '0' && c <= '9')
-                       {
                                val = (val * 10) + (long)(c - '0');
-                               if (val < 0)
-                                       break;
-                       }
                        if (c)
                                error("bad number");
                        val *= l->factor;
                }
        }
        if (all) {
-               for (l = limits; l->name; l++) { 
-                       char optbuf[40];
-                       if (getrlimit(l->cmd, &limit) < 0)
-                               error("can't get limit: %s", strerror(errno));
+               for (l = limits; l->name; l++) {
+                       getrlimit(l->cmd, &limit);
                        if (how & SOFT)
                                val = limit.rlim_cur;
                        else if (how & HARD)
                                val = limit.rlim_max;
 
-                       if (l->units)
-                               snprintf(optbuf, sizeof(optbuf),
-                                       "(%s, -%c) ", l->units, l->option);
-                       else
-                               snprintf(optbuf, sizeof(optbuf),
-                                       "(-%c) ", l->option);
-                       out1fmt("%-18s %18s ", l->name, optbuf);
+                       out1fmt("%-13s (-%c %-11s) ", l->name, l->option,
+                           l->unit);
                        if (val == RLIM_INFINITY)
                                out1fmt("unlimited\n");
                        else
                        {
                                val /= l->factor;
-                               out1fmt("%jd\n", (intmax_t)val);
+#ifdef BSD4_4
+                               out1fmt("%lld\n", (long long) val);
+#else
+                               out1fmt("%ld\n", (long) val);
+#endif
                        }
                }
                return 0;
        }
 
-       if (getrlimit(l->cmd, &limit) < 0)
-               error("can't get limit: %s", strerror(errno));
+       getrlimit(l->cmd, &limit);
        if (set) {
-               if (how & SOFT)
-                       limit.rlim_cur = val;
                if (how & HARD)
                        limit.rlim_max = val;
+               if (how & SOFT)
+                       limit.rlim_cur = val;
                if (setrlimit(l->cmd, &limit) < 0)
-                       error("bad limit: %s", strerror(errno));
+                       error("error setting limit (%s)", strerror(errno));
        } else {
                if (how & SOFT)
                        val = limit.rlim_cur;
@@ -485,12 +446,12 @@ ulimitcmd(int argc __unused, char **argv __unused)
                else
                {
                        val /= l->factor;
-                       out1fmt("%jd\n", (intmax_t)val);
+#ifdef BSD4_4
+                       out1fmt("%lld\n", (long long) val);
+#else
+                       out1fmt("%ld\n", (long) val);
+#endif
                }
        }
        return 0;
 }
-
-/*
- * $PchId: miscbltin.c,v 1.7 2006/05/23 11:59:08 philip Exp $
- */
diff --git a/bin/sh/miscbltin.h b/bin/sh/miscbltin.h
new file mode 100644 (file)
index 0000000..4c12c82
--- /dev/null
@@ -0,0 +1,31 @@
+/*     $NetBSD: miscbltin.h,v 1.3 2003/08/21 17:57:53 christos Exp $   */
+
+/*
+ * Copyright (c) 1997 Christos Zoulas.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+int readcmd(int, char **);
+int umaskcmd(int, char **);
+int ulimitcmd(int, char **);
old mode 100755 (executable)
new mode 100644 (file)
similarity index 57%
rename from minix/commands/ash/mkbuiltins.sh
rename to bin/sh/mkbuiltins
index 73109ad..2ebf7ac
@@ -1,4 +1,5 @@
 #!/bin/sh -
+#      $NetBSD: mkbuiltins,v 1.22 2009/10/06 19:56:58 apb Exp $
 #
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
@@ -14,7 +15,7 @@
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
-# 4. Neither the name of the University nor the names of its contributors
+# 3. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
 #
 # SUCH DAMAGE.
 #
 #      @(#)mkbuiltins  8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/mkbuiltins,v 1.13 2004/04/06 20:06:51 markm Exp $
 
-#temp=`/usr/bin/mktemp -t ka`
-temp=/tmp/mkb$$
 havehist=1
-if [ "X$1" = "X-h" ]; then
+if [ x"$1" = x"-h" ]; then
        havehist=0
        shift
 fi
+
+shell=$1
+builtins=$2
+objdir=$3
+
 havejobs=0
-if [ "X$1" = "X-j" ]; then
-       havejobs=0
-       shift
-elif grep '^#define[    ]*JOBS[         ]*1' $2 > /dev/null
-then   havejobs=1
+if grep '^#define JOBS[         ]*1' ${shell} > /dev/null
+then
+       havejobs=1
 fi
-objdir=$1
-exec > ${objdir}/builtins.c
-cat <<\!
-/*
+
+exec <$builtins 3> ${objdir}/builtins.c 4> ${objdir}/builtins.h
+
+echo '/*
  * This file was generated by the mkbuiltins program.
  */
 
-#include <stdlib.h>
 #include "shell.h"
 #include "builtins.h"
 
-!
-awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \
-    print $0}' $3 | sed 's/-[hj]//' > $temp
-#awk '{        printf "int %s();\n", $1}' $temp
-echo '
-int (*const builtinfunc[]) (int, char **) = {'
-awk '/^[^#]/ { printf "\t%s,\n", $1}' $temp
-echo '};
-
-const struct builtincmd builtincmd[] = {'
-awk '{ for (i = 2 ; i <= NF ; i++) {
-               printf "\t{ \"%s\", %d },\n",  $i, NR-1
-       }}' $temp
-echo ' { NULL, 0 }
-};'
-
-exec > ${objdir}/builtins.h
-cat <<\!
-/*
+const struct builtincmd builtincmd[] = {
+' >&3
+
+echo '/*
  * This file was generated by the mkbuiltins program.
  */
 
-!
-tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ < $temp |
-       awk '{  printf "#define %s %d\n", $1, NR-1}'
-echo '
+#include <sys/cdefs.h>
+
 struct builtincmd {
-      char *name;
-      int code;
+      const char *name;
+      int (*builtin)(int, char **);
 };
 
-extern int (*const builtinfunc[]) (int, char **);
-extern const struct builtincmd builtincmd[];'
-awk '{ printf "int %s (int, char **);\n", $1 }' < $temp
-rm -f $temp
+extern const struct builtincmd builtincmd[];
+extern const struct builtincmd splbltincmd[];
 
-#
-# $PchId: mkbuiltins,v 1.6 2006/05/22 12:42:58 philip Exp $
+' >&4
+
+specials=
+
+while read line
+do
+       set -- $line
+       [ -z "$1" ] && continue
+       case "$1" in
+       \#if*|\#def*|\#end*)
+               echo $line >&3
+               echo $line >&4
+               continue
+               ;;
+       \#*)
+               continue
+               ;;
+       esac
+
+       func=$1
+       shift
+       [ x"$1" = x'-j' ] && {
+               [ $havejobs = 0 ] && continue
+               shift
+       }
+       [ x"$1" = x'-h' ] && {
+               [ $havehist = 0 ] && continue
+               shift
+       }
+       echo 'int '"$func"'(int, char **);' >&4
+       while
+               [ $# != 0 ] && [ x"$1" != x'#' ]
+       do
+               [ x"$1" = x'-s' ] && {
+                       specials="$specials $2 $func"
+                       shift 2
+                       continue;
+               }
+               [ x"$1" = x'-u' ] && shift
+               echo '  { "'$1'",       '"$func"' },' >&3
+               shift
+       done
+done
+
+echo ' { 0, 0 },' >&3
+echo '};' >&3
+echo >&3
+echo 'const struct builtincmd splbltincmd[] = {' >&3
+
+set -- $specials
+while
+       [ $# != 0 ]
+do
+       echo '  { "'$1'",       '"$2"' },' >&3
+       shift 2
+done
+
+echo ' { 0, 0 },' >&3
+echo "};" >&3
diff --git a/bin/sh/mkinit.sh b/bin/sh/mkinit.sh
new file mode 100755 (executable)
index 0000000..a7dcb91
--- /dev/null
@@ -0,0 +1,170 @@
+#! /bin/sh
+#      $NetBSD: mkinit.sh,v 1.5 2008/10/23 20:21:57 apb Exp $
+
+# Copyright (c) 2003 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by David Laight.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+srcs="$*"
+
+nl='
+'
+openparen='('
+backslash='\'
+
+includes=' "shell.h" "mystring.h" "init.h" '
+defines=
+decles=
+event_init=
+event_reset=
+event_shellproc=
+
+for src in $srcs; do
+       exec <$src
+       decnl="$nl"
+       while IFS=; read -r line; do
+               [ "$line" = x ]
+               case "$line " in
+               INIT["{         "]* ) event=init;;
+               RESET["{        "]* ) event=reset;;
+               SHELLPROC["{    "]* ) event=shellproc;;
+               INCLUDE[\ \     ]* )
+                       IFS='   '
+                       set -- $line
+                       # ignore duplicates
+                       [ "${includes}" != "${includes%* $2 }" ] && continue
+                       includes="$includes$2 "
+                       continue
+                       ;;
+               MKINIT\  )
+                       # struct declaration
+                       decles="$decles$nl"
+                       while
+                               read -r line
+                               decles="${decles}${line}${nl}"
+                               [ "$line" != "};" ]
+                       do
+                               :
+                       done
+                       decnl="$nl"
+                       continue
+                       ;;
+               MKINIT["{       "]* )
+                       # strip initialiser
+                       def=${line#MKINIT}
+                       comment="${def#*;}"
+                       def="${def%;$comment}"
+                       def="${def%%=*}"
+                       def="${def% }"
+                       decles="${decles}${decnl}extern${def};${comment}${nl}"
+                       decnl=
+                       continue
+                       ;;
+               \#define[\ \    ]* )
+                       IFS='   '
+                       set -- $line
+                       # Ignore those with arguments
+                       [ "$2" = "${2##*$openparen}" ] || continue
+                       # and multiline definitions
+                       [ "$line" = "${line%$backslash}" ] || continue
+                       defines="${defines}#undef       $2${nl}${line}${nl}"
+                       continue
+                       ;;
+               * ) continue;;
+               esac
+               # code for events
+               ev="${nl}       /* from $src: */${nl}   {${nl}"
+               # Indent the text by an extra <tab>
+               while
+                       read -r line
+                       [ "$line" != "}" ]
+               do
+                       [ -n "$line" -a "$line" = "${line###}" ] &&
+                               line="  $line"
+                       ev="${ev}${line}${nl}"
+               done
+               ev="${ev}       }${nl}"
+               eval event_$event=\"\$event_$event\$ev\"
+       done
+done
+
+exec >init.c.tmp
+
+echo "/*"
+echo " * This file was generated by the mkinit program."
+echo " */"
+echo
+
+IFS=' '
+for f in $includes; do
+       echo "#include $f"
+done
+
+echo
+echo
+echo
+echo "$defines"
+echo
+echo "$decles"
+echo
+echo
+echo "/*"
+echo " * Initialization code."
+echo " */"
+echo
+echo "void"
+echo "init(void)"
+echo "{"
+echo "${event_init}"
+echo "}"
+echo
+echo
+echo
+echo "/*"
+echo " * This routine is called when an error or an interrupt occurs in an"
+echo " * interactive shell and control is returned to the main command loop."
+echo " */"
+echo
+echo "void"
+echo "reset(void)"
+echo "{"
+echo "${event_reset}"
+echo "}"
+echo
+echo
+echo
+echo "/*"
+echo " * This routine is called to initialize the shell to run a shell procedure."
+echo " */"
+echo
+echo "void"
+echo "initshellproc(void)"
+echo "{"
+echo "${event_shellproc}"
+echo "}"
+
+exec >&-
+mv init.c.tmp init.c
diff --git a/bin/sh/mknodes.sh b/bin/sh/mknodes.sh
new file mode 100755 (executable)
index 0000000..2208fd8
--- /dev/null
@@ -0,0 +1,214 @@
+#! /bin/sh
+#      $NetBSD: mknodes.sh,v 1.2 2008/04/29 06:53:00 martin Exp $
+
+# Copyright (c) 2003 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by David Laight.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+nodetypes=$1
+nodes_pat=$2
+objdir="$3"
+
+exec <$nodetypes
+exec >$objdir/nodes.h.tmp
+
+echo "/*"
+echo " * This file was generated by mknodes.sh"
+echo " */"
+echo
+
+tagno=0
+while IFS=; read -r line; do
+       line="${line%%#*}"
+       IFS='   '
+       set -- $line
+       IFS=
+       [ -z "$2" ] && continue
+       case "$line" in
+       ["      "]* )
+               IFS=' '
+               [ $field = 0 ] && struct_list="$struct_list $struct"
+               eval field_${struct}_$field=\"\$*\"
+               eval numfld_$struct=\$field
+               field=$(($field + 1))
+               ;;
+       * )
+               define=$1
+               struct=$2
+               echo "#define $define $tagno"
+               tagno=$(($tagno + 1))
+               eval define_$struct=\"\$define_$struct \$define\"
+               struct_define="$struct_define $struct"
+               field=0
+               ;;
+       esac
+done
+
+echo
+
+IFS=' '
+for struct in $struct_list; do
+       echo
+       echo
+       echo "struct $struct {"
+       field=0
+       while
+               eval line=\"\$field_${struct}_$field\"
+               field=$(($field + 1))
+               [ -n "$line" ]
+       do
+               IFS=' '
+               set -- $line
+               name=$1
+               case $2 in
+               nodeptr ) type="union node *";;
+               nodelist ) type="struct nodelist *";;
+               string ) type="char *";;
+               int ) type="int ";;
+               * ) name=; shift 2; type="$*";;
+               esac
+               echo "      $type$name;"
+       done
+       echo "};"
+done
+
+echo
+echo
+echo "union node {"
+echo "      int type;"
+for struct in $struct_list; do
+       echo "      struct $struct $struct;"
+done
+echo "};"
+echo
+echo
+echo "struct nodelist {"
+echo " struct nodelist *next;"
+echo " union node *n;"
+echo "};"
+echo
+echo
+echo "union node *copyfunc(union node *);"
+echo "void freefunc(union node *);"
+
+mv $objdir/nodes.h.tmp $objdir/nodes.h || exit 1
+
+exec <$nodes_pat
+exec >$objdir/nodes.c.tmp
+
+echo "/*"
+echo " * This file was generated by mknodes.sh"
+echo " */"
+echo
+
+while IFS=; read -r line; do
+       IFS='   '
+       set -- $line
+       IFS=
+       case "$1" in
+       '%SIZES' )
+               echo "static const short nodesize[$tagno] = {"
+               IFS=' '
+               for struct in $struct_define; do
+                       echo "      SHELL_ALIGN(sizeof (struct $struct)),"
+               done
+               echo "};"
+               ;;
+       '%CALCSIZE' )
+               echo "      if (n == NULL)"
+               echo "      return;"
+               echo "      funcblocksize += nodesize[n->type];"
+               echo "      switch (n->type) {"
+               IFS=' '
+               for struct in $struct_list; do
+                       eval defines=\"\$define_$struct\"
+                       for define in $defines; do
+                               echo "      case $define:"
+                       done
+                       eval field=\$numfld_$struct
+                       while
+                               [ $field != 0 ]
+                       do
+                               eval line=\"\$field_${struct}_$field\"
+                               field=$(($field - 1))
+                               IFS=' '
+                               set -- $line
+                               name=$1
+                               cl=")"
+                               case $2 in
+                               nodeptr ) fn=calcsize;;
+                               nodelist ) fn=sizenodelist;;
+                               string ) fn="funcstringsize += strlen"
+                                       cl=") + 1";;
+                               * ) continue;;
+                               esac
+                               echo "      ${fn}(n->$struct.$name${cl};"
+                       done
+                       echo "      break;"
+               done
+               echo "      };"
+               ;;
+       '%COPY' )
+               echo "      if (n == NULL)"
+               echo "      return NULL;"
+               echo "      new = funcblock;"
+               echo "      funcblock = (char *) funcblock + nodesize[n->type];"
+               echo "      switch (n->type) {"
+               IFS=' '
+               for struct in $struct_list; do
+                       eval defines=\"\$define_$struct\"
+                       for define in $defines; do
+                               echo "      case $define:"
+                       done
+                       eval field=\$numfld_$struct
+                       while
+                               [ $field != 0 ]
+                       do
+                               eval line=\"\$field_${struct}_$field\"
+                               field=$(($field - 1))
+                               IFS=' '
+                               set -- $line
+                               name=$1
+                               case $2 in
+                               nodeptr ) fn="copynode(";;
+                               nodelist ) fn="copynodelist(";;
+                               string ) fn="nodesavestr(";;
+                               int ) fn=;;
+                               * ) continue;;
+                               esac
+                               f="$struct.$name"
+                               echo "      new->$f = ${fn}n->$f${fn:+)};"
+                       done
+                       echo "      break;"
+               done
+               echo "      };"
+               echo "      new->type = n->type;"
+               ;;
+       * ) echo "$line";;
+       esac
+done
+
+mv $objdir/nodes.c.tmp $objdir/nodes.c || exit 1
old mode 100755 (executable)
new mode 100644 (file)
similarity index 75%
rename from minix/commands/ash/mktokens.sh
rename to bin/sh/mktokens
index e529902..d12bdee
@@ -1,4 +1,5 @@
 #!/bin/sh -
+#      $NetBSD: mktokens,v 1.12 2008/10/25 22:18:15 apb Exp $
 #
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
@@ -14,7 +15,7 @@
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
-# 4. Neither the name of the University nor the names of its contributors
+# 3. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
 #
 # SUCH DAMAGE.
 #
 #      @(#)mktokens    8.1 (Berkeley) 5/31/93
-# $FreeBSD: src/bin/sh/mktokens,v 1.9 2004/04/06 20:06:51 markm Exp $
 
-# All calls to awk removed, because Minix bawk is deficient.  (kjb)
+: ${AWK:=awk}
+: ${SED:=sed}
 
 # The following is a list of tokens.  The second column is nonzero if the
 # token marks the end of a list.  The third column is the name to print in
 # error messages.
 
-#temp=`/usr/bin/mktemp -t ka`
-temp=/tmp/mkt$$
-cat > $temp <<\!
+cat > /tmp/ka$$ <<\!
 TEOF   1       end of file
 TNL    0       newline
 TSEMI  0       ";"
@@ -71,54 +70,26 @@ TCASE       0       "case"
 TESAC  1       "esac"
 TNOT   0       "!"
 !
-nl=`wc -l $temp`
+nl=`wc -l /tmp/ka$$`
 exec > token.h
-i=0
-while read line
-do
-       set -$- $line
-       echo "#define $1 $i"
-       i=`expr $i + 1`
-done <$temp
+${AWK} '{print "#define " $1 " " NR-1}' /tmp/ka$$
 echo '
 /* Array indicating which tokens mark the end of a list */
 const char tokendlist[] = {'
-while read line
-do
-       set -$- $line
-       echo "  $2,"
-done <$temp
+${AWK} '{print "\t" $2 ","}' /tmp/ka$$
 echo '};
 
 const char *const tokname[] = {'
-sed -e 's/"/\\"/g' \
+${SED} -e 's/"/\\"/g' \
     -e 's/[^    ]*[     ][      ]*[^    ]*[     ][      ]*\(.*\)/      "\1",/' \
-    $temp
+    /tmp/ka$$
 echo '};
 '
-i=0
-go=
-sed 's/"//g' $temp |
-       while read line
-       do
-               set -$- $line
-               if [ "$1" = TIF ]
-               then
-                       echo "#define KWDOFFSET $i"
-                       echo
-                       echo "const char *const parsekwd[] = {"
-                       go=true
-               fi
-               if [ "$go" ]
-               then
-                       echo "  \"$3\","
-               fi
-               i=`expr $i + 1`
-       done
+${SED} 's/"//g' /tmp/ka$$ | ${AWK} '
+/TIF/{print "#define KWDOFFSET " NR-1; print ""; 
+      print "const char *const parsekwd[] = {"}
+/TIF/,/neverfound/{print "     \"" $3 "\","}'
 echo ' 0
 };'
 
-rm $temp
-
-#
-# $PchId: mktokens,v 1.5 2006/05/22 12:43:35 philip Exp $
+rm /tmp/ka$$
similarity index 84%
rename from minix/commands/ash/myhistedit.h
rename to bin/sh/myhistedit.h
index f6e295bda4293c0862b80bafcdf7c191c70ec3ac..be66df04d213704f1797ad478e8afd6dc446e3ea 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: myhistedit.h,v 1.11 2011/06/18 21:18:46 christos Exp $ */
+
 /*-
  * Copyright (c) 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -10,7 +12,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -27,7 +29,6 @@
  * SUCH DAMAGE.
  *
  *     @(#)myhistedit.h        8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/myhistedit.h,v 1.10 2004/04/06 20:06:51 markm Exp $
  */
 
 #include <histedit.h>
@@ -38,13 +39,8 @@ extern int displayhist;
 
 void histedit(void);
 void sethistsize(const char *);
-int histcmd(int, char **);
-int bindcmd(int, char **);
-
-/* From libedit */
-void  re_goto_bottom(EditLine *);
-
-/*
- * $PchId: myhistedit.h,v 1.5 2006/03/29 15:55:18 philip Exp $
- */
+void setterm(const char *);
+int inputrc(int, char **);
+int not_fcnumber(char *);
+int str_to_event(const char *, int);
 
similarity index 90%
rename from minix/commands/ash/mystring.c
rename to bin/sh/mystring.c
index 7957c333a77b59a21c62c537593edf5706ad1328..d2d5825520d45a7e7f69e82dd42eba8d9123f429 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: mystring.c,v 1.17 2013/04/28 17:01:28 dholland Exp $   */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: mystring.c,v 1.17 2013/04/28 17:01:28 dholland Exp $");
 #endif
 #endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/mystring.c,v 1.13 2004/04/06 20:06:51 markm Exp $");
-*/
 
 /*
  * String functions.
@@ -57,7 +58,7 @@ __FBSDID("$FreeBSD: src/bin/sh/mystring.c,v 1.13 2004/04/06 20:06:51 markm Exp $
 #include "mystring.h"
 
 
-char nullstr[1];               /* zero length string */
+const char nullstr[1];         /* zero length string */
 
 /*
  * equal - #defined in mystring.h
@@ -109,8 +110,9 @@ prefix(const char *pfx, const char *string)
 int
 number(const char *s)
 {
+
        if (! is_number(s))
-               error("Illegal number: %s", (char *)s);
+               error("Illegal number: %s", s);
        return atoi(s);
 }
 
@@ -129,7 +131,3 @@ is_number(const char *p)
        } while (*++p != '\0');
        return 1;
 }
-
-/*
- * $PchId: mystring.c,v 1.4 2006/05/22 12:21:53 philip Exp $
- */
similarity index 90%
rename from minix/commands/ash/mystring.h
rename to bin/sh/mystring.h
index 9e9939cd0efb28ccda95954c4e2e2b80bf41f0d3..08a73e9e5b25d5bb26c5df33bf2122d8967d0e30 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: mystring.h,v 1.11 2003/08/07 09:05:35 agc Exp $        */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -30,7 +32,6 @@
  * SUCH DAMAGE.
  *
  *     @(#)mystring.h  8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/mystring.h,v 1.8 2004/04/06 20:06:51 markm Exp $
  */
 
 #include <string.h>
@@ -42,7 +43,3 @@ int is_number(const char *);
 
 #define equal(s1, s2)  (strcmp(s1, s2) == 0)
 #define scopy(s1, s2)  ((void)strcpy(s2, s1))
-
-/*
- * $PchId: mystring.h,v 1.3 2006/03/29 15:49:08 philip Exp $
- */
similarity index 80%
rename from minix/commands/ash/nodes.c.pat
rename to bin/sh/nodes.c.pat
index fb867053e06b0face215daf6b9ae6a71e6b01ca0..979e6b00eb7b3194a2c528a157cf38c1e28dd7e9 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: nodes.c.pat,v 1.13 2012/03/20 18:42:29 matt Exp $      */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -30,7 +32,6 @@
  * SUCH DAMAGE.
  *
  *     @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/nodes.c.pat,v 1.15 2004/04/06 20:06:51 markm Exp $
  */
 
 #include <stdlib.h>
 #include "shell.h"
 #include "nodes.h"
 #include "memalloc.h"
+#include "machdep.h"
 #include "mystring.h"
 
-#ifndef __minix
-#include <sys/param.h>
-#endif
-#include "machdep.h"
 
-STATIC int     funcblocksize;  /* size of structures in function */
-STATIC int     funcstringsize; /* size of strings in node */
-STATIC pointer funcblock;      /* block to allocate function from */
-STATIC char   *funcstring;     /* block to allocate strings from */
+int     funcblocksize;         /* size of structures in function */
+int     funcstringsize;                /* size of strings in node */
+pointer funcblock;             /* block to allocate function from */
+char   *funcstring;            /* block to allocate strings from */
 
 %SIZES
 
@@ -77,7 +75,7 @@ copyfunc(union node *n)
        funcstringsize = 0;
        calcsize(n);
        funcblock = ckmalloc(funcblocksize + funcstringsize);
-       funcstring = (char *)funcblock + funcblocksize;
+       funcstring = (char *) funcblock + funcblocksize;
        return copynode(n);
 }
 
@@ -95,7 +93,7 @@ STATIC void
 sizenodelist(struct nodelist *lp)
 {
        while (lp) {
-               funcblocksize += ALIGN(sizeof(struct nodelist));
+               funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
                calcsize(lp->n);
                lp = lp->next;
        }
@@ -122,7 +120,8 @@ copynodelist(struct nodelist *lp)
        lpp = &start;
        while (lp) {
                *lpp = funcblock;
-               funcblock = (char *)funcblock + ALIGN(sizeof(struct nodelist));
+               funcblock = (char *) funcblock +
+                   SHELL_ALIGN(sizeof(struct nodelist));
                (*lpp)->n = copynode(lp->n);
                lp = lp->next;
                lpp = &(*lpp)->next;
@@ -136,11 +135,11 @@ copynodelist(struct nodelist *lp)
 STATIC char *
 nodesavestr(char *s)
 {
-       char *p = s;
-       char *q = funcstring;
+       register char *p = s;
+       register char *q = funcstring;
        char   *rtn = funcstring;
 
-       while ((*q++ = *p++) != '\0')
+       while ((*q++ = *p++) != 0)
                continue;
        funcstring = q;
        return rtn;
@@ -158,7 +157,3 @@ freefunc(union node *n)
        if (n)
                ckfree(n);
 }
-
-/*
- * $PchId: nodes.c.pat,v 1.5 2006/05/22 12:43:57 philip Exp $
- */
similarity index 94%
rename from minix/commands/ash/nodetypes
rename to bin/sh/nodetypes
index 2c25c1d33753c2fa5807a9dc377e28d5a8a9d1cf..4bf4ae0b0ad51bb86c554259da0ceb1b54f50ba8 100644 (file)
@@ -1,4 +1,4 @@
-#
+#      $NetBSD: nodetypes,v 1.13 2009/05/26 07:30:51 joerg Exp $
 # Copyright (c) 1991, 1993
 #      The Regents of the University of California.  All rights reserved.
 #
@@ -13,7 +13,7 @@
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
-# 4. Neither the name of the University nor the names of its contributors
+# 3. Neither the name of the University nor the names of its contributors
 #    may be used to endorse or promote products derived from this software
 #    without specific prior written permission.
 #
@@ -30,7 +30,6 @@
 # SUCH DAMAGE.
 #
 #      @(#)nodetypes   8.2 (Berkeley) 5/4/95
-# $FreeBSD: src/bin/sh/nodetypes,v 1.9 2004/04/06 20:06:51 markm Exp $
 
 # This file describes the nodes used in parse trees.  Unindented lines
 # contain a node type followed by a structure tag.  Subsequent indented
@@ -65,7 +64,7 @@ NPIPE npipe                   # a pipeline
        backgnd   int                   # set to run pipeline in background
        cmdlist   nodelist              # the commands in the pipeline
 
-NREDIR nredir                  # redirection (of a compex command)
+NREDIR nredir                  # redirection (of a complex command)
        type      int
        n         nodeptr               # the command
        redirect  nodeptr               # list of file redirections
@@ -113,10 +112,10 @@ NARG narg                 # represents a word
        backquote nodelist              # list of commands in back quotes
 
 NTO nfile                      # fd> fname
+NCLOBBER nfile                 # fd>| fname
 NFROM nfile                    # fd< fname
 NFROMTO nfile                  # fd<> fname
 NAPPEND nfile                  # fd>> fname
-NCLOBBER nfile                 # fd>| fname
        type      int
        next      nodeptr               # next redirection in list
        fd        int                   # file descriptor being redirected
@@ -140,8 +139,5 @@ NXHERE nhere                        # fd<<!
        doc       nodeptr               # input to command (NARG node)
 
 NNOT nnot                      # ! command  (actually pipeline)
-       type    int
-       com     nodeptr
-
-#
-# $PchId: nodetypes,v 1.3 2006/03/29 15:43:35 philip Exp $
+       type      int
+       com       nodeptr
similarity index 80%
rename from minix/commands/ash/options.c
rename to bin/sh/options.c
index 23de7140934336a7f730f413c3c86f2fbbffa5de..8fa50ffc012657ce83f2e30d0351ec360be08839 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: options.c,v 1.43 2012/03/20 18:42:29 matt Exp $        */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)options.c  8.2 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: options.c,v 1.43 2012/03/20 18:42:29 matt Exp $");
 #endif
 #endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $");
-*/
 
 #include <signal.h>
 #include <unistd.h>
@@ -48,6 +49,7 @@ __FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $"
 #define DEFINE_OPTIONS
 #include "options.h"
 #undef DEFINE_OPTIONS
+#include "builtins.h"
 #include "nodes.h"     /* for other header files */
 #include "eval.h"
 #include "jobs.h"
@@ -58,17 +60,16 @@ __FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $"
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
-#include "builtins.h"
-#if !defined(NO_HISTORY)
+#ifndef SMALL
 #include "myhistedit.h"
 #endif
+#include "show.h"
 
 char *arg0;                    /* value of $0 */
 struct shparam shellparam;     /* current positional parameters */
 char **argptr;                 /* argument list for builtin commands */
-char *shoptarg;                        /* set by nextopt (like getopt) */
+char *optionarg;               /* set by nextopt (like getopt) */
 char *optptr;                  /* used by nextopt */
-int editable;                  /* isatty(0) && isatty(1) */ 
 
 char *minusc;                  /* argument to -c option */
 
@@ -86,33 +87,43 @@ STATIC int getopts(char *, char *, char **, char ***, char **);
 void
 procargs(int argc, char **argv)
 {
-       int i;
+       size_t i;
 
        argptr = argv;
        if (argc > 0)
                argptr++;
        for (i = 0; i < NOPTS; i++)
                optlist[i].val = 2;
-       privileged = (getuid() != geteuid() || getgid() != getegid());
        options(1);
        if (*argptr == NULL && minusc == NULL)
                sflag = 1;
-       editable = (isatty(0) && isatty(1));
-       if (iflag == 2 && sflag == 1 && editable)
+       if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
                iflag = 1;
+       if (iflag == 1 && sflag == 2)
+               iflag = 2;
        if (mflag == 2)
                mflag = iflag;
        for (i = 0; i < NOPTS; i++)
                if (optlist[i].val == 2)
                        optlist[i].val = 0;
+#if DEBUG == 2
+       debug = 1;
+#endif
        arg0 = argv[0];
        if (sflag == 0 && minusc == NULL) {
-               commandname = arg0 = *argptr++;
-               setinputfile(commandname, 0);
+               commandname = argv[0];
+               arg0 = *argptr++;
+               setinputfile(arg0, 0);
+               commandname = arg0;
        }
        /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
-       if (argptr && minusc && *argptr)
-               arg0 = *argptr++;
+       if (minusc != NULL) {
+               if (argptr == NULL || *argptr == NULL)
+                       error("Bad -c option");
+               minusc = *argptr++;
+               if (*argptr != 0)
+                       arg0 = *argptr++;
+       }
 
        shellparam.p = argptr;
        shellparam.reset = 1;
@@ -121,9 +132,6 @@ procargs(int argc, char **argv)
                shellparam.nparam++;
                argptr++;
        }
-#ifdef __minix
-       if(!Eflag && !Vflag) Eflag = 1;
-#endif
        optschanged();
 }
 
@@ -132,7 +140,7 @@ void
 optschanged(void)
 {
        setinteractive(iflag);
-#if !defined(NO_HISTORY)
+#ifndef SMALL
        histedit();
 #endif
        setjobctl(mflag);
@@ -146,6 +154,7 @@ optschanged(void)
 STATIC void
 options(int cmdline)
 {
+       static char empty[] = "";
        char *p;
        int val;
        int c;
@@ -175,65 +184,62 @@ options(int cmdline)
                }
                while ((c = *p++) != '\0') {
                        if (c == 'c' && cmdline) {
-                               char *q;
-#ifdef NOHACK  /* removing this code allows sh -ce 'foo' for compat */
-                               if (*p == '\0')
-#endif
-                                       q = *argptr++;
-                               if (q == NULL || minusc != NULL)
-                                       error("Bad -c option");
-                               minusc = q;
-#ifdef NOHACK
-                               break;
-#endif
+                               /* command is after shell args*/
+                               minusc = empty;
                        } else if (c == 'o') {
                                minus_o(*argptr, val);
                                if (*argptr)
                                        argptr++;
                        } else {
-                               if (c == 'p' && !val && privileged) {
-                                       (void) setuid(getuid());
-                                       (void) setgid(getgid());
-                               }
                                setoption(c, val);
                        }
                }
        }
 }
 
+static void
+set_opt_val(size_t i, int val)
+{
+       size_t j;
+       int flag;
+
+       if (val && (flag = optlist[i].opt_set)) {
+               /* some options (eg vi/emacs) are mutually exclusive */
+               for (j = 0; j < NOPTS; j++)
+                   if (optlist[j].opt_set == flag)
+                       optlist[j].val = 0;
+       }
+       optlist[i].val = val;
+#ifdef DEBUG
+       if (&optlist[i].val == &debug)
+               opentrace();
+#endif
+}
+
 STATIC void
 minus_o(char *name, int val)
 {
-       int doneset, i;
+       size_t i;
 
        if (name == NULL) {
                if (val) {
-                       /* "Pretty" output. */
                        out1str("Current option settings\n");
-                       for (i = 0; i < NOPTS; i++)
+                       for (i = 0; i < NOPTS; i++) {
                                out1fmt("%-16s%s\n", optlist[i].name,
                                        optlist[i].val ? "on" : "off");
+                       }
                } else {
-                       /* Output suitable for re-input to shell. */
-                       for (doneset = i = 0; i < NOPTS; i++)
-                               if (optlist[i].val) {
-                                       if (!doneset) {
-                                               out1str("set");
-                                               doneset = 1;
-                                       }
-                                       out1fmt(" -o %s", optlist[i].name);
-                               }
-                       if (doneset)
-                               out1c('\n');
+                       out1str("set");
+                       for (i = 0; i < NOPTS; i++) {
+                               out1fmt(" %co %s",
+                                       "+-"[optlist[i].val], optlist[i].name);
+                       }
+                       out1str("\n");
                }
        } else {
                for (i = 0; i < NOPTS; i++)
                        if (equal(name, optlist[i].name)) {
-                               if (!val && privileged && equal(name, "privileged")) {
-                                       (void) setuid(getuid());
-                                       (void) setgid(getgid());
-                               }
-                               setoption(optlist[i].letter, val);
+                               set_opt_val(i, val);
                                return;
                        }
                error("Illegal option -o %s", name);
@@ -244,21 +250,15 @@ minus_o(char *name, int val)
 STATIC void
 setoption(int flag, int val)
 {
-       int i;
+       size_t i;
 
        for (i = 0; i < NOPTS; i++)
                if (optlist[i].letter == flag) {
-                       optlist[i].val = val;
-                       if (val) {
-                               /* #%$ hack for ksh semantics */
-                               if (flag == 'V')
-                                       Eflag = 0;
-                               else if (flag == 'E')
-                                       Vflag = 0;
-                       }
+                       set_opt_val( i, val );
                        return;
                }
        error("Illegal option -%c", flag);
+       /* NOTREACHED */
 }
 
 
@@ -269,7 +269,7 @@ INCLUDE "options.h"
 SHELLPROC {
        int i;
 
-       for (i = 0; i < NOPTS; i++)
+       for (i = 0; optlist[i].name; i++)
                optlist[i].val = 0;
        optschanged();
 
@@ -288,7 +288,8 @@ setparam(char **argv)
        char **ap;
        int nparam;
 
-       for (nparam = 0 ; argv[nparam] ; nparam++);
+       for (nparam = 0 ; argv[nparam] ; nparam++)
+               continue;
        ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
        while (*argv) {
                *ap++ = savestr(*argv++);
@@ -307,7 +308,7 @@ setparam(char **argv)
  */
 
 void
-freeparam(struct shparam *param)
+freeparam(volatile struct shparam *param)
 {
        char **ap;
 
@@ -358,7 +359,7 @@ int
 setcmd(int argc, char **argv)
 {
        if (argc == 1)
-               return showvarscmd(argc, argv);
+               return showvars(0, 0, 1);
        INTOFF;
        options(0);
        optschanged();
@@ -389,7 +390,7 @@ getoptsreset(const char *value)
 int
 getoptscmd(int argc, char **argv)
 {
-       char **optbase = NULL;
+       char **optbase;
 
        if (argc < 3)
                error("usage: getopts optstring var [arg]");
@@ -409,17 +410,16 @@ getoptscmd(int argc, char **argv)
 }
 
 STATIC int
-getopts(char *optstr, char *optvar, char **optfirst, char ***optnext,
-    char **optptr)
+getopts(char *optstr, char *optvar, char **optfirst, char ***optnext, char **optpptr)
 {
        char *p, *q;
        char c = '?';
        int done = 0;
        int ind = 0;
        int err = 0;
-       char s[10];
+       char s[12];
 
-       if ((p = *optptr) == NULL || *p == '\0') {
+       if ((p = *optpptr) == NULL || *p == '\0') {
                /* Current word is done, advance */
                if (*optnext == NULL)
                        return 1;
@@ -444,10 +444,9 @@ atend:
                                s[0] = c;
                                s[1] = '\0';
                                err |= setvarsafe("OPTARG", s, 0);
-                       }
-                       else {
-                               out1fmt("Illegal option -%c\n", c);
-                               (void) unsetvar("OPTARG");
+                       } else {
+                               outfmt(&errout, "Illegal option -%c\n", c);
+                               (void) unsetvar("OPTARG", 0);
                        }
                        c = '?';
                        goto bad;
@@ -463,10 +462,9 @@ atend:
                                s[1] = '\0';
                                err |= setvarsafe("OPTARG", s, 0);
                                c = ':';
-                       }
-                       else {
-                               out1fmt("No arg for -%c option\n", c);
-                               (void) unsetvar("OPTARG");
+                       } else {
+                               outfmt(&errout, "No arg for -%c option\n", c);
+                               (void) unsetvar("OPTARG", 0);
                                c = '?';
                        }
                        goto bad;
@@ -474,11 +472,10 @@ atend:
 
                if (p == **optnext)
                        (*optnext)++;
-               setvarsafe("OPTARG", p, 0);
+               err |= setvarsafe("OPTARG", p, 0);
                p = NULL;
-       }
-       else
-               setvarsafe("OPTARG", "", 0);
+       } else
+               err |= setvarsafe("OPTARG", "", 0);
        ind = *optnext - optfirst + 1;
        goto out;
 
@@ -487,7 +484,7 @@ bad:
        *optnext = NULL;
        p = NULL;
 out:
-       *optptr = p;
+       *optpptr = p;
        fmtstr(s, sizeof(s), "%d", ind);
        err |= setvarsafe("OPTIND", s, VNOFUNC);
        s[0] = c;
@@ -495,7 +492,7 @@ out:
        err |= setvarsafe(optvar, s, 0);
        if (err) {
                *optnext = NULL;
-               *optptr = NULL;
+               *optpptr = NULL;
                flushall();
                exraise(EXERROR);
        }
@@ -514,9 +511,10 @@ out:
  */
 
 int
-nextopt(char *optstring)
+nextopt(const char *optstring)
 {
-       char *p, *q;
+       char *p;
+       const char *q;
        char c;
 
        if ((p = optptr) == NULL || *p == '\0') {
@@ -537,13 +535,9 @@ nextopt(char *optstring)
        if (*++q == ':') {
                if (*p == '\0' && (p = *argptr++) == NULL)
                        error("No arg for -%c option", c);
-               shoptarg = p;
+               optionarg = p;
                p = NULL;
        }
        optptr = p;
        return c;
 }
-
-/*
- * $PchId: options.c,v 1.6 2006/05/29 13:09:12 philip Exp $
- */
similarity index 56%
rename from minix/commands/ash/options.h
rename to bin/sh/options.h
index de1a55eba5e43af02dd6daaab822bb4eacd1fea1..0bf4a2a5d3e76e1f2d7bec0d05f90e133a30769f 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: options.h,v 1.20 2011/06/18 21:18:46 christos Exp $    */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -30,7 +32,6 @@
  * SUCH DAMAGE.
  *
  *     @(#)options.h   8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/options.h,v 1.13 2004/04/06 20:06:51 markm Exp $
  */
 
 struct shparam {
@@ -43,57 +44,74 @@ struct shparam {
 };
 
 
+struct optent {
+       const char *name;               /* for set -o <name> */
+       const char letter;              /* set [+/-]<letter> and $- */
+       const char opt_set;             /* mutually exclusive option set */
+       unsigned char val;              /* value of <letter>flag */
+};
+
+/* Those marked [U] are required by posix, but have no effect! */
+
+#ifdef DEFINE_OPTIONS
+#define DEF_OPTS(name, letter, opt_set) {name, letter, opt_set, 0},
+struct optent optlist[] = {
+#else
+#define DEF_OPTS(name, letter, opt_set)
+#endif
+#define DEF_OPT(name,letter) DEF_OPTS(name, letter, 0)
 
+DEF_OPT( "errexit",    'e' )   /* exit on error */
 #define eflag optlist[0].val
+DEF_OPT( "noglob",     'f' )   /* no pathname expansion */
 #define fflag optlist[1].val
+DEF_OPT( "ignoreeof",  'I' )   /* do not exit on EOF */
 #define Iflag optlist[2].val
+DEF_OPT( "interactive",'i' )   /* interactive shell */
 #define iflag optlist[3].val
+DEF_OPT( "monitor",    'm' )   /* job control */
 #define mflag optlist[4].val
+DEF_OPT( "noexec",     'n' )   /* [U] do not exec commands */
 #define nflag optlist[5].val
+DEF_OPT( "stdin",      's' )   /* read from stdin */
 #define sflag optlist[6].val
+DEF_OPT( "xtrace",     'x' )   /* trace after expansion */
 #define xflag optlist[7].val
+DEF_OPT( "verbose",    'v' )   /* trace read input */
 #define vflag optlist[8].val
+DEF_OPTS( "vi",                'V', 'V' )      /* vi style editing */
 #define Vflag optlist[9].val
+DEF_OPTS( "emacs",     'E', 'V' )      /* emacs style editing */
 #define        Eflag optlist[10].val
+DEF_OPT( "noclobber",  'C' )   /* do not overwrite files with > */
 #define        Cflag optlist[11].val
+DEF_OPT( "allexport",  'a' )   /* export all variables */
 #define        aflag optlist[12].val
+DEF_OPT( "notify",     'b' )   /* [U] report completion of background jobs */
 #define        bflag optlist[13].val
+DEF_OPT( "nounset",    'u' )   /* error expansion of unset variables */
 #define        uflag optlist[14].val
-#define        privileged optlist[15].val
-#define        Tflag optlist[16].val
-#define        Pflag optlist[17].val
-
-#define NOPTS  18
-
-struct optent {
-       const char *name;
-       const char letter;
-       char val;
-};
+DEF_OPT( "quietprofile", 'q' )
+#define        qflag optlist[15].val
+DEF_OPT( "nolog",      0 )     /* [U] no functon defs in command history */
+#define        nolog optlist[16].val
+DEF_OPT( "cdprint",    0 )     /* always print result of cd */
+#define        cdprint optlist[17].val
+DEF_OPT( "tabcomplete",        0 )     /* <tab> causes filename expansion */
+#define        tabcomplete optlist[18].val
+#ifdef DEBUG
+DEF_OPT( "debug",      0 )     /* enable debug prints */
+#define        debug optlist[19].val
+#endif
 
 #ifdef DEFINE_OPTIONS
-struct optent optlist[NOPTS] = {
-       { "errexit",    'e',    0 },
-       { "noglob",     'f',    0 },
-       { "ignoreeof",  'I',    0 },
-       { "interactive",'i',    0 },
-       { "monitor",    'm',    0 },
-       { "noexec",     'n',    0 },
-       { "stdin",      's',    0 },
-       { "xtrace",     'x',    0 },
-       { "verbose",    'v',    0 },
-       { "vi",         'V',    0 },
-       { "emacs",      'E',    0 },
-       { "noclobber",  'C',    0 },
-       { "allexport",  'a',    0 },
-       { "notify",     'b',    0 },
-       { "nounset",    'u',    0 },
-       { "privileged", 'p',    0 },
-       { "trapsasync", 'T',    0 },
-       { "physical",   'P',    0 },
+       { 0, 0, 0, 0 },
 };
+#define NOPTS (sizeof optlist / sizeof optlist[0] - 1)
+int sizeof_optlist = sizeof optlist;
 #else
-extern struct optent optlist[NOPTS];
+extern struct optent optlist[];
+extern int sizeof_optlist;
 #endif
 
 
@@ -101,20 +119,12 @@ extern char *minusc;              /* argument to -c option */
 extern char *arg0;             /* $0 */
 extern struct shparam shellparam;  /* $@ */
 extern char **argptr;          /* argument list for builtin commands */
-extern char *shoptarg;         /* set by nextopt */
+extern char *optionarg;                /* set by nextopt */
 extern char *optptr;           /* used by nextopt */
-extern int editable;           /* isatty(0) && isatty(1) */ 
 
 void procargs(int, char **);
 void optschanged(void);
 void setparam(char **);
-void freeparam(struct shparam *);
-int shiftcmd(int, char **);
-int setcmd(int, char **);
-int getoptscmd(int, char **);
-int nextopt(char *);
+void freeparam(volatile struct shparam *);
+int nextopt(const char *);
 void getoptsreset(const char *);
-
-/*
- * $PchId: options.h,v 1.5 2006/05/29 13:08:45 philip Exp $
- */
similarity index 76%
rename from minix/commands/ash/output.c
rename to bin/sh/output.c
index 5af44ae84eb723824a3b4d68c2aa403c1e8a19b3..cd33e8e0f96ef7094fbc4fddb1b55bf1863fdfe3 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: output.c,v 1.33 2010/08/30 06:27:14 christos Exp $     */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
-static char sccsid[] = "@(#)output.c   8.1 (Berkeley) 5/31/93";
+static char sccsid[] = "@(#)output.c   8.2 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: output.c,v 1.33 2010/08/30 06:27:14 christos Exp $");
 #endif
 #endif /* not lint */
 
@@ -47,28 +52,26 @@ static char sccsid[] = "@(#)output.c        8.1 (Berkeley) 5/31/93";
  *     Our output routines may be smaller than the stdio routines.
  */
 
+#include <sys/types.h>         /* quad_t */
+#include <sys/param.h>         /* BSD4_4 */
+#include <sys/ioctl.h>
+
 #include <stdio.h>     /* defines BUFSIZ */
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
 #include "shell.h"
 #include "syntax.h"
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
-#include "var.h"
-#ifdef __STDC__
-#include "stdarg.h"
-#else
-#include <varargs.h>
-#endif
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
 
 
 #define OUTBUFSIZ BUFSIZ
 #define BLOCK_OUT -2           /* output to a fixed block of memory */
 #define MEM_OUT -3             /* output to dynamically allocated memory */
-#define OUTPUT_ERR 01          /* error occurred on output */
 
 
 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
@@ -102,11 +105,8 @@ RESET {
  */
 
 void
-open_mem(block, length, file)
-       char *block;
-       int length;
-       struct output *file;
-       {
+open_mem(char *block, int length, struct output *file)
+{
        file->nextc = block;
        file->nleft = --length;
        file->fd = BLOCK_OUT;
@@ -116,16 +116,9 @@ open_mem(block, length, file)
 
 
 void
-out1str(p)
-       const char *p;
-       {
-       outstr(p, out1);
-}
-
-void
-out1qstr(const char *p)
+out1str(const char *p)
 {
-       outqstr(p, out1);
+       outstr(p, out1);
 }
 
 
@@ -137,43 +130,49 @@ out2str(const char *p)
 
 
 void
-outstr(p, file)
-       register const char *p;
-       register struct output *file;
-       {
+outstr(const char *p, struct output *file)
+{
        while (*p)
                outc(*p++, file);
        if (file == out2)
                flushout(file);
 }
 
-/* Like outstr(), but quote for re-input into the shell. */
+
 void
-outqstr(const char *p, struct output *file)
+out2shstr(const char *p)
 {
-       char ch;
+       outshstr(p, out2);
+}
 
-       if (p[strcspn(p, "|&;<>()$`\\\"'")] == '\0' && (!ifsset() ||
-           p[strcspn(p, ifsval())] == '\0')) {
-               outstr(p, file);
-               return;
-       }
 
-       out1c('\'');
-       while ((ch = *p++) != '\0') {
-               switch (ch) {
-               case '\'':
-                       /*
-                        * Can't quote single quotes inside single quotes;
-                        * close them, write escaped single quote, open again.
-                        */
-                       outstr("'\\''", file);
-                       break;
-               default:
-                       outc(ch, file);
+void
+outshstr(const char *p, struct output *file)
+{
+       static const char norm_chars [] \
+               = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-=";
+       int need_q = p[0] == 0 || p[strspn(p, norm_chars)] != 0;
+       char c;
+
+       if (need_q)
+               outc('\'', file);
+
+       while (c = *p++, c != 0){
+               if (c != '\''){
+                       outc(c, file);
+               }else{
+                       outc('\'', file);
+                       outc('\\', file);
+                       outc(c, file);
+                       outc('\'', file);
                }
        }
-       out1c('\'');
+
+       if (need_q)
+               outc('\'', file);
+
+       if (file == out2)
+               flushout(file);
 }
 
 
@@ -181,9 +180,8 @@ char out_junk[16];
 
 
 void
-emptyoutbuf(dest)
-       struct output *dest;
-       {
+emptyoutbuf(struct output *dest)
+{
        int offset;
 
        if (dest->fd == BLOCK_OUT) {
@@ -212,16 +210,16 @@ emptyoutbuf(dest)
 
 
 void
-flushall() {
+flushall(void)
+{
        flushout(&output);
        flushout(&errout);
 }
 
 
 void
-flushout(dest)
-       struct output *dest;
-       {
+flushout(struct output *dest)
+{
 
        if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
                return;
@@ -233,7 +231,8 @@ flushout(dest)
 
 
 void
-freestdout() {
+freestdout(void)
+{
        INTOFF;
        if (output.buf) {
                ckfree(output.buf);
@@ -244,7 +243,6 @@ freestdout() {
 }
 
 
-#ifdef __STDC__
 void
 outfmt(struct output *file, const char *fmt, ...)
 {
@@ -266,8 +264,9 @@ out1fmt(const char *fmt, ...)
        va_end(ap);
 }
 
+#ifdef DEBUG
 void
-dbgprintf(const char *fmt, ...)
+debugprintf(const char *fmt, ...)
 {
        va_list ap;
 
@@ -276,9 +275,10 @@ dbgprintf(const char *fmt, ...)
        va_end(ap);
        flushout(out2);
 }
+#endif
 
 void
-fmtstr(char *outbuf, int length, const char *fmt, ...)
+fmtstr(char *outbuf, size_t length, const char *fmt, ...)
 {
        va_list ap;
        struct output strout;
@@ -295,82 +295,11 @@ fmtstr(char *outbuf, int length, const char *fmt, ...)
        va_end(ap);
 }
 
-#else /* not __STDC__ */
-
-void
-outfmt(va_alist)
-       va_dcl
-       {
-       va_list ap;
-       struct output *file;
-       char *fmt;
-
-       va_start(ap);
-       file = va_arg(ap, struct output *);
-       fmt = va_arg(ap, char *);
-       doformat(file, fmt, ap);
-       va_end(ap);
-}
-
-
-void
-out1fmt(va_alist)
-       va_dcl
-       {
-       va_list ap;
-       char *fmt;
-
-       va_start(ap);
-       fmt = va_arg(ap, char *);
-       doformat(out1, fmt, ap);
-       va_end(ap);
-}
-
-void
-dbgprintf(va_alist)
-       va_dcl
-       {
-       va_list ap;
-       char *fmt;
-
-       va_start(ap);
-       fmt = va_arg(ap, char *);
-       doformat(out2, fmt, ap);
-       va_end(ap);
-       flushout(out2);
-}
-
-void
-fmtstr(va_alist)
-       va_dcl
-       {
-       va_list ap;
-       struct output strout;
-       char *outbuf;
-       int length;
-       char *fmt;
-
-       va_start(ap);
-       outbuf = va_arg(ap, char *);
-       length = va_arg(ap, int);
-       fmt = va_arg(ap, char *);
-       strout.nextc = outbuf;
-       strout.nleft = length;
-       strout.fd = BLOCK_OUT;
-       strout.flags = 0;
-       doformat(&strout, fmt, ap);
-       outc('\0', &strout);
-       if (strout.flags & OUTPUT_ERR)
-               outbuf[length - 1] = '\0';
-}
-#endif /* __STDC__ */
-
-
 /*
  * Formatted output.  This routine handles a subset of the printf formats:
- * - Formats supported: d, u, o, X, s, and c.
+ * - Formats supported: d, u, o, p, X, s, and c.
  * - The x format is also accepted but is treated like X.
- * - The l modifier is accepted.
+ * - The l, ll and q modifiers are accepted.
  * - The - and # flags are accepted; # only works with the o format.
  * - Width and precision may be specified with any format except c.
  * - An * may be given for the width or precision.
@@ -381,27 +310,40 @@ fmtstr(va_alist)
 
 #define TEMPSIZE 24
 
-#ifdef __STDC__
-static const char digit[16] = "0123456789ABCDEF";
-#else
-static const char digit[17] = "0123456789ABCDEF";
+#ifdef BSD4_4
+#define HAVE_VASPRINTF 1
 #endif
 
-
 void
 doformat(struct output *dest, const char *f, va_list ap)
 {
-       register char c;
+#if    HAVE_VASPRINTF
+       char *s;
+
+       vasprintf(&s, f, ap);
+       if (s == NULL)
+               error("Could not allocate formatted output buffer");
+       outstr(s, dest);
+       free(s);     
+#else  /* !HAVE_VASPRINTF */
+       static const char digit[] = "0123456789ABCDEF";
+       char c;
        char temp[TEMPSIZE];
        int flushleft;
        int sharp;
        int width;
        int prec;
        int islong;
+       int isquad;
        char *p;
        int sign;
+#ifdef BSD4_4
+       quad_t l;
+       u_quad_t num;
+#else
        long l;
-       unsigned long num;
+       u_long num;
+#endif
        unsigned base;
        int len;
        int size;
@@ -417,6 +359,7 @@ doformat(struct output *dest, const char *f, va_list ap)
                width = 0;
                prec = -1;
                islong = 0;
+               isquad = 0;
                for (;;) {
                        if (*f == '-')
                                flushleft++;
@@ -446,11 +389,23 @@ doformat(struct output *dest, const char *f, va_list ap)
                        }
                }
                if (*f == 'l') {
-                       islong++;
+                       f++;
+                       if (*f == 'l') {
+                               isquad++;
+                               f++;
+                       } else
+                               islong++;
+               } else if (*f == 'q') {
+                       isquad++;
                        f++;
                }
                switch (*f) {
                case 'd':
+#ifdef BSD4_4
+                       if (isquad)
+                               l = va_arg(ap, quad_t);
+                       else
+#endif
                        if (islong)
                                l = va_arg(ap, long);
                        else
@@ -469,12 +424,21 @@ doformat(struct output *dest, const char *f, va_list ap)
                case 'o':
                        base = 8;
                        goto uns_number;
+               case 'p':
+                       outc('0', dest);
+                       outc('x', dest);
+                       /*FALLTHROUGH*/
                case 'x':
                        /* we don't implement 'x'; treat like 'X' */
                case 'X':
                        base = 16;
 uns_number:      /* an unsigned number */
                        sign = 0;
+#ifdef BSD4_4
+                       if (isquad)
+                               num = va_arg(ap, u_quad_t);
+                       else
+#endif
                        if (islong)
                                num = va_arg(ap, unsigned long);
                        else
@@ -542,6 +506,7 @@ number:               /* process a number */
                }
                f++;
        }
+#endif /* !HAVE_VASPRINTF */
 }
 
 
@@ -551,11 +516,8 @@ number:              /* process a number */
  */
 
 int
-xwrite(fd, buf, nbytes)
-       int fd;
-       char *buf;
-       int nbytes;
-       {
+xwrite(int fd, char *buf, int nbytes)
+{
        int ntry;
        int i;
        int n;
@@ -578,6 +540,17 @@ xwrite(fd, buf, nbytes)
        }
 }
 
+
 /*
- * $PchId: output.c,v 1.6 2006/05/22 12:46:03 philip Exp $
+ * Version of ioctl that retries after a signal is caught.
+ * XXX unused function
  */
+
+int
+xioctl(int fd, unsigned long request, char *arg)
+{
+       int i;
+
+       while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
+       return i;
+}
similarity index 82%
rename from minix/commands/ash/output.h
rename to bin/sh/output.h
index 59c36b3a578498fc56c4ec2d5972789ff82d6271..618a09533046c2a944786e74c2251e734e66ef85 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: output.h,v 1.24 2012/03/15 02:02:20 joerg Exp $        */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -30,7 +32,6 @@
  * SUCH DAMAGE.
  *
  *     @(#)output.h    8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/output.h,v 1.13 2004/04/06 20:06:51 markm Exp $
  */
 
 #ifndef OUTPUT_INCL
@@ -46,41 +47,38 @@ struct output {
        short flags;
 };
 
+/* flags for ->flags */
+#define OUTPUT_ERR 01          /* error occurred on output */
+
 extern struct output output;
 extern struct output errout;
 extern struct output memout;
 extern struct output *out1;
 extern struct output *out2;
 
-#ifndef __printflike
-#define __printflike(a,b)
-#endif
-
 void open_mem(char *, int, struct output *);
 void out1str(const char *);
-void out1qstr(const char *);
 void out2str(const char *);
-void out2qstr(const char *);
 void outstr(const char *, struct output *);
-void outqstr(const char *, struct output *);
+void out2shstr(const char *);
+void outshstr(const char *, struct output *);
 void emptyoutbuf(struct output *);
 void flushall(void);
 void flushout(struct output *);
 void freestdout(void);
 void outfmt(struct output *, const char *, ...) __printflike(2, 3);
 void out1fmt(const char *, ...) __printflike(1, 2);
-void dbgprintf(const char *, ...) __printflike(1, 2);
-void fmtstr(char *, int, const char *, ...) __printflike(3, 4);
+#ifdef DEBUG
+void debugprintf(const char *, ...) __printflike(1, 2);
+#endif
+void fmtstr(char *, size_t, const char *, ...) __printflike(3, 4);
 void doformat(struct output *, const char *, va_list) __printflike(2, 0);
 int xwrite(int, char *, int);
+int xioctl(int, unsigned long, char *);
 
 #define outc(c, file)  (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
-#define out1c(c)       outc(c, out1);
-#define out2c(c)       outc(c, out2);
+#define out1c(c)       outc(c, out1)
+#define out2c(c)       outc(c, out2)
 
 #define OUTPUT_INCL
 #endif
-
-/*
- * $PchId: output.h,v 1.5 2006/05/23 12:04:54 philip Exp $
- */
similarity index 77%
rename from minix/commands/ash/parser.c
rename to bin/sh/parser.c
index e06521400d24027e7014494a5d36166422461abf..2304e9304bc14d16a30a8fcee3d8cb3a23d89fdf 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: parser.c,v 1.85 2013/10/02 21:48:55 christos Exp $     */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)parser.c   8.7 (Berkeley) 5/16/95";
+#else
+__RCSID("$NetBSD: parser.c,v 1.85 2013/10/02 21:48:55 christos Exp $");
 #endif
 #endif /* not lint */
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/parser.c,v 1.51.2.1 2005/03/03 03:43:20 obrien Exp $");
-*/
 
+#include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
+#include <limits.h>
 
 #include "shell.h"
 #include "parser.h"
 #include "nodes.h"
 #include "expand.h"    /* defines rmescapes() */
+#include "eval.h"      /* defines commandname */
+#include "redir.h"     /* defines copyfd() */
 #include "syntax.h"
 #include "options.h"
 #include "input.h"
@@ -57,8 +61,7 @@ __FBSDID("$FreeBSD: src/bin/sh/parser.c,v 1.51.2.1 2005/03/03 03:43:20 obrien Ex
 #include "mystring.h"
 #include "alias.h"
 #include "show.h"
-#include "eval.h"
-#if !defined(NO_HISTORY)
+#ifndef SMALL
 #include "myhistedit.h"
 #endif
 
@@ -66,12 +69,13 @@ __FBSDID("$FreeBSD: src/bin/sh/parser.c,v 1.51.2.1 2005/03/03 03:43:20 obrien Ex
  * Shell command parser.
  */
 
-#define        EOFMARKLEN      79
-#define        PROMPTLEN       128
+#define EOFMARKLEN 79
 
 /* values returned by readtoken */
 #include "token.h"
 
+#define OPENBRACE '{'
+#define CLOSEBRACE '}'
 
 
 struct heredoc {
@@ -83,31 +87,24 @@ struct heredoc {
 
 
 
-STATIC struct heredoc *heredoclist;    /* list of here documents to read */
-STATIC int parsebackquote;     /* nonzero if we are inside backquotes */
-STATIC int doprompt;           /* if set, prompt the user */
-STATIC int needprompt;         /* true if interactive and at start of line */
-STATIC int lasttoken;          /* last token read */
+static int noalias = 0;                /* when set, don't handle aliases */
+struct heredoc *heredoclist;   /* list of here documents to read */
+int parsebackquote;            /* nonzero if we are inside backquotes */
+int doprompt;                  /* if set, prompt the user */
+int needprompt;                        /* true if interactive and at start of line */
+int lasttoken;                 /* last token read */
 MKINIT int tokpushback;                /* last token pushed back */
-STATIC char *wordtext;         /* text of last word returned by readtoken */
-MKINIT int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
-STATIC struct nodelist *backquotelist;
-STATIC union node *redirnode;
-STATIC struct heredoc *heredoc;
-STATIC int quoteflag;          /* set if (part of) last token was quoted */
-STATIC int startlinno;         /* line # where last token started */
-
-/* XXX When 'noaliases' is set to one, no alias expansion takes place. */
-static int noaliases = 0;
-
-#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
-#ifdef GDB_HACK
-static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
-static const char types[] = "}-+?=";
-#endif
+char *wordtext;                        /* text of last word returned by readtoken */
+MKINIT int checkkwd;           /* 1 == check for kwds, 2 == also eat newlines */
+struct nodelist *backquotelist;
+union node *redirnode;
+struct heredoc *heredoc;
+int quoteflag;                 /* set if (part of) last token was quoted */
+int startlinno;                        /* line # where last token started */
+int funclinno;                 /* line # where the current function started */
 
 
-STATIC union node *list(int);
+STATIC union node *list(int, int);
 STATIC union node *andor(void);
 STATIC union node *pipeline(void);
 STATIC union node *command(void);
@@ -120,8 +117,8 @@ STATIC int readtoken(void);
 STATIC int xxreadtoken(void);
 STATIC int readtoken1(int, char const *, char *, int);
 STATIC int noexpand(char *);
-STATIC void synexpect(int);
-STATIC void synerror(char *);
+STATIC void synexpect(int) __dead;
+STATIC void synerror(const char *) __dead;
 STATIC void setprompt(int);
 
 
@@ -134,13 +131,11 @@ union node *
 parsecmd(int interact)
 {
        int t;
-       extern int exitstatus;
 
        tokpushback = 0;
        doprompt = interact;
        if (doprompt)
-               setprompt(exitstatus == 0 || (vpse.flags & VUNSET)
-                                       ? 1 : -1);
+               setprompt(1);
        else
                setprompt(0);
        needprompt = 0;
@@ -150,15 +145,16 @@ parsecmd(int interact)
        if (t == TNL)
                return NULL;
        tokpushback++;
-       return list(1);
+       return list(1, 0);
 }
 
 
 STATIC union node *
-list(int nlflag)
+list(int nlflag, int erflag)
 {
        union node *n1, *n2, *n3;
        int tok;
+       TRACE(("list: entered\n"));
 
        checkkwd = 2;
        if (nlflag == 0 && tokendlist[peektoken()])
@@ -194,7 +190,7 @@ list(int nlflag)
                case TBACKGND:
                case TSEMI:
                        tok = readtoken();
-                       /* FALLTHROUGH */
+                       /* fall through */
                case TNL:
                        if (tok == TNL) {
                                parseheredoc();
@@ -214,7 +210,7 @@ list(int nlflag)
                                pungetc();              /* push back EOF on input */
                        return n1;
                default:
-                       if (nlflag)
+                       if (nlflag || erflag)
                                synexpect(-1);
                        tokpushback++;
                        return n1;
@@ -230,6 +226,7 @@ andor(void)
        union node *n1, *n2, *n3;
        int t;
 
+       TRACE(("andor: entered\n"));
        n1 = pipeline();
        for (;;) {
                if ((t = readtoken()) == TAND) {
@@ -258,10 +255,14 @@ pipeline(void)
        struct nodelist *lp, *prev;
        int negate;
 
-       negate = 0;
        TRACE(("pipeline: entered\n"));
-       while (readtoken() == TNOT)
+
+       negate = 0;
+       checkkwd = 2;
+       while (readtoken() == TNOT) {
+               TRACE(("pipeline: TNOT recognized\n"));
                negate = !negate;
+       }
        tokpushback++;
        n1 = command();
        if (readtoken() == TPIPE) {
@@ -282,6 +283,7 @@ pipeline(void)
        }
        tokpushback++;
        if (negate) {
+               TRACE(("negate pipeline\n"));
                n2 = (union node *)stalloc(sizeof (struct nnot));
                n2->type = NNOT;
                n2->nnot.com = n1;
@@ -301,6 +303,8 @@ command(void)
        union node *redir, **rpp;
        int t, negate = 0;
 
+       TRACE(("command: entered\n"));
+
        checkkwd = 2;
        redir = NULL;
        n1 = NULL;
@@ -324,24 +328,22 @@ command(void)
        case TIF:
                n1 = (union node *)stalloc(sizeof (struct nif));
                n1->type = NIF;
-               if ((n1->nif.test = list(0)) == NULL)
-                       synexpect(-1);
+               n1->nif.test = list(0, 0);
                if (readtoken() != TTHEN)
                        synexpect(TTHEN);
-               n1->nif.ifpart = list(0);
+               n1->nif.ifpart = list(0, 0);
                n2 = n1;
                while (readtoken() == TELIF) {
                        n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
                        n2 = n2->nif.elsepart;
                        n2->type = NIF;
-                       if ((n2->nif.test = list(0)) == NULL)
-                               synexpect(-1);
+                       n2->nif.test = list(0, 0);
                        if (readtoken() != TTHEN)
                                synexpect(TTHEN);
-                       n2->nif.ifpart = list(0);
+                       n2->nif.ifpart = list(0, 0);
                }
                if (lasttoken == TELSE)
-                       n2->nif.elsepart = list(0);
+                       n2->nif.elsepart = list(0, 0);
                else {
                        n2->nif.elsepart = NULL;
                        tokpushback++;
@@ -355,13 +357,12 @@ command(void)
                int got;
                n1 = (union node *)stalloc(sizeof (struct nbinary));
                n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
-               if ((n1->nbinary.ch1 = list(0)) == NULL)
-                       synexpect(-1);
+               n1->nbinary.ch1 = list(0, 0);
                if ((got=readtoken()) != TDO) {
 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                        synexpect(TDO);
                }
-               n1->nbinary.ch2 = list(0);
+               n1->nbinary.ch2 = list(0, 0);
                if (readtoken() != TDONE)
                        synexpect(TDONE);
                checkkwd = 1;
@@ -388,13 +389,11 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                        if (lasttoken != TNL && lasttoken != TSEMI)
                                synexpect(-1);
                } else {
-#ifndef GDB_HACK
-                       static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
+                       static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
                                                                   '@', '=', '\0'};
-#endif
                        n2 = (union node *)stalloc(sizeof (struct narg));
                        n2->type = NARG;
-                       n2->narg.text = (char *)argvars;
+                       n2->narg.text = argvars;
                        n2->narg.backquote = NULL;
                        n2->narg.next = NULL;
                        n1->nfor.args = n2;
@@ -412,7 +411,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                        t = TEND;
                else
                        synexpect(-1);
-               n1->nfor.body = list(0);
+               n1->nfor.body = list(0, 0);
                if (readtoken() != t)
                        synexpect(t);
                checkkwd = 1;
@@ -431,14 +430,14 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                if (lasttoken != TWORD || ! equal(wordtext, "in"))
                        synerror("expecting \"in\"");
                cpp = &n1->ncase.cases;
-               noaliases = 1;  /* turn off alias expansion */
+               noalias = 1;
                checkkwd = 2, readtoken();
-               while (lasttoken != TESAC) {
+               do {
                        *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
-                       cp->type = NCLIST;
-                       app = &cp->nclist.pattern;
                        if (lasttoken == TLP)
                                readtoken();
+                       cp->type = NCLIST;
+                       app = &cp->nclist.pattern;
                        for (;;) {
                                *app = ap = (union node *)stalloc(sizeof (struct narg));
                                ap->type = NARG;
@@ -450,48 +449,54 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                                readtoken();
                        }
                        ap->narg.next = NULL;
-                       if (lasttoken != TRP)
-                               noaliases = 0, synexpect(TRP);
-                       cp->nclist.body = list(0);
+                       noalias = 0;
+                       if (lasttoken != TRP) {
+                               synexpect(TRP);
+                       }
+                       cp->nclist.body = list(0, 0);
 
                        checkkwd = 2;
                        if ((t = readtoken()) != TESAC) {
-                               if (t != TENDCASE)
-                                       noaliases = 0, synexpect(TENDCASE);
-                               else
-                                       checkkwd = 2, readtoken();
+                               if (t != TENDCASE) {
+                                       noalias = 0;
+                                       synexpect(TENDCASE);
+                               } else {
+                                       noalias = 1;
+                                       checkkwd = 2;
+                                       readtoken();
+                               }
                        }
                        cpp = &cp->nclist.next;
-               }
-               noaliases = 0;  /* reset alias expansion */
+               } while(lasttoken != TESAC);
+               noalias = 0;
                *cpp = NULL;
                checkkwd = 1;
                break;
        case TLP:
                n1 = (union node *)stalloc(sizeof (struct nredir));
                n1->type = NSUBSHELL;
-               n1->nredir.n = list(0);
+               n1->nredir.n = list(0, 0);
                n1->nredir.redirect = NULL;
                if (readtoken() != TRP)
                        synexpect(TRP);
                checkkwd = 1;
                break;
        case TBEGIN:
-               n1 = list(0);
+               n1 = list(0, 0);
                if (readtoken() != TEND)
                        synexpect(TEND);
                checkkwd = 1;
                break;
        /* Handle an empty command like other simple commands.  */
        case TSEMI:
-       case TAND:
-       case TOR:
                /*
                 * An empty command before a ; doesn't make much sense, and
                 * should certainly be disallowed in the case of `if ;'.
                 */
                if (!redir)
                        synexpect(-1);
+       case TAND:
+       case TOR:
        case TNL:
        case TEOF:
        case TWORD:
@@ -501,6 +506,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
                goto checkneg;
        default:
                synexpect(-1);
+               /* NOTREACHED */
        }
 
        /* Now check for redirection which may follow command */
@@ -523,6 +529,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
 
 checkneg:
        if (negate) {
+               TRACE(("negate command\n"));
                n2 = (union node *)stalloc(sizeof (struct nnot));
                n2->type = NNOT;
                n2->nnot.com = n1;
@@ -556,7 +563,7 @@ simplecmd(union node **rpp, union node *redir)
        orig_rpp = rpp;
 
        while (readtoken() == TNOT) {
-               TRACE(("command: TNOT recognized\n"));
+               TRACE(("simplcmd: TNOT recognized\n"));
                negate = !negate;
        }
        tokpushback++;
@@ -578,12 +585,13 @@ simplecmd(union node **rpp, union node *redir)
                        /* We have a function */
                        if (readtoken() != TRP)
                                synexpect(TRP);
-#ifdef notdef
-                       if (! goodname(n->narg.text))
+                       funclinno = plinno;
+                       rmescapes(n->narg.text);
+                       if (!goodname(n->narg.text))
                                synerror("Bad function name");
-#endif
                        n->type = NDEFUN;
                        n->narg.next = command();
+                       funclinno = 0;
                        goto checkneg;
                } else {
                        tokpushback++;
@@ -600,6 +608,7 @@ simplecmd(union node **rpp, union node *redir)
 
 checkneg:
        if (negate) {
+               TRACE(("negate simplecmd\n"));
                n2 = (union node *)stalloc(sizeof (struct nnot));
                n2->type = NNOT;
                n2->nnot.com = n;
@@ -623,7 +632,7 @@ makename(void)
 }
 
 void fixredir(union node *n, const char *text, int err)
-{
+       {
        TRACE(("Fix redir %s %d\n", text, err));
        if (!err)
                n->ndup.vname = NULL;
@@ -723,10 +732,10 @@ readtoken(void)
 {
        int t;
        int savecheckkwd = checkkwd;
-       struct alias *ap;
-#if DEBUG
+#ifdef DEBUG
        int alreadyseen = tokpushback;
 #endif
+       struct alias *ap;
 
        top:
        t = xxreadtoken();
@@ -748,17 +757,18 @@ readtoken(void)
                 */
                if (t == TWORD && !quoteflag)
                {
-                       const char * const *pp;
+                       const char *const *pp;
 
                        for (pp = parsekwd; *pp; pp++) {
                                if (**pp == *wordtext && equal(*pp, wordtext))
                                {
-                                       lasttoken = t = pp - parsekwd + KWDOFFSET;
+                                       lasttoken = t = pp - 
+                                           parsekwd + KWDOFFSET;
                                        TRACE(("keyword %s recognized\n", tokname[t]));
                                        goto out;
                                }
                        }
-                       if (noaliases == 0 &&
+                       if(!noalias &&
                            (ap = lookupalias(wordtext, 1)) != NULL) {
                                pushstring(ap->val, strlen(ap->val), ap);
                                checkkwd = savecheckkwd;
@@ -768,12 +778,7 @@ readtoken(void)
 out:
                checkkwd = (t == TNOT) ? savecheckkwd : 0;
        }
-#if DEBUG
-       if (!alreadyseen)
-           TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
-       else
-           TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
-#endif
+       TRACE(("%stoken %s %s\n", alreadyseen ? "reread " : "", tokname[t], t == TWORD ? wordtext : ""));
        return (t);
 }
 
@@ -814,8 +819,6 @@ xxreadtoken(void)
        startlinno = plinno;
        for (;;) {      /* until token or start of word found */
                c = pgetc_macro();
-               if (c == ' ' || c == '\t')
-                       continue;               /* quick check for white space first */
                switch (c) {
                case ' ': case '\t':
                        continue;
@@ -864,7 +867,7 @@ xxreadtoken(void)
                }
        }
 breakloop:
-       return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
+       return readtoken1(c, BASESYNTAX, NULL, 0);
 #undef RETURN
 }
 
@@ -889,55 +892,77 @@ breakloop:
 #define PARSEBACKQNEW()        {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
 #define        PARSEARITH()    {goto parsearith; parsearith_return:;}
 
+/*
+ * Keep track of nested doublequotes in dblquote and doublequotep.
+ * We use dblquote for the first 32 levels, and we expand to a malloc'ed
+ * region for levels above that. Usually we never need to malloc.
+ * This code assumes that an int is 32 bits. We don't use uint32_t,
+ * because the rest of the code does not.
+ */
+#define ISDBLQUOTE() ((varnest < 32) ? (dblquote & (1 << varnest)) : \
+    (dblquotep[(varnest / 32) - 1] & (1 << (varnest % 32))))
+
+#define SETDBLQUOTE() \
+    if (varnest < 32) \
+       dblquote |= (1 << varnest); \
+    else \
+       dblquotep[(varnest / 32) - 1] |= (1 << (varnest % 32))
+
+#define CLRDBLQUOTE() \
+    if (varnest < 32) \
+       dblquote &= ~(1 << varnest); \
+    else \
+       dblquotep[(varnest / 32) - 1] &= ~(1 << (varnest % 32))
+
 STATIC int
-readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
+readtoken1(int firstc, char const *syn, char *eofmark, int striptabs)
 {
+       char const * volatile syntax = syn;
        int c = firstc;
-       char *out;
+       char * volatile out;
        int len;
        char line[EOFMARKLEN + 1];
        struct nodelist *bqlist;
-       int quotef;
-       int dblquote;
-       int varnest;    /* levels of variables expansion */
-       int arinest;    /* levels of arithmetic expansion */
-       int parenlevel; /* levels of parens in arithmetic */
-       int oldstyle;
-       char const *prevsyntax; /* syntax before arithmetic */
-       int synentry;
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &out;
-       (void) &quotef;
-       (void) &dblquote;
-       (void) &varnest;
-       (void) &arinest;
-       (void) &parenlevel;
-       (void) &oldstyle;
-       (void) &prevsyntax;
-       (void) &syntax;
-       (void) &synentry;
+       volatile int quotef;
+       int * volatile dblquotep = NULL;
+       volatile size_t maxnest = 32;
+       volatile int dblquote;
+       volatile size_t varnest;        /* levels of variables expansion */
+       volatile int arinest;   /* levels of arithmetic expansion */
+       volatile int parenlevel;        /* levels of parens in arithmetic */
+       volatile int oldstyle;
+       char const * volatile prevsyntax;       /* syntax before arithmetic */
+#ifdef __GNUC__
+       prevsyntax = NULL;      /* XXX gcc4 */
 #endif
 
        startlinno = plinno;
        dblquote = 0;
-       if (syntax == DQSYNTAX)
-               dblquote = 1;
+       varnest = 0;
+       if (syntax == DQSYNTAX) {
+               SETDBLQUOTE();
+       }
        quotef = 0;
        bqlist = NULL;
-       varnest = 0;
        arinest = 0;
        parenlevel = 0;
 
        STARTSTACKSTR(out);
        loop: { /* for each line, until end of word */
+#if ATTY
+               if (c == '\034' && doprompt
+                && attyset() && ! equal(termval(), "emacs")) {
+                       attyline();
+                       if (syntax == BASESYNTAX)
+                               return readtoken();
+                       c = pgetc();
+                       goto loop;
+               }
+#endif
                CHECKEND();     /* set c to PEOF if at end of here document */
                for (;;) {      /* until end of line or end of word */
-                       CHECKSTRSPACE(3, out);  /* permit 3 calls to USTPUTC */
-
-                       synentry = syntax[c];
-
-                       switch(synentry) {
+                       CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
+                       switch(syntax[c]) {
                        case CNL:       /* '\n' */
                                if (syntax == BASESYNTAX)
                                        goto endword;   /* exit outer loop */
@@ -953,7 +978,7 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
                                USTPUTC(c, out);
                                break;
                        case CCTL:
-                               if (eofmark == NULL || dblquote)
+                               if (eofmark == NULL || ISDBLQUOTE())
                                        USTPUTC(CTLESC, out);
                                USTPUTC(c, out);
                                break;
@@ -962,55 +987,91 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
                                if (c == PEOF) {
                                        USTPUTC('\\', out);
                                        pungetc();
-                               } else if (c == '\n') {
+                                       break;
+                               }
+                               if (c == '\n') {
                                        if (doprompt)
                                                setprompt(2);
                                        else
                                                setprompt(0);
-                               } else {
-                                       if (dblquote && c != '\\' &&
-                                           c != '`' && c != '$' &&
-                                           (c != '"' || eofmark != NULL))
-                                               USTPUTC('\\', out);
-                                       if (SQSYNTAX[c] == CCTL)
-                                               USTPUTC(CTLESC, out);
-                                       else if (eofmark == NULL)
-                                               USTPUTC(CTLQUOTEMARK, out);
+                                       break;
+                               }
+                               quotef = 1;
+                               if (ISDBLQUOTE() && c != '\\' &&
+                                   c != '`' && c != '$' &&
+                                   (c != '"' || eofmark != NULL))
+                                       USTPUTC('\\', out);
+                               if (SQSYNTAX[c] == CCTL)
+                                       USTPUTC(CTLESC, out);
+                               else if (eofmark == NULL) {
+                                       USTPUTC(CTLQUOTEMARK, out);
                                        USTPUTC(c, out);
-                                       quotef++;
+                                       if (varnest != 0)
+                                               USTPUTC(CTLQUOTEEND, out);
+                                       break;
                                }
+                               USTPUTC(c, out);
                                break;
                        case CSQUOTE:
-                               if (eofmark == NULL)
-                                       USTPUTC(CTLQUOTEMARK, out);
-                               syntax = SQSYNTAX;
+                               if (syntax != SQSYNTAX) {
+                                       if (eofmark == NULL)
+                                               USTPUTC(CTLQUOTEMARK, out);
+                                       quotef = 1;
+                                       syntax = SQSYNTAX;
+                                       break;
+                               }
+                               if (eofmark != NULL && arinest == 0 &&
+                                   varnest == 0) {
+                                       /* Ignore inside quoted here document */
+                                       USTPUTC(c, out);
+                                       break;
+                               }
+                               /* End of single quotes... */
+                               if (arinest)
+                                       syntax = ARISYNTAX;
+                               else {
+                                       syntax = BASESYNTAX;
+                                       if (varnest != 0)
+                                               USTPUTC(CTLQUOTEEND, out);
+                               }
                                break;
                        case CDQUOTE:
-                               if (eofmark == NULL)
-                                       USTPUTC(CTLQUOTEMARK, out);
-                               syntax = DQSYNTAX;
-                               dblquote = 1;
-                               break;
-                       case CENDQUOTE:
                                if (eofmark != NULL && arinest == 0 &&
                                    varnest == 0) {
+                                       /* Ignore inside here document */
                                        USTPUTC(c, out);
-                               } else {
-                                       if (arinest) {
+                                       break;
+                               }
+                               quotef = 1;
+                               if (arinest) {
+                                       if (ISDBLQUOTE()) {
                                                syntax = ARISYNTAX;
-                                               dblquote = 0;
-                                       } else if (eofmark == NULL) {
-                                               syntax = BASESYNTAX;
-                                               dblquote = 0;
+                                               CLRDBLQUOTE();
+                                       } else {
+                                               syntax = DQSYNTAX;
+                                               SETDBLQUOTE();
+                                               USTPUTC(CTLQUOTEMARK, out);
                                        }
-                                       quotef++;
+                                       break;
+                               }
+                               if (eofmark != NULL)
+                                       break;
+                               if (ISDBLQUOTE()) {
+                                       if (varnest != 0)
+                                               USTPUTC(CTLQUOTEEND, out);
+                                       syntax = BASESYNTAX;
+                                       CLRDBLQUOTE();
+                               } else {
+                                       syntax = DQSYNTAX;
+                                       SETDBLQUOTE();
+                                       USTPUTC(CTLQUOTEMARK, out);
                                }
                                break;
                        case CVAR:      /* '$' */
                                PARSESUB();             /* parse substitution */
                                break;
-                       case CENDVAR:   /* '}' */
-                               if (varnest > 0) {
+                       case CENDVAR:   /* CLOSEBRACE */
+                               if (varnest > 0 && !ISDBLQUOTE()) {
                                        varnest--;
                                        USTPUTC(CTLENDVAR, out);
                                } else {
@@ -1031,9 +1092,9 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
                                                        USTPUTC(CTLENDARI, out);
                                                        syntax = prevsyntax;
                                                        if (syntax == DQSYNTAX)
-                                                               dblquote = 1;
+                                                               SETDBLQUOTE();
                                                        else
-                                                               dblquote = 0;
+                                                               CLRDBLQUOTE();
                                                } else
                                                        USTPUTC(')', out);
                                        } else {
@@ -1052,7 +1113,7 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
                        case CEOF:
                                goto endword;           /* exit outer loop */
                        default:
-                               if (varnest == 0)
+                               if (varnest == 0 && !ISDBLQUOTE())
                                        goto endword;   /* exit outer loop */
                                USTPUTC(c, out);
                        }
@@ -1062,10 +1123,11 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
 endword:
        if (syntax == ARISYNTAX)
                synerror("Missing '))'");
-       if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
+       if (syntax != BASESYNTAX && /* ! parsebackquote && */ eofmark == NULL)
                synerror("Unterminated quoted string");
        if (varnest != 0) {
                startlinno = plinno;
+               /* { */
                synerror("Missing '}'");
        }
        USTPUTC('\0', out);
@@ -1086,6 +1148,8 @@ endword:
        backquotelist = bqlist;
        grabstackblock(len);
        wordtext = out;
+       if (dblquotep != NULL)
+           ckfree(dblquotep);
        return lasttoken = TWORD;
 /* end of readtoken routine */
 
@@ -1109,7 +1173,7 @@ checkend: {
 
                                p = line;
                                for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
-                               if (*p == '\n' && *q == '\0') {
+                               if ((*p == '\0' || *p == '\n') && *q == '\0') {
                                        c = PEOF;
                                        plinno++;
                                        needprompt = doprompt;
@@ -1139,18 +1203,18 @@ parseredir: {
                c = pgetc();
                if (c == '>')
                        np->type = NAPPEND;
-               else if (c == '&')
-                       np->type = NTOFD;
                else if (c == '|')
                        np->type = NCLOBBER;
+               else if (c == '&')
+                       np->type = NTOFD;
                else {
                        np->type = NTO;
                        pungetc();
                }
        } else {        /* c == '<' */
                np->nfile.fd = 0;
-               c = pgetc();
-               if (c == '<') {
+               switch (c = pgetc()) {
+               case '<':
                        if (sizeof (struct nfile) != sizeof (struct nhere)) {
                                np = (union node *)stalloc(sizeof (struct nhere));
                                np->nfile.fd = 0;
@@ -1164,13 +1228,20 @@ parseredir: {
                                heredoc->striptabs = 0;
                                pungetc();
                        }
-               } else if (c == '&')
+                       break;
+
+               case '&':
                        np->type = NFROMFD;
-               else if (c == '>')
+                       break;
+
+               case '>':
                        np->type = NFROMTO;
-               else {
+                       break;
+
+               default:
                        np->type = NFROM;
                        pungetc();
+                       break;
                }
        }
        if (fd != '\0')
@@ -1186,17 +1257,17 @@ parseredir: {
  */
 
 parsesub: {
+       char buf[10];
        int subtype;
        int typeloc;
        int flags;
        char *p;
-#ifndef GDB_HACK
        static const char types[] = "}-+?=";
-#endif
-       int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
+       int i;
+       int linno;
 
        c = pgetc();
-       if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
+       if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) {
                USTPUTC('$', out);
                pungetc();
        } else if (c == '(') {  /* $(command) or $((arith)) */
@@ -1211,11 +1282,11 @@ parsesub: {
                typeloc = out - stackblock();
                USTPUTC(VSNORMAL, out);
                subtype = VSNORMAL;
-               if (c == '{') {
-                       bracketed_name = 1;
+               flags = 0;
+               if (c == OPENBRACE) {
                        c = pgetc();
                        if (c == '#') {
-                               if ((c = pgetc()) == '}')
+                               if ((c = pgetc()) == CLOSEBRACE)
                                        c = '#';
                                else
                                        subtype = VSLENGTH;
@@ -1224,32 +1295,41 @@ parsesub: {
                                subtype = 0;
                }
                if (is_name(c)) {
+                       p = out;
                        do {
                                STPUTC(c, out);
                                c = pgetc();
                        } while (is_in_name(c));
+                       if (out - p == 6 && strncmp(p, "LINENO", 6) == 0) {
+                               /* Replace the variable name with the
+                                * current line number. */
+                               linno = plinno;
+                               if (funclinno != 0)
+                                       linno -= funclinno - 1;
+                               snprintf(buf, sizeof(buf), "%d", linno);
+                               STADJUST(-6, out);
+                               for (i = 0; buf[i] != '\0'; i++)
+                                       STPUTC(buf[i], out);
+                               flags |= VSLINENO;
+                       }
                } else if (is_digit(c)) {
-                       if (bracketed_name) {
-                               do {
-                                       STPUTC(c, out);
-                                       c = pgetc();
-                               } while (is_digit(c));
-                       } else {
-                               STPUTC(c, out);
+                       do {
+                               USTPUTC(c, out);
                                c = pgetc();
-                       }
-               } else {
-                       if (! is_special(c))
-badsub:                                synerror("Bad substitution");
+                       } while (is_digit(c));
+               }
+               else if (is_special(c)) {
                        USTPUTC(c, out);
                        c = pgetc();
                }
+               else
+badsub:                        synerror("Bad substitution");
+
                STPUTC('=', out);
-               flags = 0;
                if (subtype == 0) {
                        switch (c) {
                        case ':':
-                               flags = VSNUL;
+                               flags |= VSNUL;
                                c = pgetc();
                                /*FALLTHROUGH*/
                        default:
@@ -1275,11 +1355,17 @@ badsub:                         synerror("Bad substitution");
                } else {
                        pungetc();
                }
-               if (subtype != VSLENGTH && (dblquote || arinest))
+               if (ISDBLQUOTE() || arinest)
                        flags |= VSQUOTE;
                *(stackblock() + typeloc) = subtype | flags;
-               if (subtype != VSNORMAL)
+               if (subtype != VSNORMAL) {
                        varnest++;
+                       if (varnest >= maxnest) {
+                               dblquotep = ckrealloc(dblquotep, maxnest / 8);
+                               dblquotep[(maxnest / 32) - 1] = 0;
+                               maxnest += 32;
+                       }
+               }
        }
        goto parsesub_return;
 }
@@ -1296,15 +1382,11 @@ parsebackq: {
        struct nodelist **nlpp;
        int savepbq;
        union node *n;
-       char *volatile str;
+       char *volatile str = NULL;
        struct jmploc jmploc;
-       struct jmploc *volatile savehandler;
+       struct jmploc *volatile savehandler = NULL;
        int savelen;
        int saveprompt;
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &saveprompt;
-#endif
 
        savepbq = parsebackquote;
        if (setjmp(jmploc.loc)) {
@@ -1328,24 +1410,24 @@ parsebackq: {
                 /* We must read until the closing backquote, giving special
                    treatment to some slashes, and then push the string and
                    reread it as input, interpreting it normally.  */
-                char *out;
-                int c;
-                int savelen;
-                char *str;
+                char *pout;
+                int pc;
+                int psavelen;
+                char *pstr;
 
 
-                STARTSTACKSTR(out);
+                STARTSTACKSTR(pout);
                for (;;) {
                        if (needprompt) {
                                setprompt(2);
                                needprompt = 0;
                        }
-                       switch (c = pgetc()) {
+                       switch (pc = pgetc()) {
                        case '`':
                                goto done;
 
                        case '\\':
-                                if ((c = pgetc()) == '\n') {
+                                if ((pc = pgetc()) == '\n') {
                                        plinno++;
                                        if (doprompt)
                                                setprompt(2);
@@ -1359,9 +1441,9 @@ parsebackq: {
                                         */
                                        continue;
                                }
-                                if (c != '\\' && c != '`' && c != '$'
-                                    && (!dblquote || c != '"'))
-                                        STPUTC('\\', out);
+                                if (pc != '\\' && pc != '`' && pc != '$'
+                                    && (!ISDBLQUOTE() || pc != '"'))
+                                        STPUTC('\\', pout);
                                break;
 
                        case '\n':
@@ -1377,15 +1459,14 @@ parsebackq: {
                        default:
                                break;
                        }
-                       STPUTC(c, out);
+                       STPUTC(pc, pout);
                 }
 done:
-                STPUTC('\0', out);
-                savelen = out - stackblock();
-                if (savelen > 0) {
-                        str = ckmalloc(savelen);
-                        memcpy(str, stackblock(), savelen);
-                       setinputstring(str, 1);
+                STPUTC('\0', pout);
+                psavelen = pout - stackblock();
+                if (psavelen > 0) {
+                       pstr = grabstackstr(pout);
+                       setinputstring(pstr, 1);
                 }
         }
        nlpp = &bqlist;
@@ -1398,9 +1479,10 @@ done:
        if (oldstyle) {
                saveprompt = doprompt;
                doprompt = 0;
-       }
+       } else
+               saveprompt = 0;
 
-       n = list(0);
+       n = list(0, oldstyle);
 
        if (oldstyle)
                doprompt = saveprompt;
@@ -1431,7 +1513,7 @@ done:
        }
        parsebackquote = savepbq;
        handler = savehandler;
-       if (arinest || dblquote)
+       if (arinest || ISDBLQUOTE())
                USTPUTC(CTLBACKQ | CTLQUOTE, out);
        else
                USTPUTC(CTLBACKQ, out);
@@ -1450,7 +1532,7 @@ parsearith: {
                prevsyntax = syntax;
                syntax = ARISYNTAX;
                USTPUTC(CTLARI, out);
-               if (dblquote)
+               if (ISDBLQUOTE())
                        USTPUTC('"',out);
                else
                        USTPUTC(' ',out);
@@ -1488,7 +1570,7 @@ noexpand(char *text)
 
        p = text;
        while ((c = *p++) != '\0') {
-               if ( c == CTLQUOTEMARK)
+               if (c == CTLQUOTEMARK)
                        continue;
                if (c == CTLESC)
                        p++;
@@ -1506,7 +1588,7 @@ noexpand(char *text)
 
 int
 goodname(char *name)
-{
+       {
        char *p;
 
        p = name;
@@ -1538,16 +1620,20 @@ synexpect(int token)
                fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
        }
        synerror(msg);
+       /* NOTREACHED */
 }
 
 
 STATIC void
-synerror(char *msg)
+synerror(const char *msg)
 {
        if (commandname)
                outfmt(&errout, "%s: %d: ", commandname, startlinno);
+       else
+               outfmt(&errout, "%s: ", getprogname());
        outfmt(&errout, "Syntax error: %s\n", msg);
-       error((char *)NULL);
+       error(NULL);
+       /* NOTREACHED */
 }
 
 STATIC void
@@ -1555,9 +1641,9 @@ setprompt(int which)
 {
        whichprompt = which;
 
-#ifndef NO_HISTORY
+#ifndef SMALL
        if (!el)
-#endif /* !NO_HISTORY */
+#endif
                out2str(getprompt(NULL));
 }
 
@@ -1565,110 +1651,17 @@ setprompt(int which)
  * called by editline -- any expansions to the prompt
  *    should be added here.
  */
-char *
-getprompt(void *unused __unused)
-{
-       static char ps[PROMPTLEN];
-       char *fmt;
-       int i, j, trim;
-
-       /*
-        * Select prompt format.
-        */
+const char *
+getprompt(void *unused)
+       {
        switch (whichprompt) {
-       case -1:
-               fmt = pseval();
-               break;
        case 0:
-               fmt = "";
-               break;
+               return "";
        case 1:
-               fmt = ps1val();
-               break;
+               return ps1val();
        case 2:
-               fmt = ps2val();
-               break;
+               return ps2val();
        default:
                return "<internal prompt error>";
        }
-
-       /*
-        * Format prompt string.
-        */
-       for (i = 0; (i < 127) && (*fmt != '\0'); i++, fmt++)
-               if (*fmt == '\\')
-                       switch (*++fmt) {
-
-                               /*
-                                * Hostname.
-                                *
-                                * \h specifies just the local hostname,
-                                * \H specifies fully-qualified hostname.
-                                */
-                       case 'h':
-                       case 'H':
-                               ps[i] == '\0';
-                               gethostname(&ps[i], PROMPTLEN - i);
-                               /* Skip to end of hostname. */
-                               trim = (*fmt == 'h') ? '.' : '\0';
-                               while ((ps[i+1] != '\0') && (ps[i+1] != trim))
-                                       i++;
-                               break;
-
-                               /*
-                                * Working directory.
-                                *
-                                * \W specifies just the final component,
-                                * \w specifies the entire path.
-                                */
-                       case 'W':
-                       case 'w':
-                               ps[i] == '\0';
-                               getcwd(&ps[i], PROMPTLEN - i);
-                               if (*fmt == 'W') {
-                                       /* Final path component only. */
-                                       trim = 1;
-                                       for (j = i; ps[j] != '\0'; j++)
-                                         if (ps[j] == '/')
-                                               trim = j + 1;
-                                       memmove(&ps[i], &ps[trim],
-                                           j - trim + 1);
-                               }
-                               /* Skip to end of path. */
-                               while (ps[i + 1] != '\0')
-                                       i++;
-                               break;
-
-                               /*
-                                * Superuser status.
-                                *
-                                * '$' for normal users, '#' for root.
-                                */
-                       case '$':
-                               ps[i] = (geteuid() != 0) ? '$' : '#';
-                               break;
-
-                               /*
-                                * A literal \.
-                                */
-                       case '\\':
-                               ps[i] = '\\';
-                               break;
-
-                               /*
-                                * Emit unrecognized formats verbatim.
-                                */
-                       default:
-                               ps[i++] = '\\';
-                               ps[i] = *fmt;
-                               break;
-                       }
-               else
-                       ps[i] = *fmt;
-       ps[i] = '\0';
-       return (ps);
 }
-
-/*
- * $PchId: parser.c,v 1.6 2006/05/29 13:08:11 philip Exp $
- */
similarity index 78%
rename from minix/commands/ash/parser.h
rename to bin/sh/parser.h
index 522902a4b0884695f68ea4bb25572b782fd82feb..cc4910f84f9db3140e0df99adf9d467ace963cbe 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: parser.h,v 1.18 2013/10/02 19:52:58 christos Exp $     */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)parser.h    8.3 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/parser.h,v 1.10 2004/04/06 20:06:51 markm Exp $
  */
 
 /* control characters in argument strings */
-#define CTLESC '\201'
-#define CTLVAR '\202'
+#define CTL_FIRST '\201'       /* first 'special' character */
+#define CTLESC '\201'          /* escape next character */
+#define CTLVAR '\202'          /* variable defn */
 #define CTLENDVAR '\203'
 #define CTLBACKQ '\204'
 #define CTLQUOTE 01            /* ored with CTLBACKQ code if in quotes */
 /*     CTLBACKQ | CTLQUOTE == '\205' */
-#define        CTLARI  '\206'
+#define        CTLARI  '\206'          /* arithmetic expression */
 #define        CTLENDARI '\207'
 #define        CTLQUOTEMARK '\210'
+#define        CTLQUOTEEND '\211'      /* only inside ${...} */
+#define        CTL_LAST '\211'         /* last 'special' character */
 
 /* variable substitution byte (follows CTLVAR) */
-#define VSTYPE 0x0f            /* type of variable substitution */
-#define VSNUL  0x10            /* colon--treat the empty string as unset */
-#define VSQUOTE 0x80           /* inside double quotes--suppress splitting */
+#define VSTYPE         0x0f    /* type of variable substitution */
+#define VSNUL          0x10    /* colon--treat the empty string as unset */
+#define VSLINENO       0x20    /* expansion of $LINENO, the line number
+                                  follows immediately */
+#define VSQUOTE                0x80    /* inside double quotes--suppress splitting */
 
 /* values of VSTYPE field */
 #define VSNORMAL       0x1             /* normal variable:  $var or ${var} */
@@ -75,8 +81,4 @@ extern int whichprompt;               /* 1 == PS1, 2 == PS2 */
 union node *parsecmd(int);
 void fixredir(union node *, const char *, int);
 int goodname(char *);
-char *getprompt(void *);
-
-/*
- * $PchId: parser.h,v 1.3 2006/03/29 14:33:35 philip Exp $
- */
+const char *getprompt(void *);
similarity index 71%
rename from minix/commands/ash/redir.c
rename to bin/sh/redir.c
index 9fa35de48e6a4b4c4d7329711601b67ef1ba6b09..a2ab3798360a659bb916ec07174c7b4eff61b7a5 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: redir.c,v 1.35 2013/06/27 23:22:04 yamt Exp $  */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)redir.c    8.2 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: redir.c,v 1.35 2013/06/27 23:22:04 yamt Exp $");
 #endif
 #endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/redir.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
-*/
 
 #include <sys/types.h>
-#include <sys/stat.h>
+#include <sys/param.h> /* PIPE_BUF */
 #include <signal.h>
 #include <string.h>
 #include <fcntl.h>
@@ -53,25 +54,31 @@ __FBSDID("$FreeBSD: src/bin/sh/redir.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
  * Code for dealing with input/output redirection.
  */
 
+#include "main.h"
 #include "shell.h"
 #include "nodes.h"
 #include "jobs.h"
+#include "options.h"
 #include "expand.h"
 #include "redir.h"
 #include "output.h"
 #include "memalloc.h"
 #include "error.h"
-#include "options.h"
 
 
 #define EMPTY -2               /* marks an unused slot in redirtab */
-#define PIPESIZE 4096          /* amount of buffering in a pipe */
+#define        CLOSED -1               /* fd was not open before redir */
+#ifndef PIPE_BUF
+# define PIPESIZE 4096         /* amount of buffering in a pipe */
+#else
+# define PIPESIZE PIPE_BUF
+#endif
 
 
 MKINIT
 struct redirtab {
        struct redirtab *next;
-       int renamed[10];
+       short renamed[10];
 };
 
 
@@ -82,10 +89,10 @@ MKINIT struct redirtab *redirlist;
  * background commands, where we want to redirect fd0 to /dev/null only
  * if it hasn't already been redirected.
 */
-STATIC int fd0_redirected = 0;
+int fd0_redirected = 0;
 
-STATIC void openredirect(union node *, char[10 ]);
-STATIC int openhere(union node *);
+STATIC void openredirect(union node *, char[10], int);
+STATIC int openhere(const union node *);
 
 
 /*
@@ -103,13 +110,15 @@ redirect(union node *redir, int flags)
        struct redirtab *sv = NULL;
        int i;
        int fd;
-       int try;
        char memory[10];        /* file descriptors to write to memory */
 
        for (i = 10 ; --i >= 0 ; )
                memory[i] = 0;
        memory[1] = flags & REDIR_BACKQ;
        if (flags & REDIR_PUSH) {
+               /* We don't have to worry about REDIR_VFORK here, as
+                * flags & REDIR_PUSH is never true if REDIR_VFORK is set.
+                */
                sv = ckmalloc(sizeof (struct redirtab));
                for (i = 0 ; i < 10 ; i++)
                        sv->renamed[i] = EMPTY;
@@ -118,38 +127,32 @@ redirect(union node *redir, int flags)
        }
        for (n = redir ; n ; n = n->nfile.next) {
                fd = n->nfile.fd;
-               try = 0;
                if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
                    n->ndup.dupfd == fd)
                        continue; /* redirect from/to same file descriptor */
 
                if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
                        INTOFF;
-again:
                        if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
                                switch (errno) {
                                case EBADF:
-                                       if (!try) {
-                                               openredirect(n, memory);
-                                               try++;
-                                               goto again;
-                                       }
-                                       /* FALLTHROUGH*/
+                                       i = CLOSED;
+                                       break;
                                default:
                                        INTON;
                                        error("%d: %s", fd, strerror(errno));
-                                       break;
+                                       /* NOTREACHED */
                                }
-                       }
-                       if (!try) {
-                               sv->renamed[fd] = i;
-                       }
+                       } else
+                               (void)fcntl(i, F_SETFD, FD_CLOEXEC);
+                       sv->renamed[fd] = i;
                        INTON;
+               } else {
+                       close(fd);
                }
-               if (fd == 0)
-                       fd0_redirected++;
-               if (!try)
-                       openredirect(n, memory);
+                if (fd == 0)
+                        fd0_redirected++;
+               openredirect(n, memory, flags);
        }
        if (memory[1])
                out1 = &memout;
@@ -159,15 +162,12 @@ again:
 
 
 STATIC void
-openredirect(union node *redir, char memory[10])
+openredirect(union node *redir, char memory[10], int flags)
 {
-       struct stat sb;
        int fd = redir->nfile.fd;
        char *fname;
        int f;
-
-       /* Assume redirection succeeds. */
-       { extern int exitstatus; exitstatus = 0; }
+       int oflags = O_WRONLY|O_CREAT|O_TRUNC, eflags;
 
        /*
         * We suppress interrupts so that we won't leave open file
@@ -179,56 +179,64 @@ openredirect(union node *redir, char memory[10])
        switch (redir->nfile.type) {
        case NFROM:
                fname = redir->nfile.expfname;
-               if ((f = open(fname, O_RDONLY)) < 0)
-                       error("cannot open %s: %s", fname, strerror(errno));
-movefd:
-               if (f != fd) {
-                       dup2(f, fd);
-                       close(f);
-               }
+               if (flags & REDIR_VFORK)
+                       eflags = O_NONBLOCK;
+               else
+                       eflags = 0;
+               if ((f = open(fname, O_RDONLY|eflags)) < 0)
+                       goto eopen;
+               if (eflags)
+                       (void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags);
                break;
        case NFROMTO:
                fname = redir->nfile.expfname;
-               if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
-                       error("cannot create %s: %s", fname, strerror(errno));
-               goto movefd;
+               if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
+                       goto ecreate;
+               break;
        case NTO:
-               fname = redir->nfile.expfname;
-               if (Cflag && stat(fname, &sb) != -1 && S_ISREG(sb.st_mode))
-                       error("cannot create %s: %s", fname,
-                           strerror(EEXIST));
-               if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
-                       error("cannot create %s: %s", fname, strerror(errno));
-               goto movefd;
+               if (Cflag)
+                       oflags |= O_EXCL;
+               /* FALLTHROUGH */
        case NCLOBBER:
                fname = redir->nfile.expfname;
-               if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
-                       error("cannot create %s: %s", fname, strerror(errno));
-               goto movefd;
+               if ((f = open(fname, oflags, 0666)) < 0)
+                       goto ecreate;
+               break;
        case NAPPEND:
                fname = redir->nfile.expfname;
                if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
-                       error("cannot create %s: %s", fname, strerror(errno));
-               goto movefd;
+                       goto ecreate;
+               break;
        case NTOFD:
        case NFROMFD:
                if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
                        if (memory[redir->ndup.dupfd])
                                memory[fd] = 1;
                        else
-                               dup2(redir->ndup.dupfd, fd);
-               } else {
-                       close(fd);
+                               copyfd(redir->ndup.dupfd, fd, 1);
                }
-               break;
+               INTON;
+               return;
        case NHERE:
        case NXHERE:
                f = openhere(redir);
-               goto movefd;
+               break;
        default:
                abort();
        }
+
+       if (f != fd) {
+               copyfd(f, fd, 1);
+               close(f);
+       }
        INTON;
+       return;
+ecreate:
+       exerrno = 1;
+       error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
+eopen:
+       exerrno = 1;
+       error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
 }
 
 
@@ -239,13 +247,13 @@ movefd:
  */
 
 STATIC int
-openhere(union node *redir)
+openhere(const union node *redir)
 {
        int pip[2];
        int len = 0;
 
        if (pipe(pip) < 0)
-               error("Pipe call failed: %s", strerror(errno));
+               error("Pipe call failed");
        if (redir->type == NHERE) {
                len = strlen(redir->nhere.doc->narg.text);
                if (len <= PIPESIZE) {
@@ -253,12 +261,14 @@ openhere(union node *redir)
                        goto out;
                }
        }
-       if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
+       if (forkshell(NULL, NULL, FORK_NOJOB) == 0) {
                close(pip[0]);
                signal(SIGINT, SIG_IGN);
                signal(SIGQUIT, SIG_IGN);
                signal(SIGHUP, SIG_IGN);
+#ifdef SIGTSTP
                signal(SIGTSTP, SIG_IGN);
+#endif
                signal(SIGPIPE, SIG_DFL);
                if (redir->type == NHERE)
                        xwrite(pip[1], redir->nhere.doc->narg.text, len);
@@ -287,11 +297,10 @@ popredir(void)
                if (rp->renamed[i] != EMPTY) {
                         if (i == 0)
                                 fd0_redirected--;
+                       close(i);
                        if (rp->renamed[i] >= 0) {
-                               dup2(rp->renamed[i], i);
+                               copyfd(rp->renamed[i], i, 1);
                                close(rp->renamed[i]);
-                       } else {
-                               close(i);
                        }
                }
        }
@@ -315,15 +324,14 @@ RESET {
 }
 
 SHELLPROC {
-       clearredir();
+       clearredir(0);
 }
 
 #endif
 
 /* Return true if fd 0 has already been redirected at least once.  */
 int
-fd0_redirected_p(void)
-{
+fd0_redirected_p (void) {
         return fd0_redirected != 0;
 }
 
@@ -332,7 +340,7 @@ fd0_redirected_p(void)
  */
 
 void
-clearredir(void)
+clearredir(int vforked)
 {
        struct redirtab *rp;
        int i;
@@ -342,11 +350,34 @@ clearredir(void)
                        if (rp->renamed[i] >= 0) {
                                close(rp->renamed[i]);
                        }
-                       rp->renamed[i] = EMPTY;
+                       if (!vforked)
+                               rp->renamed[i] = EMPTY;
                }
        }
 }
 
+
+
 /*
- * $PchId: redir.c,v 1.5 2006/05/22 12:27:37 philip Exp $
+ * Copy a file descriptor to be >= to.  Returns -1
+ * if the source file descriptor is closed, EMPTY if there are no unused
+ * file descriptors left.
  */
+
+int
+copyfd(int from, int to, int equal)
+{
+       int newfd;
+
+       if (equal)
+               newfd = dup2(from, to);
+       else
+               newfd = fcntl(from, F_DUPFD, to);
+       if (newfd < 0) {
+               if (errno == EMFILE)
+                       return EMPTY;
+               else
+                       error("%d: %s", from, strerror(errno));
+       }
+       return newfd;
+}
similarity index 88%
rename from minix/commands/ash/redir.h
rename to bin/sh/redir.h
index 9b665d06f92e329d92e14e74bd2a9acc8a679b8b..923619fbd89bce2fe474e6465dbb9a2f9c10b093 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: redir.h,v 1.16 2011/02/17 15:13:49 pooka Exp $ */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)redir.h     8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/redir.h,v 1.10 2004/04/06 20:06:51 markm Exp $
  */
 
 /* flags passed to redirect */
 #define REDIR_PUSH 01          /* save previous values of file descriptors */
 #define REDIR_BACKQ 02         /* save the command output in memory */
+#define REDIR_VFORK 04         /* running under vfork(2), be careful */
 
 union node;
 void redirect(union node *, int);
 void popredir(void);
 int fd0_redirected_p(void);
-void clearredir(void);
-
+void clearredir(int);
+int copyfd(int, int, int);
 
-/*
- * $PchId: redir.h,v 1.3 2006/03/29 14:13:34 philip Exp $
- */
diff --git a/bin/sh/sh.1 b/bin/sh/sh.1
new file mode 100644 (file)
index 0000000..05e8d74
--- /dev/null
@@ -0,0 +1,2002 @@
+.\"    $NetBSD: sh.1,v 1.111 2013/10/02 20:42:56 christos Exp $
+.\" Copyright (c) 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Kenneth Almquist.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"    @(#)sh.1        8.6 (Berkeley) 5/4/95
+.\"
+.Dd October 2, 2013
+.Dt SH 1
+.Os
+.Sh NAME
+.Nm sh
+.Nd command interpreter (shell)
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Op Ar command_file Oo Ar argument ... Oc
+.Ek
+.Nm
+.Fl c
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Ar command_string
+.Op Ar command_name Oo Ar argument ... Oc
+.Ek
+.Nm
+.Fl s
+.Bk -words
+.Op Fl aCefnuvxIimqVEb
+.Op Cm +aCefnuvxIimqVEb
+.Ek
+.Bk -words
+.Op Fl o Ar option_name
+.Op Cm +o Ar option_name
+.Ek
+.Bk -words
+.Op Ar argument ...
+.Ek
+.Sh DESCRIPTION
+.Nm
+is the standard command interpreter for the system.
+The current version of
+.Nm
+is in the process of being changed to conform with the
+.Tn POSIX
+1003.2 and 1003.2a specifications for the shell.
+This version has many
+features which make it appear similar in some respects to the Korn shell,
+but it is not a Korn shell clone (see
+.Xr ksh 1 ) .
+Only features designated by
+.Tn POSIX ,
+plus a few Berkeley extensions, are being incorporated into this shell.
+.\" We expect
+.\" .Tn POSIX
+.\" conformance by the time 4.4 BSD is released.
+This man page is not intended
+to be a tutorial or a complete specification of the shell.
+.Ss Overview
+The shell is a command that reads lines from either a file or the
+terminal, interprets them, and generally executes other commands.
+It is the program that is running when a user logs into the system
+(although a user can select a different shell with the
+.Xr chsh 1
+command).
+The shell implements a language that has flow control
+constructs, a macro facility that provides a variety of features in
+addition to data storage, along with built in history and line editing
+capabilities.
+It incorporates many features to aid interactive use and
+has the advantage that the interpretative language is common to both
+interactive and non-interactive use (shell scripts).
+That is, commands
+can be typed directly to the running shell or can be put into a file and
+the file can be executed directly by the shell.
+.Ss Invocation
+If no arguments are present and if the standard input of the shell
+is connected to a terminal (or if the
+.Fl i
+flag is set),
+and the
+.Fl c
+option is not present, the shell is considered an interactive shell.
+An interactive shell generally prompts before each command and handles
+programming and command errors differently (as described below).
+When first starting,
+the shell inspects argument 0, and if it begins with a dash
+.Sq - ,
+the shell is also considered
+a login shell.
+This is normally done automatically by the system
+when the user first logs in.
+A login shell first reads commands
+from the files
+.Pa /etc/profile
+and
+.Pa .profile
+if they exist.
+If the environment variable
+.Ev ENV
+is set on entry to a shell, or is set in the
+.Pa .profile
+of a login shell, the shell next reads
+commands from the file named in
+.Ev ENV .
+Therefore, a user should place commands that are to be executed only at
+login time in the
+.Pa .profile
+file, and commands that are executed for every shell inside the
+.Ev ENV
+file.
+To set the
+.Ev ENV
+variable to some file, place the following line in your
+.Pa .profile
+of your home directory
+.Pp
+.Dl ENV=$HOME/.shinit; export ENV
+.Pp
+substituting for
+.Dq .shinit
+any filename you wish.
+Since the
+.Ev ENV
+file is read for every invocation of the shell, including shell scripts
+and non-interactive shells, the following paradigm is useful for
+restricting commands in the
+.Ev ENV
+file to interactive invocations.
+Place commands within the
+.Dq case
+and
+.Dq esac
+below (these commands are described later):
+.Pp
+.Bl -item -compact -offset indent
+.It
+.Li case $- in *i*)
+.Bl -item -compact -offset indent
+.It
+.Li # commands for interactive use only
+.It
+.Li ...
+.El
+.It
+.Li esac
+.El
+.Pp
+If command line arguments besides the options have been specified, then
+the shell treats the first argument as the name of a file from which to
+read commands (a shell script), and the remaining arguments are set as the
+positional parameters of the shell ($1, $2, etc).
+Otherwise, the shell
+reads commands from its standard input.
+.Ss Argument List Processing
+All of the single letter options have a corresponding name that can be
+used as an argument to the
+.Fl o
+option.
+The set
+.Fl o
+name is provided next to the single letter option in
+the description below.
+Specifying a dash
+.Dq -
+turns the option on, while using a plus
+.Dq +
+disables the option.
+The following options can be set from the command line or
+with the
+.Ic set
+built-in (described later).
+.Bl -tag -width aaaallexportfoo -offset indent
+.It Fl a Em allexport
+Export all variables assigned to.
+.It Fl c
+Read commands from the
+.Ar command_string
+operand instead of from the standard input.
+Special parameter 0 will be set from the
+.Ar command_name
+operand and the positional parameters ($1, $2, etc.)
+set from the remaining argument operands.
+.It Fl C Em noclobber
+Don't overwrite existing files with
+.Dq \*[Gt] .
+.It Fl e Em errexit
+If not interactive, exit immediately if any untested command fails.
+The exit status of a command is considered to be
+explicitly tested if the command is used to control an
+.Ic if ,
+.Ic elif ,
+.Ic while ,
+or
+.Ic until ,
+or if the command is the left hand operand of an
+.Dq \*[Am]\*[Am]
+or
+.Dq ||
+operator.
+.It Fl f Em noglob
+Disable pathname expansion.
+.It Fl n Em noexec
+If not interactive, read commands but do not execute them.
+This is useful for checking the syntax of shell scripts.
+.It Fl u Em nounset
+Write a message to standard error when attempting to expand a variable
+that is not set, and if the shell is not interactive, exit immediately.
+.It Fl v Em verbose
+The shell writes its input to standard error as it is read.
+Useful for debugging.
+.It Fl x Em xtrace
+Write each command to standard error (preceded by a
+.Sq +\  )
+before it is executed.
+Useful for debugging.
+.It Fl q Em quietprofile
+If the
+.Fl v
+or
+.Fl x
+options have been set, do not apply them when reading
+initialization files, these being
+.Pa /etc/profile ,
+.Pa .profile ,
+and the file specified by the
+.Ev ENV
+environment variable.
+.It Fl I Em ignoreeof
+Ignore EOFs from input when interactive.
+.It Fl i Em interactive
+Force the shell to behave interactively.
+.It Fl m Em monitor
+Turn on job control (set automatically when interactive).
+.It Fl s Em stdin
+Read commands from standard input (set automatically if no file arguments
+are present).
+This option has no effect when set after the shell has
+already started running (i.e. with
+.Ic set ) .
+.It Fl V Em vi
+Enable the built-in
+.Xr vi 1
+command line editor (disables
+.Fl E
+if it has been set).
+(See the
+.Sx Command Line Editing
+section below.)
+.It Fl E Em emacs
+Enable the built-in emacs style
+command line editor (disables
+.Fl V
+if it has been set).
+(See the
+.Sx Command Line Editing
+section below.)
+.It Fl b Em notify
+Enable asynchronous notification of background job completion.
+(Not implemented.)
+.It "\ \ " Em cdprint
+Make an interactive shell always print the new directory name when
+changed by the
+.Ic cd
+command.
+.It "\ \ " Em tabcomplete
+Enables filename completion in the command line editor.
+Typing a tab character will extend the current input word to match a
+filename.
+If more than one filename matches it is only extended to be the common prefix.
+Typing a second tab character will list all the matching names.
+One of the editing modes, either
+.Fl E
+or
+.Fl V ,
+must be enabled for this to work.
+.El
+.Ss Lexical Structure
+The shell reads input in terms of lines from a file and breaks it up into
+words at whitespace (blanks and tabs), and at certain sequences of
+characters that are special to the shell called
+.Dq operators .
+There are two types of operators: control operators and redirection
+operators (their meaning is discussed later).
+Following is a list of operators:
+.Bl -ohang -offset indent
+.It "Control operators:"
+.Dl \*[Am]  \*[Am]\*[Am]  \&(  \&)  \&;  ;; | || \*[Lt]newline\*[Gt]
+.It "Redirection operators:"
+.Dl \*[Lt]  \*[Gt]  \*[Gt]|  \*[Lt]\*[Lt]  \*[Gt]\*[Gt]  \*[Lt]\*[Am]  \*[Gt]\*[Am]  \*[Lt]\*[Lt]-  \*[Lt]\*[Gt]
+.El
+.Ss Quoting
+Quoting is used to remove the special meaning of certain characters or
+words to the shell, such as operators, whitespace, or keywords.
+There are three types of quoting: matched single quotes,
+matched double quotes, and backslash.
+.Ss Backslash
+A backslash preserves the literal meaning of the following
+character, with the exception of
+.Aq newline .
+A backslash preceding a
+.Aq newline
+is treated as a line continuation.
+.Ss Single Quotes
+Enclosing characters in single quotes preserves the literal meaning of all
+the characters (except single quotes, making it impossible to put
+single quotes in a single-quoted string).
+.Ss Double Quotes
+Enclosing characters within double quotes preserves the literal
+meaning of all characters except dollar sign
+.Pq $ ,
+backquote
+.Pq ` ,
+and backslash
+.Pq \e .
+The backslash inside double quotes is historically weird, and serves to
+quote only the following characters:
+.Dl $  `  \*q  \e  \*[Lt]newline\*[Gt] .
+Otherwise it remains literal.
+.Ss Reserved Words
+Reserved words are words that have special meaning to the
+shell and are recognized at the beginning of a line and
+after a control operator.
+The following are reserved words:
+.Bl -column while while while while while -offset indent
+.It ! Ta elif Ta fi Ta while Ta case
+.It else Ta for Ta then Ta { Ta }
+.It do Ta done Ta until Ta if Ta esac
+.El
+.Pp
+Their meaning is discussed later.
+.Ss Aliases
+An alias is a name and corresponding value set using the
+.Ic alias
+built-in command.
+Whenever a reserved word may occur (see above),
+and after checking for reserved words, the shell
+checks the word to see if it matches an alias.
+If it does, it replaces it in the input stream with its value.
+For example, if there is an alias called
+.Dq lf
+with the value
+.Dq "ls -F" ,
+then the input:
+.Pp
+.Dl lf foobar Aq return
+.Pp
+would become
+.Pp
+.Dl ls -F foobar Aq return
+.Pp
+Aliases provide a convenient way for naive users to create shorthands for
+commands without having to learn how to create functions with arguments.
+They can also be used to create lexically obscure code.
+This use is discouraged.
+.Ss Commands
+The shell interprets the words it reads according to a language, the
+specification of which is outside the scope of this man page (refer to the
+BNF in the
+.Tn POSIX
+1003.2 document).
+Essentially though, a line is read and if the first
+word of the line (or after a control operator) is not a reserved word,
+then the shell has recognized a simple command.
+Otherwise, a complex
+command or some other special construct may have been recognized.
+.Ss Simple Commands
+If a simple command has been recognized, the shell performs
+the following actions:
+.Bl -enum -offset indent
+.It
+Leading words of the form
+.Dq name=value
+are stripped off and assigned to the environment of the simple command.
+Redirection operators and their arguments (as described below) are
+stripped off and saved for processing.
+.It
+The remaining words are expanded as described in the
+.Sx Word Expansions
+section below,
+and the first remaining word is considered the command name and the
+command is located.
+The remaining words are considered the arguments of the command.
+If no command name resulted, then the
+.Dq name=value
+variable assignments recognized in item 1 affect the current shell.
+.It
+Redirections are performed as described in the next section.
+.El
+.Ss Redirections
+Redirections are used to change where a command reads its input or sends
+its output.
+In general, redirections open, close, or duplicate an
+existing reference to a file.
+The overall format used for redirection is:
+.Pp
+.Dl [n] Va redir-op Ar file
+.Pp
+where
+.Va redir-op
+is one of the redirection operators mentioned previously.
+Following is a list of the possible redirections.
+The
+.Bq n
+is an optional number, as in
+.Sq 3
+(not
+.Sq Bq 3 ) ,
+that refers to a file descriptor.
+.Bl -tag -width aaabsfiles -offset indent
+.It [n] Ns \*[Gt] file
+Redirect standard output (or n) to file.
+.It [n] Ns \*[Gt]| file
+Same, but override the
+.Fl C
+option.
+.It [n] Ns \*[Gt]\*[Gt] file
+Append standard output (or n) to file.
+.It [n] Ns \*[Lt] file
+Redirect standard input (or n) from file.
+.It [n1] Ns \*[Lt]\*[Am] Ns n2
+Duplicate standard input (or n1) from file descriptor n2.
+.It [n] Ns \*[Lt]\*[Am]-
+Close standard input (or n).
+.It [n1] Ns \*[Gt]\*[Am] Ns n2
+Duplicate standard output (or n1) to n2.
+.It [n] Ns \*[Gt]\*[Am]-
+Close standard output (or n).
+.It [n] Ns \*[Lt]\*[Gt] file
+Open file for reading and writing on standard input (or n).
+.El
+.Pp
+The following redirection is often called a
+.Dq here-document .
+.Bl -item -offset indent
+.It
+.Li [n]\*[Lt]\*[Lt] delimiter
+.Dl here-doc-text ...
+.Li delimiter
+.El
+.Pp
+All the text on successive lines up to the delimiter, or to an EOF, is
+saved away and made available to the command on standard input, or file
+descriptor n if it is specified.
+If the delimiter as specified on the initial line is
+quoted, then the here-doc-text is treated literally; otherwise, the text is
+subjected to parameter expansion, command substitution, and arithmetic
+expansion as described in the
+.Sx Word Expansions
+section below.
+If the operator is
+.Dq \*[Lt]\*[Lt]-
+instead of
+.Dq \*[Lt]\*[Lt] ,
+then leading tabs in the here-doc-text are stripped.
+.Ss Search and Execution
+There are three types of commands: shell functions, built-in commands, and
+normal programs -- and the command is searched for (by name) in that order.
+They each are executed in a different way.
+.Pp
+When a shell function is executed, all of the shell positional parameters
+(except $0, which remains unchanged) are set to the arguments of the shell
+function.
+The variables which are explicitly placed in the environment of
+the command (by placing assignments to them before the function name) are
+made local to the function and are set to the values given.
+Then the command given in the function definition is executed.
+The positional parameters are restored to their original values
+when the command completes.
+This all occurs within the current shell.
+.Pp
+Shell built-ins are executed internally to the shell, without spawning a
+new process.
+.Pp
+Otherwise, if the command name doesn't match a function or built-in, the
+command is searched for as a normal program in the file system (as
+described in the next section).
+When a normal program is executed, the shell runs the program,
+passing the arguments and the environment to the program.
+If the program is not a normal executable file (i.e., if it does
+not begin with the "magic number" whose
+.Tn ASCII
+representation is "#!", so
+.Xr execve 2
+returns
+.Er ENOEXEC
+then) the shell will interpret the program in a subshell.
+The child shell will reinitialize itself in this case,
+so that the effect will be as if a
+new shell had been invoked to handle the ad-hoc shell script, except that
+the location of hashed commands located in the parent shell will be
+remembered by the child.
+.Pp
+Note that previous versions of this document and the source code itself
+misleadingly and sporadically refer to a shell script without a magic
+number as a "shell procedure".
+.Ss Path Search
+When locating a command, the shell first looks to see if it has a shell
+function by that name.
+Then it looks for a built-in command by that name.
+If a built-in command is not found, one of two things happen:
+.Bl -enum
+.It
+Command names containing a slash are simply executed without performing
+any searches.
+.It
+The shell searches each entry in
+.Ev PATH
+in turn for the command.
+The value of the
+.Ev PATH
+variable should be a series of entries separated by colons.
+Each entry consists of a directory name.
+The current directory may be indicated
+implicitly by an empty directory name, or explicitly by a single period.
+.El
+.Ss Command Exit Status
+Each command has an exit status that can influence the behavior
+of other shell commands.
+The paradigm is that a command exits
+with zero for normal or success, and non-zero for failure,
+error, or a false indication.
+The man page for each command
+should indicate the various exit codes and what they mean.
+Additionally, the built-in commands return exit codes, as does
+an executed shell function.
+.Pp
+If a command consists entirely of variable assignments then the
+exit status of the command is that of the last command substitution
+if any, otherwise 0.
+.Ss Complex Commands
+Complex commands are combinations of simple commands with control
+operators or reserved words, together creating a larger complex command.
+More generally, a command is one of the following:
+.Bl -bullet
+.It
+simple command
+.It
+pipeline
+.It
+list or compound-list
+.It
+compound command
+.It
+function definition
+.El
+.Pp
+Unless otherwise stated, the exit status of a command is that of the last
+simple command executed by the command.
+.Ss Pipelines
+A pipeline is a sequence of one or more commands separated
+by the control operator |.
+The standard output of all but
+the last command is connected to the standard input
+of the next command.
+The standard output of the last
+command is inherited from the shell, as usual.
+.Pp
+The format for a pipeline is:
+.Pp
+.Dl [!] command1 [ | command2 ...]
+.Pp
+The standard output of command1 is connected to the standard input of
+command2.
+The standard input, standard output, or both of a command is
+considered to be assigned by the pipeline before any redirection specified
+by redirection operators that are part of the command.
+.Pp
+If the pipeline is not in the background (discussed later), the shell
+waits for all commands to complete.
+.Pp
+If the reserved word ! does not precede the pipeline, the exit status is
+the exit status of the last command specified in the pipeline.
+Otherwise, the exit status is the logical NOT of the exit status of the
+last command.
+That is, if the last command returns zero, the exit status
+is 1; if the last command returns greater than zero, the exit status is
+zero.
+.Pp
+Because pipeline assignment of standard input or standard output or both
+takes place before redirection, it can be modified by redirection.
+For example:
+.Pp
+.Dl $ command1 2\*[Gt]\*[Am]1 | command2
+.Pp
+sends both the standard output and standard error of command1
+to the standard input of command2.
+.Pp
+A ; or
+.Aq newline
+terminator causes the preceding AND-OR-list (described
+next) to be executed sequentially; a \*[Am] causes asynchronous execution of
+the preceding AND-OR-list.
+.Pp
+Note that unlike some other shells, each process in the pipeline is a
+child of the invoking shell (unless it is a shell built-in, in which case
+it executes in the current shell -- but any effect it has on the
+environment is wiped).
+.Ss Background Commands -- \*[Am]
+If a command is terminated by the control operator ampersand (\*[Am]), the
+shell executes the command asynchronously -- that is, the shell does not
+wait for the command to finish before executing the next command.
+.Pp
+The format for running a command in background is:
+.Pp
+.Dl command1 \*[Am] [command2 \*[Am] ...]
+.Pp
+If the shell is not interactive, the standard input of an asynchronous
+command is set to
+.Pa /dev/null .
+.Ss Lists -- Generally Speaking
+A list is a sequence of zero or more commands separated by newlines,
+semicolons, or ampersands, and optionally terminated by one of these three
+characters.
+The commands in a list are executed in the order they are written.
+If command is followed by an ampersand, the shell starts the
+command and immediately proceed onto the next command; otherwise it waits
+for the command to terminate before proceeding to the next one.
+.Ss Short-Circuit List Operators
+.Dq \*[Am]\*[Am]
+and
+.Dq ||
+are AND-OR list operators.
+.Dq \*[Am]\*[Am]
+executes the first command, and then executes the second command if and only
+if the exit status of the first command is zero.
+.Dq ||
+is similar, but executes the second command if and only if the exit status
+of the first command is nonzero.
+.Dq \*[Am]\*[Am]
+and
+.Dq ||
+both have the same priority.
+Note that these operators are left-associative, so
+.Dq true || echo bar \*[Am]\*[Am] echo baz
+writes
+.Dq baz
+and nothing else.
+This is not the way it works in C.
+Also, if you forget the left-hand side (for example when continuing lines but
+forgetting to use a backslash) it defaults to a true statement.
+This behavior is not useful and should not be relied upon.
+.Ss Flow-Control Constructs -- if, while, for, case
+The syntax of the if command is
+.Bd -literal -offset indent
+if list
+then list
+[ elif list
+then    list ] ...
+[ else list ]
+fi
+.Ed
+.Pp
+The syntax of the while command is
+.Bd -literal -offset indent
+while list
+do   list
+done
+.Ed
+.Pp
+The two lists are executed repeatedly while the exit status of the
+first list is zero.
+The until command is similar, but has the word
+until in place of while, which causes it to
+repeat until the exit status of the first list is zero.
+.Pp
+The syntax of the for command is
+.Bd -literal -offset indent
+for variable in word ...
+do   list
+done
+.Ed
+.Pp
+The words are expanded, and then the list is executed repeatedly with the
+variable set to each word in turn.
+do and done may be replaced with
+.Dq {
+and
+.Dq } .
+.Pp
+The syntax of the break and continue command is
+.Bd -literal -offset indent
+break [ num ]
+continue [ num ]
+.Ed
+.Pp
+Break terminates the num innermost for or while loops.
+Continue continues with the next iteration of the innermost loop.
+These are implemented as built-in commands.
+.Pp
+The syntax of the case command is
+.Bd -literal -offset indent
+case word in
+pattern) list ;;
+\&...
+esac
+.Ed
+.Pp
+The pattern can actually be one or more patterns (see
+.Sx Shell Patterns
+described later), separated by
+.Dq \*(Ba
+characters.
+.Ss Grouping Commands Together
+Commands may be grouped by writing either
+.Pp
+.Dl (list)
+.Pp
+or
+.Pp
+.Dl { list; }
+.Pp
+The first of these executes the commands in a subshell.
+Built-in commands grouped into a (list) will not affect the current shell.
+The second form does not fork another shell so is slightly more efficient.
+Grouping commands together this way allows you to redirect
+their output as though they were one program:
+.Bd -literal -offset indent
+{ echo -n \*q hello \*q ; echo \*q world" ; } \*[Gt] greeting
+.Ed
+.Pp
+Note that
+.Dq }
+must follow a control operator (here,
+.Dq \&; )
+so that it is recognized as a reserved word and not as another command argument.
+.Ss Functions
+The syntax of a function definition is
+.Pp
+.Dl name ( ) command
+.Pp
+A function definition is an executable statement; when executed it
+installs a function named name and returns an exit status of zero.
+The command is normally a list enclosed between
+.Dq {
+and
+.Dq } .
+.Pp
+Variables may be declared to be local to a function by using a local
+command.
+This should appear as the first statement of a function, and the syntax is
+.Pp
+.Dl local [ variable | - ] ...
+.Pp
+.Dq Local
+is implemented as a built-in command.
+.Pp
+When a variable is made local, it inherits the initial value and exported
+and read-only flags from the variable with the same name in the surrounding
+scope, if there is one.
+Otherwise, the variable is initially unset.
+The shell uses dynamic scoping, so that if you make the variable x local to
+function f, which then calls function g, references to the variable x made
+inside g will refer to the variable x declared inside f, not to the global
+variable named x.
+.Pp
+The only special parameter that can be made local is
+.Dq - .
+Making
+.Dq -
+local causes any shell options that are changed via the set command inside the
+function to be restored to their original values when the function
+returns.
+.Pp
+The syntax of the return command is
+.Pp
+.Dl return [ exitstatus ]
+.Pp
+It terminates the currently executing function.
+Return is implemented as a built-in command.
+.Ss Variables and Parameters
+The shell maintains a set of parameters.
+A parameter denoted by a name is called a variable.
+When starting up, the shell turns all the environment
+variables into shell variables.
+New variables can be set using the form
+.Pp
+.Dl name=value
+.Pp
+Variables set by the user must have a name consisting solely of
+alphabetics, numerics, and underscores - the first of which must not be
+numeric.
+A parameter can also be denoted by a number or a special
+character as explained below.
+.Ss Positional Parameters
+A positional parameter is a parameter denoted by a number (n \*[Gt] 0).
+The shell sets these initially to the values of its command line arguments
+that follow the name of the shell script.
+The
+.Ic set
+built-in can also be used to set or reset them.
+.Ss Special Parameters
+A special parameter is a parameter denoted by one of the following special
+characters.
+The value of the parameter is listed next to its character.
+.Bl -tag -width thinhyphena
+.It *
+Expands to the positional parameters, starting from one.
+When the
+expansion occurs within a double-quoted string it expands to a single
+field with the value of each parameter separated by the first character of
+the
+.Ev IFS
+variable, or by a
+.Aq space
+if
+.Ev IFS
+is unset.
+.It @
+Expands to the positional parameters, starting from one.
+When the expansion occurs within double quotes, each positional
+parameter expands as a separate argument.
+If there are no positional parameters, the
+expansion of @ generates zero arguments, even when @ is
+double-quoted.
+What this basically means, for example, is
+if $1 is
+.Dq abc
+and $2 is
+.Dq def ghi ,
+then
+.Qq $@
+expands to
+the two arguments:
+.Pp
+.Sm off
+.Dl \*q abc \*q \  \*q def\ ghi \*q
+.Sm on
+.It #
+Expands to the number of positional parameters.
+.It \&?
+Expands to the exit status of the most recent pipeline.
+.It - (Hyphen.)
+Expands to the current option flags (the single-letter
+option names concatenated into a string) as specified on
+invocation, by the set built-in command, or implicitly
+by the shell.
+.It $
+Expands to the process ID of the invoked shell.
+A subshell retains the same value of $ as its parent.
+.It \&!
+Expands to the process ID of the most recent background
+command executed from the current shell.
+For a pipeline, the process ID is that of the last command in the pipeline.
+.It 0 (Zero.)
+Expands to the name of the shell or shell script.
+.El
+.Ss Word Expansions
+This section describes the various expansions that are performed on words.
+Not all expansions are performed on every word, as explained later.
+.Pp
+Tilde expansions, parameter expansions, command substitutions, arithmetic
+expansions, and quote removals that occur within a single word expand to a
+single field.
+It is only field splitting or pathname expansion that can
+create multiple fields from a single word.
+The single exception to this
+rule is the expansion of the special parameter @ within double quotes, as
+was described above.
+.Pp
+The order of word expansion is:
+.Bl -enum
+.It
+Tilde Expansion, Parameter Expansion, Command Substitution,
+Arithmetic Expansion (these all occur at the same time).
+.It
+Field Splitting is performed on fields
+generated by step (1) unless the
+.Ev IFS
+variable is null.
+.It
+Pathname Expansion (unless set
+.Fl f
+is in effect).
+.It
+Quote Removal.
+.El
+.Pp
+The $ character is used to introduce parameter expansion, command
+substitution, or arithmetic evaluation.
+.Ss Tilde Expansion (substituting a user's home directory)
+A word beginning with an unquoted tilde character (~) is
+subjected to tilde expansion.
+All the characters up to
+a slash (/) or the end of the word are treated as a username
+and are replaced with the user's home directory.
+If the username is missing (as in
+.Pa ~/foobar ) ,
+the tilde is replaced with the value of the
+.Va HOME
+variable (the current user's home directory).
+.Ss Parameter Expansion
+The format for parameter expansion is as follows:
+.Pp
+.Dl ${expression}
+.Pp
+where expression consists of all characters until the matching
+.Dq } .
+Any
+.Dq }
+escaped by a backslash or within a quoted string, and characters in
+embedded arithmetic expansions, command substitutions, and variable
+expansions, are not examined in determining the matching
+.Dq } .
+.Pp
+The simplest form for parameter expansion is:
+.Pp
+.Dl ${parameter}
+.Pp
+The value, if any, of parameter is substituted.
+.Pp
+The parameter name or symbol can be enclosed in braces, which are
+optional except for positional parameters with more than one digit or
+when parameter is followed by a character that could be interpreted as
+part of the name.
+If a parameter expansion occurs inside double quotes:
+.Bl -enum
+.It
+Pathname expansion is not performed on the results of the expansion.
+.It
+Field splitting is not performed on the results of the
+expansion, with the exception of the special rules for @.
+.El
+.Pp
+In addition, a parameter expansion can be modified by using one of the
+following formats.
+If the
+.Dq Dv \&:
+is omitted in the following modifiers, then the expansion is applied only
+to unset parameters, not null ones.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${parameter:-word}
+Use Default Values.
+If parameter is unset or null, the expansion of word
+is substituted; otherwise, the value of parameter is substituted.
+.It ${parameter:=word}
+Assign Default Values.
+If parameter is unset or null, the expansion of
+word is assigned to parameter.
+In all cases, the final value of parameter is substituted.
+Only variables, not positional parameters or special
+parameters, can be assigned in this way.
+.It ${parameter:?[word]}
+Indicate Error if Null or Unset.
+If parameter is unset or null, the
+expansion of word (or a message indicating it is unset if word is omitted)
+is written to standard error and the shell exits with a nonzero exit status.
+Otherwise, the value of parameter is substituted.
+An interactive shell need not exit.
+.It ${parameter:+word}
+Use Alternative Value.
+If parameter is unset or null, null is
+substituted; otherwise, the expansion of word is substituted.
+.It ${#parameter}
+String Length.
+The length in characters of the value of parameter.
+.El
+.Pp
+The following four varieties of parameter expansion provide for substring
+processing.
+In each case, pattern matching notation (see
+.Sx Shell Patterns ) ,
+rather than regular expression notation, is used to evaluate the patterns.
+If parameter is * or @, the result of the expansion is unspecified.
+Enclosing the full parameter expansion string in double quotes does not
+cause the following four varieties of pattern characters to be quoted,
+whereas quoting characters within the braces has this effect.
+.Bl -tag -width aaparameterwordaaaaa
+.It ${parameter%word}
+Remove Smallest Suffix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the
+smallest portion of the suffix matched by the pattern deleted.
+.It ${parameter%%word}
+Remove Largest Suffix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the largest
+portion of the suffix matched by the pattern deleted.
+.It ${parameter#word}
+Remove Smallest Prefix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the
+smallest portion of the prefix matched by the pattern deleted.
+.It ${parameter##word}
+Remove Largest Prefix Pattern.
+The word is expanded to produce a pattern.
+The parameter expansion then results in parameter, with the largest
+portion of the prefix matched by the pattern deleted.
+.El
+.Ss Command Substitution
+Command substitution allows the output of a command to be substituted in
+place of the command name itself.
+Command substitution occurs when the command is enclosed as follows:
+.Pp
+.Dl $(command)
+.Pp
+or
+.Po
+.Dq backquoted
+version
+.Pc :
+.Pp
+.Dl `command`
+.Pp
+The shell expands the command substitution by executing command in a
+subshell environment and replacing the command substitution with the
+standard output of the command, removing sequences of one or more
+.Ao newline Ac Ns s
+at the end of the substitution.
+(Embedded
+.Ao newline Ac Ns s
+before
+the end of the output are not removed; however, during field splitting,
+they may be translated into
+.Ao space Ac Ns s ,
+depending on the value of
+.Ev IFS
+and quoting that is in effect.)
+.Ss Arithmetic Expansion
+Arithmetic expansion provides a mechanism for evaluating an arithmetic
+expression and substituting its value.
+The format for arithmetic expansion is as follows:
+.Pp
+.Dl $((expression))
+.Pp
+The expression is treated as if it were in double quotes, except
+that a double quote inside the expression is not treated specially.
+The shell expands all tokens in the expression for parameter expansion,
+command substitution, and quote removal.
+.Pp
+Next, the shell treats this as an arithmetic expression and
+substitutes the value of the expression.
+.Pp
+Arithmetic expressions use a syntax similar to that
+of the C language, and are evaluated using the
+.Ql intmax_t
+data type (this is an extension to
+.Tn POSIX ,
+which requires only
+.Ql long
+arithmetic).
+Shell variables may be referenced by name inside an arithmetic
+expression, without needing a
+.Dq \&$
+sign.
+.Ss White Space Splitting (Field Splitting)
+After parameter expansion, command substitution, and
+arithmetic expansion the shell scans the results of
+expansions and substitutions that did not occur in double quotes for
+field splitting and multiple fields can result.
+.Pp
+The shell treats each character of the
+.Ev IFS
+as a delimiter and use the delimiters to split the results of parameter
+expansion and command substitution into fields.
+.Pp
+Non-whitespace characters in
+.Ev IFS
+are treated strictly as parameter terminators.
+So adjacent non-whitespace
+.Ev IFS
+characters will produce empty parameters.
+.Pp
+If
+.Ev IFS
+is unset it is assumed to contain space, tab, and newline.
+.Ss Pathname Expansion (File Name Generation)
+Unless the
+.Fl f
+flag is set, file name generation is performed after word splitting is
+complete.
+Each word is viewed as a series of patterns, separated by slashes.
+The process of expansion replaces the word with the names of all
+existing files whose names can be formed by replacing each pattern with a
+string that matches the specified pattern.
+There are two restrictions on
+this: first, a pattern cannot match a string containing a slash, and
+second, a pattern cannot match a string starting with a period unless the
+first character of the pattern is a period.
+The next section describes the
+patterns used for both Pathname Expansion and the
+.Ic case
+command.
+.Ss Shell Patterns
+A pattern consists of normal characters, which match themselves,
+and meta-characters.
+The meta-characters are
+.Dq \&! ,
+.Dq * ,
+.Dq \&? ,
+and
+.Dq \&[ .
+These characters lose their special meanings if they are quoted.
+When command or variable substitution is performed
+and the dollar sign or backquotes are not double-quoted,
+the value of the variable or the output of
+the command is scanned for these characters and they are turned into
+meta-characters.
+.Pp
+An asterisk
+.Pq Dq *
+matches any string of characters.
+A question mark
+.Pq Dq \&?
+matches any single character.
+A left bracket
+.Pq Dq \&[
+introduces a character class.
+The end of the character class is indicated by a right bracket
+.Pq Dq \&] ;
+if this
+.Dq \&]
+is missing then the
+.Dq \&[
+matches a
+.Dq \&[
+rather than introducing a character class.
+A character class matches any of the characters between the square brackets.
+A range of characters may be specified using a minus sign
+.Pq Dq - .
+The character class may be complemented
+by making an exclamation mark
+.Pq Dq \&!
+the first character of the character class.
+.Pp
+To include a
+.Dq \&]
+in a character class, make it the first character listed (after the
+.Dq \&! ,
+if any).
+To include a
+.Dq - ,
+make it the first or last character listed.
+.Ss Built-ins
+This section lists the built-in commands which are built-in because they
+need to perform some operation that can't be performed by a separate
+process.
+In addition to these, there are several other commands that may
+be built in for efficiency (e.g.
+.Xr printf 1 ,
+.Xr echo 1 ,
+.Xr test 1 ,
+etc).
+.Bl -tag -width 5n
+.It :
+A null command that returns a 0 (true) exit value.
+.It \&. file
+The commands in the specified file are read and executed by the shell.
+.It alias Op Ar name Ns Op Ar "=string ..."
+If
+.Ar name=string
+is specified, the shell defines the alias
+.Ar name
+with value
+.Ar string .
+If just
+.Ar name
+is specified, the value of the alias
+.Ar name
+is printed.
+With no arguments, the
+.Ic alias
+built-in prints the
+names and values of all defined aliases (see
+.Ic unalias ) .
+.It bg [ Ar job ] ...
+Continue the specified jobs (or the current job if no
+jobs are given) in the background.
+.It command Oo Fl p Oc Oo Fl v Oc Oo Fl V Oc Ar command Oo Ar arg ... Oc
+Execute the specified command but ignore shell functions when searching
+for it.
+(This is useful when you
+have a shell function with the same name as a built-in command.)
+.Bl -tag -width 5n
+.It Fl p
+search for command using a
+.Ev PATH
+that guarantees to find all the standard utilities.
+.It Fl V
+Do not execute the command but
+search for the command and print the resolution of the
+command search.
+This is the same as the
+.Ic type
+built-in.
+.It Fl v
+Do not execute the command but
+search for the command and print the absolute pathname
+of utilities, the name for built-ins or the expansion of aliases.
+.El
+.It cd Oo Fl P Oc Op Ar directory Op Ar replace
+Switch to the specified directory (default
+.Ev $HOME ) .
+If
+.Ar replace
+is specified, then the new directory name is generated by replacing
+the first occurrence of
+.Ar directory
+in the current directory name with
+.Ar replace .
+If
+.Ar directory
+is
+.Sq - ,
+then the current working directory is changed to the previous current
+working directory as set in
+.Ev OLDPWD .
+Otherwise if an entry for
+.Ev CDPATH
+appears in the environment of the
+.Ic cd
+command or the shell variable
+.Ev CDPATH
+is set and the directory name does not begin with a slash,
+or its first (or only) component isn't dot or dot dot,
+then the directories listed in
+.Ev CDPATH
+will be searched for the specified directory.
+The format of
+.Ev CDPATH
+is the same as that of
+.Ev PATH .
+.Pp
+The
+.Fl P
+option instructs the shell to update
+.Ev PWD
+with the specified physical directory path and change to that directory.
+This is the default.
+.Pp
+When the directory changes, the variable
+.Ev OLDPWD
+is set to the working directory before the change.
+.Pp
+Some shells also support a
+.Fl L
+option, which instructs the shell to update
+.Ev PWD
+with the logical path and to change the current directory
+accordingly.
+This is not supported.
+.Pp
+In an interactive shell, the
+.Ic cd
+command will print out the name of the
+directory that it actually switched to if this is different from the name
+that the user gave.
+These may be different either because the
+.Ev CDPATH
+mechanism was used or because a symbolic link was crossed.
+.It eval Ar string ...
+Concatenate all the arguments with spaces.
+Then re-parse and execute the command.
+.It exec Op Ar command arg ...
+Unless command is omitted, the shell process is replaced with the
+specified program (which must be a real program, not a shell built-in or
+function).
+Any redirections on the
+.Ic exec
+command are marked as permanent, so that they are not undone when the
+.Ic exec
+command finishes.
+.It exit Op Ar exitstatus
+Terminate the shell process.
+If
+.Ar exitstatus
+is given it is used as the exit status of the shell; otherwise the
+exit status of the preceding command is used.
+.It export Ar name ...
+.It export Fl p
+The specified names are exported so that they will appear in the
+environment of subsequent commands.
+The only way to un-export a variable is to unset it.
+The shell allows the value of a variable to be set at the
+same time it is exported by writing
+.Pp
+.Dl export name=value
+.Pp
+With no arguments the export command lists the names of all exported variables.
+With the
+.Fl p
+option specified the output will be formatted suitably for non-interactive use.
+.It fc Oo Fl e Ar editor Oc Oo Ar first Oo Ar last Oc Oc
+.It fc Fl l Oo Fl nr Oc Oo Ar first Oo Ar last Oc Oc
+.It fc Fl s Oo Ar old=new Oc Oo Ar first Oc
+The
+.Ic fc
+built-in lists, or edits and re-executes, commands previously entered
+to an interactive shell.
+.Bl -tag -width 5n
+.It Fl e No editor
+Use the editor named by editor to edit the commands.
+The editor string is a command name, subject to search via the
+.Ev PATH
+variable.
+The value in the
+.Ev FCEDIT
+variable is used as a default when
+.Fl e
+is not specified.
+If
+.Ev FCEDIT
+is null or unset, the value of the
+.Ev EDITOR
+variable is used.
+If
+.Ev EDITOR
+is null or unset,
+.Xr ed 1
+is used as the editor.
+.It Fl l No (ell)
+List the commands rather than invoking an editor on them.
+The commands are written in the sequence indicated by
+the first and last operands, as affected by
+.Fl r ,
+with each command preceded by the command number.
+.It Fl n
+Suppress command numbers when listing with -l.
+.It Fl r
+Reverse the order of the commands listed (with
+.Fl l )
+or edited (with neither
+.Fl l
+nor
+.Fl s ) .
+.It Fl s
+Re-execute the command without invoking an editor.
+.It first
+.It last
+Select the commands to list or edit.
+The number of previous commands that
+can be accessed are determined by the value of the
+.Ev HISTSIZE
+variable.
+The value of first or last or both are one of the following:
+.Bl -tag -width 5n
+.It [+]number
+A positive number representing a command number; command numbers can be
+displayed with the
+.Fl l
+option.
+.It Fl number
+A negative decimal number representing the command that was executed
+number of commands previously.
+For example, \-1 is the immediately previous command.
+.El
+.It string
+A string indicating the most recently entered command that begins with
+that string.
+If the old=new operand is not also specified with
+.Fl s ,
+the string form of the first operand cannot contain an embedded equal sign.
+.El
+.Pp
+The following environment variables affect the execution of fc:
+.Bl -tag -width HISTSIZE
+.It Ev FCEDIT
+Name of the editor to use.
+.It Ev HISTSIZE
+The number of previous commands that are accessible.
+.El
+.It fg Op Ar job
+Move the specified job or the current job to the foreground.
+.It getopts Ar optstring var
+The
+.Tn POSIX
+.Ic getopts
+command, not to be confused with the
+.Em Bell Labs
+-derived
+.Xr getopt 1 .
+.Pp
+The first argument should be a series of letters, each of which may be
+optionally followed by a colon to indicate that the option requires an
+argument.
+The variable specified is set to the parsed option.
+.Pp
+The
+.Ic getopts
+command deprecates the older
+.Xr getopt 1
+utility due to its handling of arguments containing whitespace.
+.Pp
+The
+.Ic getopts
+built-in may be used to obtain options and their arguments
+from a list of parameters.
+When invoked,
+.Ic getopts
+places the value of the next option from the option string in the list in
+the shell variable specified by
+.Va var
+and its index in the shell variable
+.Ev OPTIND .
+When the shell is invoked,
+.Ev OPTIND
+is initialized to 1.
+For each option that requires an argument, the
+.Ic getopts
+built-in will place it in the shell variable
+.Ev OPTARG .
+If an option is not allowed for in the
+.Va optstring ,
+then
+.Ev OPTARG
+will be unset.
+.Pp
+.Va optstring
+is a string of recognized option letters (see
+.Xr getopt 3 ) .
+If a letter is followed by a colon, the option is expected to have an
+argument which may or may not be separated from it by whitespace.
+If an option character is not found where expected,
+.Ic getopts
+will set the variable
+.Va var
+to a
+.Dq \&? ;
+.Ic getopts
+will then unset
+.Ev OPTARG
+and write output to standard error.
+By specifying a colon as the first character of
+.Va optstring
+all errors will be ignored.
+.Pp
+A nonzero value is returned when the last option is reached.
+If there are no remaining arguments,
+.Ic getopts
+will set
+.Va var
+to the special option,
+.Dq -- ,
+otherwise, it will set
+.Va var
+to
+.Dq \&? .
+.Pp
+The following code fragment shows how one might process the arguments
+for a command that can take the options
+.Op a
+and
+.Op b ,
+and the option
+.Op c ,
+which requires an argument.
+.Bd -literal -offset indent
+while getopts abc: f
+do
+       case $f in
+       a | b)  flag=$f;;
+       c)      carg=$OPTARG;;
+       \e?)    echo $USAGE; exit 1;;
+       esac
+done
+shift $(expr $OPTIND - 1)
+.Ed
+.Pp
+This code will accept any of the following as equivalent:
+.Bd -literal -offset indent
+cmd \-acarg file file
+cmd \-a \-c arg file file
+cmd \-carg -a file file
+cmd \-a \-carg \-\- file file
+.Ed
+.It hash Fl rv Ar command ...
+The shell maintains a hash table which remembers the
+locations of commands.
+With no arguments whatsoever,
+the
+.Ic hash
+command prints out the contents of this table.
+Entries which have not been looked at since the last
+.Ic cd
+command are marked with an asterisk; it is possible for these entries
+to be invalid.
+.Pp
+With arguments, the
+.Ic hash
+command removes the specified commands from the hash table (unless
+they are functions) and then locates them.
+With the
+.Fl v
+option, hash prints the locations of the commands as it finds them.
+The
+.Fl r
+option causes the hash command to delete all the entries in the hash table
+except for functions.
+.It inputrc Ar file
+Read the
+.Va file
+to set keybindings as defined by
+.Xr editrc 5 .
+.It jobid Op Ar job
+Print the process id's of the processes in the job.
+If the
+.Ar job
+argument is omitted, the current job is used.
+.It jobs
+This command lists out all the background processes
+which are children of the current shell process.
+.It pwd Op Fl \&LP
+Print the current directory.
+If
+.Fl L
+is specified the cached value (initially set from
+.Ev PWD )
+is checked to see if it refers to the current directory; if it does
+the value is printed.
+Otherwise the current directory name is found using
+.Xr getcwd 3 .
+The environment variable
+.Ev PWD
+is set to the printed value.
+.Pp
+The default is
+.Ic pwd
+.Fl L ,
+but note that the built-in
+.Ic cd
+command doesn't currently support the
+.Fl L
+option and will cache (almost) the absolute path.
+If
+.Ic cd
+is changed,
+.Ic pwd
+may be changed to default to
+.Ic pwd
+.Fl P .
+.Pp
+If the current directory is renamed and replaced by a symlink to the
+same directory, or the initial
+.Ev PWD
+value followed a symbolic link, then the cached value may not
+be the absolute path.
+.Pp
+The built-in command may differ from the program of the same name because
+the program will use
+.Ev PWD
+and the built-in uses a separately cached value.
+.It read Oo Fl p Ar prompt Oc Oo Fl r Oc Ar variable Oo Ar ... Oc
+The prompt is printed if the
+.Fl p
+option is specified and the standard input is a terminal.
+Then a line is read from the standard input.
+The trailing newline is deleted from the
+line and the line is split as described in the
+.Sx Word Expansions
+section above, and the pieces are assigned to the variables in order.
+If there are more pieces than variables, the remaining pieces
+(along with the characters in
+.Ev IFS
+that separated them) are assigned to the last variable.
+If there are more variables than pieces,
+the remaining variables are assigned the null string.
+The
+.Ic read
+built-in will indicate success unless EOF is encountered on input, in
+which case failure is returned.
+.Pp
+By default, unless the
+.Fl r
+option is specified, the backslash
+.Dq \e
+acts as an escape character, causing the following character to be treated
+literally.
+If a backslash is followed by a newline, the backslash and the
+newline will be deleted.
+.It readonly Ar name ...
+.It readonly Fl p
+The specified names are marked as read only, so that they cannot be
+subsequently modified or unset.
+The shell allows the value of a variable
+to be set at the same time it is marked read only by writing
+.Pp
+.Dl readonly name=value
+.Pp
+With no arguments the readonly command lists the names of all read only
+variables.
+With the
+.Fl p
+option specified the output will be formatted suitably for non-interactive use.
+.Pp
+.It set Oo { Fl options | Cm +options | Cm \-- } Oc Ar arg ...
+The
+.Ic set
+command performs three different functions.
+.Pp
+With no arguments, it lists the values of all shell variables.
+.Pp
+If options are given, it sets the specified option
+flags, or clears them as described in the
+.Sx Argument List Processing
+section.
+.Pp
+The third use of the set command is to set the values of the shell's
+positional parameters to the specified arguments.
+To change the positional
+parameters without changing any options, use
+.Dq --
+as the first argument to set.
+If no arguments are present, the set command
+will clear all the positional parameters (equivalent to executing
+.Dq shift $# . )
+.It setvar Ar variable Ar value
+Assigns value to variable.
+(In general it is better to write
+variable=value rather than using
+.Ic setvar .
+.Ic setvar
+is intended to be used in
+functions that assign values to variables whose names are passed as
+parameters.)
+.It shift Op Ar n
+Shift the positional parameters n times.
+A
+.Ic shift
+sets the value of
+.Va $1
+to the value of
+.Va $2 ,
+the value of
+.Va $2
+to the value of
+.Va $3 ,
+and so on, decreasing
+the value of
+.Va $#
+by one.
+If there are zero positional parameters,
+.Ic shift
+does nothing.
+.It trap Oo Fl l Oc
+.It trap Oo Ar action Oc Ar signal ...
+Cause the shell to parse and execute action when any of the specified
+signals are received.
+The signals are specified by signal number or as the name of the signal.
+If
+.Ar signal
+is
+.Li 0
+or its equivalent, EXIT,
+the action is executed when the shell exits.
+.Ar action
+may be null, which cause the specified signals to be ignored.
+With
+.Ar action
+omitted or set to
+.Sq -
+the specified signals are set to their default action.
+When the shell forks off a subshell, it resets trapped (but not ignored)
+signals to the default action.
+On non-interactive shells, the
+.Ic trap
+command has no effect on signals that were
+ignored on entry to the shell.
+On interactive shells, the
+.Ic trap
+command will catch or reset signals ignored on entry.
+Issuing
+.Ic trap
+with option
+.Ar -l
+will print a list of valid signal names.
+.Ic trap
+without any arguments cause it to write a list of signals and their
+associated action to the standard output in a format that is suitable
+as an input to the shell that achieves the same trapping results.
+.Pp
+Examples:
+.Pp
+.Dl trap
+.Pp
+List trapped signals and their corresponding action
+.Pp
+.Dl trap -l
+.Pp
+Print a list of valid signals
+.Pp
+.Dl trap '' INT QUIT tstp 30
+.Pp
+Ignore signals INT QUIT TSTP USR1
+.Pp
+.Dl trap date INT
+.Pp
+Print date upon receiving signal INT
+.It type Op Ar name ...
+Interpret each name as a command and print the resolution of the command
+search.
+Possible resolutions are:
+shell keyword, alias, shell built-in,
+command, tracked alias and not found.
+For aliases the alias expansion is
+printed; for commands and tracked aliases the complete pathname of the
+command is printed.
+.It ulimit Oo Fl H \*(Ba Fl S Oc Oo Fl a \*(Ba Fl btfdscmlrpnv Oo Ar value Oc Oc
+Inquire about or set the hard or soft limits on processes or set new
+limits.
+The choice between hard limit (which no process is allowed to
+violate, and which may not be raised once it has been lowered) and soft
+limit (which causes processes to be signaled but not necessarily killed,
+and which may be raised) is made with these flags:
+.Bl -tag -width Fl
+.It Fl H
+set or inquire about hard limits
+.It Fl S
+set or inquire about soft limits.
+If neither
+.Fl H
+nor
+.Fl S
+is specified, the soft limit is displayed or both limits are set.
+If both are specified, the last one wins.
+.El
+.Pp
+The limit to be interrogated or set, then, is chosen by specifying
+any one of these flags:
+.Bl -tag -width Fl
+.It Fl a
+show all the current limits
+.It Fl b
+show or set the limit on the socket buffer size of a process (in bytes)
+.It Fl t
+show or set the limit on CPU time (in seconds)
+.It Fl f
+show or set the limit on the largest file that can be created
+(in 512-byte blocks)
+.It Fl d
+show or set the limit on the data segment size of a process (in kilobytes)
+.It Fl s
+show or set the limit on the stack size of a process (in kilobytes)
+.It Fl c
+show or set the limit on the largest core dump size that can be produced
+(in 512-byte blocks)
+.It Fl m
+show or set the limit on the total physical memory that can be
+in use by a process (in kilobytes)
+.It Fl l
+show or set the limit on how much memory a process can lock with
+.Xr mlock 2
+(in kilobytes)
+.It Fl r
+show or set the limit on the number of threads this user can
+have at one time
+.It Fl p
+show or set the limit on the number of processes this user can
+have at one time
+.It Fl n
+show or set the limit on the number of files a process can have open at once
+.It Fl v
+show or set the limit on how large a process address space can be
+.El
+.Pp
+If none of these is specified, it is the limit on file size that is shown
+or set.
+If value is specified, the limit is set to that number; otherwise
+the current limit is displayed.
+.Pp
+Limits of an arbitrary process can be displayed or set using the
+.Xr sysctl 8
+utility.
+.Pp
+.It umask Op Ar mask
+Set the value of umask (see
+.Xr umask 2 )
+to the specified octal value.
+If the argument is omitted, the umask value is printed.
+.It unalias Oo Fl a Oc Oo Ar name Oc
+If
+.Ar name
+is specified, the shell removes that alias.
+If
+.Fl a
+is specified, all aliases are removed.
+.It unset Ar name ...
+The specified variables and functions are unset and unexported.
+If a given name corresponds to both a variable and a function, both
+the variable and the function are unset.
+.It wait Op Ar job
+Wait for the specified job to complete and return the exit status of the
+last process in the job.
+If the argument is omitted, wait for all jobs to
+complete and then return an exit status of zero.
+.El
+.Ss Command Line Editing
+When
+.Nm
+is being used interactively from a terminal, the current command
+and the command history (see
+.Ic fc
+in the
+.Sx Built-ins
+section)
+can be edited using emacs-mode or vi-mode command-line editing.
+The command
+.Ql set -o emacs
+enables emacs-mode editing.
+The command
+.Ql set -o vi
+enables vi-mode editing and places the current shell process into
+.Ar vi
+insert mode.
+(See the
+.Sx Argument List Processing
+section above.)
+.Pp
+The
+.Ar vi
+mode uses commands similar to a subset of those described in the
+.Xr vi 1
+man page.
+With vi-mode
+enabled,
+.Nm sh
+can be switched between insert mode and command mode.
+It's similar to
+.Xr vi 1 :
+pressing the
+.Aq ESC
+key will throw you into command VI command mode.
+Pressing the
+.Aq return
+key while in command mode will pass the line to the shell.
+.Pp
+The
+.Ar emacs
+mode uses commands similar to a subset available in
+the
+.Xr emacs 1
+editor.
+With emacs-mode enabled, special keys can be used to modify the text
+in the buffer using the control key.
+.Pp
+.Nm
+uses the
+.Xr editline 3
+library.
+.Sh ENVIRONMENT
+.Bl -tag -width MAILCHECK
+.It Ev HOME
+Set automatically by
+.Xr login 1
+from the user's login directory in the password file
+.Pq Xr passwd 5 .
+This environment variable also functions as the default argument for the
+.Ic cd
+built-in.
+.It Ev PATH
+The default search path for executables.
+See the
+.Sx Path Search
+section above.
+.It Ev CDPATH
+The search path used with the
+.Ic cd
+built-in.
+.It Ev LINENO
+The current line number in the script or function.
+.It Ev LANG
+The string used to specify localization information that allows users
+to work with different culture-specific and language conventions.
+See
+.Xr nls 7 .
+.It Ev MAIL
+The name of a mail file, that will be checked for the arrival of new mail.
+Overridden by
+.Ev MAILPATH .
+.It Ev MAILCHECK
+The frequency in seconds that the shell checks for the arrival of mail
+in the files specified by the
+.Ev MAILPATH
+or the
+.Ev MAIL
+file.
+If set to 0, the check will occur at each prompt.
+.It Ev MAILPATH
+A colon
+.Dq \&:
+separated list of file names, for the shell to check for incoming mail.
+This environment setting overrides the
+.Ev MAIL
+setting.
+There is a maximum of 10 mailboxes that can be monitored at once.
+.It Ev PS1
+The primary prompt string, which defaults to
+.Dq $ \  ,
+unless you are the superuser, in which case it defaults to
+.Dq # \  .
+.It Ev PS2
+The secondary prompt string, which defaults to
+.Dq \*[Gt] \  .
+.It Ev PS4
+Output before each line when execution trace (set -x) is enabled,
+defaults to
+.Dq + \  .
+.It Ev IFS
+Input Field Separators.
+This is normally set to
+.Aq space ,
+.Aq tab ,
+and
+.Aq newline .
+See the
+.Sx White Space Splitting
+section for more details.
+.It Ev TERM
+The default terminal setting for the shell.
+This is inherited by
+children of the shell, and is used in the history editing modes.
+.It Ev HISTSIZE
+The number of lines in the history buffer for the shell.
+.El
+.Sh FILES
+.Bl -item
+.It
+.Pa $HOME/.profile
+.It
+.Pa /etc/profile
+.El
+.Sh EXIT STATUS
+Errors that are detected by the shell, such as a syntax error, will cause the
+shell to exit with a non-zero exit status.
+If the shell is not an
+interactive shell, the execution of the shell file will be aborted.
+Otherwise
+the shell will return the exit status of the last command executed, or
+if the exit built-in is used with a numeric argument, it will return the
+argument.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr echo 1 ,
+.Xr getopt 1 ,
+.Xr ksh 1 ,
+.Xr login 1 ,
+.Xr printf 1 ,
+.Xr test 1 ,
+.Xr editline 3 ,
+.Xr getopt 3 ,
+.\" .Xr profile 4 ,
+.Xr editrc 5 ,
+.Xr passwd 5 ,
+.Xr environ 7 ,
+.Xr nls 7 ,
+.Xr sysctl 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
+It was, however, unmaintainable so we wrote this one.
+.Sh BUGS
+Setuid shell scripts should be avoided at all costs, as they are a
+significant security risk.
+.Pp
+PS1, PS2, and PS4 should be subject to parameter expansion before
+being displayed.
+.Pp
+The characters generated by filename completion should probably be quoted
+to ensure that the filename is still valid after the input line has been
+processed.
similarity index 66%
rename from minix/commands/ash/shell.h
rename to bin/sh/shell.h
index 9d76acf0de1933d3a2dcc35cec36e02a86a6d483..4df721a80e239f0716ce8987a2b41c4d5dfd9a85 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: shell.h,v 1.18 2013/04/28 17:01:28 dholland Exp $      */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)shell.h     8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/shell.h,v 1.17 2004/04/06 20:06:51 markm Exp $
  */
 
-#include <sys/types.h> /* for mode_t */
-
 /*
  * The follow should be set to reflect the type of system you have:
  *     JOBS -> 1 if you have Berkeley job control, 0 otherwise.
- *     TILDE -> 1 if you want the shell to expand ~logname.
- *     USEGETPW -> 1 if getpwnam() must be used to look up a name.
- *     READLINE -> 1 if line editing by readline() should be enabled.
+ *     SHORTNAMES -> 1 if your linker cannot handle long names.
  *     define BSD if you are running 4.2 BSD or later.
  *     define SYSV if you are running under System V.
- *     define DEBUG=1 to compile in debugging (set global "debug" to turn on)
+ *     define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
  *     define DEBUG=2 to compile in and turn on debugging.
+ *     define DO_SHAREDVFORK to indicate that vfork(2) shares its address
+ *            with its parent.
  *
- * When debugging is on, debugging info will be written to $HOME/trace and
+ * When debugging is on, debugging info will be written to ./trace and
  * a quit signal will generate a core dump.
  */
 
-#ifndef JOBS
-#define        JOBS 1
-#endif
+#include <sys/param.h>
+
+#if defined(__minix)
+#define JOBS 0
+#else
+#define JOBS 1
+#endif /* defined(__minix) */
 #ifndef BSD
 #define BSD 1
 #endif
-#ifndef DEBUG
-#define DEBUG 0
-#endif
-#define POSIX 1
 
-/*
- * Type of used arithmetics. SUSv3 requires us to have at least signed long.
- */
-typedef long arith_t;
-#define        ARITH_FORMAT_STR  "%ld"
-#define        atoarith_t(arg)  strtol(arg, NULL, 0)
-#define        strtoarith_t(nptr, endptr, base)  strtol(nptr, endptr, base)
+#ifndef DO_SHAREDVFORK
+#if !defined(__minix)
+#if __NetBSD_Version__ >= 104000000
+#define DO_SHAREDVFORK
+#endif
+#endif /* !defined(__minix) */
+#endif
 
 typedef void *pointer;
-#define STATIC  static
-#define MKINIT  /* empty */
+#ifndef NULL
+#define NULL (void *)0
+#endif
+#define STATIC /* empty */
+#define MKINIT /* empty */
+
+#include <sys/cdefs.h>
 
-extern char nullstr[1];                /* null string */
+extern const char nullstr[1];          /* null string */
 
-#if DEBUG
-#define TRACE(param)  sh_trace param
+
+#ifdef DEBUG
+#define TRACE(param)   trace param
+#define TRACEV(param)  tracev param
 #else
 #define TRACE(param)
+#define TRACEV(param)
 #endif
-
-/*
- * $PchId: shell.h,v 1.7 2006/05/22 12:47:00 philip Exp $
- */
similarity index 83%
rename from minix/commands/ash/show.c
rename to bin/sh/show.c
index 1b848927e831590cd68acdc4058fcabc57b2175b..9c008715dc2aaa067bdb7a6920e0a0c4bf79cd5a 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: show.c,v 1.28 2011/08/23 10:01:32 christos Exp $       */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)show.c     8.3 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: show.c,v 1.28 2011/08/23 10:01:32 christos Exp $");
 #endif
 #endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/show.c,v 1.21 2004/04/06 20:06:51 markm Exp $");
-*/
 
-#include <fcntl.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <stdarg.h>
-#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
 
 #include "shell.h"
 #include "parser.h"
 #include "nodes.h"
 #include "mystring.h"
 #include "show.h"
+#include "options.h"
+
 
-#if DEBUG
-static void trputc(int c);
+#ifdef DEBUG
 static void shtree(union node *, int, char *, FILE*);
 static void shcmd(union node *, FILE *);
 static void sharg(union node *, FILE *);
 static void indent(int, char *, FILE *);
 static void trstring(char *);
-static void showtree(union node *n);
 
 
-static void
+void
 showtree(union node *n)
 {
        trputs("showtree called\n");
@@ -74,7 +74,7 @@ static void
 shtree(union node *n, int ind, char *pfx, FILE *fp)
 {
        struct nodelist *lp;
-       char *s;
+       const char *s;
 
        if (n == NULL)
                return;
@@ -126,7 +126,7 @@ shcmd(union node *cmd, FILE *fp)
 {
        union node *np;
        int first;
-       char *s;
+       const char *s;
        int dftfd;
 
        first = 1;
@@ -141,22 +141,19 @@ shcmd(union node *cmd, FILE *fp)
                        putchar(' ');
                switch (np->nfile.type) {
                        case NTO:       s = ">";  dftfd = 1; break;
+                       case NCLOBBER:  s = ">|"; dftfd = 1; break;
                        case NAPPEND:   s = ">>"; dftfd = 1; break;
                        case NTOFD:     s = ">&"; dftfd = 1; break;
-                       case NCLOBBER:  s = ">|"; dftfd = 1; break;
                        case NFROM:     s = "<";  dftfd = 0; break;
-                       case NFROMTO:   s = "<>"; dftfd = 0; break;
                        case NFROMFD:   s = "<&"; dftfd = 0; break;
+                       case NFROMTO:   s = "<>"; dftfd = 0; break;
                        default:        s = "*error*"; dftfd = 0; break;
                }
                if (np->nfile.fd != dftfd)
                        fprintf(fp, "%d", np->nfile.fd);
                fputs(s, fp);
                if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
-                       if (np->ndup.dupfd >= 0)
-                               fprintf(fp, "%d", np->ndup.dupfd);
-                       else
-                               fprintf(fp, "-");
+                       fprintf(fp, "%d", np->ndup.dupfd);
                } else {
                        sharg(np->nfile.fname, fp);
                }
@@ -175,7 +172,6 @@ sharg(union node *arg, FILE *fp)
 
        if (arg->type != NARG) {
                printf("<node type %d>\n", arg->type);
-               fflush(stdout);
                abort();
        }
        bqlist = arg->narg.backquote;
@@ -262,6 +258,8 @@ indent(int amount, char *pfx, FILE *fp)
                putc('\t', fp);
        }
 }
+#endif
+
 
 
 /*
@@ -271,46 +269,52 @@ indent(int amount, char *pfx, FILE *fp)
 
 FILE *tracefile;
 
-#if DEBUG == 2
-int debug = 1;
-#else
-int debug = 0;
-#endif
-
 
-static void
+#ifdef DEBUG
+void
 trputc(int c)
 {
-       if (tracefile == NULL)
+       if (debug != 1 || !tracefile)
                return;
        putc(c, tracefile);
-       if (c == '\n')
-               fflush(tracefile);
 }
-
+#endif
 
 void
-sh_trace(const char *fmt, ...)
+trace(const char *fmt, ...)
 {
+#ifdef DEBUG
        va_list va;
+
+       if (debug != 1 || !tracefile)
+               return;
        va_start(va, fmt);
-       if (tracefile != NULL) {
-               (void) vfprintf(tracefile, fmt, va);
-               if (strchr(fmt, '\n'))
-                       (void) fflush(tracefile);
-       }
+       (void) vfprintf(tracefile, fmt, va);
        va_end(va);
+#endif
+}
+
+void
+tracev(const char *fmt, va_list va)
+{
+#ifdef DEBUG
+       va_list ap;
+       if (debug != 1 || !tracefile)
+               return;
+       va_copy(ap, va);
+       (void) vfprintf(tracefile, fmt, ap);
+       va_end(ap);
+#endif
 }
 
 
+#ifdef DEBUG
 void
-trputs(char *s)
+trputs(const char *s)
 {
-       if (tracefile == NULL)
+       if (debug != 1 || !tracefile)
                return;
        fputs(s, tracefile);
-       if (strchr(s, '\n'))
-               fflush(tracefile);
 }
 
 
@@ -320,7 +324,7 @@ trstring(char *s)
        char *p;
        char c;
 
-       if (tracefile == NULL)
+       if (debug != 1 || !tracefile)
                return;
        putc('"', tracefile);
        for (p = s ; *p ; p++) {
@@ -352,12 +356,14 @@ backslash:          putc('\\', tracefile);
        }
        putc('"', tracefile);
 }
+#endif
 
 
 void
 trargs(char **ap)
 {
-       if (tracefile == NULL)
+#ifdef DEBUG
+       if (debug != 1 || !tracefile)
                return;
        while (*ap) {
                trstring(*ap++);
@@ -366,18 +372,25 @@ trargs(char **ap)
                else
                        putc('\n', tracefile);
        }
-       fflush(tracefile);
+#endif
 }
 
 
+#ifdef DEBUG
 void
 opentrace(void)
 {
        char s[100];
+#ifdef O_APPEND
        int flags;
+#endif
 
-       if (!debug)
+       if (debug != 1) {
+               if (tracefile)
+                       fflush(tracefile);
+               /* leave open because libedit might be using it */
                return;
+       }
 #ifdef not_this_way
        {
                char *p;
@@ -391,19 +404,27 @@ opentrace(void)
                strcat(s, "/trace");
        }
 #else
-       scopy("./trace", s);
+       snprintf(s, sizeof(s), "./trace.%d", (int)getpid());
 #endif /* not_this_way */
-       if ((tracefile = fopen(s, "a")) == NULL) {
-               fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
-               return;
+       if (tracefile) {
+               if (!freopen(s, "a", tracefile)) {
+                       fprintf(stderr, "Can't re-open %s\n", s);
+                       tracefile = NULL;
+                       debug = 0;
+                       return;
+               }
+       } else {
+               if ((tracefile = fopen(s, "a")) == NULL) {
+                       fprintf(stderr, "Can't open %s\n", s);
+                       debug = 0;
+                       return;
+               }
        }
+#ifdef O_APPEND
        if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
                fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
+#endif
+       setlinebuf(tracefile);
        fputs("\nTracing started.\n", tracefile);
-       fflush(tracefile);
 }
 #endif /* DEBUG */
-
-/*
- * $PchId: show.c,v 1.6 2006/05/22 12:27:51 philip Exp $
- */
similarity index 84%
rename from minix/commands/ash/show.h
rename to bin/sh/show.h
index 59cb3e752c4dccad6f270f88c73e3749d5c1f3cb..3152ff277f3659a66ed9962f1a5ec483b185dd04 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: show.h,v 1.7 2003/08/07 09:05:38 agc Exp $     */
+
 /*-
  * Copyright (c) 1995
  *      The Regents of the University of California.  All rights reserved.
@@ -10,7 +12,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)show.h      1.1 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/show.h,v 1.11 2004/04/06 20:06:51 markm Exp $
  */
 
-#ifdef DEBUG
-void sh_trace(const char *, ...);
+#include <stdarg.h>
+
+union node;
+void showtree(union node *);
+void trace(const char *, ...);
+void tracev(const char *, va_list);
 void trargs(char **);
-void trputs(char *);
+#ifdef DEBUG
+void trputc(int);
+void trputs(const char *);
 void opentrace(void);
 #endif
-
-/*
- * $PchId: show.h,v 1.4 2006/03/29 13:28:45 philip Exp $
- */
diff --git a/bin/sh/syntax.c b/bin/sh/syntax.c
new file mode 100644 (file)
index 0000000..e064729
--- /dev/null
@@ -0,0 +1,105 @@
+/*     $NetBSD: syntax.c,v 1.3 2012/03/28 20:11:25 christos Exp $      */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: syntax.c,v 1.3 2012/03/28 20:11:25 christos Exp $");
+
+#include <limits.h>
+#include "shell.h"
+#include "syntax.h"
+#include "parser.h"
+
+#if CWORD != 0
+#error initialisation assumes 'CWORD' is zero
+#endif
+
+#define ndx(ch) (ch + 1 - CHAR_MIN)
+#define set(ch, val) [ndx(ch)] = val,
+#define set_range(s, e, val) [ndx(s) ... ndx(e)] = val,
+
+/* syntax table used when not in quotes */
+const char basesyntax[257] = { CEOF,
+    set_range(CTL_FIRST, CTL_LAST, CCTL)
+    set('\n', CNL)
+    set('\\', CBACK)
+    set('\'', CSQUOTE)
+    set('"', CDQUOTE)
+    set('`', CBQUOTE)
+    set('$', CVAR)
+    set('}', CENDVAR)
+    set('<', CSPCL)
+    set('>', CSPCL)
+    set('(', CSPCL)
+    set(')', CSPCL)
+    set(';', CSPCL)
+    set('&', CSPCL)
+    set('|', CSPCL)
+    set(' ', CSPCL)
+    set('\t', CSPCL)
+};
+
+/* syntax table used when in double quotes */
+const char dqsyntax[257] = { CEOF,
+    set_range(CTL_FIRST, CTL_LAST, CCTL)
+    set('\n', CNL)
+    set('\\', CBACK)
+    set('"', CDQUOTE)
+    set('`', CBQUOTE)
+    set('$', CVAR)
+    set('}', CENDVAR)
+    /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+    set('!', CCTL)
+    set('*', CCTL)
+    set('?', CCTL)
+    set('[', CCTL)
+    set('=', CCTL)
+    set('~', CCTL)
+    set(':', CCTL)
+    set('/', CCTL)
+    set('-', CCTL)
+};
+
+/* syntax table used when in single quotes */
+const char sqsyntax[257] = { CEOF,
+    set_range(CTL_FIRST, CTL_LAST, CCTL)
+    set('\n', CNL)
+    set('\'', CSQUOTE)
+    /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
+    set('!', CCTL)
+    set('*', CCTL)
+    set('?', CCTL)
+    set('[', CCTL)
+    set('=', CCTL)
+    set('~', CCTL)
+    set(':', CCTL)
+    set('/', CCTL)
+    set('-', CCTL)
+};
+
+/* syntax table used when in arithmetic */
+const char arisyntax[257] = { CEOF,
+    set_range(CTL_FIRST, CTL_LAST, CCTL)
+    set('\n', CNL)
+    set('\\', CBACK)
+    set('`', CBQUOTE)
+    set('\'', CSQUOTE)
+    set('"', CDQUOTE)
+    set('$', CVAR)
+    set('}', CENDVAR)
+    set('(', CLP)
+    set(')', CRP)
+};
+
+/* character classification table */
+const char is_type[257] = { 0,
+    set_range('0', '9', ISDIGIT)
+    set_range('a', 'z', ISLOWER)
+    set_range('A', 'Z', ISUPPER)
+    set('_', ISUNDER)
+    set('#', ISSPECL)
+    set('?', ISSPECL)
+    set('$', ISSPECL)
+    set('!', ISSPECL)
+    set('-', ISSPECL)
+    set('*', ISSPECL)
+    set('@', ISSPECL)
+};
diff --git a/bin/sh/syntax.h b/bin/sh/syntax.h
new file mode 100644 (file)
index 0000000..89a32dc
--- /dev/null
@@ -0,0 +1,83 @@
+/*     $NetBSD: syntax.h,v 1.2 2004/01/17 17:38:12 dsl Exp $   */
+
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <ctype.h>
+
+/* Syntax classes */
+#define CWORD 0                        /* character is nothing special */
+#define CNL 1                  /* newline character */
+#define CBACK 2                        /* a backslash character */
+#define CSQUOTE 3              /* single quote */
+#define CDQUOTE 4              /* double quote */
+#define CBQUOTE 5              /* backwards single quote */
+#define CVAR 6                 /* a dollar sign */
+#define CENDVAR 7              /* a '}' character */
+#define CLP 8                  /* a left paren in arithmetic */
+#define CRP 9                  /* a right paren in arithmetic */
+#define CEOF 10                        /* end of file */
+#define CCTL 11                        /* like CWORD, except it must be escaped */
+#define CSPCL 12               /* these terminate a word */
+
+/* Syntax classes for is_ functions */
+#define ISDIGIT 01             /* a digit */
+#define ISUPPER 02             /* an upper case letter */
+#define ISLOWER 04             /* a lower case letter */
+#define ISUNDER 010            /* an underscore */
+#define ISSPECL 020            /* the name of a special parameter */
+
+#define PEOF (CHAR_MIN - 1)
+#define SYNBASE (-PEOF)
+/* XXX UPEOF is CHAR_MAX, so is a valid 'char' value... */
+#define UPEOF ((char)PEOF)
+
+
+#define BASESYNTAX (basesyntax + SYNBASE)
+#define DQSYNTAX (dqsyntax + SYNBASE)
+#define SQSYNTAX (sqsyntax + SYNBASE)
+#define ARISYNTAX (arisyntax + SYNBASE)
+
+/* These defines assume that the digits are contiguous */
+#define is_digit(c)    ((unsigned)((c) - '0') <= 9)
+#define is_alpha(c)    (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && isalpha((unsigned char)(c)))
+#define is_name(c)     (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalpha((unsigned char)(c))))
+#define is_in_name(c)  (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalnum((unsigned char)(c))))
+#define is_special(c)  ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
+#define digit_val(c)   ((c) - '0')
+
+extern const char basesyntax[];
+extern const char dqsyntax[];
+extern const char sqsyntax[];
+extern const char arisyntax[];
+extern const char is_type[];
diff --git a/bin/sh/trap.c b/bin/sh/trap.c
new file mode 100644 (file)
index 0000000..d48b94b
--- /dev/null
@@ -0,0 +1,475 @@
+/*     $NetBSD: trap.c,v 1.35 2011/06/18 21:18:46 christos Exp $       */
+
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)trap.c     8.5 (Berkeley) 6/5/95";
+#else
+__RCSID("$NetBSD: trap.c,v 1.35 2011/06/18 21:18:46 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"     /* for other headers */
+#include "eval.h"
+#include "jobs.h"
+#include "show.h"
+#include "options.h"
+#include "builtins.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "trap.h"
+#include "mystring.h"
+#include "var.h"
+
+
+/*
+ * Sigmode records the current value of the signal handlers for the various
+ * modes.  A value of zero means that the current handler is not known.
+ * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
+ */
+
+#define S_DFL 1                        /* default signal handling (SIG_DFL) */
+#define S_CATCH 2              /* signal is caught */
+#define S_IGN 3                        /* signal is ignored (SIG_IGN) */
+#define S_HARD_IGN 4           /* signal is ignored permenantly */
+#define S_RESET 5              /* temporary - to reset a hard ignored sig */
+
+
+char *trap[NSIG+1];            /* trap handler commands */
+MKINIT char sigmode[NSIG];     /* current value of signal */
+volatile char gotsig[NSIG];    /* indicates specified signal received */
+int pendingsigs;               /* indicates some signal received */
+
+static int getsigaction(int, sig_t *);
+
+/*
+ * return the signal number described by `p' (as a number or a name)
+ * or -1 if it isn't one
+ */
+
+static int
+signame_to_signum(const char *p)
+{
+       int i;
+
+       if (is_number(p))
+               return number(p);
+
+       if (strcasecmp(p, "exit") == 0 )
+               return 0;
+       
+       if (strncasecmp(p, "sig", 3) == 0)
+               p += 3;
+
+       for (i = 0; i < NSIG; ++i)
+               if (strcasecmp (p, sys_signame[i]) == 0)
+                       return i;
+       return -1;
+}
+
+/*
+ * Print a list of valid signal names
+ */
+static void
+printsignals(void)
+{
+       int n;
+
+       out1str("EXIT ");
+
+       for (n = 1; n < NSIG; n++) {
+               out1fmt("%s", sys_signame[n]);
+               if ((n == NSIG/2) ||  n == (NSIG - 1))
+                       out1str("\n");
+               else
+                       out1c(' ');
+       }
+}
+
+/*
+ * The trap builtin.
+ */
+
+int
+trapcmd(int argc, char **argv)
+{
+       char *action;
+       char **ap;
+       int signo;
+
+       if (argc <= 1) {
+               for (signo = 0 ; signo <= NSIG ; signo++)
+                       if (trap[signo] != NULL) {
+                               out1fmt("trap -- ");
+                               print_quoted(trap[signo]);
+                               out1fmt(" %s\n",
+                                   (signo) ? sys_signame[signo] : "EXIT");
+                       }
+               return 0;
+       }
+       ap = argv + 1;
+
+       action = NULL;
+
+       if (strcmp(*ap, "--") == 0)
+               if (*++ap == NULL)
+                       return 0;
+
+       if (signame_to_signum(*ap) == -1) {
+               if ((*ap)[0] == '-') {
+                       if ((*ap)[1] == '\0')
+                               ap++;
+                       else if ((*ap)[1] == 'l' && (*ap)[2] == '\0') {
+                               printsignals();
+                               return 0;
+                       }
+                       else
+                               error("bad option %s\n", *ap);
+               }
+               else
+                       action = *ap++;
+       }
+
+       while (*ap) {
+               if (is_number(*ap))
+                       signo = number(*ap);
+               else
+                       signo = signame_to_signum(*ap);
+
+               if (signo < 0 || signo > NSIG)
+                       error("%s: bad trap", *ap);
+
+               INTOFF;
+               if (action)
+                       action = savestr(action);
+
+               if (trap[signo])
+                       ckfree(trap[signo]);
+
+               trap[signo] = action;
+
+               if (signo != 0)
+                       setsignal(signo, 0);
+               INTON;
+               ap++;
+       }
+       return 0;
+}
+
+
+
+/*
+ * Clear traps on a fork or vfork.
+ * Takes one arg vfork, to tell it to not be destructive of
+ * the parents variables.
+ */
+
+void
+clear_traps(int vforked)
+{
+       char **tp;
+
+       for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
+               if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
+                       INTOFF;
+                       if (!vforked) {
+                               ckfree(*tp);
+                               *tp = NULL;
+                       }
+                       if (tp != &trap[0])
+                               setsignal(tp - trap, vforked);
+                       INTON;
+               }
+       }
+}
+
+
+
+/*
+ * Set the signal handler for the specified signal.  The routine figures
+ * out what it should be set to.
+ */
+
+sig_t
+setsignal(int signo, int vforked)
+{
+       int action;
+       sig_t sigact = SIG_DFL, sig;
+       char *t, tsig;
+
+       if ((t = trap[signo]) == NULL)
+               action = S_DFL;
+       else if (*t != '\0')
+               action = S_CATCH;
+       else
+               action = S_IGN;
+       if (rootshell && !vforked && action == S_DFL) {
+               switch (signo) {
+               case SIGINT:
+                       if (iflag || minusc || sflag == 0)
+                               action = S_CATCH;
+                       break;
+               case SIGQUIT:
+#ifdef DEBUG
+                       if (debug)
+                               break;
+#endif
+                       /* FALLTHROUGH */
+               case SIGTERM:
+                       if (iflag)
+                               action = S_IGN;
+                       break;
+#if JOBS
+               case SIGTSTP:
+               case SIGTTOU:
+                       if (mflag)
+                               action = S_IGN;
+                       break;
+#endif
+               }
+       }
+
+       t = &sigmode[signo - 1];
+       tsig = *t;
+       if (tsig == 0) {
+               /*
+                * current setting unknown
+                */
+               if (!getsigaction(signo, &sigact)) {
+                       /*
+                        * Pretend it worked; maybe we should give a warning
+                        * here, but other shells don't. We don't alter
+                        * sigmode, so that we retry every time.
+                        */
+                       return 0;
+               }
+               if (sigact == SIG_IGN) {
+                       /*
+                        * POSIX 3.14.13 states that non-interactive shells
+                        * should ignore trap commands for signals that were
+                        * ignored upon entry, and leaves the behavior
+                        * unspecified for interactive shells. On interactive
+                        * shells, or if job control is on, and we have a job
+                        * control related signal, we allow the trap to work.
+                        *
+                        * This change allows us to be POSIX compliant, and
+                        * at the same time override the default behavior if
+                        * we need to by setting the interactive flag.
+                        */
+                       if ((mflag && (signo == SIGTSTP ||
+                            signo == SIGTTIN || signo == SIGTTOU)) || iflag) {
+                               tsig = S_IGN;
+                       } else
+                               tsig = S_HARD_IGN;
+               } else {
+                       tsig = S_RESET; /* force to be set */
+               }
+       }
+       if (tsig == S_HARD_IGN || tsig == action)
+               return 0;
+       switch (action) {
+               case S_DFL:     sigact = SIG_DFL;       break;
+               case S_CATCH:   sigact = onsig;         break;
+               case S_IGN:     sigact = SIG_IGN;       break;
+       }
+       sig = signal(signo, sigact);
+       if (sig != SIG_ERR) {
+               sigset_t ss;
+               if (!vforked)
+                       *t = action;
+               if (action == S_CATCH)
+                       (void)siginterrupt(signo, 1);
+               /*
+                * If our parent accidentally blocked signals for
+                * us make sure we unblock them
+                */
+               (void)sigemptyset(&ss);
+               (void)sigaddset(&ss, signo);
+               (void)sigprocmask(SIG_UNBLOCK, &ss, NULL);
+       }
+       return sig;
+}
+
+/*
+ * Return the current setting for sig w/o changing it.
+ */
+static int
+getsigaction(int signo, sig_t *sigact)
+{
+       struct sigaction sa;
+
+       if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
+               return 0;
+       *sigact = (sig_t) sa.sa_handler;
+       return 1;
+}
+
+/*
+ * Ignore a signal.
+ */
+
+void
+ignoresig(int signo, int vforked)
+{
+       if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
+               signal(signo, SIG_IGN);
+       }
+       if (!vforked)
+               sigmode[signo - 1] = S_HARD_IGN;
+}
+
+
+#ifdef mkinit
+INCLUDE <signal.h>
+INCLUDE "trap.h"
+
+SHELLPROC {
+       char *sm;
+
+       clear_traps(0);
+       for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
+               if (*sm == S_IGN)
+                       *sm = S_HARD_IGN;
+       }
+}
+#endif
+
+
+
+/*
+ * Signal handler.
+ */
+
+void
+onsig(int signo)
+{
+       signal(signo, onsig);
+       if (signo == SIGINT && trap[SIGINT] == NULL) {
+               onint();
+               return;
+       }
+       gotsig[signo - 1] = 1;
+       pendingsigs++;
+}
+
+
+
+/*
+ * Called to execute a trap.  Perhaps we should avoid entering new trap
+ * handlers while we are executing a trap handler.
+ */
+
+void
+dotrap(void)
+{
+       int i;
+       int savestatus;
+
+       for (;;) {
+               for (i = 1 ; ; i++) {
+                       if (gotsig[i - 1])
+                               break;
+                       if (i >= NSIG)
+                               goto done;
+               }
+               gotsig[i - 1] = 0;
+               savestatus=exitstatus;
+               evalstring(trap[i], 0);
+               exitstatus=savestatus;
+       }
+done:
+       pendingsigs = 0;
+}
+
+
+
+/*
+ * Controls whether the shell is interactive or not.
+ */
+
+
+void
+setinteractive(int on)
+{
+       static int is_interactive;
+
+       if (on == is_interactive)
+               return;
+       setsignal(SIGINT, 0);
+       setsignal(SIGQUIT, 0);
+       setsignal(SIGTERM, 0);
+       is_interactive = on;
+}
+
+
+
+/*
+ * Called to exit the shell.
+ */
+
+void
+exitshell(int status)
+{
+       struct jmploc loc1, loc2;
+       char *p;
+
+       TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
+       if (setjmp(loc1.loc)) {
+               goto l1;
+       }
+       if (setjmp(loc2.loc)) {
+               goto l2;
+       }
+       handler = &loc1;
+       if ((p = trap[0]) != NULL && *p != '\0') {
+               trap[0] = NULL;
+               evalstring(p, 0);
+       }
+l1:   handler = &loc2;                 /* probably unnecessary */
+       flushall();
+#if JOBS
+       setjobctl(0);
+#endif
+l2:   _exit(status);
+       /* NOTREACHED */
+}
similarity index 80%
rename from minix/commands/ash/trap.h
rename to bin/sh/trap.h
index a61672ab61a7469ecd8f7367ae1a7c0b1d0a8b05..0a1d69875b690c714ada22b23e4e96a2a175a183 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: trap.h,v 1.20 2012/03/15 02:02:20 joerg Exp $  */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  *
  *     @(#)trap.h      8.3 (Berkeley) 6/5/95
- * $FreeBSD: src/bin/sh/trap.h,v 1.12 2004/04/06 20:06:51 markm Exp $
  */
 
 extern int pendingsigs;
-extern int in_dotrap;
-extern int is_interactive;
-extern volatile sig_atomic_t gotwinch;
 
-int trapcmd(int, char **);
-void clear_traps(void);
-void setsignal(int);
-void ignoresig(int);
+void clear_traps(int);
+sig_t setsignal(int, int);
+void ignoresig(int, int);
+void onsig(int);
 void dotrap(void);
 void setinteractive(int);
-void exitshell(int);
-char *strsiglist(int);
-
-/*
- * $PchId: trap.h,v 1.6 2006/05/22 12:48:30 philip Exp $
- */
+void exitshell(int) __dead;
similarity index 60%
rename from minix/commands/ash/var.c
rename to bin/sh/var.c
index 061d3a5a027e545f632333e31545edc396db213f..d2ff93a15f71b2124366eab3b1abbf5b55b6b5a7 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: var.c,v 1.43 2013/11/01 16:49:02 christos Exp $        */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)var.c      8.3 (Berkeley) 5/4/95";
+#else
+__RCSID("$NetBSD: var.c,v 1.43 2013/11/01 16:49:02 christos Exp $");
 #endif
 #endif /* not lint */
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/var.c,v 1.26.2.1 2004/09/30 04:41:55 des Exp $");
-*/
 
 #include <unistd.h>
 #include <stdlib.h>
-#ifndef NO_PATHS_H
+#include <string.h>
 #include <paths.h>
-#endif
+#include <limits.h>
 
 /*
  * Shell variables.
  */
 
-#include <locale.h>
-
 #include "shell.h"
 #include "output.h"
 #include "expand.h"
@@ -60,49 +59,57 @@ __FBSDID("$FreeBSD: src/bin/sh/var.c,v 1.26.2.1 2004/09/30 04:41:55 des Exp $");
 #include "exec.h"
 #include "syntax.h"
 #include "options.h"
+#include "builtins.h"
 #include "mail.h"
 #include "var.h"
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
 #include "parser.h"
-#if !defined(NO_HISTORY)
+#include "show.h"
+#ifndef SMALL
 #include "myhistedit.h"
 #endif
 
-#include "builtins.h"
-
-#ifndef _PATH_DEFPATH
-#define _PATH_DEFPATH "/usr/bin:/bin"
-#endif
-
+#ifdef SMALL
 #define VTABSIZE 39
+#else
+#define VTABSIZE 517
+#endif
 
 
 struct varinit {
        struct var *var;
        int flags;
-       char *text;
+       const char *text;
        void (*func)(const char *);
 };
 
+struct localvar *localvars;
 
-#ifndef NO_HISTORY
+#if ATTY
+struct var vatty;
+#endif
+#ifndef SMALL
 struct var vhistsize;
+struct var vterm;
 #endif
 struct var vifs;
 struct var vmail;
 struct var vmpath;
 struct var vpath;
-struct var vppid;
 struct var vps1;
 struct var vps2;
-struct var vpse;
+struct var vps4;
 struct var vvers;
-STATIC struct var voptind;
+struct var voptind;
 
-STATIC const struct varinit varinit[] = {
-#if !defined(NO_HISTORY)
+const struct varinit varinit[] = {
+#if ATTY
+       { &vatty,       VSTRFIXED|VTEXTFIXED|VUNSET,    "ATTY=",
+         NULL },
+#endif
+#ifndef SMALL
        { &vhistsize,   VSTRFIXED|VTEXTFIXED|VUNSET,    "HISTSIZE=",
          sethistsize },
 #endif
@@ -114,26 +121,27 @@ STATIC const struct varinit varinit[] = {
          NULL },
        { &vpath,       VSTRFIXED|VTEXTFIXED,           "PATH=" _PATH_DEFPATH,
          changepath },
-       { &vppid,       VSTRFIXED|VTEXTFIXED|VUNSET,    "PPID=",
-         NULL },
        /*
         * vps1 depends on uid
         */
        { &vps2,        VSTRFIXED|VTEXTFIXED,           "PS2=> ",
          NULL },
-       { &vpse,        VSTRFIXED|VTEXTFIXED|VUNSET,    "PSE=",
+       { &vps4,        VSTRFIXED|VTEXTFIXED,           "PS4=+ ",
          NULL },
-       { &voptind,     VSTRFIXED|VTEXTFIXED,           "OPTIND=1",
+#ifndef SMALL
+       { &vterm,       VSTRFIXED|VTEXTFIXED|VUNSET,    "TERM=",
+         setterm },
+#endif
+       { &voptind,     VSTRFIXED|VTEXTFIXED|VNOFUNC,   "OPTIND=1",
          getoptsreset },
        { NULL, 0,                              NULL,
          NULL }
 };
 
-STATIC struct var *vartab[VTABSIZE];
+struct var *vartab[VTABSIZE];
 
-STATIC struct var **hashvar(char *);
-STATIC int varequal(char *, char *);
-STATIC int localevar(char *);
+STATIC int strequal(const char *, const char *);
+STATIC struct var *find_var(const char *, struct var ***, int *);
 
 /*
  * Initialize the varable symbol tables and import the environment
@@ -141,9 +149,9 @@ STATIC int localevar(char *);
 
 #ifdef mkinit
 INCLUDE "var.h"
+MKINIT char **environ;
 INIT {
        char **envp;
-       extern char **environ;
 
        initvar();
        for (envp = environ ; *envp ; envp++) {
@@ -163,35 +171,28 @@ INIT {
 void
 initvar(void)
 {
-       char ppid[20];
        const struct varinit *ip;
        struct var *vp;
        struct var **vpp;
 
        for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
-               if ((vp->flags & VEXPORT) == 0) {
-                       vpp = hashvar(ip->text);
-                       vp->next = *vpp;
-                       *vpp = vp;
-                       vp->text = ip->text;
-                       vp->flags = ip->flags;
-                       vp->func = ip->func;
-               }
+               if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
+                       continue;
+               vp->next = *vpp;
+               *vpp = vp;
+               vp->text = strdup(ip->text);
+               vp->flags = ip->flags;
+               vp->func = ip->func;
        }
        /*
         * PS1 depends on uid
         */
-       if ((vps1.flags & VEXPORT) == 0) {
-               vpp = hashvar("PS1=");
+       if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
                vps1.next = *vpp;
                *vpp = &vps1;
-               vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
+               vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
                vps1.flags = VSTRFIXED|VTEXTFIXED;
        }
-       if ((vppid.flags & VEXPORT) == 0) {
-               fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
-               setvarsafe("PPID", ppid, 0);
-       }
 }
 
 /*
@@ -199,15 +200,11 @@ initvar(void)
  */
 
 int
-setvarsafe(char *name, char *val, int flags)
+setvarsafe(const char *name, const char *val, int flags)
 {
        struct jmploc jmploc;
        struct jmploc *volatile savehandler = handler;
-       int err = 0;
-#if __GNUC__
-       /* Avoid longjmp clobbering */
-       (void) &err;
-#endif
+       int volatile err = 0;
 
        if (setjmp(jmploc.loc))
                err = 1;
@@ -220,14 +217,16 @@ setvarsafe(char *name, char *val, int flags)
 }
 
 /*
- * Set the value of a variable.  The flags argument is tored with the
+ * Set the value of a variable.  The flags argument is ored with the
  * flags of the variable.  If val is NULL, the variable is unset.
  */
 
 void
-setvar(char *name, char *val, int flags)
+setvar(const char *name, const char *val, int flags)
 {
-       char *p, *q;
+       const char *p;
+       const char *q;
+       char *d;
        int len;
        int namelen;
        char *nameeq;
@@ -255,37 +254,18 @@ setvar(char *name, char *val, int flags)
        } else {
                len += strlen(val);
        }
-       p = nameeq = ckmalloc(len);
+       d = nameeq = ckmalloc(len);
        q = name;
        while (--namelen >= 0)
-               *p++ = *q++;
-       *p++ = '=';
-       *p = '\0';
+               *d++ = *q++;
+       *d++ = '=';
+       *d = '\0';
        if (val)
-               scopy(val, p);
+               scopy(val, d);
        setvareq(nameeq, flags);
 }
 
-STATIC int
-localevar(char *s)
-{
-       static char *lnames[7] = {
-               "ALL", "COLLATE", "CTYPE", "MONETARY",
-               "NUMERIC", "TIME", NULL
-       };
-       char **ss;
 
-       if (*s != 'L')
-               return 0;
-       if (varequal(s + 1, "ANG"))
-               return 1;
-       if (strncmp(s + 1, "C_", 2) != 0)
-               return 0;
-       for (ss = lnames; *ss ; ss++)
-               if (varequal(s + 3, *ss))
-                       return 1;
-       return 0;
-}
 
 /*
  * Same as setvar except that the variable and value are passed in
@@ -298,56 +278,47 @@ void
 setvareq(char *s, int flags)
 {
        struct var *vp, **vpp;
-       int len;
+       int nlen;
 
        if (aflag)
                flags |= VEXPORT;
-       vpp = hashvar(s);
-       for (vp = *vpp ; vp ; vp = vp->next) {
-               if (varequal(s, vp->text)) {
-                       if (vp->flags & VREADONLY) {
-                               len = strchr(s, '=') - s;
-                               error("%.*s: is read only", len, s);
-                       }
-                       INTOFF;
-
-                       if (vp->func && (flags & VNOFUNC) == 0)
-                               (*vp->func)(strchr(s, '=') + 1);
-
-                       if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
-                               ckfree(vp->text);
-
-                       vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
-                       vp->flags |= flags;
-                       vp->text = s;
-
-                       /*
-                        * We could roll this to a function, to handle it as
-                        * a regular variable function callback, but why bother?
-                        */
-                       if (vp == &vmpath || (vp == &vmail && ! mpathset()))
-                               chkmail(1);
-                       if ((vp->flags & VEXPORT) && localevar(s)) {
-                               putenv(s);
-                               (void) setlocale(LC_ALL, "");
-                       }
-                       INTON;
+       vp = find_var(s, &vpp, &nlen);
+       if (vp != NULL) {
+               if (vp->flags & VREADONLY)
+                       error("%.*s: is read only", vp->name_len, s);
+               if (flags & VNOSET)
                        return;
-               }
+               INTOFF;
+
+               if (vp->func && (flags & VNOFUNC) == 0)
+                       (*vp->func)(s + vp->name_len + 1);
+
+               if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+                       ckfree(vp->text);
+
+               vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
+               vp->flags |= flags & ~VNOFUNC;
+               vp->text = s;
+
+               /*
+                * We could roll this to a function, to handle it as
+                * a regular variable function callback, but why bother?
+                */
+               if (vp == &vmpath || (vp == &vmail && ! mpathset()))
+                       chkmail(1);
+               INTON;
+               return;
        }
        /* not found */
+       if (flags & VNOSET)
+               return;
        vp = ckmalloc(sizeof (*vp));
-       vp->flags = flags;
+       vp->flags = flags & ~VNOFUNC;
        vp->text = s;
+       vp->name_len = nlen;
        vp->next = *vpp;
        vp->func = NULL;
-       INTOFF;
        *vpp = vp;
-       if ((vp->flags & VEXPORT) && localevar(s)) {
-               putenv(s);
-               (void) setlocale(LC_ALL, "");
-       }
-       INTON;
 }
 
 
@@ -357,17 +328,25 @@ setvareq(char *s, int flags)
  */
 
 void
-listsetvar(struct strlist *list)
+listsetvar(struct strlist *list, int flags)
 {
        struct strlist *lp;
 
        INTOFF;
        for (lp = list ; lp ; lp = lp->next) {
-               setvareq(savestr(lp->text), 0);
+               setvareq(savestr(lp->text), flags);
        }
        INTON;
 }
 
+void
+listmklocal(struct strlist *list, int flags)
+{
+       struct strlist *lp;
+
+       for (lp = list ; lp ; lp = lp->next)
+               mklocal(lp->text, flags);
+}
 
 
 /*
@@ -375,18 +354,14 @@ listsetvar(struct strlist *list)
  */
 
 char *
-lookupvar(char *name)
+lookupvar(const char *name)
 {
        struct var *v;
 
-       for (v = *hashvar(name) ; v ; v = v->next) {
-               if (varequal(v->text, name)) {
-                       if (v->flags & VUNSET)
-                               return NULL;
-                       return strchr(v->text, '=') + 1;
-               }
-       }
-       return NULL;
+       v = find_var(name, NULL, NULL);
+       if (v == NULL || v->flags & VUNSET)
+               return NULL;
+       return v->text + v->name_len + 1;
 }
 
 
@@ -398,24 +373,21 @@ lookupvar(char *name)
  */
 
 char *
-bltinlookup(char *name, int doall)
+bltinlookup(const char *name, int doall)
 {
        struct strlist *sp;
        struct var *v;
 
        for (sp = cmdenviron ; sp ; sp = sp->next) {
-               if (varequal(sp->text, name))
+               if (strequal(sp->text, name))
                        return strchr(sp->text, '=') + 1;
        }
-       for (v = *hashvar(name) ; v ; v = v->next) {
-               if (varequal(v->text, name)) {
-                       if ((v->flags & VUNSET)
-                        || (!doall && (v->flags & VEXPORT) == 0))
-                               return NULL;
-                       return strchr(v->text, '=') + 1;
-               }
-       }
-       return NULL;
+
+       v = find_var(name, NULL, NULL);
+
+       if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT)))
+               return NULL;
+       return v->text + v->name_len + 1;
 }
 
 
@@ -431,7 +403,8 @@ environment(void)
        int nenv;
        struct var **vpp;
        struct var *vp;
-       char **env, **ep;
+       char **env;
+       char **ep;
 
        nenv = 0;
        for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
@@ -457,6 +430,8 @@ environment(void)
  */
 
 #ifdef mkinit
+void shprocvar(void);
+
 SHELLPROC {
        shprocvar();
 }
@@ -496,24 +471,94 @@ shprocvar(void)
  * any variables.
  */
 
+void
+print_quoted(const char *p)
+{
+       const char *q;
+
+       if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) {
+               out1fmt("%s", p);
+               return;
+       }
+       while (*p) {
+               if (*p == '\'') {
+                       out1fmt("\\'");
+                       p++;
+                       continue;
+               }
+               q = strchr(p, '\'');
+               if (!q) {
+                       out1fmt("'%s'", p );
+                       return;
+               }
+               out1fmt("'%.*s'", (int)(q - p), p );
+               p = q;
+       }
+}
+
+static int
+sort_var(const void *v_v1, const void *v_v2)
+{
+       const struct var * const *v1 = v_v1;
+       const struct var * const *v2 = v_v2;
+
+       /* XXX Will anyone notice we include the '=' of the shorter name? */
+       return strcoll((*v1)->text, (*v2)->text);
+}
+
+/*
+ * POSIX requires that 'set' (but not export or readonly) output the
+ * variables in lexicographic order - by the locale's collating order (sigh).
+ * Maybe we could keep them in an ordered balanced binary tree
+ * instead of hashed lists.
+ * For now just roll 'em through qsort for printing...
+ */
+
 int
-showvarscmd(int argc __unused, char **argv __unused)
+showvars(const char *name, int flag, int show_value)
 {
        struct var **vpp;
        struct var *vp;
-       const char *s;
+       const char *p;
+
+       static struct var **list;       /* static in case we are interrupted */
+       static int list_len;
+       int count = 0;
+
+       if (!list) {
+               list_len = 32;
+               list = ckmalloc(list_len * sizeof *list);
+       }
 
        for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
                for (vp = *vpp ; vp ; vp = vp->next) {
-                       if (vp->flags & VUNSET)
+                       if (flag && !(vp->flags & flag))
+                               continue;
+                       if (vp->flags & VUNSET && !(show_value & 2))
                                continue;
-                       for (s = vp->text; *s != '='; s++)
-                               out1c(*s);
-                       out1c('=');
-                       out1qstr(s + 1);
-                       out1c('\n');
+                       if (count >= list_len) {
+                               list = ckrealloc(list,
+                                       (list_len << 1) * sizeof *list);
+                               list_len <<= 1;
+                       }
+                       list[count++] = vp;
                }
        }
+
+       qsort(list, count, sizeof *list, sort_var);
+
+       for (vpp = list; count--; vpp++) {
+               vp = *vpp;
+               if (name)
+                       out1fmt("%s ", name);
+               for (p = vp->text ; *p != '=' ; p++)
+                       out1c(*p);
+               if (!(vp->flags & VUNSET) && show_value) {
+                       out1fmt("=");
+                       print_quoted(++p);
+               }
+               out1c('\n');
+       }
        return 0;
 }
 
@@ -526,71 +571,29 @@ showvarscmd(int argc __unused, char **argv __unused)
 int
 exportcmd(int argc, char **argv)
 {
-       struct var **vpp;
        struct var *vp;
        char *name;
-       char *p;
-       char *cmdname;
-       int ch, values;
+       const char *p;
        int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
+       int pflag;
 
-       cmdname = argv[0];
-       optreset = optind = 1;
-       opterr = 0;
-       values = 0;
-       while ((ch = getopt(argc, argv, "p")) != -1) {
-               switch (ch) {
-               case 'p':
-                       values = 1;
-                       break;
-               case '?':
-               default:
-                       error("unknown option: -%c", optopt);
-               }
+       pflag = nextopt("p") == 'p' ? 3 : 0;
+       if (argc <= 1 || pflag) {
+               showvars( pflag ? argv[0] : 0, flag, pflag );
+               return 0;
        }
-       argc -= optind;
-       argv += optind;
-
-       listsetvar(cmdenviron);
-       if (argc != 0) {
-               while ((name = *argptr++) != NULL) {
-                       if ((p = strchr(name, '=')) != NULL) {
-                               p++;
-                       } else {
-                               vpp = hashvar(name);
-                               for (vp = *vpp ; vp ; vp = vp->next) {
-                                       if (varequal(vp->text, name)) {
-
-                                               vp->flags |= flag;
-                                               if ((vp->flags & VEXPORT) && localevar(vp->text)) {
-                                                       putenv(vp->text);
-                                                       (void) setlocale(LC_ALL, "");
-                                               }
-                                               goto found;
-                                       }
-                               }
-                       }
-                       setvar(name, p, flag);
-found:;
-               }
-       } else {
-               for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-                       for (vp = *vpp ; vp ; vp = vp->next) {
-                               if (vp->flags & flag) {
-                                       if (values) {
-                                               out1str(cmdname);
-                                               out1c(' ');
-                                       }
-                                       for (p = vp->text ; *p != '=' ; p++)
-                                               out1c(*p);
-                                       if (values && !(vp->flags & VUNSET)) {
-                                               out1c('=');
-                                               out1qstr(p + 1);
-                                       }
-                                       out1c('\n');
-                               }
+
+       while ((name = *argptr++) != NULL) {
+               if ((p = strchr(name, '=')) != NULL) {
+                       p++;
+               } else {
+                       vp = find_var(name, NULL, NULL);
+                       if (vp != NULL) {
+                               vp->flags |= flag;
+                               continue;
                        }
                }
+               setvar(name, p, flag);
        }
        return 0;
 }
@@ -601,28 +604,28 @@ found:;
  */
 
 int
-localcmd(int argc __unused, char **argv __unused)
+localcmd(int argc, char **argv)
 {
        char *name;
 
        if (! in_function())
                error("Not in a function");
        while ((name = *argptr++) != NULL) {
-               mklocal(name);
+               mklocal(name, 0);
        }
        return 0;
 }
 
 
 /*
- * Make a variable a local variable.  When a variable is made local, it's
+ * Make a variable a local variable.  When a variable is made local, its
  * value and flags are saved in a localvar structure.  The saved values
  * will be restored when the shell function returns.  We handle the name
  * "-" as a special case.
  */
 
 void
-mklocal(char *name)
+mklocal(const char *name, int flags)
 {
        struct localvar *lvp;
        struct var **vpp;
@@ -631,17 +634,17 @@ mklocal(char *name)
        INTOFF;
        lvp = ckmalloc(sizeof (struct localvar));
        if (name[0] == '-' && name[1] == '\0') {
-               lvp->text = ckmalloc(sizeof optlist);
-               memcpy(lvp->text, optlist, sizeof optlist);
+               char *p;
+               p = ckmalloc(sizeof_optlist);
+               lvp->text = memcpy(p, optlist, sizeof_optlist);
                vp = NULL;
        } else {
-               vpp = hashvar(name);
-               for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
+               vp = find_var(name, &vpp, NULL);
                if (vp == NULL) {
                        if (strchr(name, '='))
-                               setvareq(savestr(name), VSTRFIXED);
+                               setvareq(savestr(name), VSTRFIXED|flags);
                        else
-                               setvar(name, NULL, VSTRFIXED);
+                               setvar(name, NULL, VSTRFIXED|flags);
                        vp = *vpp;      /* the new variable */
                        lvp->text = NULL;
                        lvp->flags = VUNSET;
@@ -649,8 +652,8 @@ mklocal(char *name)
                        lvp->text = vp->text;
                        lvp->flags = vp->flags;
                        vp->flags |= VSTRFIXED|VTEXTFIXED;
-                       if (strchr(name, '='))
-                               setvareq(savestr(name), 0);
+                       if (name[vp->name_len] == '=')
+                               setvareq(savestr(name), flags);
                }
        }
        lvp->vp = vp;
@@ -673,12 +676,15 @@ poplocalvars(void)
        while ((lvp = localvars) != NULL) {
                localvars = lvp->next;
                vp = lvp->vp;
+               TRACE(("poplocalvar %s", vp ? vp->text : "-"));
                if (vp == NULL) {       /* $- saved */
-                       memcpy(optlist, lvp->text, sizeof optlist);
+                       memcpy(optlist, lvp->text, sizeof_optlist);
                        ckfree(lvp->text);
                } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
-                       (void)unsetvar(vp->text);
+                       (void)unsetvar(vp->text, 0);
                } else {
+                       if (vp->func && (vp->flags & VNOFUNC) == 0)
+                               (*vp->func)(lvp->text + vp->name_len + 1);
                        if ((vp->flags & VTEXTFIXED) == 0)
                                ckfree(vp->text);
                        vp->flags = lvp->flags;
@@ -709,7 +715,7 @@ setvarcmd(int argc, char **argv)
  */
 
 int
-unsetcmd(int argc __unused, char **argv __unused)
+unsetcmd(int argc, char **argv)
 {
        char **ap;
        int i;
@@ -717,11 +723,11 @@ unsetcmd(int argc __unused, char **argv __unused)
        int flg_var = 0;
        int ret = 0;
 
-       while ((i = nextopt("vf")) != '\0') {
+       while ((i = nextopt("evf")) != '\0') {
                if (i == 'f')
                        flg_func = 1;
                else
-                       flg_var = 1;
+                       flg_var = i;
        }
        if (flg_func == 0 && flg_var == 0)
                flg_var = 1;
@@ -730,7 +736,7 @@ unsetcmd(int argc __unused, char **argv __unused)
                if (flg_func)
                        ret |= unsetfunc(*ap);
                if (flg_var)
-                       ret |= unsetvar(*ap);
+                       ret |= unsetvar(*ap, flg_var == 'e');
        }
        return ret;
 }
@@ -741,58 +747,38 @@ unsetcmd(int argc __unused, char **argv __unused)
  */
 
 int
-unsetvar(char *s)
+unsetvar(const char *s, int unexport)
 {
        struct var **vpp;
        struct var *vp;
 
-       vpp = hashvar(s);
-       for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
-               if (varequal(vp->text, s)) {
-                       if (vp->flags & VREADONLY)
-                               return (1);
-                       INTOFF;
-                       if (*(strchr(vp->text, '=') + 1) != '\0')
-                               setvar(s, nullstr, 0);
-                       if ((vp->flags & VEXPORT) && localevar(vp->text)) {
-                               unsetenv(s);
-                               setlocale(LC_ALL, "");
-                       }
-                       vp->flags &= ~VEXPORT;
-                       vp->flags |= VUNSET;
-                       if ((vp->flags & VSTRFIXED) == 0) {
-                               if ((vp->flags & VTEXTFIXED) == 0)
-                                       ckfree(vp->text);
-                               *vpp = vp->next;
-                               ckfree(vp);
-                       }
-                       INTON;
-                       return (0);
-               }
-       }
-
-       return (0);
-}
-
-
-
-/*
- * Find the appropriate entry in the hash table from the name.
- */
+       vp = find_var(s, &vpp, NULL);
+       if (vp == NULL)
+               return 0;
 
-STATIC struct var **
-hashvar(char *p)
-{
-       unsigned int hashval;
+       if (vp->flags & VREADONLY)
+               return 1;
 
-       hashval = ((unsigned char) *p) << 4;
-       while (*p && *p != '=')
-               hashval += (unsigned char) *p++;
-       return &vartab[hashval % VTABSIZE];
+       INTOFF;
+       if (unexport) {
+               vp->flags &= ~VEXPORT;
+       } else {
+               if (vp->text[vp->name_len + 1] != '\0')
+                       setvar(s, nullstr, 0);
+               vp->flags &= ~VEXPORT;
+               vp->flags |= VUNSET;
+               if ((vp->flags & VSTRFIXED) == 0) {
+                       if ((vp->flags & VTEXTFIXED) == 0)
+                               ckfree(vp->text);
+                       *vpp = vp->next;
+                       ckfree(vp);
+               }
+       }
+       INTON;
+       return 0;
 }
 
 
-
 /*
  * Returns true if the two strings specify the same varable.  The first
  * variable name is terminated by '='; the second may be terminated by
@@ -800,7 +786,7 @@ hashvar(char *p)
  */
 
 STATIC int
-varequal(char *p, char *q)
+strequal(const char *p, const char *q)
 {
        while (*p == *q++) {
                if (*p++ == '=')
@@ -812,5 +798,39 @@ varequal(char *p, char *q)
 }
 
 /*
- * $PchId: var.c,v 1.5 2006/05/22 12:28:49 philip Exp $
+ * Search for a variable.
+ * 'name' may be terminated by '=' or a NUL.
+ * vppp is set to the pointer to vp, or the list head if vp isn't found
+ * lenp is set to the number of charactets in 'name'
  */
+
+STATIC struct var *
+find_var(const char *name, struct var ***vppp, int *lenp)
+{
+       unsigned int hashval;
+       int len;
+       struct var *vp, **vpp;
+       const char *p = name;
+
+       hashval = 0;
+       while (*p && *p != '=')
+               hashval = 2 * hashval + (unsigned char)*p++;
+       len = p - name;
+
+       if (lenp)
+               *lenp = len;
+       vpp = &vartab[hashval % VTABSIZE];
+       if (vppp)
+               *vppp = vpp;
+
+       for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
+               if (vp->name_len != len)
+                       continue;
+               if (memcmp(vp->text, name, len) != 0)
+                       continue;
+               if (vppp)
+                       *vppp = vpp;
+               return vp;
+       }
+       return NULL;
+}
similarity index 75%
rename from minix/commands/ash/var.h
rename to bin/sh/var.h
index afa62565a7516857c35fffd2ee5f58c4a326ca08..c5b6927693de6a0ce019dde2f8565078d8a6f482 100644 (file)
@@ -1,3 +1,5 @@
+/*     $NetBSD: var.h,v 1.25 2011/06/18 21:18:46 christos Exp $        */
+
 /*-
  * Copyright (c) 1991, 1993
  *     The Regents of the University of California.  All rights reserved.
@@ -13,7 +15,7 @@
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -30,7 +32,6 @@
  * SUCH DAMAGE.
  *
  *     @(#)var.h       8.2 (Berkeley) 5/4/95
- * $FreeBSD: src/bin/sh/var.h,v 1.12 2004/04/06 20:06:51 markm Exp $
  */
 
 /*
 /* flags */
 #define VEXPORT                0x01    /* variable is exported */
 #define VREADONLY      0x02    /* variable cannot be modified */
-#define VSTRFIXED      0x04    /* variable struct is staticly allocated */
-#define VTEXTFIXED     0x08    /* text is staticly allocated */
+#define VSTRFIXED      0x04    /* variable struct is statically allocated */
+#define VTEXTFIXED     0x08    /* text is statically allocated */
 #define VSTACK         0x10    /* text is allocated on the stack */
 #define VUNSET         0x20    /* the variable is not set */
 #define VNOFUNC                0x40    /* don't call the callback function */
+#define VNOSET         0x80    /* do not set variable - just readonly test */
 
 
 struct var {
        struct var *next;               /* next entry in hash list */
        int flags;                      /* flags are defined above */
        char *text;                     /* name=value */
+       int name_len;                   /* length of name */
        void (*func)(const char *);
                                        /* function to be called when  */
                                        /* the variable gets set/unset */
@@ -65,17 +68,21 @@ struct localvar {
 };
 
 
-struct localvar *localvars;
+extern struct localvar *localvars;
 
+#if ATTY
+extern struct var vatty;
+#endif
 extern struct var vifs;
 extern struct var vmail;
 extern struct var vmpath;
 extern struct var vpath;
-extern struct var vppid;
 extern struct var vps1;
 extern struct var vps2;
-extern struct var vpse;
-#ifndef NO_HISTORY
+extern struct var vps4;
+#ifndef SMALL
+extern struct var vterm;
+extern struct var vtermcap;
 extern struct var vhistsize;
 #endif
 
@@ -92,33 +99,31 @@ extern struct var vhistsize;
 #define pathval()      (vpath.text + 5)
 #define ps1val()       (vps1.text + 4)
 #define ps2val()       (vps2.text + 4)
-#define pseval()       (vpse.text + 4)
+#define ps4val()       (vps4.text + 4)
 #define optindval()    (voptind.text + 7)
-#ifndef NO_HISTORY
+#ifndef SMALL
 #define histsizeval()  (vhistsize.text + 9)
+#define termval()      (vterm.text + 5)
 #endif
 
+#if ATTY
+#define attyset()      ((vatty.flags & VUNSET) == 0)
+#endif
 #define mpathset()     ((vmpath.flags & VUNSET) == 0)
 
 void initvar(void);
-void setvar(char *, char *, int);
+void setvar(const char *, const char *, int);
 void setvareq(char *, int);
 struct strlist;
-void listsetvar(struct strlist *);
-char *lookupvar(char *);
-char *bltinlookup(char *, int);
+void listsetvar(struct strlist *, int);
+char *lookupvar(const char *);
+char *bltinlookup(const char *, int);
 char **environment(void);
 void shprocvar(void);
-int showvarscmd(int, char **);
-int exportcmd(int, char **);
-int localcmd(int, char **);
-void mklocal(char *);
+int showvars(const char *, int, int);
+void mklocal(const char *, int);
+void listmklocal(struct strlist *, int);
 void poplocalvars(void);
-int setvarcmd(int, char **);
-int unsetcmd(int, char **);
-int unsetvar(char *);
-int setvarsafe(char *, char *, int);
-
-/*
- * $PchId: var.h,v 1.4 2006/03/29 12:04:45 philip Exp $
- */
+int unsetvar(const char *, int);
+int setvarsafe(const char *, const char *, int);
+void print_quoted(const char *);
index 8546028f28eaa85aeb85374423eadc48571593a8..1d3a961659f194c7e769a77df6a542207b80cd1b 100644 (file)
 ./usr/Makefile                         minix-sys
 ./usr/man                              minix-sys
 ./usr/man/man1                         minix-sys
-./usr/man/man1/..1                     minix-sys
+./usr/man/man1/..1                     minix-sys       obsolete
 ./usr/man/man1/[.1                     minix-sys
 ./usr/man/man1/addr2line.1             minix-sys       binutils
 ./usr/man/man1/apropos.1               minix-sys
 ./usr/man/man1/ar.1                    minix-sys       binutils
 ./usr/man/man1/as.1                    minix-sys       binutils
 ./usr/man/man1/asa.1                   minix-sys
-./usr/man/man1/ash.1                   minix-sys
+./usr/man/man1/ash.1                   minix-sys       obsolete
 ./usr/man/man1/at.1                    minix-sys
 ./usr/man/man1/atf2kyua.1              minix-sys       kyua
 ./usr/man/man1/atf-check.1             minix-sys       atf
 ./usr/man/man1/banner.1                        minix-sys
 ./usr/man/man1/basename.1              minix-sys
 ./usr/man/man1/bdes.1                  minix-sys
-./usr/man/man1/break.1                 minix-sys
+./usr/man/man1/break.1                 minix-sys       obsolete
 ./usr/man/man1/bsdtar.1                        minix-sys
 ./usr/man/man1/bsfilt.1                        minix-sys
 ./usr/man/man1/bunzip2.1               minix-sys
 ./usr/man/man1/c++.1                   minix-sys       gcccmds
 ./usr/man/man1/cal.1                   minix-sys
 ./usr/man/man1/calendar.1              minix-sys
-./usr/man/man1/case.1                  minix-sys
+./usr/man/man1/case.1                  minix-sys       obsolete
 ./usr/man/man1/cat.1                   minix-sys
 ./usr/man/man1/cawf.1                  minix-sys
 ./usr/man/man1/cc.1                    minix-sys       gcccmds
 ./usr/man/man1/cccp.1                  minix-sys       gcccmds
-./usr/man/man1/cd.1                    minix-sys
+./usr/man/man1/cd.1                    minix-sys       obsolete
 ./usr/man/man1/c++filt.1               minix-sys       binutils
 ./usr/man/man1/checknr.1               minix-sys
 ./usr/man/man1/chfn.1                  minix-sys
 ./usr/man/man1/colrm.1                 minix-sys
 ./usr/man/man1/column.1                        minix-sys
 ./usr/man/man1/comm.1                  minix-sys
-./usr/man/man1/command.1               minix-sys
+./usr/man/man1/command.1               minix-sys       obsolete
 ./usr/man/man1/compress.1              minix-sys
-./usr/man/man1/continue.1              minix-sys
+./usr/man/man1/continue.1              minix-sys       obsolete
 ./usr/man/man1/cp.1                    minix-sys
 ./usr/man/man1/cpio.1                  minix-sys
 ./usr/man/man1/cpp.1                   minix-sys       gcccmds
 ./usr/man/man1/eject.1                 minix-sys
 ./usr/man/man1/elfedit.1               minix-sys       binutils
 ./usr/man/man1/env.1                   minix-sys
-./usr/man/man1/eval.1                  minix-sys
+./usr/man/man1/eval.1                  minix-sys       obsolete
 ./usr/man/man1/ex.1                    minix-sys
-./usr/man/man1/exec.1                  minix-sys
-./usr/man/man1/exit.1                  minix-sys
+./usr/man/man1/exec.1                  minix-sys       obsolete
+./usr/man/man1/exit.1                  minix-sys       obsolete
 ./usr/man/man1/expand.1                        minix-sys
-./usr/man/man1/export.1                        minix-sys
+./usr/man/man1/export.1                        minix-sys       obsolete
 ./usr/man/man1/expr.1                  minix-sys
 ./usr/man/man1/false.1                 minix-sys
 ./usr/man/man1/fetch.1                 minix-sys
 ./usr/man/man1/flex.1                  minix-sys
 ./usr/man/man1/flexdoc.1               minix-sys
 ./usr/man/man1/fold.1                  minix-sys
-./usr/man/man1/for.1                   minix-sys
+./usr/man/man1/for.1                   minix-sys       obsolete
 ./usr/man/man1/format.1                        minix-sys
 ./usr/man/man1/fpr.1                   minix-sys
 ./usr/man/man1/from.1                  minix-sys
 ./usr/man/man1/gcpp.1                  minix-sys       gcccmds
 ./usr/man/man1/genassym.1              minix-sys
 ./usr/man/man1/getopt.1                        minix-sys
-./usr/man/man1/getopts.1               minix-sys
+./usr/man/man1/getopts.1               minix-sys       obsolete
 ./usr/man/man1/gprof.1                 minix-sys       binutils
 ./usr/man/man1/grep.1                  minix-sys
 ./usr/man/man1/groups.1                        minix-sys
 ./usr/man/man1/gzcat.1                 minix-sys
 ./usr/man/man1/gzexe.1                 minix-sys
 ./usr/man/man1/gzip.1                  minix-sys
-./usr/man/man1/hash.1                  minix-sys
+./usr/man/man1/hash.1                  minix-sys       obsolete
 ./usr/man/man1/head.1                  minix-sys
 ./usr/man/man1/hexdump.1               minix-sys
 ./usr/man/man1/host.1                  minix-sys
 ./usr/man/man1/hostaddr.1              minix-sys
 ./usr/man/man1/hostname.1              minix-sys
 ./usr/man/man1/id.1                    minix-sys
-./usr/man/man1/if.1                    minix-sys
+./usr/man/man1/if.1                    minix-sys       obsolete
 ./usr/man/man1/ifdef.1                 minix-sys
 ./usr/man/man1/indent.1                        minix-sys
 ./usr/man/man1/info.1                  minix-sys
 ./usr/man/man1/isodir.1                        minix-sys
 ./usr/man/man1/isoinfo.1               minix-sys
 ./usr/man/man1/isoread.1               minix-sys
-./usr/man/man1/jobs.1                  minix-sys
+./usr/man/man1/jobs.1                  minix-sys       obsolete
 ./usr/man/man1/join.1                  minix-sys
 ./usr/man/man1/jot.1                   minix-sys
 ./usr/man/man1/kill.1                  minix-sys
 ./usr/man/man1/ln.1                    minix-sys
 ./usr/man/man1/loadfont.1              minix-sys
 ./usr/man/man1/loadkeys.1              minix-sys
-./usr/man/man1/local.1                 minix-sys
+./usr/man/man1/local.1                 minix-sys       obsolete
 ./usr/man/man1/lock.1                  minix-sys
 ./usr/man/man1/logger.1                        minix-sys
 ./usr/man/man1/login.1                 minix-sys
 ./usr/man/man1/pwhash.1                        minix-sys
 ./usr/man/man1/ranlib.1                        minix-sys       binutils
 ./usr/man/man1/rcp.1                   minix-sys
-./usr/man/man1/read.1                  minix-sys
+./usr/man/man1/read.1                  minix-sys       obsolete
 ./usr/man/man1/readelf.1               minix-sys       binutils
 ./usr/man/man1/readlink.1              minix-sys
-./usr/man/man1/readonly.1              minix-sys
+./usr/man/man1/readonly.1              minix-sys       obsolete
 ./usr/man/man1/recwave.1               minix-sys
 ./usr/man/man1/remsync.1               minix-sys
-./usr/man/man1/return.1                        minix-sys
+./usr/man/man1/return.1                        minix-sys       obsolete
 ./usr/man/man1/rev.1                   minix-sys
 ./usr/man/man1/rget.1                  minix-sys
 ./usr/man/man1/rlogin.1                        minix-sys
 ./usr/man/man1/sdiff.1                 minix-sys
 ./usr/man/man1/sed.1                   minix-sys
 ./usr/man/man1/seq.1                   minix-sys
-./usr/man/man1/set.1                   minix-sys
-./usr/man/man1/setvar.1                        minix-sys
+./usr/man/man1/set.1                   minix-sys       obsolete
+./usr/man/man1/setvar.1                        minix-sys       obsolete
 ./usr/man/man1/sh.1                    minix-sys
 ./usr/man/man1/sha1.1                  minix-sys
 ./usr/man/man1/shar.1                  minix-sys
-./usr/man/man1/shift.1                 minix-sys
+./usr/man/man1/shift.1                 minix-sys       obsolete
 ./usr/man/man1/shlock.1                        minix-sys
 ./usr/man/man1/shuffle.1               minix-sys
 ./usr/man/man1/size.1                  minix-sys       binutils
 ./usr/man/man1/touch.1                 minix-sys
 ./usr/man/man1/tput.1                  minix-sys
 ./usr/man/man1/tr.1                    minix-sys
-./usr/man/man1/trap.1                  minix-sys
+./usr/man/man1/trap.1                  minix-sys       obsolete
 ./usr/man/man1/true.1                  minix-sys
 ./usr/man/man1/truncate.1              minix-sys
 ./usr/man/man1/tsort.1                 minix-sys
 ./usr/man/man1/tty.1                   minix-sys
 ./usr/man/man1/ul.1                    minix-sys
-./usr/man/man1/umask.1                 minix-sys
+./usr/man/man1/umask.1                 minix-sys       obsolete
 ./usr/man/man1/umount.1                        minix-sys
 ./usr/man/man1/uname.1                 minix-sys
 ./usr/man/man1/uncompress.1            minix-sys
 ./usr/man/man1/uniq.1                  minix-sys
 ./usr/man/man1/units.1                 minix-sys
 ./usr/man/man1/unlzma.1                        minix-sys
-./usr/man/man1/unset.1                 minix-sys
+./usr/man/man1/unset.1                 minix-sys       obsolete
 ./usr/man/man1/unvis.1                 minix-sys
 ./usr/man/man1/unxz.1                  minix-sys
 ./usr/man/man1/unzip.1                 minix-sys
 ./usr/man/man1/vis.1                   minix-sys
 ./usr/man/man1/vol.1                   minix-sys
 ./usr/man/man1/w.1                     minix-sys
-./usr/man/man1/wait.1                  minix-sys
+./usr/man/man1/wait.1                  minix-sys       obsolete
 ./usr/man/man1/wall.1                  minix-sys
 ./usr/man/man1/wc.1                    minix-sys
 ./usr/man/man1/what.1                  minix-sys
 ./usr/share/doc/psd/19.curses/twinkle1.c       minix-sys
 ./usr/share/doc/psd/19.curses/twinkle2.c       minix-sys
 ./usr/share/doc/psd/19.curses/win_st.c minix-sys
+./usr/share/doc/usd                    minix-sys
+./usr/share/doc/usd/03.shell           minix-sys
+./usr/share/doc/usd/03.shell/Makefile  minix-sys
+./usr/share/doc/usd/03.shell/Rv7man    minix-sys
+./usr/share/doc/usd/03.shell/t1                minix-sys
+./usr/share/doc/usd/03.shell/t2                minix-sys
+./usr/share/doc/usd/03.shell/t3                minix-sys
+./usr/share/doc/usd/03.shell/t4                minix-sys
+./usr/share/doc/usd/03.shell/t.mac     minix-sys
 ./usr/share/examples                   minix-sys       atf
 ./usr/share/examples/atf               minix-sys       atf
 ./usr/share/examples/atf/atf-run.hooks minix-sys       atf,!kyua
index 7d68a01b0538fa8d70f240e0e426baec3f3184a7..a1f56ae3d7b90e7d351f990fd62ac240a1e55057 100644 (file)
 ./usr/share/doc/html/bzip2
 ./usr/share/doc/psd
 ./usr/share/doc/psd/19.curses
+./usr/share/doc/usd
+./usr/share/doc/usd/03.shell
 ./usr/share/info
 ./usr/share/games
 ./usr/share/games/fortune
index 6daff7af1ae98b66bfe9e9c19721894cffcb17b9..57e791d1b5420d02a2b175050b822151a704c196 100755 (executable)
@@ -2,6 +2,7 @@
 
 # Activate emacs keybindings and command line history support
 set -o emacs
+set -o tabcomplete
 
 # Set the default path
 PATH=/usr/local/bin:/usr/pkg/bin:/usr/bin:/bin:/usr/games
index 854f7634a2b3c1dd476af6ee14f5642bf33f2313..00bb9d82a0e97ead10f3672e156e927fb1235693 100644 (file)
@@ -2,7 +2,7 @@
 
 .include <bsd.own.mk>
 
-SUBDIR=        add_route arp ash at backup btrace \
+SUBDIR=        add_route arp at backup btrace \
        cawf cdprobe \
        ci cleantmp cmp co \
        compress crc cron crontab \
diff --git a/minix/commands/ash/Makefile b/minix/commands/ash/Makefile
deleted file mode 100644 (file)
index bcf56e6..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-# Makefile for ash.
-
-.include <bsd.own.mk>
-
-PROG=  sh
-BINDIR=        /bin
-MAN=
-
-# Enable this line to disable command line editing
-#EDIT=-DNO_HISTORY
-
-# Enable this line if your system does not have a <paths.h>
-#NO_PATHS_H=-DNO_PATHS_H
-
-# Enable this if you don't want job control
-NO_JOBS=-DJOBS=0
-MKB_NO_JOBS=-j
-
-SRCS=  alias.c arith.y arith_lex.l cd.c complete.c eval.c exec.c expand.c \
-       histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
-       mystring.c options.c output.c parser.c redir.c show.c \
-       trap.c var.c setmode.c
-
-.include "${.CURDIR}/bltin/Makefile.inc"
-
-GENSRCS= builtins.c init.c nodes.c syntax.c operators.c signames.c
-GENHDRS= builtins.h nodes.h syntax.h token.h operators.h signames.h
-
-SRCS+= ${GENSRCS}
-
-CLEANFILES+=${GENSRCS} ${GENHDRS}
-
-DPADD+= ${LIBL} ${LIBEDIT}
-LDADD+= -ll -ledit
-
-CPPFLAGS+= -DSHELL
-CPPFLAGS+=${EDIT} ${NO_PATHS_H} ${NO_JOBS}
-
-CPPFLAGS+= -I. -I${.CURDIR}
-
-# A. Generate C tools used to build ash
-.for tool in init nodes signames syntax
-${.OBJDIR}/mk${tool}: ${.CURDIR}/mk${tool}.c
-       ${HOST_CC} ${HOST_CFLAGS} ${HOST_CPPFLAGS} ${.ALLSRC} -o ${.TARGET}
-
-CLEANFILES+= ${.OBJDIR}/mk${tool}
-.endfor
-
-# B. Generates C sources from C tools
-NODES_ARGS:= ${.CURDIR}/nodetypes ${.CURDIR}/nodes.c.pat
-INIT_ARGS:= alias.c eval.c exec.c input.c jobs.c options.c parser.c \
-            redir.c trap.c var.c
-
-.for tool in nodes signames syntax
-${tool}.c ${tool}.h: ${.OBJDIR}/mk${tool}
-       ${.OBJDIR}/mk${tool} ${${tool:tu}_ARGS}
-.endfor
-
-init.c: ${.OBJDIR}/mkinit \
-        alias.c eval.c exec.c input.c jobs.c options.c parser.c \
-        redir.c trap.c var.c
-       ${.OBJDIR}/mkinit ${.ALLSRC:S,^${.OBJDIR}/mkinit$,,}
-
-# C. Generates C sources from shell scripts
-token.h:
-       ${.CURDIR}/mktokens.sh
-
-builtins.c builtins.h:
-       ${.CURDIR}/mkbuiltins.sh ${MKB_NO_JOBS} . ${.CURDIR}/shell.h ${.CURDIR}/builtins.def
-
-operators.c operators.h:
-       ${.CURDIR}/bltin/mkexpr.sh ${.CURDIR}/bltin/unary_op ${.CURDIR}/bltin/binary_op
-
-# D. Generates sources from yacc/lex
-LFLAGS=        -8      # 8-bit lex scanner for arithmetic
-
-YFLAGS:= -d
-CLEANFILES+= arith.h arith.y.o
-
-parser.c: token.h
-y.tab.h: arith.y
-arith.h: y.tab.h
-arith_lex.l: arith.h
-
-# Explicit dependencies to ensure creation when needed
-# LSC FIXME Under MINIX, the build system curiously needs more help.
-# is it because of the missing order tools?
-expand.c: arith.h
-trap.c: signames.h
-cd.c complete.c eval.c exec.c expand.c jobs.c main.c options.c parser.c redir.c show.c trap.c var.c: nodes.h
-eval.c exec.c expand.c input.c input.h jobs.c mystring.c output.c parser.c trap.c var.c: syntax.h
-cd.c eval.c exec.c histedit.cjobs.c main.c miscbltin.c options.c trap.c var.c: builtins.h
-
-# LSC: Seems that this file is implicitly taken into account by NetBSD's make, 
-# still seems to be ignored / not found currently.
-# It's a sad story, as it has default rules to manage yacc / lex files. So for
-# a happy ending here it is explicitly included:
-.include <sys.mk>
-
-.include <bsd.prog.mk>
-
diff --git a/minix/commands/ash/arith.y b/minix/commands/ash/arith.y
deleted file mode 100644 (file)
index 50dfd5e..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-%{
-/*-
- * Copyright (c) 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if 0
-#ifndef lint
-static char sccsid[] = "@(#)arith.y    8.3 (Berkeley) 5/4/95";
-#endif
-#endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/arith.y,v 1.19 2004/05/24 10:11:31 stefanf Exp $");
-*/
-
-#include <limits.h>
-#include <stdio.h>
-
-
-#include "shell.h"
-#include "expand.h"
-#include "var.h"
-%}
-%union {
-       arith_t l_value;
-       char* s_value;
-}
-%token <l_value> ARITH_NUM ARITH_LPAREN ARITH_RPAREN
-%token <s_value> ARITH_VAR
-
-%type <l_value>        expr
-%right ARITH_ASSIGN
-%right ARITH_ADDASSIGN ARITH_SUBASSIGN
-%right ARITH_MULASSIGN ARITH_DIVASSIGN ARITH_REMASSIGN
-%right ARITH_RSHASSIGN ARITH_LSHASSIGN
-%right ARITH_BANDASSIGN ARITH_BXORASSIGN ARITH_BORASSIGN
-%left ARITH_OR
-%left ARITH_AND
-%left ARITH_BOR
-%left ARITH_BXOR
-%left ARITH_BAND
-%left ARITH_EQ ARITH_NE
-%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
-%left ARITH_LSHIFT ARITH_RSHIFT
-%left ARITH_ADD ARITH_SUB
-%left ARITH_MUL ARITH_DIV ARITH_REM
-%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
-%%
-
-exp:
-       expr
-               { return ($1); }
-       ;
-
-expr:
-       ARITH_LPAREN expr ARITH_RPAREN
-               { $$ = $2; } |
-       expr ARITH_OR expr
-               { $$ = $1 ? $1 : $3 ? $3 : 0; } |
-       expr ARITH_AND expr
-               { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } |
-       expr ARITH_BOR expr
-               { $$ = $1 | $3; } |
-       expr ARITH_BXOR expr
-               { $$ = $1 ^ $3; } |
-       expr ARITH_BAND expr
-               { $$ = $1 & $3; } |
-       expr ARITH_EQ expr
-               { $$ = $1 == $3; } |
-       expr ARITH_GT expr
-               { $$ = $1 > $3; } |
-       expr ARITH_GE expr
-               { $$ = $1 >= $3; } |
-       expr ARITH_LT expr
-               { $$ = $1 < $3; } |
-       expr ARITH_LE expr
-               { $$ = $1 <= $3; } |
-       expr ARITH_NE expr
-               { $$ = $1 != $3; } |
-       expr ARITH_LSHIFT expr
-               { $$ = $1 << $3; } |
-       expr ARITH_RSHIFT expr
-               { $$ = $1 >> $3; } |
-       expr ARITH_ADD expr
-               { $$ = $1 + $3; } |
-       expr ARITH_SUB expr
-               { $$ = $1 - $3; } |
-       expr ARITH_MUL expr
-               { $$ = $1 * $3; } |
-       expr ARITH_DIV expr
-               {
-               if ($3 == 0)
-                       yyerror("division by zero");
-               $$ = $1 / $3;
-               } |
-       expr ARITH_REM expr
-               {
-               if ($3 == 0)
-                       yyerror("division by zero");
-               $$ = $1 % $3;
-               } |
-       ARITH_NOT expr
-               { $$ = !($2); } |
-       ARITH_BNOT expr
-               { $$ = ~($2); } |
-       ARITH_SUB expr %prec ARITH_UNARYMINUS
-               { $$ = -($2); } |
-       ARITH_ADD expr %prec ARITH_UNARYPLUS
-               { $$ = $2; } |
-       ARITH_NUM |
-       ARITH_VAR
-               {
-               char *p;
-               arith_t arith_val;
-               char *str_val;
-
-               if (lookupvar($1) == NULL)
-                       setvarsafe($1, "0", 0);
-               str_val = lookupvar($1);
-               arith_val = strtoarith_t(str_val, &p, 0);
-               /*
-                * Conversion is successful only in case
-                * we've converted _all_ characters.
-                */
-               if (*p != '\0')
-                       yyerror("variable conversion error");
-               $$ = arith_val;
-               } |
-       ARITH_VAR ARITH_ASSIGN expr
-               {
-               if (arith_assign($1, $3) != 0)
-                       yyerror("variable assignment error");
-               $$ = $3;
-               } |
-       ARITH_VAR ARITH_ADDASSIGN expr
-               {
-               arith_t value;
-
-               value = atoarith_t(lookupvar($1)) + $3;
-               if (arith_assign($1, value) != 0)
-                       yyerror("variable assignment error");
-               $$ = value;
-               } |
-       ARITH_VAR ARITH_SUBASSIGN expr
-               {
-               arith_t value;
-
-               value = atoarith_t(lookupvar($1)) - $3;
-               if (arith_assign($1, value) != 0)
-                       yyerror("variable assignment error");
-               $$ = value;
-               } |
-       ARITH_VAR ARITH_MULASSIGN expr
-               {
-               arith_t value;
-
-               value = atoarith_t(lookupvar($1)) * $3;
-               if (arith_assign($1, value) != 0)
-                       yyerror("variable assignment error");
-               $$ = value;
-               } |
-       ARITH_VAR ARITH_DIVASSIGN expr
-               {
-               arith_t value;
-
-               if ($3 == 0)
-                       yyerror("division by zero");
-
-               value = atoarith_t(lookupvar($1)) / $3;
-               if (arith_assign($1, value) != 0)
-                       yyerror("variable assignment error");
-               $$ = value;
-               } |
-       ARITH_VAR ARITH_REMASSIGN expr
-               {
-               arith_t value;
-
-               if ($3 == 0)
-                       yyerror("division by zero");
-
-               value = atoarith_t(lookupvar($1)) % $3;
-               if (arith_assign($1, value) != 0)
-                       yyerror("variable assignment error");
-               $$ = value;
-               } |
-       ARITH_VAR ARITH_RSHASSIGN expr
-               {
-               arith_t value;
-
-               value = atoarith_t(lookupvar($1)) >> $3;
-               if (arith_assign($1, value) != 0)
-                       yyerror("variable assignment error");
-               $$ = value;
-               } |
-       ARITH_VAR ARITH_LSHASSIGN expr
-               {
-               arith_t value;
-
-               value = atoarith_t(lookupvar($1)) << $3;
-               if (arith_assign($1, value) != 0)
-                       yyerror("variable assignment error");
-               $$ = value;
-               } |
-       ARITH_VAR ARITH_BANDASSIGN expr
-               {
-               arith_t value;
-
-               value = atoarith_t(lookupvar($1)) & $3;
-               if (arith_assign($1, value) != 0)
-                       yyerror("variable assignment error");
-               $$ = value;
-               } |
-       ARITH_VAR ARITH_BXORASSIGN expr
-               {
-               arith_t value;
-
-               value = atoarith_t(lookupvar($1)) ^ $3;
-               if (arith_assign($1, value) != 0)
-                       yyerror("variable assignment error");
-               $$ = value;
-               } |
-       ARITH_VAR ARITH_BORASSIGN expr
-               {
-               arith_t value;
-
-               value = atoarith_t(lookupvar($1)) | $3;
-               if (arith_assign($1, value) != 0)
-                       yyerror("variable assignment error");
-               $$ = value;
-               } ;
-%%
-#include "error.h"
-#include "output.h"
-#include "memalloc.h"
-
-#define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
-
-char *arith_buf, *arith_startbuf;
-
-int yylex(void);
-int yyparse(void);
-
-int
-arith_assign(char *name, arith_t value)
-{
-       char *str;
-       int ret;
-
-       str = (char *)ckmalloc(lstrlen(value));
-       sprintf(str, ARITH_FORMAT_STR, value);
-       ret = setvarsafe(name, str, 0);
-       free(str);
-       return ret;
-}
-
-int
-arith(char *s)
-{
-       long result;
-
-       arith_buf = arith_startbuf = s;
-
-       INTOFF;
-       result = yyparse();
-       arith_lex_reset();      /* Reprime lex. */
-       INTON;
-
-       return result;
-}
-
-void
-yyerror(char *s)
-{
-
-       yyerrok;
-       yyclearin;
-       arith_lex_reset();      /* Reprime lex. */
-       error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
-}
-
-/*
- *  The exp(1) builtin.
- */
-int
-expcmd(int argc, char **argv)
-{
-       char *p;
-       char *concat;
-       char **ap;
-       long i;
-
-       if (argc > 1) {
-               p = argv[1];
-               if (argc > 2) {
-                       /*
-                        * Concatenate arguments.
-                        */
-                       STARTSTACKSTR(concat);
-                       ap = argv + 2;
-                       for (;;) {
-                               while (*p)
-                                       STPUTC(*p++, concat);
-                               if ((p = *ap++) == NULL)
-                                       break;
-                               STPUTC(' ', concat);
-                       }
-                       STPUTC('\0', concat);
-                       p = grabstackstr(concat);
-               }
-       } else
-               p = "";
-
-       i = arith(p);
-
-       out1fmt("%ld\n", i);
-       return !i;
-}
-
-/*************************/
-#ifdef TEST_ARITH
-#include <stdio.h>
-main(int argc, char *argv[])
-{
-       printf("%d\n", exp(argv[1]));
-}
-
-error(char *s)
-{
-       fprintf(stderr, "exp: %s\n", s);
-       exit(1);
-}
-#endif
diff --git a/minix/commands/ash/arith_lex.h b/minix/commands/ash/arith_lex.h
deleted file mode 100644 (file)
index 301befa..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
-arith_lex.h
-
-Created:       July 1995 by Philip Homburg <philip@cs.vu.nl>
-*/
-
-int yylex(void);
-void arith_lex_reset(void);
-
-/*
- * $PchId: arith_lex.h,v 1.1 2001/05/18 19:57:55 philip Exp $
- */
diff --git a/minix/commands/ash/bltin/LICENSE b/minix/commands/ash/bltin/LICENSE
deleted file mode 100644 (file)
index 83685c5..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-                   ASH GENERAL PUBLIC LICENSE
-
-  1. You may copy and distribute ash code or code derived from it in
-source or object form, provided that you conspicuously and appropriately
-publish on each copy a valid copyright notice "Copyright 1989 by Kenneth
-Almquist." (or with whatever year is appropriate); keep intact the
-notices on all files that refer to this License Agreement and to the
-absence of any warranty; and give any other recipients of the ash program
-a copy of this License Agreement along with the program.
-
-  2. You may not copy, sublicense, distribute or transfer ash except as
-expressly provided under this License Agreement.  Any attempt otherwise
-to copy, sublicense, distribute or transfer ash is void and your rights
-to use ash under this License agreement shall be automatically terminated.
-However, parties who have received computer software programs from you
-with this License Agreement will not have their licenses terminated so
-long as such parties remain in full compliance.
-
-
-                          NO WARRANTY
-
-  Because ash is licensed free of charge, I provide absolutely no
-warranty, to the extent permitted by applicable state law.  Except
-when otherwise stated in writing, Kenneth Almquist and/or other
-parties provide ash "as is" without warranty of any kind, either
-expressed or implied, including, but not limited to, the implied
-warranties of merchantability and fitness for a particular purpose.
-The entire risk as to the quality and performance of the program is
-with you.  Should the ash program prove defective, you assume the cost
-of all necessary servicing, repair or correction.
-
- In no event unless required by applicable law will Kenneth Almquist
-and/or any other party who may modify and redistribute ash as permitted
-above, be liable to you for damages, including any lost profits, lost
-monies, or other special, incidental or consequential damages arising
-out of the use or inability to use (including but not limited to loss
-of data or data being rendered inaccurate or losses sustained by third
-parties or a failure of the program to operate with programs provided
-by other parties) the program, even if you have been advised of the
-possibility of such damages, or for any claim by any other party.
diff --git a/minix/commands/ash/bltin/Makefile.inc b/minix/commands/ash/bltin/Makefile.inc
deleted file mode 100644 (file)
index 5e13a4d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-
-.PATH: ${.CURDIR}/bltin
-
-SRCS+= echo.c error.c expr.c regexp.c
-
-# LSC Again nbmake seems dumber on MINIX...
-expr.c: operators.h
diff --git a/minix/commands/ash/bltin/binary_op b/minix/commands/ash/bltin/binary_op
deleted file mode 100644 (file)
index 985fe40..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-# List of binary operators used by test/expr.
-#
-# Copyright 1989 by Kenneth Almquist.  All rights reserved.
-# This file is part of ash, which is distributed under the terms specified
-# by the Ash General Public License.  See the file named LICENSE.
-
-OR1     -o     1
-OR2     |      1
-AND1    -a     2
-AND2    &      2
-STREQ   =      4    OP_STRING
-STRNE   !=     4    OP_STRING
-NEWER   -newer 4    OP_STRING
-NEWER   -nt    4    OP_STRING
-OLDER   -ot    4    OP_STRING
-EQ      -eq    4    OP_INT
-NE      -ne    4    OP_INT
-GT      -gt    4    OP_INT
-LT      -lt    4    OP_INT
-LE      -le    4    OP_INT
-GE      -ge    4    OP_INT
-PLUS    +      5    OP_INT
-MINUS   -      5    OP_INT
-TIMES   *      6    OP_INT
-DIVIDE  /      6    OP_INT
-REM     %      6    OP_INT
-MATCHPAT :     7    OP_STRING
diff --git a/minix/commands/ash/bltin/catf.c b/minix/commands/ash/bltin/catf.c
deleted file mode 100644 (file)
index c7aee99..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copy the files given as arguments to the standard output.  The file
- * name "-" refers to the standard input.
- *
- * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
- * This file is part of ash, which is distributed under the terms specified
- * by the Ash General Public License.  See the file named LICENSE.
- */
-
-#define main catfcmd
-
-#include "bltin.h"
-#include "../error.h"
-#include <sys/param.h>
-#include <fcntl.h>
-
-
-#ifdef SBUFSIZE
-#define BUFSIZE() SBUFSIZE
-#else
-#ifdef MAXBSIZE
-#define BUFSIZE() MAXBSIZE
-#else
-#define BUFSIZE() BSIZE
-#endif
-#endif
-
-
-main(argc, argv)  char **argv; {
-      char *filename;
-      char *buf = stalloc(BUFSIZE());
-      int fd;
-      int i;
-#ifdef SHELL
-      volatile int input;
-      struct jmploc jmploc;
-      struct jmploc *volatile savehandler;
-#endif
-
-      INITARGS(argv);
-#ifdef SHELL
-      input = -1;
-      if (setjmp(jmploc.loc)) {
-           close(input);
-           handler = savehandler;
-           longjmp(handler, 1);
-      }
-      savehandler = handler;
-      handler = &jmploc;
-#endif
-      while ((filename = *++argv) != NULL) {
-           if (filename[0] == '-' && filename[1] == '\0') {
-                 fd = 0;
-           } else {
-#ifdef SHELL
-                 INTOFF;
-                 if ((fd = open(filename, O_RDONLY)) < 0)
-                       error("Can't open %s", filename);
-                 input = fd;
-                 INTON;
-#else
-                 if ((fd = open(filename, O_RDONLY)) < 0) {
-                       fprintf(stderr, "catf: Can't open %s\n", filename);
-                       exit(2);
-                 }
-#endif
-           }
-           while ((i = read(fd, buf, BUFSIZE())) > 0) {
-#ifdef SHELL
-                 if (out1 == &memout) {
-                       register char *p;
-                       for (p = buf ; --i >= 0 ; p++) {
-                             outc(*p, &memout);
-                       }
-                 } else {
-                       write(1, buf, i);
-                 }
-#else
-                 write(1, buf, i);
-#endif
-           }
-           if (fd != 0)
-                 close(fd);
-      }
-#ifdef SHELL
-      handler = savehandler;
-#endif
-}
diff --git a/minix/commands/ash/bltin/error.c b/minix/commands/ash/bltin/error.c
deleted file mode 100644 (file)
index 7af94dd..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
- * This file is part of ash, which is distributed under the terms specified
- * by the Ash General Public License.  See the file named LICENSE.
- */
-
-#include <stdio.h>
-
-char *commandname;
-
-
-void
-#ifdef __STDC__
-error(char *msg, ...) {
-#else
-error(msg)
-      char *msg;
-      {
-#endif
-
-      fprintf(stderr, "%s: %s\n", commandname, msg);
-      exit(2);
-}
diff --git a/minix/commands/ash/bltin/expr.c b/minix/commands/ash/bltin/expr.c
deleted file mode 100644 (file)
index 3c5ca51..0000000
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * The expr and test commands.
- *
- * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
- * This file is part of ash, which is distributed under the terms specified
- * by the Ash General Public License.  See the file named LICENSE.
- */
-
-
-#include "bltin.h"
-#include "operators.h"
-#include <regex.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-
-#define STACKSIZE 12
-#define NESTINCR 16
-
-/* data types */
-#define STRING 0
-#define INTEGER 1
-#define BOOLEAN 2
-
-
-/*
- * This structure hold a value.  The type keyword specifies the type of
- * the value, and the union u holds the value.  The value of a boolean
- * is stored in u.num (1 = TRUE, 0 = FALSE).
- */
-
-struct value {
-      int type;
-      union {
-           char *string;
-           long num;
-      } u;
-};
-
-
-struct operator {
-      short op;                        /* which operator */
-      short pri;               /* priority of operator */
-};
-
-
-struct filestat {
-      char *name;              /* name of file */
-      int rcode;               /* return code from stat */
-      struct stat stat;                /* status info on file */
-};
-
-
-extern char *match_begin[10];  /* matched string */
-extern short match_length[10]; /* defined in regexp.c */
-extern short number_parens;    /* number of \( \) pairs */
-
-
-#ifdef __STDC__
-static int expr_is_false(struct value *);
-static void expr_operator(int, struct value *, struct filestat *);
-static int lookup_op(char *, char *const*);
-#else
-static int expr_is_false();
-static void expr_operator();
-static int lookup_op();
-#endif
-
-
-
-int exprcmd(argc, argv) int argc; char **argv; {
-      char **ap;
-      char *opname;
-      char c;
-      char *p;
-      int print;
-      int nest;                /* parenthises nesting */
-      int op;
-      int pri;
-      int skipping;
-      int binary;
-      struct operator opstack[STACKSIZE];
-      struct operator *opsp;
-      struct value valstack[STACKSIZE + 1];
-      struct value *valsp;
-      struct filestat fs;
-
-      INITARGS(argv);
-      c = **argv;
-      print = 1;
-      if (c == 't')
-           print = 0;
-      else if (c == '[') {
-           if (! equal(argv[argc - 1], "]"))
-                 error("missing ]");
-           argv[argc - 1] = NULL;
-           print = 0;
-      }
-      ap = argv + 1;
-      fs.name = NULL;
-
-      /*
-       * We use operator precedence parsing, evaluating the expression
-       * as we parse it.  Parentheses are handled by bumping up the
-       * priority of operators using the variable "nest."  We use the
-       * variable "skipping" to turn off evaluation temporarily for the
-       * short circuit boolean operators.  (It is important do the short
-       * circuit evaluation because under NFS a stat operation can take
-       * infinitely long.)
-       */
-
-      nest = 0;
-      skipping = 0;
-      opsp = opstack + STACKSIZE;
-      valsp = valstack;
-      if (*ap == NULL) {
-           valstack[0].type = BOOLEAN;
-           valstack[0].u.num = 0;
-           goto done;
-      }
-      for (;;) {
-           opname = *ap++;
-           if (opname == NULL)
-syntax:                  error("syntax error");
-           if (opname[0] == '(' && opname[1] == '\0') {
-                 nest += NESTINCR;
-                 continue;
-           } else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) {
-                 if (opsp == &opstack[0])
-overflow:              error("Expression too complex");
-                 --opsp;
-                 opsp->op = op;
-                 opsp->pri = op_priority[op] + nest;
-                 continue;
-
-           } else {
-                 if (opname[0] == '\'') {
-                       for (p = opname ; *++p != '\0' ; );
-                       if (--p > opname && *p == '\'') {
-                             *p = '\0';
-                             opname++;
-                       }
-                 }
-                 valsp->type = STRING;
-                 valsp->u.string = opname;
-                 valsp++;
-           }
-           for (;;) {
-                 opname = *ap++;
-                 if (opname == NULL) {
-                       if (nest != 0)
-                             goto syntax;
-                       pri = 0;
-                       break;
-                 }
-                 if (opname[0] != ')' || opname[1] != '\0') {
-                       if ((op = lookup_op(opname, binary_op)) < 0)
-                             goto syntax;
-                       op += FIRST_BINARY_OP;
-                       pri = op_priority[op] + nest;
-                       break;
-                 }
-                 if ((nest -= NESTINCR) < 0)
-                       goto syntax;
-           }
-           while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) {
-                 binary = opsp->op;
-                 for (;;) {
-                       valsp--;
-                       c = op_argflag[opsp->op];
-                       if (c == OP_INT) {
-                             if (valsp->type == STRING)
-                                   valsp->u.num = atol(valsp->u.string);
-                             valsp->type = INTEGER;
-                       } else if (c >= OP_STRING) { /* OP_STRING or OP_FILE */
-                             if (valsp->type == INTEGER) {
-                                   p = stalloc(32);
-#ifdef SHELL
-                                   fmtstr(p, 32, "%ld", valsp->u.num);
-#else
-                                   sprintf(p, "%d", valsp->u.num);
-#endif
-                                   valsp->u.string = p;
-                             } else if (valsp->type == BOOLEAN) {
-                                   if (valsp->u.num)
-                                         valsp->u.string = "true";
-                                   else
-                                         valsp->u.string = "";
-                             }
-                             valsp->type = STRING;
-                             if (c == OP_FILE
-                              && (fs.name == NULL
-                                  || ! equal(fs.name, valsp->u.string))) {
-                                   fs.name = valsp->u.string;
-                                   fs.rcode = stat(valsp->u.string, &fs.stat);
-                             }
-                       }
-                       if (binary < FIRST_BINARY_OP)
-                             break;
-                       binary = 0;
-                 }
-                 if (! skipping)
-                       expr_operator(opsp->op, valsp, &fs);
-                 else if (opsp->op == AND1 || opsp->op == OR1)
-                       skipping--;
-                 valsp++;              /* push value */
-                 opsp++;               /* pop operator */
-           }
-           if (opname == NULL)
-                 break;
-           if (opsp == &opstack[0])
-                 goto overflow;
-           if (op == AND1 || op == AND2) {
-                 op = AND1;
-                 if (skipping || expr_is_false(valsp - 1))
-                       skipping++;
-           }
-           if (op == OR1 || op == OR2) {
-                 op = OR1;
-                 if (skipping || ! expr_is_false(valsp - 1))
-                       skipping++;
-           }
-           opsp--;
-           opsp->op = op;
-           opsp->pri = pri;
-      }
-done:
-      if (print) {
-           if (valstack[0].type == STRING)
-                 printf("%s\n", valstack[0].u.string);
-           else if (valstack[0].type == INTEGER)
-                 printf("%ld\n", valstack[0].u.num);
-           else if (valstack[0].u.num != 0)
-                 printf("true\n");
-      }
-      return expr_is_false(&valstack[0]);
-}
-
-
-static int
-expr_is_false(val)
-      struct value *val;
-      {
-      if (val->type == STRING) {
-           if (val->u.string[0] == '\0')
-                 return 1;
-      } else { /* INTEGER or BOOLEAN */
-           if (val->u.num == 0)
-                 return 1;
-      }
-      return 0;
-}
-
-
-/*
- * Execute an operator.  Op is the operator.  Sp is the stack pointer;
- * sp[0] refers to the first operand, sp[1] refers to the second operand
- * (if any), and the result is placed in sp[0].  The operands are converted
- * to the type expected by the operator before expr_operator is called.
- * Fs is a pointer to a structure which holds the value of the last call
- * to stat, to avoid repeated stat calls on the same file.
- */
-
-static void
-expr_operator(op, sp, fs)
-      int op;
-      struct value *sp;
-      struct filestat *fs;
-      {
-      int i, r;
-      struct stat st1, st2;
-      regex_t pat;
-      regmatch_t rm[2];
-
-      switch (op) {
-      case NOT:
-           sp->u.num = expr_is_false(sp);
-           sp->type = BOOLEAN;
-           break;
-      case EXISTS:
-           if (fs->rcode >= 0) goto true;
-           goto false;
-      case ISREAD:
-           i = 04;
-           goto permission;
-      case ISWRITE:
-           i = 02;
-           goto permission;
-      case ISEXEC:
-           i = 01;
-permission:
-           if (fs->stat.st_uid == geteuid())
-                 i <<= 6;
-           else if (fs->stat.st_gid == getegid())
-                 i <<= 3;
-           goto filebit;       /* true if (stat.st_mode & i) != 0 */
-      case ISFILE:
-           i = S_IFREG;
-           goto filetype;
-      case ISDIR:
-           i = S_IFDIR;
-           goto filetype;
-      case ISCHAR:
-           i = S_IFCHR;
-           goto filetype;
-      case ISBLOCK:
-           i = S_IFBLK;
-           goto filetype;
-      case ISFIFO:
-#ifdef S_IFIFO
-           i = S_IFIFO;
-           goto filetype;
-#else
-           goto false;
-#endif
-filetype:
-           if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0) {
-true:
-                 sp->u.num = 1;
-           } else {
-false:
-                 sp->u.num = 0;
-           }
-           sp->type = BOOLEAN;
-           break;
-      case ISSETUID:
-           i = S_ISUID;
-           goto filebit;
-      case ISSETGID:
-           i = S_ISGID;
-           goto filebit;
-      case ISSTICKY:
-           i = S_ISVTX;
-filebit:
-           if (fs->stat.st_mode & i && fs->rcode >= 0)
-                 goto true;
-           goto false;
-      case ISSLINK:
-           if (lstat(fs->name, &st1) == -1)
-               goto false;
-           if (S_ISLNK(st1.st_mode))
-               goto true;
-           goto false;
-      case ISSIZE:
-           sp->u.num = fs->rcode >= 0? fs->stat.st_size : 0L;
-           sp->type = INTEGER;
-           break;
-      case OLDER:
-      case NEWER:
-           if (stat(sp->u.string, &st1) != 0) {
-                 sp->u.num = 0;
-           } else if (stat((sp + 1)->u.string, &st2) != 0) {
-                 sp->u.num = 1;
-           } else {
-               int isnewer = st1.st_mtime >= st2.st_mtime;
-               if(op == NEWER)
-                 sp->u.num = isnewer;
-               else
-                 sp->u.num = !isnewer;
-           }
-           sp->type = INTEGER;
-           break;
-      case ISTTY:
-           sp->u.num = isatty(sp->u.num);
-           sp->type = BOOLEAN;
-           break;
-      case NULSTR:
-           if (sp->u.string[0] == '\0')
-                 goto true;
-           goto false;
-      case STRLEN:
-           sp->u.num = strlen(sp->u.string);
-           sp->type = INTEGER;
-           break;
-      case OR1:
-      case AND1:
-           /*
-            * These operators are mostly handled by the parser.  If we
-            * get here it means that both operands were evaluated, so
-            * the value is the value of the second operand.
-            */
-           *sp = *(sp + 1);
-           break;
-      case STREQ:
-      case STRNE:
-           i = 0;
-           if (equal(sp->u.string, (sp + 1)->u.string))
-                 i++;
-           if (op == STRNE)
-                 i = 1 - i;
-           sp->u.num = i;
-           sp->type = BOOLEAN;
-           break;
-      case EQ:
-           if (sp->u.num == (sp + 1)->u.num)
-                 goto true;
-           goto false;
-      case NE:
-           if (sp->u.num != (sp + 1)->u.num)
-                 goto true;
-           goto false;
-      case GT:
-           if (sp->u.num > (sp + 1)->u.num)
-                 goto true;
-           goto false;
-      case LT:
-           if (sp->u.num < (sp + 1)->u.num)
-                 goto true;
-           goto false;
-      case LE:
-           if (sp->u.num <= (sp + 1)->u.num)
-                 goto true;
-           goto false;
-      case GE:
-           if (sp->u.num >= (sp + 1)->u.num)
-                 goto true;
-           goto false;
-      case PLUS:
-           sp->u.num += (sp + 1)->u.num;
-           break;
-      case MINUS:
-           sp->u.num -= (sp + 1)->u.num;
-           break;
-      case TIMES:
-           sp->u.num *= (sp + 1)->u.num;
-           break;
-      case DIVIDE:
-           if ((sp + 1)->u.num == 0)
-                 error("Division by zero");
-           sp->u.num /= (sp + 1)->u.num;
-           break;
-      case REM:
-           if ((sp + 1)->u.num == 0)
-                 error("Division by zero");
-           sp->u.num %= (sp + 1)->u.num;
-           break;
-      case MATCHPAT:
-           {
-                 r = regcomp(&pat, (sp + 1)->u.string, 0);
-                 if (r)
-                       error("Bad regular expression");
-                 if (regexec(&pat, sp->u.string, 2, rm, 0) == 0 &&
-                       rm[0].rm_so == 0)
-                 {
-                       if (pat.re_nsub > 0) {
-                             sp->u.string[rm[1].rm_eo] = '\0';
-                             sp->u.string = sp->u.string+rm[1].rm_so;
-                       } else {
-                             sp->u.num = rm[0].rm_eo;
-                             sp->type = INTEGER;
-                       }
-                 } else {
-                       if (pat.re_nsub > 0) {
-                             sp->u.string[0] = '\0';
-                       } else {
-                             sp->u.num = 0;
-                             sp->type = INTEGER;
-                       }
-                 }
-           }
-           break;
-      }
-}
-
-
-static int
-lookup_op(name, table)
-      char *name;
-      char *const*table;
-      {
-      register char *const*tp;
-      register char const *p;
-      char c = name[1];
-
-      for (tp = table ; (p = *tp) != NULL ; tp++) {
-           if (p[1] == c && equal(p, name))
-                 return tp - table;
-      }
-      return -1;
-}
diff --git a/minix/commands/ash/bltin/line.c b/minix/commands/ash/bltin/line.c
deleted file mode 100644 (file)
index aa6970e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * The line command.  Reads one line from the standard input and writes it
- * to the standard output.
- *
- * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
- * This file is part of ash, which is distributed under the terms specified
- * by the Ash General Public License.  See the file named LICENSE.
- */
-
-#define main linecmd
-
-#include "bltin.h"
-
-
-main(argc, argv)  char **argv; {
-      char c;
-
-      for (;;) {
-           if (read(0, &c, 1) != 1) {
-                 putchar('\n');
-                 return 1;
-           }
-           putchar(c);
-           if (c == '\n')
-                 return 0;
-      }
-}
diff --git a/minix/commands/ash/bltin/makefile.not b/minix/commands/ash/bltin/makefile.not
deleted file mode 100644 (file)
index ed36c73..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
-# This file is part of ash, which is distributed under the terms specified
-# by the Ash General Public License.  See the file named LICENSE.
-
-LIBFILES=catfcmd.o echocmd.o exprcmd.o linecmd.o nlechocmd.o\
-       operators.o regexp.o
-DEBUG=-g
-CFLAGS=$(DEBUG)
-#CC=gcc
-
-all:$P bltinlib.a catf echo expr line nlecho true umask
-
-bltinlib.a:$P $(LIBFILES)
-       ar rc $@ $(LIBFILES)
-
-catf: catf.c bltin.h ../shell.h ../error.h error.o stalloc.o
-       $(CC) $(CFLAGS) -o $@ catf.c error.o stalloc.o
-
-catfcmd.o: catf.c bltin.h ../shell.h ../error.h
-       $(CC) -DSHELL $(CFLAGS) -c catf.c
-       mv catf.o $@
-
-expr: expr.c bltin.h ../shell.h operators.h operators.o regexp.o error.o stalloc.o
-       $(CC) $(CFLAGS) -o $@ expr.c operators.o regexp.o error.o stalloc.o
-       -rm -f test '['
-       ln expr test
-       ln expr '['
-
-exprcmd.o: expr.c bltin.h ../shell.h operators.h
-       $(CC) -DSHELL $(CFLAGS) -c expr.c
-       mv expr.o $@
-
-operators.c operators.h: unary_op binary_op mkexpr
-       ./mkexpr
-
-operators.o: ../shell.h operators.h
-
-regexp.o: bltin.h ../shell.h
-
-echo: echo.c bltin.h ../shell.h
-       $(CC) $(CFLAGS) -o $@ echo.c
-
-echocmd.o: echo.c bltin.h ../shell.h
-       $(CC) -DSHELL $(CFLAGS) -c echo.c
-       mv echo.o $@
-
-line: line.c bltin.h ../shell.h
-       $(CC) $(CFLAGS) -o $@ line.c
-
-linecmd.o: line.c bltin.h ../shell.h
-       $(CC) -DSHELL $(CFLAGS) -c line.c
-       mv line.o $@
-
-nlecho: nlecho.c bltin.h ../shell.h
-       $(CC) $(CFLAGS) -o $@ nlecho.c
-
-nlechocmd.o: nlecho.c bltin.h ../shell.h
-       $(CC) -DSHELL $(CFLAGS) -c nlecho.c
-       mv nlecho.o $@
-
-umask: umask.c bltin.h
-       $(CC) $(CFLAGS) -o $@ umask.c
-
-true:
-       > :
-       chmod 755 :
-       rm -f true
-       ln : true
-
-stalloc.o: ../shell.h
-
diff --git a/minix/commands/ash/bltin/mkexpr.sh b/minix/commands/ash/bltin/mkexpr.sh
deleted file mode 100755 (executable)
index c01483b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-#!/bin/sh
-# Copyright 1989 by Kenneth Almquist.  All rights reserved.
-#
-# This file is part of ash.  Ash is distributed under the terms specified
-# by the Ash General Public License.  See the file named LICENSE.
-
-# All calls to awk removed, because Minix bawk is deficient.  (kjb)
-
-if [ $# -ne 2 ]
-then
-       echo "Usage: $0 <unary_op> <binary_op>" >&2
-       exit 1
-fi
-unary_op="$1"
-binary_op="$2"
-
-exec > operators.h
-i=0
-sed -e '/^[^#]/!d' "$unary_op" "$binary_op" | while read line
-do
-       set -$- $line
-       echo "#define $1 $i"
-       i=`expr $i + 1`
-done
-echo
-echo "#define FIRST_BINARY_OP" `sed -e '/^[^#]/!d' "$unary_op" | wc -l`
-echo '
-#define OP_INT 1               /* arguments to operator are integer */
-#define OP_STRING 2            /* arguments to operator are string */
-#define OP_FILE 3              /* argument is a file name */
-
-extern char *const unary_op[];
-extern char *const binary_op[];
-extern const char op_priority[];
-extern const char op_argflag[];'
-
-exec > operators.c
-echo '/*
- * Operators used in the expr/test command.
- */
-
-#include <stddef.h>
-#include "shell.h"
-#include "operators.h"
-
-char *const unary_op[] = {'
-sed -e '/^[^#]/!d
-       s/[     ][      ]*/ /g
-       s/^[^ ][^ ]* \([^ ][^ ]*\).*/      "\1",/
-       ' "$unary_op"
-echo '      NULL
-};
-
-char *const binary_op[] = {'
-sed -e '/^[^#]/!d
-       s/[     ][      ]*/ /g
-       s/^[^ ][^ ]* \([^ ][^ ]*\).*/      "\1",/
-       ' "$binary_op"
-echo '      NULL
-};
-
-const char op_priority[] = {'
-sed -e '/^[^#]/!d
-       s/[     ][      ]*/ /g
-       s/^[^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\).*/      \1,/
-       ' "$unary_op" "$binary_op"
-echo '};
-
-const char op_argflag[] = {'
-sed -e '/^[^#]/!d
-       s/[     ][      ]*/ /g
-       s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]*$/& 0/
-       s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\)/      \1,/
-       ' "$unary_op" "$binary_op"
-echo '};'
diff --git a/minix/commands/ash/bltin/myregexp.h b/minix/commands/ash/bltin/myregexp.h
deleted file mode 100644 (file)
index 83006a1..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
-myregexp.h
-
-Created:       July 1995 by Philip Homburg <philip@cs.vu.nl>
-*/
-
-char *re_compile(char *pattern);
-int re_match(char *pattern, char *string);
diff --git a/minix/commands/ash/bltin/nlecho.c b/minix/commands/ash/bltin/nlecho.c
deleted file mode 100644 (file)
index ccfb792..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Echo the command argument to the standard output, one line at a time.
- * This command is useful for debugging th shell and whenever you what
- * to output strings literally.
- *
- * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
- * This file is part of ash, which is distributed under the terms specified
- * by the Ash General Public License.  See the file named LICENSE.
- */
-
-
-#define main nlechocmd
-
-#include "bltin.h"
-
-
-main(argc, argv)  char **argv; {
-      register char **ap;
-
-      for (ap = argv + 1 ; *ap ; ap++) {
-           fputs(*ap, stdout);
-           putchar('\n');
-      }
-      return 0;
-}
diff --git a/minix/commands/ash/bltin/regexp.c b/minix/commands/ash/bltin/regexp.c
deleted file mode 100644 (file)
index 7ef68ba..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Regular expression matching for expr(1).  Bugs:  The upper bound of
- * a range specified by the \{ feature cannot be zero.
- *
- * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
- * This file is part of ash, which is distributed under the terms specified
- * by the Ash General Public License.  See the file named LICENSE.
- */
-
-#include "bltin.h"
-#include "myregexp.h"
-
-#include <stdlib.h>
-
-#define RE_END 0               /* end of regular expression */
-#define RE_LITERAL 1           /* normal character follows */
-#define RE_DOT 2               /* "." */
-#define RE_CCL 3               /* "[...]" */
-#define RE_NCCL 4              /* "[^...]" */
-#define RE_LP 5                        /* "\(" */
-#define RE_RP 6                        /* "\)" */
-#define RE_MATCHED 7           /* "\digit" */
-#define RE_EOS 8               /* "$" matches end of string */
-#define RE_STAR 9              /* "*" */
-#define RE_RANGE 10            /* "\{num,num\}" */
-
-
-
-char *match_begin[10];
-short match_length[10];
-short number_parens;
-static int match(char *pattern, char *string);
-
-
-
-char *
-re_compile(pattern)
-       char *pattern;
-       {
-       register char *p;
-       register char c;
-       char *comp;
-       register char *q;
-       char *begin;
-       char *endp;
-       register int len;
-       int first;
-       int type;
-       char *stackp;
-       char stack[10];
-       int paren_num;
-       int i;
-
-       p = pattern;
-       if (*p == '^')
-               p++;
-       comp = q = malloc(2 * strlen(p) + 1);
-       begin = q;
-       stackp = stack;
-       paren_num = 0;
-       for (;;) {
-               switch (c = *p++) {
-               case '\0':
-                       *q = '\0';
-                       goto out;
-               case '.':
-                       *q++ = RE_DOT;
-                       len = 1;
-                       break;
-               case '[':
-                       begin = q;
-                       *q = RE_CCL;
-                       if (*p == '^') {
-                               *q = RE_NCCL;
-                               p++;
-                       }
-                       q++;
-                       first = 1;
-                       while (*p != ']' || first == 1) {
-                               if (p[1] == '-' && p[2] != ']') {
-                                       *q++ = '-';
-                                       *q++ = p[0];
-                                       *q++ = p[2];
-                                       p += 3;
-                               } else if (*p == '-') {
-                                       *q++ = '-';
-                                       *q++ = '-';
-                                       *q++ = '-';
-                                       p++;
-                               } else {
-                                       *q++ = *p++;
-                               }
-                               first = 0;
-                       }
-                       p++;
-                       *q++ = '\0';
-                       len = q - begin;
-                       break;
-               case '$':
-                       if (*p != '\0')
-                               goto dft;
-                       *q++ = RE_EOS;
-                       break;
-               case '*':
-                       if (len == 0)
-                               goto dft;
-                       type = RE_STAR;
-range:
-                       i = (type == RE_RANGE)? 3 : 1;
-                       endp = q + i;
-                       begin = q - len;
-                       do {
-                               --q;
-                               *(q + i) = *q;
-                       } while (--len > 0);
-                       q = begin;
-                       *q++ = type;
-                       if (type == RE_RANGE) {
-                               i = 0;
-                               while ((unsigned)(*p - '0') <= 9)
-                                       i = 10 * i + (*p++ - '0');
-                               *q++ = i;
-                               if (*p != ',') {
-                                       *q++ = i;
-                               } else {
-                                       p++;
-                                       i = 0;
-                                       while ((unsigned)(*p - '0') <= 9)
-                                               i = 10 * i + (*p++ - '0');
-                                       *q++ = i;
-                               }
-                               if (*p != '\\' || *++p != '}')
-                                       error("RE error");
-                               p++;
-                       }
-                       q = endp;
-                       break;
-               case '\\':
-                       if ((c = *p++) == '(') {
-                               if (++paren_num > 9)
-                                       error("RE error");
-                               *q++ = RE_LP;
-                               *q++ = paren_num;
-                               *stackp++ = paren_num;
-                               len = 0;
-                       } else if (c == ')') {
-                               if (stackp == stack)
-                                       error("RE error");
-                               *q++ = RE_RP;
-                               *q++ = *--stackp;
-                               len = 0;
-                       } else if (c == '{') {
-                               type = RE_RANGE;
-                               goto range;
-                       } else if ((unsigned)(c - '1') < 9) {
-                               /* should check validity here */
-                               *q++ = RE_MATCHED;
-                               *q++ = c - '0';
-                               len = 2;
-                       } else {
-                               goto dft;
-                       }
-                       break;
-               default:
-dft:                   *q++ = RE_LITERAL;
-                       *q++ = c;
-                       len = 2;
-                       break;
-               }
-       }
-out:
-       if (stackp != stack)
-               error("RE error");
-       number_parens = paren_num;
-       return comp;
-}
-
-
-
-int
-re_match(pattern, string)
-       char *pattern;
-       char *string;
-       {
-       char **pp;
-
-       match_begin[0] = string;
-       for (pp = &match_begin[1] ; pp <= &match_begin[9] ; pp++)
-               *pp = 0;
-       return match(pattern, string);
-}
-
-
-
-static
-match(pattern, string)
-       char *pattern;
-       char *string;
-       {
-       register char *p, *q;
-       int counting;
-       int low, high, count;
-       char *curpat;
-       char *start_count;
-       int negate;
-       int found;
-       char *r;
-       int len;
-       char c;
-
-       p = pattern;
-       q = string;
-       counting = 0;
-       for (;;) {
-               if (counting) {
-                       if (++count > high)
-                               goto bad;
-                       p = curpat;
-               }
-               switch (*p++) {
-               case RE_END:
-                       match_length[0] = q - match_begin[0];
-                       return 1;
-               case RE_LITERAL:
-                       if (*q++ != *p++)
-                               goto bad;
-                       break;
-               case RE_DOT:
-                       if (*q++ == '\0')
-                               goto bad;
-                       break;
-               case RE_CCL:
-                       negate = 0;
-                       goto ccl;
-               case RE_NCCL:
-                       negate = 1;
-ccl:
-                       found = 0;
-                       c = *q++;
-                       while (*p) {
-                               if (*p == '-') {
-                                       if (c >= *++p && c <= *++p)
-                                               found = 1;
-                               } else {
-                                       if (c == *p)
-                                               found = 1;
-                               }
-                               p++;
-                       }
-                       p++;
-                       if (found == negate)
-                               goto bad;
-                       break;
-               case RE_LP:
-                       match_begin[*p++] = q;
-                       break;
-               case RE_RP:
-                       match_length[*p] = q - match_begin[*p];
-                       p++;
-                       break;
-               case RE_MATCHED:
-                       r = match_begin[*p];
-                       len = match_length[*p++];
-                       while (--len >= 0) {
-                               if (*q++ != *r++)
-                                       goto bad;
-                       }
-                       break;
-               case RE_EOS:
-                       if (*q != '\0')
-                               goto bad;
-                       break;
-               case RE_STAR:
-                       low = 0;
-                       high = 32767;
-                       goto range;
-               case RE_RANGE:
-                       low = *p++;
-                       high = *p++;
-                       if (high == 0)
-                               high = 32767;
-range:
-                       curpat = p;
-                       start_count = q;
-                       count = 0;
-                       counting++;
-                       break;
-               }
-       }
-bad:
-       if (! counting)
-               return 0;
-       len = 1;
-       if (*curpat == RE_MATCHED)
-               len = match_length[curpat[1]];
-       while (--count >= low) {
-               if (match(p, start_count + count * len))
-                       return 1;
-       }
-       return 0;
-}
diff --git a/minix/commands/ash/bltin/stalloc.c b/minix/commands/ash/bltin/stalloc.c
deleted file mode 100644 (file)
index 381271a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
- * This file is part of ash, which is distributed under the terms specified
- * by the Ash General Public License.  See the file named LICENSE.
- */
-
-#include "../shell.h"
-
-
-void error();
-pointer malloc();
-
-
-pointer
-stalloc(nbytes) {
-      register pointer p;
-
-      if ((p = malloc(nbytes)) == NULL)
-           error("Out of space");
-      return p;
-}
diff --git a/minix/commands/ash/bltin/umask.c b/minix/commands/ash/bltin/umask.c
deleted file mode 100644 (file)
index 5c1f54b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
- * This file is part of ash, which is distributed under the terms specified
- * by the Ash General Public License.  See the file named LICENSE.
- */
-
-#include <stdio.h>
-
-
-main(argc, argv)  char **argv; {
-      int mask;
-
-      if (argc > 1) {
-           fprintf(stderr, "umask: only builtin version of umask can set value\n");
-           exit(2);
-      }
-      printf("%.4o\n", umask(0));
-      return 0;
-}
diff --git a/minix/commands/ash/bltin/unary_op b/minix/commands/ash/bltin/unary_op
deleted file mode 100644 (file)
index e7a0f3c..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# List of unary operators used by test/expr.
-#
-# Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
-# This file is part of ash, which is distributed under the terms specified
-# by the Ash General Public License.  See the file named LICENSE.
-
-NOT     !      3
-EXISTS  -e     12   OP_FILE
-ISREAD  -r     12   OP_FILE
-ISWRITE  -w    12   OP_FILE
-ISEXEC  -x     12   OP_FILE
-ISFILE  -f     12   OP_FILE
-ISDIR   -d     12   OP_FILE
-ISCHAR  -c     12   OP_FILE
-ISBLOCK         -b     12   OP_FILE
-ISFIFO  -p     12   OP_FILE
-ISSETUID -u    12   OP_FILE
-ISSETGID -g    12   OP_FILE
-ISSTICKY -k    12   OP_FILE
-ISSLINK         -h     12   OP_FILE
-ISSIZE  -s     12   OP_FILE
-ISTTY   -t     12   OP_INT
-NULSTR  -z     12   OP_STRING
-STRLEN  -n     12   OP_STRING
diff --git a/minix/commands/ash/builtins b/minix/commands/ash/builtins
deleted file mode 100644 (file)
index 57409b1..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/bin/sh -
-#
-# Copyright (c) 1991, 1993
-#      The Regents of the University of California.  All rights reserved.
-#
-# This code is derived from software contributed to Berkeley by
-# Kenneth Almquist.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-#    notice, this list of conditions and the following disclaimer in the
-#    documentation and/or other materials provided with the distribution.
-# 3. All advertising materials mentioning features or use of this software
-#    must display the following acknowledgement:
-#      This product includes software developed by the University of
-#      California, Berkeley and its contributors.
-# 4. Neither the name of the University nor the names of its contributors
-#    may be used to endorse or promote products derived from this software
-#    without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-#
-#      @(#)builtins    8.1 (Berkeley) 5/31/93
-
-#
-# This file lists all the builtin commands.  The first column is the name
-# of a C routine.  The -j flag, if present, specifies that this command
-# is to be excluded from systems without job control.  The rest of the line
-# specifies the command name or names used to run the command.  The entry
-# for bltincmd, which is run when the user does not specify a command, must
-# come first.
-#
-# Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
-# This file is part of ash, which is distributed under the terms specified
-# by the Ash General Public License.  See the file named LICENSE.
-#
-# NOTE: bltincmd must come first!
-
-bltincmd       command
-#alloccmd      alloc
-bgcmd -j       bg
-breakcmd       break continue
-#catfcmd       catf
-cdcmd          cd chdir
-dotcmd         .
-echocmd                echo
-evalcmd                eval
-execcmd                exec
-exitcmd                exit
-expcmd         exp let
-exportcmd      export readonly
-#exprcmd       expr test [
-histcmd                fc
-fgcmd -j       fg
-getoptscmd     getopts
-hashcmd                hash
-jobidcmd       jobid
-jobscmd                jobs
-#linecmd               line
-localcmd       local
-#nlechocmd     nlecho
-printfcmd      printf
-pwdcmd         pwd
-readcmd                read
-returncmd      return
-setcmd         set
-setvarcmd      setvar
-shiftcmd       shift
-trapcmd                trap
-truecmd                : true
-umaskcmd       umask
-unaliascmd     unalias
-unsetcmd       unset
-waitcmd                wait
-#foocmd                foo
-aliascmd       alias
diff --git a/minix/commands/ash/complete.c b/minix/commands/ash/complete.c
deleted file mode 100644 (file)
index b7ebd30..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
-complete.c
-
-Created:       July 1995 by Philip Homburg <philip@cs.vu.nl>
-*/
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include "myhistedit.h"
-#include "shell.h"
-
-#include "complete.h"
-#include "error.h"
-#include "expand.h"
-#include "nodes.h"
-#include "memalloc.h"
-
-static char **getlist(EditLine *el, int *baselen, int *isdir);
-static char **getlist_tilde(char *prefix);
-static int vstrcmp(const void *v1, const void *v2);
-static void print_list(char **list);
-static int install_extra(EditLine *el, char **list, int baselen, int isdir);
-
-unsigned char complete(EditLine *el, int ch)
-{
-       struct stackmark mark;
-       const LineInfo *lf;
-       char **list;
-       int baselen, prefix, isdir;
-
-       /* Direct the cursor the the end of the word. */
-       for(;;)
-       {
-               lf = el_line(el);
-               if (lf->cursor < lf->lastchar &&
-                       !isspace((unsigned char)*lf->cursor))
-               {
-                       (*(char **)&lf->cursor)++;      /* XXX */
-               }
-               else
-                       break;
-       }
-
-       setstackmark(&mark);
-       list= getlist(el, &baselen, &isdir);
-       if (list)
-       {
-               prefix= install_extra(el, list, baselen, isdir);
-               el_push(el, "i");
-       }
-       popstackmark(&mark);
-       if (list)
-               return CC_REFRESH;
-       else
-               return CC_ERROR;
-}
-
-unsigned char complete_list(EditLine *el, int ch)
-{
-       struct stackmark mark;
-       char **list;
-
-       setstackmark(&mark);
-       list= getlist(el, NULL, NULL);
-       if (list)
-       {
-               print_list(list);
-               re_goto_bottom(el);
-       }
-       popstackmark(&mark);
-       if (list)
-       {
-               return CC_REFRESH;
-       }
-       else
-               return CC_ERROR;
-}
-
-unsigned char complete_or_list(EditLine *el, int ch)
-{
-       struct stackmark mark;
-       const LineInfo *lf;
-       char **list;
-       int baselen, prefix, isdir;
-
-       setstackmark(&mark);
-       list= getlist(el, &baselen, &isdir);
-       if (list)
-       {
-               prefix= install_extra(el, list, baselen, isdir);
-               if (prefix == baselen)
-               {
-                       print_list(list);
-                       re_goto_bottom(el);
-               }
-       }
-       popstackmark(&mark);
-       if (list)
-               return CC_REFRESH;
-       else
-               return CC_ERROR;
-}
-
-unsigned char complete_expand(EditLine *el, int ch)
-{
-       printf("complete_expand\n");
-       return CC_ERROR;
-}
-
-static char **getlist(EditLine *el, int *baselen, int *isdir)
-{
-       const LineInfo *lf;
-       const char *begin, *end;
-       char *dirnam, *basenam;
-       union node arg;
-       struct arglist arglist;
-       DIR *dir;
-       struct dirent *dirent;
-       int i, l, n;
-       char *p, **list;
-       struct strlist *slp, *nslp;
-       struct stat sb;
-
-       lf = el_line(el);
-
-       /* Try to find to begin and end of the word that we have to comple. */
-       begin= lf->cursor;
-       while (begin > lf->buffer && !isspace((unsigned char)begin[-1]))
-               begin--;
-       end= lf->cursor;
-       while (end < lf->lastchar && !isspace((unsigned char)end[0]))
-               end++;
-
-       *(const char **)&lf->cursor= end; /* XXX */
-
-       /* Copy the word to a string */
-       dirnam= stalloc(end-begin+1);
-       strncpy(dirnam, begin, end-begin);
-       dirnam[end-begin]= '\0';
-
-       /* Cut the word in two pieces: a path and a (partial) component. */
-       basenam= strrchr(dirnam, '/');
-       if (basenam)
-       {
-               basenam++;
-               p= stalloc(strlen(basenam) + 1);
-               strcpy(p, basenam);
-               *basenam= '\0';
-               basenam= p;
-       }
-       else
-       {
-               if (dirnam[0] == '~')
-                       return getlist_tilde(dirnam);
-               basenam= dirnam;
-               dirnam= "./";
-       }
-       if (baselen)
-               *baselen= strlen(basenam);
-
-       arg.type= NARG;
-       arg.narg.next= NULL;
-       arg.narg.text= dirnam;
-       arg.narg.backquote= NULL;
-       arglist.list= NULL;
-       arglist.lastp= &arglist.list;
-       expandarg(&arg, &arglist, EXP_TILDE);
-
-       INTOFF;
-       list= NULL;
-       dir= opendir(arglist.list->text);
-       if (dir)
-       {
-               slp= NULL;
-               n= 0;
-               l= strlen(basenam);
-               while(dirent= readdir(dir))
-               {
-                       if (strncmp(dirent->d_name, basenam, l) != 0)
-                               continue;
-                       if (l == 0 && dirent->d_name[0] == '.')
-                               continue;
-                       nslp= stalloc(sizeof(*nslp));
-                       nslp->next= slp;
-                       slp= nslp;
-                       slp->text= stalloc(strlen(dirent->d_name)+1);
-                       strcpy(slp->text, dirent->d_name);
-                       n++;
-                       if (n == 1 && isdir != NULL)
-                       {
-                               /* Try to findout whether this entry is a
-                                * file or a directory.
-                                */
-                               p= stalloc(strlen(arglist.list->text) +
-                                       strlen(dirent->d_name) + 1);
-                               strcpy(p, arglist.list->text);
-                               strcat(p, dirent->d_name);
-                               if (stat(p, &sb) == -1)
-                                       printf("stat '%s' failed: %s\n",
-                                               p, strerror(errno));
-                               if (stat(p, &sb) == 0 && S_ISDIR(sb.st_mode))
-                                       *isdir= 1;
-                               else
-                                       *isdir= 0;
-                       }
-               }
-               closedir(dir);
-               if (n != 0)
-               {
-                       list= stalloc((n+1)*sizeof(*list));
-                       for(i= 0; slp; i++, slp= slp->next)
-                               list[i]= slp->text;
-                       if (i != n)
-                               error("complete'make_list: i != n");
-                       list[i]= NULL;
-                       qsort(list, n, sizeof(*list), vstrcmp);
-               }
-       }
-       INTON;
-       return list;
-}
-
-static char **getlist_tilde(char *prefix)
-{
-       printf("should ~-complete '%s'\n", prefix);
-       return NULL;
-}
-
-static int vstrcmp(const void *v1, const void *v2)
-{
-       return strcmp(*(char **)v1, *(char **)v2);
-}
-
-#define MAXCOLS 40
-#define SEPWIDTH 4
-
-static void print_list(char **list)
-{
-       struct
-       {
-               int cols;
-               int start[MAXCOLS+1];
-               int width[MAXCOLS];
-       } best, next;
-       int e, i, j, l, n, o, cols, maxw, width;
-       int linewidth= 80;
-
-       /* Count the number of entries. */
-       for (n= 0; list[n]; n++)
-               ;       /* do nothing */
-       if (n == 0)
-               error("complete'print_list: n= 0");
-
-       /* Try to maximize the number of columns */
-       for (cols= 1; cols<= MAXCOLS; cols++)
-       {
-               next.cols= cols;
-
-               o= 0;
-               width= 0;
-               for(j= 0; j<cols; j++)
-               {
-                       next.start[j]= o;
-
-                       /* Number of entries in this column. */
-                       e= (n-o)/(cols-j);
-                       if ((n-o)%(cols-j))
-                               e++;
-
-                       maxw= 0;
-                       for (i= 0; i<e; i++)
-                       {
-                               l= strlen(list[o+i]);
-                               if (l < 6)
-                                       l= 6;
-                               l += SEPWIDTH;
-                               if (l > maxw)
-                                       maxw= l;
-                       }
-                       next.width[j]= maxw;
-                       width += maxw;
-                       o += e;
-               }
-               next.start[j]= o;
-               if (cols > 1 && width-SEPWIDTH>linewidth)
-                       break;
-               best= next;
-       }
-       cols= best.cols;
-       e= best.start[1];
-       printf("\n");
-       for(i= 0; i<e; i++)
-       {
-               for (j= 0; j<cols; j++)
-               {
-                       if (best.start[j]+i == best.start[j+1])
-                               continue;
-                       if (j < cols-1)
-                       {
-                               printf("%-*s", best.width[j],
-                                       list[best.start[j]+i]);
-                       }
-                       else
-                       {
-                               printf("%s", list[best.start[j]+i]);
-                       }
-               }
-               if (i < e-1)
-                       printf("\n");
-       }
-       fflush(stdout);
-}
-
-static int install_extra(EditLine *el, char **list, int baselen, int isdir)
-{
-       int l;
-       char *p, **lp;
-
-       l= strlen(list[0]);
-       for (lp= &list[1]; *lp; lp++)
-       {
-               while(l>0)
-               {
-                       if (strncmp(list[0], *lp, l) != 0)
-                               l--;
-                       else
-                               break;
-               }
-       }
-       if (l > baselen || list[1] == NULL)
-       {
-               p= stalloc(l-baselen+2);
-               strncpy(p, list[0]+baselen, l-baselen);
-               if (list[1] == NULL)
-               {
-                       p[l-baselen]= isdir ? '/' : ' ';
-                       p[l-baselen+1]= '\0';
-                       l++;
-               }
-               else
-                       p[l-baselen]= '\0';
-               if (el_insertstr(el, p) == -1)
-                       return -1;
-       }
-       return l;
-}
-
-/*
- * $PchId: complete.c,v 1.2 2006/04/10 14:35:53 philip Exp $
- */
diff --git a/minix/commands/ash/complete.h b/minix/commands/ash/complete.h
deleted file mode 100644 (file)
index af859f9..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
-complete.h
-
-Created:       July 1995 by Philip Homburg <philip@cs.vu.nl>
-*/
-
-unsigned char complete(EditLine *el, int ch);
-unsigned char complete_list(EditLine *el, int ch);
-unsigned char complete_or_list(EditLine *el, int ch);
-unsigned char complete_expand(EditLine *el, int ch);
-
-/*
- * $PchId: complete.h,v 1.1 2001/05/17 07:12:05 philip Exp $
- */
diff --git a/minix/commands/ash/errmsg.c b/minix/commands/ash/errmsg.c
deleted file mode 100644 (file)
index 2a0303b..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char sccsid[] = "@(#)errmsg.c   8.1 (Berkeley) 5/31/93";
-#endif /* not lint */
-
-#include "shell.h"
-#include "output.h"
-#include "errmsg.h"
-#include <errno.h>
-
-
-#define ALL (E_OPEN|E_CREAT|E_EXEC)
-
-
-struct errname {
-       short errcode;          /* error number */
-       short action;           /* operation which encountered the error */
-       char *msg;              /* text describing the error */
-};
-
-
-STATIC const struct errname errormsg[] = {
-       EINTR, ALL,     "interrupted",
-       EACCES, ALL,    "permission denied",
-       EIO, ALL,               "I/O error",
-       ENOENT, E_OPEN, "no such file",
-       ENOENT, E_CREAT,        "directory nonexistent",
-       ENOENT, E_EXEC, "not found",
-       ENOTDIR, E_OPEN,        "no such file",
-       ENOTDIR, E_CREAT,       "directory nonexistent",
-       ENOTDIR, E_EXEC,        "not found",
-       EISDIR, ALL,    "is a directory",
-/*    EMFILE, ALL,     "too many open files", */
-       ENFILE, ALL,    "file table overflow",
-       ENOSPC, ALL,    "file system full",
-#ifdef EDQUOT
-       EDQUOT, ALL,    "disk quota exceeded",
-#endif
-#ifdef ENOSR
-       ENOSR, ALL,     "no streams resources",
-#endif
-       ENXIO, ALL,     "no such device or address",
-       EROFS, ALL,     "read-only file system",
-       ETXTBSY, ALL,   "text busy",
-#ifdef SYSV
-       EAGAIN, E_EXEC, "not enough memory",
-#endif
-       ENOMEM, ALL,    "not enough memory",
-#ifdef ENOLINK
-       ENOLINK, ALL,   "remote access failed"
-#endif
-#ifdef EMULTIHOP
-       EMULTIHOP, ALL, "remote access failed",
-#endif
-#ifdef ECOMM
-       ECOMM, ALL,     "remote access failed",
-#endif
-#ifdef ESTALE
-       ESTALE, ALL,    "remote access failed",
-#endif
-#ifdef ETIMEDOUT
-       ETIMEDOUT, ALL, "remote access failed",
-#endif
-#ifdef ELOOP
-       ELOOP, ALL,     "symbolic link loop",
-#endif
-       E2BIG, E_EXEC,  "argument list too long",
-#ifdef ELIBACC
-       ELIBACC, E_EXEC,        "shared library missing",
-#endif
-       0, 0,           NULL
-};
-
-
-/*
- * Return a string describing an error.  The returned string may be a
- * pointer to a static buffer that will be overwritten on the next call.
- * Action describes the operation that got the error.
- */
-
-char *
-errmsg(e, action) {
-       struct errname const *ep;
-       static char buf[12];
-
-       for (ep = errormsg ; ep->errcode ; ep++) {
-               if (ep->errcode == e && (ep->action & action) != 0)
-                       return ep->msg;
-       }
-       fmtstr(buf, sizeof buf, "error %d", e);
-       return buf;
-}
diff --git a/minix/commands/ash/errmsg.h b/minix/commands/ash/errmsg.h
deleted file mode 100644 (file)
index 03cb605..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *     @(#)errmsg.h    8.1 (Berkeley) 5/31/93
- */
-
-#define E_OPEN 01
-#define E_CREAT 02
-#define E_EXEC 04
-
-#ifdef __STDC__
-char *errmsg(int, int);
-#else
-char *errmsg();
-#endif
diff --git a/minix/commands/ash/error.c b/minix/commands/ash/error.c
deleted file mode 100644 (file)
index a56d0f2..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)error.c    8.2 (Berkeley) 5/4/95";
-#endif
-#endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/error.c,v 1.25 2004/04/06 20:06:51 markm Exp $");
-*/
-
-/*
- * Errors and exceptions.
- */
-
-#include "shell.h"
-#include "main.h"
-#include "options.h"
-#include "output.h"
-#include "error.h"
-#include "trap.h"
-#include <signal.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-
-/*
- * Code to handle exceptions in C.
- */
-
-struct jmploc *handler;
-volatile sig_atomic_t exception;
-volatile sig_atomic_t suppressint;
-volatile sig_atomic_t intpending;
-char *commandname;
-
-
-static void exverror(int, const char *, va_list) __printf0like(2, 0);
-
-/*
- * Called to raise an exception.  Since C doesn't include exceptions, we
- * just do a longjmp to the exception handler.  The type of exception is
- * stored in the global variable "exception".
- */
-
-void
-exraise(int e)
-{
-       if (handler == NULL)
-               abort();
-       exception = e;
-       longjmp(handler->loc, 1);
-}
-
-
-/*
- * Called from trap.c when a SIGINT is received.  (If the user specifies
- * that SIGINT is to be trapped or ignored using the trap builtin, then
- * this routine is not called.)  Suppressint is nonzero when interrupts
- * are held using the INTOFF macro.  If SIGINTs are not suppressed and
- * the shell is not a root shell, then we want to be terminated if we
- * get here, as if we were terminated directly by a SIGINT.  Arrange for
- * this here.
- */
-
-void
-onint(void)
-{
-       sigset_t sigset;
-
-       /*
-        * The !in_dotrap here is safe.  The only way we can arrive here
-        * with in_dotrap set is that a trap handler set SIGINT to SIG_DFL
-        * and killed itself.
-        */
-
-       if (suppressint && !in_dotrap) {
-               intpending++;
-               return;
-       }
-       intpending = 0;
-       sigemptyset(&sigset);
-       sigprocmask(SIG_SETMASK, &sigset, NULL);
-
-       /*
-        * This doesn't seem to be needed, since main() emits a newline.
-        */
-#if 0
-       if (tcgetpgrp(0) == getpid())   
-               write(STDERR_FILENO, "\n", 1);
-#endif
-       if (rootshell && iflag)
-               exraise(EXINT);
-       else {
-               signal(SIGINT, SIG_DFL);
-               kill(getpid(), SIGINT);
-       }
-}
-
-
-/*
- * Exverror is called to raise the error exception.  If the first argument
- * is not NULL then error prints an error message using printf style
- * formatting.  It then raises the error exception.
- */
-static void
-exverror(int cond, const char *msg, va_list ap)
-{
-       CLEAR_PENDING_INT;
-       INTOFF;
-
-#if DEBUG
-       if (msg)
-               TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
-       else
-               TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
-#endif
-       if (msg) {
-               if (commandname)
-                       outfmt(&errout, "%s: ", commandname);
-               doformat(&errout, msg, ap);
-               out2c('\n');
-       }
-       flushall();
-       exraise(cond);
-}
-
-
-void
-error(const char *msg, ...)
-{
-       va_list ap;
-       va_start(ap, msg);
-       exverror(EXERROR, msg, ap);
-       va_end(ap);
-}
-
-
-void
-exerror(int cond, const char *msg, ...)
-{
-       va_list ap;
-       va_start(ap, msg);
-       exverror(cond, msg, ap);
-       va_end(ap);
-}
-
-/*
- * $PchId: error.c,v 1.5 2006/04/10 14:36:23 philip Exp $
- */
diff --git a/minix/commands/ash/jobs.c b/minix/commands/ash/jobs.c
deleted file mode 100644 (file)
index 8333f8b..0000000
+++ /dev/null
@@ -1,1300 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)jobs.c     8.5 (Berkeley) 5/4/95";
-#endif
-#endif /* not lint */
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/jobs.c,v 1.67 2004/04/06 20:06:51 markm Exp $");
-*/
-
-#include "shell.h"
-
-#include <sys/types.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <errno.h>
-#ifndef NO_PATHS_H
-#include <paths.h>
-#endif
-#include <unistd.h>
-#include <stdlib.h>
-#ifdef POSIX
-#include <signal.h>
-#include <sys/wait.h>
-#elif defined(BSD)
-#include <sys/param.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#endif
-#include <sys/ioctl.h>
-
-#if JOBS
-#include <termios.h>
-#undef CEOF                    /* syntax.h redefines this */
-#endif
-#include "redir.h"
-#include "show.h"
-#include "main.h"
-#include "parser.h"
-#include "nodes.h"
-#include "jobs.h"
-#include "options.h"
-#include "trap.h"
-#include "syntax.h"
-#include "input.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include "mystring.h"
-#include "builtins.h"
-
-#ifdef __minix
-/* #define NO_KILLPG */
-#endif
-
-#ifndef _PATH_TTY
-#define _PATH_TTY "/dev/tty"
-#endif
-#ifndef _PATH_DEVNULL
-#define _PATH_DEVNULL "/dev/null"
-#endif
-
-STATIC struct job *jobtab;     /* array of jobs */
-STATIC int njobs;              /* size of array */
-MKINIT pid_t backgndpid = -1;  /* pid of last background process */
-#if JOBS
-STATIC struct job *jobmru;     /* most recently used job list */
-STATIC pid_t initialpgrp;      /* pgrp of shell on invocation */
-#endif
-int in_waitcmd = 0;            /* are we in waitcmd()? */
-int in_dowait = 0;             /* are we in dowait()? */
-volatile sig_atomic_t breakwaitcmd = 0;        /* should wait be terminated? */
-#if JOBS
-static int ttyfd = -1;
-#endif
-
-#ifndef WCOREDUMP
-#define WCOREDUMP(s)   ((s) & 0x80)
-#endif
-
-#if JOBS
-STATIC void restartjob(struct job *);
-#endif
-STATIC void freejob(struct job *);
-STATIC struct job *getjob(char *);
-STATIC pid_t dowait(int, struct job *);
-STATIC pid_t waitproc(int, int *);
-STATIC void cmdtxt(union node *);
-STATIC void cmdputs(char *);
-#if JOBS
-STATIC void setcurjob(struct job *);
-STATIC void deljob(struct job *);
-STATIC struct job *getcurjob(struct job *);
-#endif
-STATIC void showjob(struct job *, pid_t, int, int);
-
-#ifdef NO_KILLPG
-static int killpg(pid_t,int);
-#endif
-
-/*
- * Turn job control on and off.
- */
-
-MKINIT int jobctl;
-
-#if JOBS
-void
-setjobctl(int on)
-{
-       int i;
-
-       if (on == jobctl || rootshell == 0)
-               return;
-       if (on) {
-               if (ttyfd != -1)
-                       close(ttyfd);
-               if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) {
-                       i = 0;
-                       while (i <= 2 && !isatty(i))
-                               i++;
-                       if (i > 2 || (ttyfd = fcntl(i, F_DUPFD, 10)) < 0)
-                               goto out;
-               }
-               if (ttyfd < 10) {
-                       /*
-                        * Keep our TTY file descriptor out of the way of
-                        * the user's redirections.
-                        */
-                       if ((i = fcntl(ttyfd, F_DUPFD, 10)) < 0) {
-                               close(ttyfd);
-                               ttyfd = -1;
-                               goto out;
-                       }
-                       close(ttyfd);
-                       ttyfd = i;
-               }
-               if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) {
-                       close(ttyfd);
-                       ttyfd = -1;
-                       goto out;
-               }
-               do { /* while we are in the background */
-                       initialpgrp = tcgetpgrp(ttyfd);
-                       if (initialpgrp < 0) {
-out:                           out2str("sh: can't access tty; job control turned off\n");
-                               mflag = 0;
-                               return;
-                       }
-                       if (initialpgrp == -1)
-                               initialpgrp = getpgrp();
-                       else if (initialpgrp != getpgrp()) {
-                               killpg(0, SIGTTIN);
-                               continue;
-                       }
-               } while (0);
-               setsignal(SIGTSTP);
-               setsignal(SIGTTOU);
-               setsignal(SIGTTIN);
-               setpgid(0, rootpid);
-               tcsetpgrp(ttyfd, rootpid);
-       } else { /* turning job control off */
-               setpgid(0, initialpgrp);
-               tcsetpgrp(ttyfd, initialpgrp);
-               close(ttyfd);
-               ttyfd = -1;
-               setsignal(SIGTSTP);
-               setsignal(SIGTTOU);
-               setsignal(SIGTTIN);
-       }
-       jobctl = on;
-}
-#endif
-
-
-#ifdef mkinit
-INCLUDE <sys/types.h>
-INCLUDE <stdlib.h>
-
-SHELLPROC {
-       backgndpid = -1;
-#if JOBS
-       jobctl = 0;
-#endif
-}
-
-#endif
-
-
-
-#if JOBS
-int
-fgcmd(int argc __unused, char **argv)
-{
-       struct job *jp;
-       pid_t pgrp;
-       int status;
-
-       jp = getjob(argv[1]);
-       if (jp->jobctl == 0)
-               error("job not created under job control");
-       out1str(jp->ps[0].cmd);
-       out1c('\n');
-       flushout(&output);
-       pgrp = jp->ps[0].pid;
-       tcsetpgrp(ttyfd, pgrp);
-       restartjob(jp);
-       jp->foreground = 1;
-       INTOFF;
-       status = waitforjob(jp, (int *)NULL);
-       INTON;
-       return status;
-}
-
-
-int
-bgcmd(int argc, char **argv)
-{
-       char s[64];
-       struct job *jp;
-
-       do {
-               jp = getjob(*++argv);
-               if (jp->jobctl == 0)
-                       error("job not created under job control");
-               if (jp->state == JOBDONE)
-                       continue;
-               restartjob(jp);
-               jp->foreground = 0;
-               fmtstr(s, 64, "[%td] ", jp - jobtab + 1);
-               out1str(s);
-               out1str(jp->ps[0].cmd);
-               out1c('\n');
-       } while (--argc > 1);
-       return 0;
-}
-
-
-STATIC void
-restartjob(struct job *jp)
-{
-       struct procstat *ps;
-       int i;
-
-       if (jp->state == JOBDONE)
-               return;
-       setcurjob(jp);
-       INTOFF;
-       killpg(jp->ps[0].pid, SIGCONT);
-       for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
-               if (WIFSTOPPED(ps->status)) {
-                       ps->status = -1;
-                       jp->state = 0;
-               }
-       }
-       INTON;
-}
-#endif
-
-
-int
-jobscmd(int argc, char *argv[])
-{
-       char *id;
-       int ch, sformat, lformat;
-
-       optind = optreset = 1;
-       opterr = 0;
-       sformat = lformat = 0;
-       while ((ch = getopt(argc, argv, "ls")) != -1) {
-               switch (ch) {
-               case 'l':
-                       lformat = 1;
-                       break;
-               case 's':
-                       sformat = 1;
-                       break;
-               case '?':
-               default:
-                       error("unknown option: -%c", optopt);
-               }
-       }
-       argc -= optind;
-       argv += optind;
-
-       if (argc == 0)
-               showjobs(0, sformat, lformat);
-       else
-               while ((id = *argv++) != NULL)
-                       showjob(getjob(id), 0, sformat, lformat);
-
-       return (0);
-}
-
-STATIC void
-showjob(struct job *jp, pid_t pid, int sformat, int lformat)
-{
-       char s[64];
-       struct procstat *ps;
-#if JOBS
-       struct job *j;
-#endif
-       int col, curr, i, jobno, prev, procno;
-       char c;
-
-       procno = jp->nprocs;
-       jobno = jp - jobtab + 1;
-       curr = prev = 0;
-#if JOBS
-       if ((j = getcurjob(NULL)) != NULL) {
-               curr = j - jobtab + 1;
-               if ((j = getcurjob(j)) != NULL)
-                       prev = j - jobtab + 1;
-       }
-#endif
-       for (ps = jp->ps ; ; ps++) {    /* for each process */
-               if (sformat) {
-                       out1fmt("%d\n", (int)ps->pid);
-                       goto skip;
-               }
-               if (!lformat && ps != jp->ps && pid == 0)
-                       goto skip;
-               if (pid != 0 && pid != ps->pid)
-                       goto skip;
-               if (jobno == curr && ps == jp->ps)
-                       c = '+';
-               else if (jobno == prev && ps == jp->ps)
-                       c = '-';
-               else
-                       c = ' ';
-               if (ps == jp->ps)
-                       fmtstr(s, 64, "[%d] %c ", jobno, c);
-               else
-                       fmtstr(s, 64, "    %c ", c);
-               out1str(s);
-               col = strlen(s);
-               if (lformat) {
-                       fmtstr(s, 64, "%d ", (int)ps->pid);
-                       out1str(s);
-                       col += strlen(s);
-               }
-               s[0] = '\0';
-               if (ps != jp->ps) {
-                       *s = '\0';
-               } else if (ps->status == -1) {
-                       strcpy(s, "Running");
-               } else if (WIFEXITED(ps->status)) {
-                       if (WEXITSTATUS(ps->status) == 0)
-                               strcpy(s, "Done");
-                       else
-                               fmtstr(s, 64, "Done (%d)",
-                                   WEXITSTATUS(ps->status));
-               } else {
-#if JOBS
-                       if (WIFSTOPPED(ps->status)) 
-                               i = WSTOPSIG(ps->status);
-                       else
-#endif
-                               i = WTERMSIG(ps->status);
-                       if ((i & 0x7F) < _NSIG && strsiglist(i & 0x7F))
-                               scopy(strsiglist(i & 0x7F), s);
-                       else
-                               fmtstr(s, 64, "Signal %d", i & 0x7F);
-                       if (WCOREDUMP(ps->status))
-                               strcat(s, " (core dumped)");
-               }
-               out1str(s);
-               col += strlen(s);
-               do {
-                       out1c(' ');
-                       col++;
-               } while (col < 30);
-               out1str(ps->cmd);
-               out1c('\n');
-skip:          if (--procno <= 0)
-                       break;
-       }
-}
-
-/*
- * Print a list of jobs.  If "change" is nonzero, only print jobs whose
- * statuses have changed since the last call to showjobs.
- *
- * If the shell is interrupted in the process of creating a job, the
- * result may be a job structure containing zero processes.  Such structures
- * will be freed here.
- */
-
-void
-showjobs(int change, int sformat, int lformat)
-{
-       int jobno;
-       struct job *jp;
-
-       TRACE(("showjobs(%d) called\n", change));
-       while (dowait(0, (struct job *)NULL) > 0);
-       for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
-               if (! jp->used)
-                       continue;
-               if (jp->nprocs == 0) {
-                       freejob(jp);
-                       continue;
-               }
-               if (change && ! jp->changed)
-                       continue;
-               showjob(jp, 0, sformat, lformat);
-               jp->changed = 0;
-               if (jp->state == JOBDONE) {
-                       freejob(jp);
-               }
-       }
-}
-
-
-/*
- * Mark a job structure as unused.
- */
-
-STATIC void
-freejob(struct job *jp)
-{
-       struct procstat *ps;
-       int i;
-
-       INTOFF;
-       for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
-               if (ps->cmd != nullstr)
-                       ckfree(ps->cmd);
-       }
-       if (jp->ps != &jp->ps0)
-               ckfree(jp->ps);
-       jp->used = 0;
-#if JOBS
-       deljob(jp);
-#endif
-       INTON;
-}
-
-
-
-int
-waitcmd(int argc, char **argv)
-{
-       struct job *job;
-       int status, retval;
-       struct job *jp;
-
-       if (argc > 1) {
-               job = getjob(argv[1]);
-       } else {
-               job = NULL;
-       }
-
-       /*
-        * Loop until a process is terminated or stopped, or a SIGINT is
-        * received.
-        */
-
-       in_waitcmd++;
-       do {
-               if (job != NULL) {
-                       if (job->state) {
-                               status = job->ps[job->nprocs - 1].status;
-                               if (WIFEXITED(status))
-                                       retval = WEXITSTATUS(status);
-#if JOBS
-                               else if (WIFSTOPPED(status))
-                                       retval = WSTOPSIG(status) + 128;
-#endif
-                               else
-                                       retval = WTERMSIG(status) + 128;
-                               if (! iflag)
-                                       freejob(job);
-                               in_waitcmd--;
-                               return retval;
-                       }
-               } else {
-                       for (jp = jobtab ; ; jp++) {
-                               if (jp >= jobtab + njobs) {     /* no running procs */
-                                       in_waitcmd--;
-                                       return 0;
-                               }
-                               if (jp->used && jp->state == 0)
-                                       break;
-                       }
-               }
-       } while (dowait(1, (struct job *)NULL) != -1);
-       in_waitcmd--;
-
-       return 0;
-}
-
-
-
-int
-jobidcmd(int argc __unused, char **argv)
-{
-       struct job *jp;
-       int i;
-
-       jp = getjob(argv[1]);
-       for (i = 0 ; i < jp->nprocs ; ) {
-               out1fmt("%d", (int)jp->ps[i].pid);
-               out1c(++i < jp->nprocs? ' ' : '\n');
-       }
-       return 0;
-}
-
-
-
-/*
- * Convert a job name to a job structure.
- */
-
-STATIC struct job *
-getjob(char *name)
-{
-       int jobno;
-       struct job *found, *jp;
-       pid_t pid;
-       int i;
-
-       if (name == NULL) {
-#if JOBS
-currentjob:    if ((jp = getcurjob(NULL)) == NULL)
-                       error("No current job");
-               return (jp);
-#else
-               error("No current job");
-#endif
-       } else if (name[0] == '%') {
-               if (is_digit(name[1])) {
-                       jobno = number(name + 1);
-                       if (jobno > 0 && jobno <= njobs
-                        && jobtab[jobno - 1].used != 0)
-                               return &jobtab[jobno - 1];
-#if JOBS
-               } else if (name[1] == '%' && name[2] == '\0') {
-                       goto currentjob;
-               } else if (name[1] == '+' && name[2] == '\0') {
-                       goto currentjob;
-               } else if (name[1] == '-' && name[2] == '\0') {
-                       if ((jp = getcurjob(NULL)) == NULL ||
-                           (jp = getcurjob(jp)) == NULL)
-                               error("No previous job");
-                       return (jp);
-#endif
-               } else if (name[1] == '?') {
-                       found = NULL;
-                       for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
-                               if (jp->used && jp->nprocs > 0
-                                && strstr(jp->ps[0].cmd, name + 2) != NULL) {
-                                       if (found)
-                                               error("%s: ambiguous", name);
-                                       found = jp;
-                               }
-                       }
-                       if (found != NULL)
-                               return (found);
-               } else {
-                       found = NULL;
-                       for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
-                               if (jp->used && jp->nprocs > 0
-                                && prefix(name + 1, jp->ps[0].cmd)) {
-                                       if (found)
-                                               error("%s: ambiguous", name);
-                                       found = jp;
-                               }
-                       }
-                       if (found)
-                               return found;
-               }
-       } else if (is_number(name)) {
-               pid = (pid_t)number(name);
-               for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
-                       if (jp->used && jp->nprocs > 0
-                        && jp->ps[jp->nprocs - 1].pid == pid)
-                               return jp;
-               }
-       }
-       error("No such job: %s", name);
-       /*NOTREACHED*/
-       return NULL;
-}
-
-
-
-/*
- * Return a new job structure,
- */
-
-struct job *
-makejob(union node *node __unused, int nprocs)
-{
-       int i;
-       struct job *jp;
-
-       for (i = njobs, jp = jobtab ; ; jp++) {
-               if (--i < 0) {
-                       INTOFF;
-                       if (njobs == 0) {
-                               jobtab = ckmalloc(4 * sizeof jobtab[0]);
-#if JOBS
-                               jobmru = NULL;
-#endif
-                       } else {
-                               jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
-                               memcpy(jp, jobtab, njobs * sizeof jp[0]);
-#if JOBS
-                               /* Relocate `next' pointers and list head */
-                               if (jobmru != NULL)
-                                       jobmru = &jp[jobmru - jobtab];
-                               for (i = 0; i < njobs; i++)
-                                       if (jp[i].next != NULL)
-                                               jp[i].next = &jp[jp[i].next -
-                                                   jobtab];
-#endif
-                               /* Relocate `ps' pointers */
-                               for (i = 0; i < njobs; i++)
-                                       if (jp[i].ps == &jobtab[i].ps0)
-                                               jp[i].ps = &jp[i].ps0;
-                               ckfree(jobtab);
-                               jobtab = jp;
-                       }
-                       jp = jobtab + njobs;
-                       for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
-                       INTON;
-                       break;
-               }
-               if (jp->used == 0)
-                       break;
-       }
-       INTOFF;
-       jp->state = 0;
-       jp->used = 1;
-       jp->changed = 0;
-       jp->nprocs = 0;
-       jp->foreground = 0;
-#if JOBS
-       jp->jobctl = jobctl;
-       jp->next = NULL;
-#endif
-       if (nprocs > 1) {
-               jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
-       } else {
-               jp->ps = &jp->ps0;
-       }
-       INTON;
-       TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
-           jp - jobtab + 1));
-       return jp;
-}
-
-#if JOBS
-STATIC void
-setcurjob(struct job *cj)
-{
-       struct job *jp, *prev;
-
-       for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
-               if (jp == cj) {
-                       if (prev != NULL)
-                               prev->next = jp->next;
-                       else
-                               jobmru = jp->next;
-                       jp->next = jobmru;
-                       jobmru = cj;
-                       return;
-               }
-       }
-       cj->next = jobmru;
-       jobmru = cj;
-}
-
-STATIC void
-deljob(struct job *j)
-{
-       struct job *jp, *prev;
-
-       for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
-               if (jp == j) {
-                       if (prev != NULL)
-                               prev->next = jp->next;
-                       else
-                               jobmru = jp->next;
-                       return;
-               }
-       }
-}
-
-/*
- * Return the most recently used job that isn't `nj', and preferably one
- * that is stopped.
- */
-STATIC struct job *
-getcurjob(struct job *nj)
-{
-       struct job *jp;
-
-       /* Try to find a stopped one.. */
-       for (jp = jobmru; jp != NULL; jp = jp->next)
-               if (jp->used && jp != nj && jp->state == JOBSTOPPED)
-                       return (jp);
-       /* Otherwise the most recently used job that isn't `nj' */
-       for (jp = jobmru; jp != NULL; jp = jp->next)
-               if (jp->used && jp != nj)
-                       return (jp);
-
-       return (NULL);
-}
-
-#endif
-
-/*
- * Fork of a subshell.  If we are doing job control, give the subshell its
- * own process group.  Jp is a job structure that the job is to be added to.
- * N is the command that will be evaluated by the child.  Both jp and n may
- * be NULL.  The mode parameter can be one of the following:
- *     FORK_FG - Fork off a foreground process.
- *     FORK_BG - Fork off a background process.
- *     FORK_NOJOB - Like FORK_FG, but don't give the process its own
- *                  process group even if job control is on.
- *
- * When job control is turned off, background processes have their standard
- * input redirected to /dev/null (except for the second and later processes
- * in a pipeline).
- */
-
-pid_t
-forkshell(struct job *jp, union node *n, int mode)
-{
-       pid_t pid;
-       pid_t pgrp;
-
-       TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
-           mode));
-       INTOFF;
-       flushall();
-       pid = fork();
-       if (pid == -1) {
-               TRACE(("Fork failed, errno=%d\n", errno));
-               INTON;
-               error("Cannot fork: %s", strerror(errno));
-       }
-       if (pid == 0) {
-               struct job *p;
-               int wasroot;
-               int i;
-
-               TRACE(("Child shell %d\n", (int)getpid()));
-               wasroot = rootshell;
-               rootshell = 0;
-               closescript();
-               INTON;
-               clear_traps();
-#if JOBS
-               jobctl = 0;             /* do job control only in root shell */
-               if (wasroot && mode != FORK_NOJOB && mflag) {
-                       if (jp == NULL || jp->nprocs == 0)
-                               pgrp = getpid();
-                       else
-                               pgrp = jp->ps[0].pid;
-                       if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
-                               /*** this causes superfluous TIOCSPGRPS ***/
-                               if (tcsetpgrp(ttyfd, pgrp) < 0)
-                                       error("tcsetpgrp failed, errno=%d", errno);
-                       }
-                       setsignal(SIGTSTP);
-                       setsignal(SIGTTOU);
-               } else if (mode == FORK_BG) {
-                       ignoresig(SIGINT);
-                       ignoresig(SIGQUIT);
-                       if ((jp == NULL || jp->nprocs == 0) &&
-                           ! fd0_redirected_p ()) {
-                               close(0);
-                               if (open(_PATH_DEVNULL, O_RDONLY) != 0)
-                                       error("Can't open %s: %s",
-                                           _PATH_DEVNULL, strerror(errno));
-                       }
-               }
-#else
-               if (mode == FORK_BG) {
-                       ignoresig(SIGINT);
-                       ignoresig(SIGQUIT);
-                       if ((jp == NULL || jp->nprocs == 0) &&
-                           ! fd0_redirected_p ()) {
-                               close(0);
-                               if (open(_PATH_DEVNULL, O_RDONLY) != 0)
-                                       error("Can't open %s: %s", 
-                                           _PATH_DEVNULL, strerror(errno));
-                       }
-               }
-#endif
-               INTOFF;
-               for (i = njobs, p = jobtab ; --i >= 0 ; p++)
-                       if (p->used)
-                               freejob(p);
-               INTON;
-               if (wasroot && iflag) {
-                       setsignal(SIGINT);
-                       setsignal(SIGQUIT);
-                       setsignal(SIGTERM);
-               }
-               return pid;
-       }
-       if (rootshell && mode != FORK_NOJOB && mflag) {
-               if (jp == NULL || jp->nprocs == 0)
-                       pgrp = pid;
-               else
-                       pgrp = jp->ps[0].pid;
-#if JOBS
-               setpgid(pid, pgrp);
-#endif
-       }
-       if (mode == FORK_BG)
-               backgndpid = pid;               /* set $! */
-       if (jp) {
-               struct procstat *ps = &jp->ps[jp->nprocs++];
-               ps->pid = pid;
-               ps->status = -1;
-               ps->cmd = nullstr;
-               if (iflag && rootshell && n)
-                       ps->cmd = commandtext(n);
-               jp->foreground = mode == FORK_FG;
-#if JOBS
-               setcurjob(jp);
-#endif
-       }
-       INTON;
-       TRACE(("In parent shell:  child = %d\n", (int)pid));
-       return pid;
-}
-
-
-
-/*
- * Wait for job to finish.
- *
- * Under job control we have the problem that while a child process is
- * running interrupts generated by the user are sent to the child but not
- * to the shell.  This means that an infinite loop started by an inter-
- * active user may be hard to kill.  With job control turned off, an
- * interactive user may place an interactive program inside a loop.  If
- * the interactive program catches interrupts, the user doesn't want
- * these interrupts to also abort the loop.  The approach we take here
- * is to have the shell ignore interrupt signals while waiting for a
- * foreground process to terminate, and then send itself an interrupt
- * signal if the child process was terminated by an interrupt signal.
- * Unfortunately, some programs want to do a bit of cleanup and then
- * exit on interrupt; unless these processes terminate themselves by
- * sending a signal to themselves (instead of calling exit) they will
- * confuse this approach.
- */
-
-int
-waitforjob(struct job *jp, int *origstatus)
-{
-#if JOBS
-       pid_t mypgrp = getpgrp();
-#endif
-       int status;
-       int st;
-
-       INTOFF;
-       TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
-       while (jp->state == 0)
-               if (dowait(1, jp) == -1)
-                       dotrap();
-#if JOBS
-       if (jp->jobctl) {
-               if (tcsetpgrp(ttyfd, mypgrp) < 0)
-                       error("tcsetpgrp failed, errno=%d\n", errno);
-       }
-       if (jp->state == JOBSTOPPED)
-               setcurjob(jp);
-#endif
-       status = jp->ps[jp->nprocs - 1].status;
-       if (origstatus != NULL)
-               *origstatus = status;
-       /* convert to 8 bits */
-       if (WIFEXITED(status))
-               st = WEXITSTATUS(status);
-#if JOBS
-       else if (WIFSTOPPED(status))
-               st = WSTOPSIG(status) + 128;
-#endif
-       else
-               st = WTERMSIG(status) + 128;
-       if (! JOBS || jp->state == JOBDONE)
-               freejob(jp);
-       if (int_pending()) {
-               if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
-                       kill(getpid(), SIGINT);
-               else
-                       CLEAR_PENDING_INT;
-       }
-       INTON;
-       return st;
-}
-
-
-
-/*
- * Wait for a process to terminate.
- */
-
-STATIC pid_t
-dowait(int block, struct job *job)
-{
-       pid_t pid;
-       int status, core;
-       struct procstat *sp;
-       struct job *jp;
-       struct job *thisjob;
-       int done;
-       int stopped;
-       int sig;
-       int i;
-
-       in_dowait++;
-       TRACE(("dowait(%d) called\n", block));
-       do {
-               pid = waitproc(block, &status);
-               TRACE(("wait returns %d, status=%d\n", (int)pid, status));
-       } while ((pid == -1 && errno == EINTR && breakwaitcmd == 0) ||
-                (pid > 0 && WIFSTOPPED(status) && !iflag));
-       in_dowait--;
-       if (breakwaitcmd != 0) {
-               breakwaitcmd = 0;
-               return -1;
-       }
-       if (pid <= 0)
-               return pid;
-       INTOFF;
-       thisjob = NULL;
-       for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
-               if (jp->used) {
-                       done = 1;
-                       stopped = 1;
-                       for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
-                               if (sp->pid == -1)
-                                       continue;
-                               if (sp->pid == pid) {
-                                       TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
-                                                  (int)pid, sp->status,
-                                                  status));
-                                       sp->status = status;
-                                       thisjob = jp;
-                               }
-                               if (sp->status == -1)
-                                       stopped = 0;
-                               else if (WIFSTOPPED(sp->status))
-                                       done = 0;
-                       }
-                       if (stopped) {          /* stopped or done */
-                               int state = done? JOBDONE : JOBSTOPPED;
-                               if (jp->state != state) {
-                                       TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
-                                       jp->state = state;
-#if JOBS
-                                       if (done)
-                                               deljob(jp);
-#endif
-                               }
-                       }
-               }
-       }
-       INTON;
-       if (! rootshell || ! iflag || (job && thisjob == job)) {
-               core = WCOREDUMP(status);
-#if JOBS
-               if (WIFSTOPPED(status))
-                       sig = WSTOPSIG(status);
-               else
-#endif
-               {
-                       if (WIFEXITED(status))
-                               sig = 0;
-                       else
-                               sig = WTERMSIG(status);
-               }
-               if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
-                       if (!mflag ||
-                           (thisjob->foreground && !WIFSTOPPED(status))) {
-                               i = WTERMSIG(status);
-                               if ((i & 0x7F) < _NSIG && strsiglist(i & 0x7F))
-                                       out1str(strsiglist(i & 0x7F));
-                               else
-                                       out1fmt("Signal %d", i & 0x7F);
-                               if (core)
-                                       out1str(" (core dumped)");
-                               out1c('\n');
-                       } else
-                               showjob(thisjob, pid, 0, 0);
-               }
-       } else {
-               TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
-               if (thisjob)
-                       thisjob->changed = 1;
-       }
-       return pid;
-}
-
-
-
-/*
- * Do a wait system call.  If job control is compiled in, we accept
- * stopped processes.  If block is zero, we return a value of zero
- * rather than blocking.
- */
-STATIC pid_t
-waitproc(int block, int *status)
-{
-#if POSIX
-       int flags;
-
-#if JOBS
-       flags = ((rootshell && is_interactive) ? WUNTRACED : 0);
-#else
-       flags = 0;
-#endif /* JOBS */
-       return waitpid(-1, status, (block == 0 ? WNOHANG : 0) | flags);
-#else /* !POSIX */
-       /* Assume BSD */
-       int flags;
-
-#if JOBS
-       flags = WUNTRACED;
-#else
-       flags = 0;
-#endif /* JOBS */
-       if (block == 0)
-               flags |= WNOHANG;
-       return wait3(status, flags, (struct rusage *)NULL);
-#endif /* POSIX */
-}
-
-/*
- * return 1 if there are stopped jobs, otherwise 0
- */
-int job_warning = 0;
-int
-stoppedjobs(void)
-{
-       int jobno;
-       struct job *jp;
-
-       if (job_warning)
-               return (0);
-       for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
-               if (jp->used == 0)
-                       continue;
-               if (jp->state == JOBSTOPPED) {
-                       out2str("You have stopped jobs.\n");
-                       job_warning = 2;
-                       return (1);
-               }
-       }
-
-       return (0);
-}
-
-/*
- * Return a string identifying a command (to be printed by the
- * jobs command.
- */
-
-STATIC char *cmdnextc;
-STATIC int cmdnleft;
-#define MAXCMDTEXT     200
-
-char *
-commandtext(union node *n)
-{
-       char *name;
-
-       cmdnextc = name = ckmalloc(MAXCMDTEXT);
-       cmdnleft = MAXCMDTEXT - 4;
-       cmdtxt(n);
-       *cmdnextc = '\0';
-       return name;
-}
-
-
-STATIC void
-cmdtxt(union node *n)
-{
-       union node *np;
-       struct nodelist *lp;
-       char *p;
-       int i;
-       char s[2];
-
-       if (n == NULL)
-               return;
-       switch (n->type) {
-       case NSEMI:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs("; ");
-               cmdtxt(n->nbinary.ch2);
-               break;
-       case NAND:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs(" && ");
-               cmdtxt(n->nbinary.ch2);
-               break;
-       case NOR:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs(" || ");
-               cmdtxt(n->nbinary.ch2);
-               break;
-       case NPIPE:
-               for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
-                       cmdtxt(lp->n);
-                       if (lp->next)
-                               cmdputs(" | ");
-               }
-               break;
-       case NSUBSHELL:
-               cmdputs("(");
-               cmdtxt(n->nredir.n);
-               cmdputs(")");
-               break;
-       case NREDIR:
-       case NBACKGND:
-               cmdtxt(n->nredir.n);
-               break;
-       case NIF:
-               cmdputs("if ");
-               cmdtxt(n->nif.test);
-               cmdputs("; then ");
-               cmdtxt(n->nif.ifpart);
-               cmdputs("...");
-               break;
-       case NWHILE:
-               cmdputs("while ");
-               goto until;
-       case NUNTIL:
-               cmdputs("until ");
-until:
-               cmdtxt(n->nbinary.ch1);
-               cmdputs("; do ");
-               cmdtxt(n->nbinary.ch2);
-               cmdputs("; done");
-               break;
-       case NFOR:
-               cmdputs("for ");
-               cmdputs(n->nfor.var);
-               cmdputs(" in ...");
-               break;
-       case NCASE:
-               cmdputs("case ");
-               cmdputs(n->ncase.expr->narg.text);
-               cmdputs(" in ...");
-               break;
-       case NDEFUN:
-               cmdputs(n->narg.text);
-               cmdputs("() ...");
-               break;
-       case NCMD:
-               for (np = n->ncmd.args ; np ; np = np->narg.next) {
-                       cmdtxt(np);
-                       if (np->narg.next)
-                               cmdputs(" ");
-               }
-               for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
-                       cmdputs(" ");
-                       cmdtxt(np);
-               }
-               break;
-       case NARG:
-               cmdputs(n->narg.text);
-               break;
-       case NTO:
-               p = ">";  i = 1;  goto redir;
-       case NAPPEND:
-               p = ">>";  i = 1;  goto redir;
-       case NTOFD:
-               p = ">&";  i = 1;  goto redir;
-       case NCLOBBER:
-               p = ">|"; i = 1; goto redir;
-       case NFROM:
-               p = "<";  i = 0;  goto redir;
-       case NFROMTO:
-               p = "<>";  i = 0;  goto redir;
-       case NFROMFD:
-               p = "<&";  i = 0;  goto redir;
-redir:
-               if (n->nfile.fd != i) {
-                       s[0] = n->nfile.fd + '0';
-                       s[1] = '\0';
-                       cmdputs(s);
-               }
-               cmdputs(p);
-               if (n->type == NTOFD || n->type == NFROMFD) {
-                       if (n->ndup.dupfd >= 0)
-                               s[0] = n->ndup.dupfd + '0';
-                       else
-                               s[0] = '-';
-                       s[1] = '\0';
-                       cmdputs(s);
-               } else {
-                       cmdtxt(n->nfile.fname);
-               }
-               break;
-       case NHERE:
-       case NXHERE:
-               cmdputs("<<...");
-               break;
-       default:
-               cmdputs("???");
-               break;
-       }
-}
-
-
-
-STATIC void
-cmdputs(char *s)
-{
-       char *p, *q;
-       char c;
-       int subtype = 0;
-
-       if (cmdnleft <= 0)
-               return;
-       p = s;
-       q = cmdnextc;
-       while ((c = *p++) != '\0') {
-               if (c == CTLESC)
-                       *q++ = *p++;
-               else if (c == CTLVAR) {
-                       *q++ = '$';
-                       if (--cmdnleft > 0)
-                               *q++ = '{';
-                       subtype = *p++;
-               } else if (c == '=' && subtype != 0) {
-                       *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
-                       subtype = 0;
-               } else if (c == CTLENDVAR) {
-                       *q++ = '}';
-               } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
-                       cmdnleft++;             /* ignore it */
-               else
-                       *q++ = c;
-               if (--cmdnleft <= 0) {
-                       *q++ = '.';
-                       *q++ = '.';
-                       *q++ = '.';
-                       break;
-               }
-       }
-       cmdnextc = q;
-}
-
-#ifdef NO_KILLPG
-static int killpg(grp, sig)
-pid_t grp;
-int sig;
-{
-       return kill(-grp, sig);
-}
-#endif
-
-/*
- * $PchId: jobs.c,v 1.7 2006/05/22 12:02:13 philip Exp $
- */
diff --git a/minix/commands/ash/mkinit.c b/minix/commands/ash/mkinit.c
deleted file mode 100644 (file)
index 962631f..0000000
+++ /dev/null
@@ -1,500 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char const copyright[] =
-"@(#) Copyright (c) 1991, 1993\n\
-       The Regents of the University of California.  All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)mkinit.c   8.2 (Berkeley) 5/4/95";
-#endif
-#endif /* not lint */
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/mkinit.c,v 1.17 2004/04/06 20:06:51 markm Exp $");
-*/
-
-/*
- * This program scans all the source files for code to handle various
- * special events and combines this code into one file.  This (allegedly)
- * improves the structure of the program since there is no need for
- * anyone outside of a module to know that that module performs special
- * operations on particular events.
- *
- * Usage:  mkinit sourcefile...
- */
-
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-
-/*
- * OUTFILE is the name of the output file.  Output is initially written
- * to the file OUTTEMP, which is then moved to OUTFILE.
- */
-
-#define OUTFILE "init.c"
-#define OUTTEMP "init.c.new"
-
-
-/*
- * A text structure is basicly just a string that grows as more characters
- * are added onto the end of it.  It is implemented as a linked list of
- * blocks of characters.  The routines addstr and addchar append a string
- * or a single character, respectively, to a text structure.  Writetext
- * writes the contents of a text structure to a file.
- */
-
-#define BLOCKSIZE 512
-
-struct text {
-       char *nextc;
-       int nleft;
-       struct block *start;
-       struct block *last;
-};
-
-struct block {
-       struct block *next;
-       char text[BLOCKSIZE];
-};
-
-
-/*
- * There is one event structure for each event that mkinit handles.
- */
-
-struct event {
-       char *name;             /* name of event (e.g. INIT) */
-       char *routine;          /* name of routine called on event */
-       char *comment;          /* comment describing routine */
-       struct text code;       /* code for handling event */
-};
-
-
-char writer[] = "\
-/*\n\
- * This file was generated by the mkinit program.\n\
- */\n\
-\n";
-
-char init[] = "\
-/*\n\
- * Initialization code.\n\
- */\n";
-
-char reset[] = "\
-/*\n\
- * This routine is called when an error or an interrupt occurs in an\n\
- * interactive shell and control is returned to the main command loop.\n\
- */\n";
-
-char shellproc[] = "\
-/*\n\
- * This routine is called to initialize the shell to run a shell procedure.\n\
- */\n";
-
-
-struct event event[] = {
-       {"INIT", "init", init},
-       {"RESET", "reset", reset},
-       {"SHELLPROC", "initshellproc", shellproc},
-       {NULL, NULL}
-};
-
-
-char *curfile;                         /* current file */
-int linno;                             /* current line */
-char *header_files[200];               /* list of header files */
-struct text defines;                   /* #define statements */
-struct text decls;                     /* declarations */
-int amiddecls;                         /* for formatting */
-
-
-static void readfile(char *);
-static int match(char *, char *);
-static int gooddefine(char *);
-static void doevent(struct event *, FILE *, char *);
-static void doinclude(char *);
-static void dodecl(char *, FILE *);
-static void output(void);
-static void addstr(char *, struct text *);
-static void addchar(int, struct text *);
-static void writetext(struct text *, FILE *);
-static FILE *ckfopen(char *, char *);
-static void *ckmalloc(int);
-static char *savestr(char *);
-static void error(char *);
-
-#define equal(s1, s2)  (strcmp(s1, s2) == 0)
-
-#ifndef __unused
-#define __unused  __attribute__((__unused__))
-#endif
-
-int
-main(int argc __unused, char *argv[])
-{
-       char **ap;
-
-       header_files[0] = "\"shell.h\"";
-       header_files[1] = "\"mystring.h\"";
-       for (ap = argv + 1 ; *ap ; ap++)
-               readfile(*ap);
-       output();
-       rename(OUTTEMP, OUTFILE);
-       exit(0);
-}
-
-
-/*
- * Parse an input file.
- */
-
-static void
-readfile(char *fname)
-{
-       FILE *fp;
-       char line[1024];
-       struct event *ep;
-
-       fp = ckfopen(fname, "r");
-       curfile = fname;
-       linno = 0;
-       amiddecls = 0;
-       while (fgets(line, sizeof line, fp) != NULL) {
-               linno++;
-               for (ep = event ; ep->name ; ep++) {
-                       if (line[0] == ep->name[0] && match(ep->name, line)) {
-                               doevent(ep, fp, fname);
-                               break;
-                       }
-               }
-               if (line[0] == 'I' && match("INCLUDE", line))
-                       doinclude(line);
-               if (line[0] == 'M' && match("MKINIT", line))
-                       dodecl(line, fp);
-               if (line[0] == '#' && gooddefine(line)) {
-                       char *cp;
-                       char line2[1024];
-                       static const char undef[] = "#undef ";
-
-                       strcpy(line2, line);
-                       memcpy(line2, undef, sizeof(undef) - 1);
-                       cp = line2 + sizeof(undef) - 1;
-                       while(*cp && (*cp == ' ' || *cp == '\t'))
-                               cp++;
-                       while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
-                               cp++;
-                       *cp++ = '\n'; *cp = '\0';
-                       addstr(line2, &defines);
-                       addstr(line, &defines);
-               }
-       }
-       fclose(fp);
-}
-
-
-static int
-match(char *name, char *line)
-{
-       char *p, *q;
-
-       p = name, q = line;
-       while (*p) {
-               if (*p++ != *q++)
-                       return 0;
-       }
-       if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n')
-               return 0;
-       return 1;
-}
-
-
-static int
-gooddefine(char *line)
-{
-       char *p;
-
-       if (! match("#define", line))
-               return 0;                       /* not a define */
-       p = line + 7;
-       while (*p == ' ' || *p == '\t')
-               p++;
-       while (*p != ' ' && *p != '\t') {
-               if (*p == '(')
-                       return 0;               /* macro definition */
-               p++;
-       }
-       while (*p != '\n' && *p != '\0')
-               p++;
-       if (p[-1] == '\\')
-               return 0;                       /* multi-line definition */
-       return 1;
-}
-
-
-static void
-doevent(struct event *ep, FILE *fp, char *fname)
-{
-       char line[1024];
-       int indent;
-       char *p;
-
-       sprintf(line, "\n      /* from %s: */\n", fname);
-       addstr(line, &ep->code);
-       addstr("      {\n", &ep->code);
-       for (;;) {
-               linno++;
-               if (fgets(line, sizeof line, fp) == NULL)
-                       error("Unexpected EOF");
-               if (equal(line, "}\n"))
-                       break;
-               indent = 6;
-               for (p = line ; *p == '\t' ; p++)
-                       indent += 8;
-               for ( ; *p == ' ' ; p++)
-                       indent++;
-               if (*p == '\n' || *p == '#')
-                       indent = 0;
-               while (indent >= 8) {
-                       addchar('\t', &ep->code);
-                       indent -= 8;
-               }
-               while (indent > 0) {
-                       addchar(' ', &ep->code);
-                       indent--;
-               }
-               addstr(p, &ep->code);
-       }
-       addstr("      }\n", &ep->code);
-}
-
-
-static void
-doinclude(char *line)
-{
-       char *p;
-       char *name;
-       char **pp;
-
-       for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++);
-       if (*p == '\0')
-               error("Expecting '\"' or '<'");
-       name = p;
-       while (*p != ' ' && *p != '\t' && *p != '\n')
-               p++;
-       if (p[-1] != '"' && p[-1] != '>')
-               error("Missing terminator");
-       *p = '\0';
-
-       /* name now contains the name of the include file */
-       for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++);
-       if (*pp == NULL)
-               *pp = savestr(name);
-}
-
-
-static void
-dodecl(char *line1, FILE *fp)
-{
-       char line[1024];
-       char *p, *q;
-
-       if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */
-               addchar('\n', &decls);
-               do {
-                       linno++;
-                       if (fgets(line, sizeof line, fp) == NULL)
-                               error("Unterminated structure declaration");
-                       addstr(line, &decls);
-               } while (line[0] != '}');
-               amiddecls = 0;
-       } else {
-               if (! amiddecls)
-                       addchar('\n', &decls);
-               q = NULL;
-               for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++)
-                       continue;
-               if (*p == '=') {                /* eliminate initialization */
-                       for (q = p ; *q && *q != ';' ; q++);
-                       if (*q == '\0')
-                               q = NULL;
-                       else {
-                               while (p[-1] == ' ')
-                                       p--;
-                               *p = '\0';
-                       }
-               }
-               addstr("extern", &decls);
-               addstr(line1 + 6, &decls);
-               if (q != NULL)
-                       addstr(q, &decls);
-               amiddecls = 1;
-       }
-}
-
-
-
-/*
- * Write the output to the file OUTTEMP.
- */
-
-static void
-output(void)
-{
-       FILE *fp;
-       char **pp;
-       struct event *ep;
-
-       fp = ckfopen(OUTTEMP, "w");
-       fputs(writer, fp);
-       for (pp = header_files ; *pp ; pp++)
-               fprintf(fp, "#include %s\n", *pp);
-       fputs("\n\n\n", fp);
-       writetext(&defines, fp);
-       fputs("\n\n", fp);
-       writetext(&decls, fp);
-       for (ep = event ; ep->name ; ep++) {
-               fputs("\n\n\n", fp);
-               fputs(ep->comment, fp);
-               fprintf(fp, "\nvoid\n%s(void) {\n", ep->routine);
-               writetext(&ep->code, fp);
-               fprintf(fp, "}\n");
-       }
-       fclose(fp);
-}
-
-
-/*
- * A text structure is simply a block of text that is kept in memory.
- * Addstr appends a string to the text struct, and addchar appends a single
- * character.
- */
-
-static void
-addstr(char *s, struct text *text)
-{
-       while (*s) {
-               if (--text->nleft < 0)
-                       addchar(*s++, text);
-               else
-                       *text->nextc++ = *s++;
-       }
-}
-
-
-static void
-addchar(int c, struct text *text)
-{
-       struct block *bp;
-
-       if (--text->nleft < 0) {
-               bp = ckmalloc(sizeof *bp);
-               if (text->start == NULL)
-                       text->start = bp;
-               else
-                       text->last->next = bp;
-               text->last = bp;
-               text->nextc = bp->text;
-               text->nleft = BLOCKSIZE - 1;
-       }
-       *text->nextc++ = c;
-}
-
-/*
- * Write the contents of a text structure to a file.
- */
-static void
-writetext(struct text *text, FILE *fp)
-{
-       struct block *bp;
-
-       if (text->start != NULL) {
-               for (bp = text->start ; bp != text->last ; bp = bp->next)
-                       fwrite(bp->text, sizeof (char), BLOCKSIZE, fp);
-               fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp);
-       }
-}
-
-static FILE *
-ckfopen(char *file, char *mode)
-{
-       FILE *fp;
-
-       if ((fp = fopen(file, mode)) == NULL) {
-               fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
-               exit(2);
-       }
-       return fp;
-}
-
-static void *
-ckmalloc(int nbytes)
-{
-       char *p;
-
-       if ((p = malloc(nbytes)) == NULL)
-               error("Out of space");
-       return p;
-}
-
-static char *
-savestr(char *s)
-{
-       char *p;
-
-       p = ckmalloc(strlen(s) + 1);
-       strcpy(p, s);
-       return p;
-}
-
-static void
-error(char *msg)
-{
-       if (curfile != NULL)
-               fprintf(stderr, "%s:%d: ", curfile, linno);
-       fprintf(stderr, "%s\n", msg);
-       exit(2);
-}
-
-/*
- * $PchId: mkinit.c,v 1.6 2006/05/22 12:16:50 philip Exp $
- */
diff --git a/minix/commands/ash/mknodes.c b/minix/commands/ash/mknodes.c
deleted file mode 100644 (file)
index d9582d0..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if 0
-#ifndef lint
-static char const copyright[] =
-"@(#) Copyright (c) 1991, 1993\n\
-       The Regents of the University of California.  All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)mknodes.c  8.2 (Berkeley) 5/4/95";
-#endif /* not lint */
-#endif
-/*
-__FBSDID("$FreeBSD: src/bin/sh/mknodes.c,v 1.17 2004/04/06 20:06:51 markm Exp $");
-*/
-
-/*
- * This program reads the nodetypes file and nodes.c.pat file.  It generates
- * the files nodes.h and nodes.c.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <stdarg.h>
-
-#define MAXTYPES 50            /* max number of node types */
-#define MAXFIELDS 20           /* max fields in a structure */
-#define BUFLEN 100             /* size of character buffers */
-
-/* field types */
-#define T_NODE 1               /* union node *field */
-#define T_NODELIST 2           /* struct nodelist *field */
-#define T_STRING 3
-#define T_INT 4                        /* int field */
-#define T_OTHER 5              /* other */
-#define T_TEMP 6               /* don't copy this field */
-
-
-struct field {                 /* a structure field */
-       char *name;             /* name of field */
-       int type;                       /* type of field */
-       char *decl;             /* declaration of field */
-};
-
-
-struct str {                   /* struct representing a node structure */
-       char *tag;              /* structure tag */
-       int nfields;            /* number of fields in the structure */
-       struct field field[MAXFIELDS];  /* the fields of the structure */
-       int done;                       /* set if fully parsed */
-};
-
-
-static int ntypes;                     /* number of node types */
-static char *nodename[MAXTYPES];       /* names of the nodes */
-static struct str *nodestr[MAXTYPES];  /* type of structure used by the node */
-static int nstr;                       /* number of structures */
-static struct str str[MAXTYPES];       /* the structures */
-static struct str *curstr;             /* current structure */
-static FILE *infp;
-static char line[1024];
-static int linno;
-static char *linep;
-
-#ifndef __printf0like
-#define __printf0like(a,b)
-#endif
-
-static void parsenode(void);
-static void parsefield(void);
-static void output(char *);
-static void outsizes(FILE *);
-static void outfunc(FILE *, int);
-static void indent(int, FILE *);
-static int nextfield(char *);
-static void skipbl(void);
-static int readline(void);
-static void error(const char *, ...) __printf0like(1, 2);
-static char *savestr(const char *);
-
-
-int
-main(int argc, char *argv[])
-{
-       if (argc != 3)
-               error("usage: mknodes file");
-       infp = stdin;
-       if ((infp = fopen(argv[1], "r")) == NULL)
-               error("Can't open %s: %s", argv[1], strerror(errno));
-       while (readline()) {
-               if (line[0] == ' ' || line[0] == '\t')
-                       parsefield();
-               else if (line[0] != '\0')
-                       parsenode();
-       }
-       output(argv[2]);
-       exit(0);
-}
-
-
-
-static void
-parsenode(void)
-{
-       char name[BUFLEN];
-       char tag[BUFLEN];
-       struct str *sp;
-
-       if (curstr && curstr->nfields > 0)
-               curstr->done = 1;
-       nextfield(name);
-       if (! nextfield(tag))
-               error("Tag expected");
-       if (*linep != '\0')
-               error("Garbage at end of line");
-       nodename[ntypes] = savestr(name);
-       for (sp = str ; sp < str + nstr ; sp++) {
-               if (strcmp(sp->tag, tag) == 0)
-                       break;
-       }
-       if (sp >= str + nstr) {
-               sp->tag = savestr(tag);
-               sp->nfields = 0;
-               curstr = sp;
-               nstr++;
-       }
-       nodestr[ntypes] = sp;
-       ntypes++;
-}
-
-
-static void
-parsefield(void)
-{
-       char name[BUFLEN];
-       char type[BUFLEN];
-       char decl[2 * BUFLEN];
-       struct field *fp;
-
-       if (curstr == NULL || curstr->done)
-               error("No current structure to add field to");
-       if (! nextfield(name))
-               error("No field name");
-       if (! nextfield(type))
-               error("No field type");
-       fp = &curstr->field[curstr->nfields];
-       fp->name = savestr(name);
-       if (strcmp(type, "nodeptr") == 0) {
-               fp->type = T_NODE;
-               sprintf(decl, "union node *%s", name);
-       } else if (strcmp(type, "nodelist") == 0) {
-               fp->type = T_NODELIST;
-               sprintf(decl, "struct nodelist *%s", name);
-       } else if (strcmp(type, "string") == 0) {
-               fp->type = T_STRING;
-               sprintf(decl, "char *%s", name);
-       } else if (strcmp(type, "int") == 0) {
-               fp->type = T_INT;
-               sprintf(decl, "int %s", name);
-       } else if (strcmp(type, "other") == 0) {
-               fp->type = T_OTHER;
-       } else if (strcmp(type, "temp") == 0) {
-               fp->type = T_TEMP;
-       } else {
-               error("Unknown type %s", type);
-       }
-       if (fp->type == T_OTHER || fp->type == T_TEMP) {
-               skipbl();
-               fp->decl = savestr(linep);
-       } else {
-               if (*linep)
-                       error("Garbage at end of line");
-               fp->decl = savestr(decl);
-       }
-       curstr->nfields++;
-}
-
-
-char writer[] = "\
-/*\n\
- * This file was generated by the mknodes program.\n\
- */\n\
-\n";
-
-static void
-output(char *file)
-{
-       FILE *hfile;
-       FILE *cfile;
-       FILE *patfile;
-       int i;
-       struct str *sp;
-       struct field *fp;
-       char *p;
-
-       if ((patfile = fopen(file, "r")) == NULL)
-               error("Can't open %s: %s", file, strerror(errno));
-       if ((hfile = fopen("nodes.h", "w")) == NULL)
-               error("Can't create nodes.h: %s", strerror(errno));
-       if ((cfile = fopen("nodes.c", "w")) == NULL)
-               error("Can't create nodes.c");
-       fputs(writer, hfile);
-       for (i = 0 ; i < ntypes ; i++)
-               fprintf(hfile, "#define %s %d\n", nodename[i], i);
-       fputs("\n\n\n", hfile);
-       for (sp = str ; sp < &str[nstr] ; sp++) {
-               fprintf(hfile, "struct %s {\n", sp->tag);
-               for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) {
-                       fprintf(hfile, "      %s;\n", fp->decl);
-               }
-               fputs("};\n\n\n", hfile);
-       }
-       fputs("union node {\n", hfile);
-       fprintf(hfile, "      int type;\n");
-       for (sp = str ; sp < &str[nstr] ; sp++) {
-               fprintf(hfile, "      struct %s %s;\n", sp->tag, sp->tag);
-       }
-       fputs("};\n\n\n", hfile);
-       fputs("struct nodelist {\n", hfile);
-       fputs("\tstruct nodelist *next;\n", hfile);
-       fputs("\tunion node *n;\n", hfile);
-       fputs("};\n\n\n", hfile);
-       fputs("union node *copyfunc(union node *);\n", hfile);
-       fputs("void freefunc(union node *);\n", hfile);
-
-       fputs(writer, cfile);
-       while (fgets(line, sizeof line, patfile) != NULL) {
-               for (p = line ; *p == ' ' || *p == '\t' ; p++);
-               if (strcmp(p, "%SIZES\n") == 0)
-                       outsizes(cfile);
-               else if (strcmp(p, "%CALCSIZE\n") == 0)
-                       outfunc(cfile, 1);
-               else if (strcmp(p, "%COPY\n") == 0)
-                       outfunc(cfile, 0);
-               else
-                       fputs(line, cfile);
-       }
-}
-
-
-
-static void
-outsizes(FILE *cfile)
-{
-       int i;
-
-       fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
-       for (i = 0 ; i < ntypes ; i++) {
-               fprintf(cfile, "      ALIGN(sizeof (struct %s)),\n", nodestr[i]->tag);
-       }
-       fprintf(cfile, "};\n");
-}
-
-
-static void
-outfunc(FILE *cfile, int calcsize)
-{
-       struct str *sp;
-       struct field *fp;
-       int i;
-
-       fputs("      if (n == NULL)\n", cfile);
-       if (calcsize)
-               fputs("     return;\n", cfile);
-       else
-               fputs("     return NULL;\n", cfile);
-       if (calcsize)
-               fputs("      funcblocksize += nodesize[n->type];\n", cfile);
-       else {
-               fputs("      new = funcblock;\n", cfile);
-               fputs("      funcblock = (char *)funcblock + nodesize[n->type];\n", cfile);
-       }
-       fputs("      switch (n->type) {\n", cfile);
-       for (sp = str ; sp < &str[nstr] ; sp++) {
-               for (i = 0 ; i < ntypes ; i++) {
-                       if (nodestr[i] == sp)
-                               fprintf(cfile, "      case %s:\n", nodename[i]);
-               }
-               for (i = sp->nfields ; --i >= 1 ; ) {
-                       fp = &sp->field[i];
-                       switch (fp->type) {
-                       case T_NODE:
-                               if (calcsize) {
-                                       indent(12, cfile);
-                                       fprintf(cfile, "calcsize(n->%s.%s);\n",
-                                               sp->tag, fp->name);
-                               } else {
-                                       indent(12, cfile);
-                                       fprintf(cfile, "new->%s.%s = copynode(n->%s.%s);\n",
-                                               sp->tag, fp->name, sp->tag, fp->name);
-                               }
-                               break;
-                       case T_NODELIST:
-                               if (calcsize) {
-                                       indent(12, cfile);
-                                       fprintf(cfile, "sizenodelist(n->%s.%s);\n",
-                                               sp->tag, fp->name);
-                               } else {
-                                       indent(12, cfile);
-                                       fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s);\n",
-                                               sp->tag, fp->name, sp->tag, fp->name);
-                               }
-                               break;
-                       case T_STRING:
-                               if (calcsize) {
-                                       indent(12, cfile);
-                                       fprintf(cfile, "funcstringsize += strlen(n->%s.%s) + 1;\n",
-                                               sp->tag, fp->name);
-                               } else {
-                                       indent(12, cfile);
-                                       fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s);\n",
-                                               sp->tag, fp->name, sp->tag, fp->name);
-                               }
-                               break;
-                       case T_INT:
-                       case T_OTHER:
-                               if (! calcsize) {
-                                       indent(12, cfile);
-                                       fprintf(cfile, "new->%s.%s = n->%s.%s;\n",
-                                               sp->tag, fp->name, sp->tag, fp->name);
-                               }
-                               break;
-                       }
-               }
-               indent(12, cfile);
-               fputs("break;\n", cfile);
-       }
-       fputs("      };\n", cfile);
-       if (! calcsize)
-               fputs("      new->type = n->type;\n", cfile);
-}
-
-
-static void
-indent(int amount, FILE *fp)
-{
-       while (amount >= 8) {
-               putc('\t', fp);
-               amount -= 8;
-       }
-       while (--amount >= 0) {
-               putc(' ', fp);
-       }
-}
-
-
-static int
-nextfield(char *buf)
-{
-       char *p, *q;
-
-       p = linep;
-       while (*p == ' ' || *p == '\t')
-               p++;
-       q = buf;
-       while (*p != ' ' && *p != '\t' && *p != '\0')
-               *q++ = *p++;
-       *q = '\0';
-       linep = p;
-       return (q > buf);
-}
-
-
-static void
-skipbl(void)
-{
-       while (*linep == ' ' || *linep == '\t')
-               linep++;
-}
-
-
-static int
-readline(void)
-{
-       char *p;
-
-       if (fgets(line, 1024, infp) == NULL)
-               return 0;
-       for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++);
-       while (p > line && (p[-1] == ' ' || p[-1] == '\t'))
-               p--;
-       *p = '\0';
-       linep = line;
-       linno++;
-       if (p - line > BUFLEN)
-               error("Line too long");
-       return 1;
-}
-
-
-
-static void
-error(const char *msg, ...)
-{
-       va_list va;
-       va_start(va, msg);
-
-       (void) fprintf(stderr, "line %d: ", linno);
-       (void) vfprintf(stderr, msg, va);
-       (void) fputc('\n', stderr);
-
-       va_end(va);
-
-       exit(2);
-}
-
-
-
-static char *
-savestr(const char *s)
-{
-       char *p;
-
-       if ((p = malloc(strlen(s) + 1)) == NULL)
-               error("Out of space");
-       (void) strcpy(p, s);
-       return p;
-}
-
-/*
- * $PchId: mknodes.c,v 1.6 2006/05/23 12:05:14 philip Exp $
- */
diff --git a/minix/commands/ash/mksignames.c b/minix/commands/ash/mksignames.c
deleted file mode 100644 (file)
index b787861..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1991, 1993\n\
-       The Regents of the University of California.  All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)mksignames.c       8.1 (Berkeley) 5/31/93";
-#endif /* not lint */
-
-/*
- * This program generates the signames.h and signames.c files.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-
-int main(int argc, char *argv[]);
-
-struct sig {
-       int signo;              /* signal number */
-       char *name;             /* signal name (without leading "SIG") */
-       char *mesg;             /* description */
-};
-
-
-struct sig sigtab[] = {
-       SIGHUP, "HUP", "Hangup",
-       SIGINT, "INT", "Interrupt",     /* normally don't print message */
-       SIGQUIT, "QUIT", "Quit",
-       SIGILL, "ILL", "Illegal instruction",
-       SIGTRAP, "TRAP", "Trace/BPT trap",
-#ifdef SIGABRT
-       SIGABRT, "ABRT", "abort",
-#endif
-#if defined(SIGIOT) && (! defined(SIGABRT) || SIGABRT != SIGIOT)
-       SIGIOT, "IOT", "abort",
-#endif
-#ifdef SIGEMT
-       SIGEMT, "EMT", "EMT trap",
-#endif
-       SIGFPE, "FPE", "Floating exception",
-       SIGKILL, "KILL", "Killed",
-       SIGBUS, "BUS", "Bus error",
-       SIGSEGV, "SEGV", "Memory fault",
-#ifdef SIGSYS
-       SIGSYS, "SYS", "Bad system call",
-#endif
-       SIGPIPE, "PIPE", "Broken pipe", /* normally don't print message */
-       SIGALRM, "ALRM", "Alarm call",
-       SIGTERM, "TERM", "Terminated",
-#ifdef SIGUSR1
-       SIGUSR1, "USR1", "User signal 1",
-#endif
-#ifdef SIGUSR2
-       SIGUSR2, "USR2", "User signal 2",
-#endif
-#ifdef SIGCLD
-       SIGCLD, "CLD", NULL,
-#endif
-#if defined(SIGCHLD) && ! defined(SIGCLD)
-       SIGCHLD, "CLD", NULL,
-#endif
-#ifdef SIGPWR
-       SIGPWR, "PWR", "Power fail",
-#endif
-#ifdef SIGPOLL
-       SIGPOLL, "POLL", "Poll",
-#endif
-       /* Now for the BSD signals */
-#ifdef SIGURG
-       SIGURG, "URG", NULL,
-#endif
-#ifdef SIGSTOP
-       SIGSTOP, "STOP", "Stopped",
-#endif
-#ifdef SIGTSTP
-       SIGTSTP, "TSTP", "Stopped",
-#endif
-#ifdef SIGCONT
-       SIGCONT, "CONT", NULL,
-#endif
-#ifdef SIGTTIN
-       SIGTTIN, "TTIN", "Stopped (input)",
-#endif
-#ifdef SIGTTOU
-       SIGTTOU, "TTOU", "Stopped (output)",
-#endif
-#ifdef SIGIO
-       SIGIO, "IO", NULL,
-#endif
-#ifdef SIGXCPU
-       SIGXCPU, "XCPU", "Time limit exceeded",
-#endif
-#ifdef SIGXFSZ
-       SIGXFSZ, "XFSZ", NULL,
-#endif
-#ifdef SIGVTALRM
-       SIGVTALRM, "VTALARM", "Virtual alarm",
-#endif
-#ifdef SIGPROF
-       SIGPROF, "PROF", "Profiling alarm",
-#endif
-#ifdef SIGWINCH
-       SIGWINCH, "WINCH", NULL,
-#endif
-       0, NULL, NULL
-};
-
-
-#define MAXSIG 64
-
-
-char *sigmesg[MAXSIG + 1];
-
-
-char writer[] = "\
-/*\n\
- * This file was generated by the mksignames program.\n\
- */\n\
-\n";
-
-
-
-main(argc, argv)  char **argv; {
-       FILE *cfile, *hfile;    
-       struct sig *sigp;
-       int maxsig;
-       int i;
-
-       if ((cfile = fopen("signames.c", "w")) == NULL) {
-               fputs("Can't create signames.c\n", stderr);
-               exit(2);
-       }
-       if ((hfile = fopen("signames.h", "w")) == NULL) {
-               fputs("Can't create signames.h\n", stderr);
-               exit(2);
-       }
-       maxsig = 0;
-       for (sigp = sigtab ; sigp->signo != 0 ; sigp++) {
-               if (sigp->signo < 0 || sigp->signo > MAXSIG)
-                       continue;
-               sigmesg[sigp->signo] = sigp->mesg;
-               if (maxsig < sigp->signo)
-                       maxsig = sigp->signo;
-       }
-
-       fputs(writer, hfile);
-       fprintf(hfile, "#define MAXSIG %d\n\n", maxsig);
-       fprintf(hfile, "extern char *const sigmesg[MAXSIG+1];\n");
-
-       fputs(writer, cfile);
-       fprintf(cfile, "#include \"shell.h\"\n\n");
-       fprintf(cfile, "char *const sigmesg[%d] = {\n", maxsig + 1);
-       for (i = 0 ; i <= maxsig ; i++) {
-               if (sigmesg[i] == NULL) {
-                       fprintf(cfile, "      0,\n");
-               } else {
-                       fprintf(cfile, "      \"%s\",\n", sigmesg[i]);
-               }
-       }
-       fprintf(cfile, "};\n");
-       exit(0);
-}
-
-/*
- * $PchId: mksignames.c,v 1.2 2001/05/14 19:22:26 philip Exp $
- */
diff --git a/minix/commands/ash/mksyntax.c b/minix/commands/ash/mksyntax.c
deleted file mode 100644 (file)
index 40b8250..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if 0
-#ifndef lint
-static char const copyright[] =
-"@(#) Copyright (c) 1991, 1993\n\
-       The Regents of the University of California.  All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)mksyntax.c 8.2 (Berkeley) 5/4/95";
-#endif /* not lint */
-#endif
-#include <sys/cdefs.h>
-/*
-__FBSDID("$FreeBSD: src/bin/sh/mksyntax.c,v 1.23 2004/04/06 20:06:51 markm Exp $");
-*/
-
-/*
- * This program creates syntax.h and syntax.c.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "parser.h"
-
-struct synclass {
-       char *name;
-       char *comment;
-};
-
-/* Syntax classes */
-struct synclass synclass[] = {
-       { "CWORD",      "character is nothing special" },
-       { "CNL",        "newline character" },
-       { "CBACK",      "a backslash character" },
-       { "CSQUOTE",    "single quote" },
-       { "CDQUOTE",    "double quote" },
-       { "CENDQUOTE",  "a terminating quote" },
-       { "CBQUOTE",    "backwards single quote" },
-       { "CVAR",       "a dollar sign" },
-       { "CENDVAR",    "a '}' character" },
-       { "CLP",        "a left paren in arithmetic" },
-       { "CRP",        "a right paren in arithmetic" },
-       { "CEOF",       "end of file" },
-       { "CCTL",       "like CWORD, except it must be escaped" },
-       { "CSPCL",      "these terminate a word" },
-       { NULL,         NULL }
-};
-
-
-/*
- * Syntax classes for is_ functions.  Warning:  if you add new classes
- * you may have to change the definition of the is_in_name macro.
- */
-struct synclass is_entry[] = {
-       { "ISDIGIT",    "a digit" },
-       { "ISUPPER",    "an upper case letter" },
-       { "ISLOWER",    "a lower case letter" },
-       { "ISUNDER",    "an underscore" },
-       { "ISSPECL",    "the name of a special parameter" },
-       { NULL,         NULL }
-};
-
-static char writer[] = "\
-/*\n\
- * This file was generated by the mksyntax program.\n\
- */\n\
-\n";
-
-
-static FILE *cfile;
-static FILE *hfile;
-static char *syntax[513];
-static int base;
-static int size;       /* number of values which a char variable can have */
-static int nbits;      /* number of bits in a character */
-static int digit_contig;/* true if digits are contiguous */
-
-static void filltable(char *);
-static void init(void);
-static void add(char *, char *);
-static void print(char *);
-static void output_type_macros(void);
-static void digit_convert(void);
-
-#ifndef __unused
-#define __unused  __attribute__((__unused__))
-#endif
-
-int
-main(int argc __unused, char **argv __unused)
-{
-       char c;
-       char d;
-       int sign;
-       int i;
-       char buf[80];
-       int pos;
-       static char digit[] = "0123456789";
-
-       /* Create output files */
-       if ((cfile = fopen("syntax.c", "w")) == NULL) {
-               perror("syntax.c");
-               exit(2);
-       }
-       if ((hfile = fopen("syntax.h", "w")) == NULL) {
-               perror("syntax.h");
-               exit(2);
-       }
-       fputs(writer, hfile);
-       fputs(writer, cfile);
-
-       /* Determine the characteristics of chars. */
-       c = -1;
-       if (c < 0)
-               sign = 1;
-       else
-               sign = 0;
-       for (nbits = 1 ; ; nbits++) {
-               d = (1 << nbits) - 1;
-               if (d == c)
-                       break;
-       }
-#if 0
-       printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits);
-#endif
-       if (nbits > 9) {
-               fputs("Characters can't have more than 9 bits\n", stderr);
-               exit(2);
-       }
-       size = (1 << nbits) + 1;
-       base = 1;
-       if (sign)
-               base += 1 << (nbits - 1);
-       digit_contig = 1;
-       for (i = 0 ; i < 10 ; i++) {
-               if (digit[i] != '0' + i)
-                       digit_contig = 0;
-       }
-
-       fputs("#include <ctype.h>\n", hfile);
-
-       /* Generate the #define statements in the header file */
-       fputs("/* Syntax classes */\n", hfile);
-       for (i = 0 ; synclass[i].name ; i++) {
-               sprintf(buf, "#define %s %d", synclass[i].name, i);
-               fputs(buf, hfile);
-               for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
-                       putc('\t', hfile);
-               fprintf(hfile, "/* %s */\n", synclass[i].comment);
-       }
-       putc('\n', hfile);
-       fputs("/* Syntax classes for is_ functions */\n", hfile);
-       for (i = 0 ; is_entry[i].name ; i++) {
-               sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
-               fputs(buf, hfile);
-               for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
-                       putc('\t', hfile);
-               fprintf(hfile, "/* %s */\n", is_entry[i].comment);
-       }
-       putc('\n', hfile);
-       fprintf(hfile, "#define SYNBASE %d\n", base);
-       fprintf(hfile, "#define PEOF %d\n\n", -base);
-       putc('\n', hfile);
-       fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
-       fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
-       fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
-       fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile);
-       putc('\n', hfile);
-       output_type_macros();           /* is_digit, etc. */
-       putc('\n', hfile);
-
-       /* Generate the syntax tables. */
-       fputs("#include \"shell.h\"\n", cfile);
-       fputs("#include \"syntax.h\"\n\n", cfile);
-       init();
-       fputs("/* syntax table used when not in quotes */\n", cfile);
-       add("\n", "CNL");
-       add("\\", "CBACK");
-       add("'", "CSQUOTE");
-       add("\"", "CDQUOTE");
-       add("`", "CBQUOTE");
-       add("$", "CVAR");
-       add("}", "CENDVAR");
-       add("<>();&| \t", "CSPCL");
-       print("basesyntax");
-       init();
-       fputs("\n/* syntax table used when in double quotes */\n", cfile);
-       add("\n", "CNL");
-       add("\\", "CBACK");
-       add("\"", "CENDQUOTE");
-       add("`", "CBQUOTE");
-       add("$", "CVAR");
-       add("}", "CENDVAR");
-       /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
-       add("!*?[=~:/-", "CCTL");
-       print("dqsyntax");
-       init();
-       fputs("\n/* syntax table used when in single quotes */\n", cfile);
-       add("\n", "CNL");
-       add("'", "CENDQUOTE");
-       /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
-       add("!*?[=~:/-", "CCTL");
-       print("sqsyntax");
-       init();
-       fputs("\n/* syntax table used when in arithmetic */\n", cfile);
-       add("\n", "CNL");
-       add("\\", "CBACK");
-       add("`", "CBQUOTE");
-       add("'", "CSQUOTE");
-       add("\"", "CDQUOTE");
-       add("$", "CVAR");
-       add("}", "CENDVAR");
-       add("(", "CLP");
-       add(")", "CRP");
-       print("arisyntax");
-       filltable("0");
-       fputs("\n/* character classification table */\n", cfile);
-       add("0123456789", "ISDIGIT");
-       add("abcdefghijklmnopqrstucvwxyz", "ISLOWER");
-       add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER");
-       add("_", "ISUNDER");
-       add("#?$!-*@", "ISSPECL");
-       print("is_type");
-       if (! digit_contig)
-               digit_convert();
-       exit(0);
-}
-
-
-
-/*
- * Clear the syntax table.
- */
-
-static void
-filltable(char *dftval)
-{
-       int i;
-
-       for (i = 0 ; i < size ; i++)
-               syntax[i] = dftval;
-}
-
-
-/*
- * Initialize the syntax table with default values.
- */
-
-static void
-init(void)
-{
-       filltable("CWORD");
-       syntax[0] = "CEOF";
-       syntax[base + CTLESC] = "CCTL";
-       syntax[base + CTLVAR] = "CCTL";
-       syntax[base + CTLENDVAR] = "CCTL";
-       syntax[base + CTLBACKQ] = "CCTL";
-       syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL";
-       syntax[base + CTLARI] = "CCTL";
-       syntax[base + CTLENDARI] = "CCTL";
-       syntax[base + CTLQUOTEMARK] = "CCTL";
-}
-
-
-/*
- * Add entries to the syntax table.
- */
-
-static void
-add(char *p, char *type)
-{
-       while (*p)
-               syntax[*p++ + base] = type;
-}
-
-
-
-/*
- * Output the syntax table.
- */
-
-static void
-print(char *name)
-{
-       int i;
-       int col;
-
-       fprintf(hfile, "extern const char %s[];\n", name);
-       fprintf(cfile, "const char %s[%d] = {\n", name, size);
-       col = 0;
-       for (i = 0 ; i < size ; i++) {
-               if (i == 0) {
-                       fputs("      ", cfile);
-               } else if ((i & 03) == 0) {
-                       fputs(",\n      ", cfile);
-                       col = 0;
-               } else {
-                       putc(',', cfile);
-                       while (++col < 9 * (i & 03))
-                               putc(' ', cfile);
-               }
-               fputs(syntax[i], cfile);
-               col += strlen(syntax[i]);
-       }
-       fputs("\n};\n", cfile);
-}
-
-
-
-/*
- * Output character classification macros (e.g. is_digit).  If digits are
- * contiguous, we can test for them quickly.
- */
-
-static char *macro[] = {
-       "#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)",
-       "#define is_alpha(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && isalpha((unsigned char) (c)))",
-       "#define is_name(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && ((c) == '_' || isalpha((unsigned char) (c))))",
-       "#define is_in_name(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && ((c) == '_' || isalnum((unsigned char) (c))))",
-       "#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))",
-       NULL
-};
-
-static void
-output_type_macros(void)
-{
-       char **pp;
-
-       if (digit_contig)
-               macro[0] = "#define is_digit(c)\t((unsigned)((c) - '0') <= 9)";
-       for (pp = macro ; *pp ; pp++)
-               fprintf(hfile, "%s\n", *pp);
-       if (digit_contig)
-               fputs("#define digit_val(c)\t((c) - '0')\n", hfile);
-       else
-               fputs("#define digit_val(c)\t(digit_value[c])\n", hfile);
-}
-
-
-
-/*
- * Output digit conversion table (if digits are not contiguous).
- */
-
-static void
-digit_convert(void)
-{
-       int maxdigit;
-       static char digit[] = "0123456789";
-       char *p;
-       int i;
-
-       maxdigit = 0;
-       for (p = digit ; *p ; p++)
-               if (*p > maxdigit)
-                       maxdigit = *p;
-       fputs("extern const char digit_value[];\n", hfile);
-       fputs("\n\nconst char digit_value[] = {\n", cfile);
-       for (i = 0 ; i <= maxdigit ; i++) {
-               for (p = digit ; *p && *p != i ; p++);
-               if (*p == '\0')
-                       p = digit;
-               fprintf(cfile, "      %d,\n", (int)(p - digit));
-       }
-       fputs("};\n", cfile);
-}
-
-/*
- * $PchId: mksyntax.c,v 1.7 2006/05/23 12:04:27 philip Exp $
- */
diff --git a/minix/commands/ash/setmode.c b/minix/commands/ash/setmode.c
deleted file mode 100644 (file)
index 80f66ae..0000000
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Copyright (c) 1989, 1993, 1994
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Dave Borman at Cray Research, Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)setmode.c  8.2 (Berkeley) 3/25/94";
-#endif /* LIBC_SCCS and not lint */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdlib.h>
-
-#ifdef SETMODE_DEBUG
-#include <stdio.h>
-#endif
-
-#include "shell.h"
-
-#ifndef S_ISTXT
-#define S_ISTXT        S_ISVTX
-#endif
-
-#define        SET_LEN 6               /* initial # of bitcmd struct to malloc */
-#define        SET_LEN_INCR 4          /* # of bitcmd structs to add as needed */
-
-typedef struct bitcmd {
-       char    cmd;
-       char    cmd2;
-       mode_t  bits;
-} BITCMD;
-
-#define        CMD2_CLR        0x01
-#define        CMD2_SET        0x02
-#define        CMD2_GBITS      0x04
-#define        CMD2_OBITS      0x08
-#define        CMD2_UBITS      0x10
-
-static BITCMD  *addcmd (BITCMD *, int, int, int, unsigned int);
-static void     compress_mode (BITCMD *);
-#ifdef SETMODE_DEBUG
-static void     dumpmode __P((BITCMD *));
-#endif
-
-/*
- * Given the old mode and an array of bitcmd structures, apply the operations
- * described in the bitcmd structures to the old mode, and return the new mode.
- * Note that there is no '=' command; a strict assignment is just a '-' (clear
- * bits) followed by a '+' (set bits).
- */
-mode_t
-getmode(bbox, omode)
-       void *bbox;
-       mode_t omode;
-{
-       register BITCMD *set;
-       register mode_t clrval, newmode, value;
-
-       set = (BITCMD *)bbox;
-       newmode = omode;
-       for (value = 0;; set++)
-               switch(set->cmd) {
-               /*
-                * When copying the user, group or other bits around, we "know"
-                * where the bits are in the mode so that we can do shifts to
-                * copy them around.  If we don't use shifts, it gets real
-                * grundgy with lots of single bit checks and bit sets.
-                */
-               case 'u':
-                       value = (newmode & S_IRWXU) >> 6;
-                       goto common;
-
-               case 'g':
-                       value = (newmode & S_IRWXG) >> 3;
-                       goto common;
-
-               case 'o':
-                       value = newmode & S_IRWXO;
-common:                        if (set->cmd2 & CMD2_CLR) {
-                               clrval =
-                                   (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
-                               if (set->cmd2 & CMD2_UBITS)
-                                       newmode &= ~((clrval<<6) & set->bits);
-                               if (set->cmd2 & CMD2_GBITS)
-                                       newmode &= ~((clrval<<3) & set->bits);
-                               if (set->cmd2 & CMD2_OBITS)
-                                       newmode &= ~(clrval & set->bits);
-                       }
-                       if (set->cmd2 & CMD2_SET) {
-                               if (set->cmd2 & CMD2_UBITS)
-                                       newmode |= (value<<6) & set->bits;
-                               if (set->cmd2 & CMD2_GBITS)
-                                       newmode |= (value<<3) & set->bits;
-                               if (set->cmd2 & CMD2_OBITS)
-                                       newmode |= value & set->bits;
-                       }
-                       break;
-
-               case '+':
-                       newmode |= set->bits;
-                       break;
-
-               case '-':
-                       newmode &= ~set->bits;
-                       break;
-
-               case 'X':
-                       if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
-                               newmode |= set->bits;
-                       break;
-
-               case '\0':
-               default:
-#ifdef SETMODE_DEBUG
-                       (void)printf("getmode:%04o -> %04o\n", omode, newmode);
-#endif
-                       return (newmode);
-               }
-}
-
-#define        ADDCMD(a, b, c, d)                                              \
-       if (set >= endset) {                                            \
-               register BITCMD *newset;                                \
-               setlen += SET_LEN_INCR;                                 \
-               newset = realloc(saveset, sizeof(BITCMD) * setlen);     \
-               if (!saveset)                                           \
-                       return (NULL);                                  \
-               set = newset + (set - saveset);                         \
-               saveset = newset;                                       \
-               endset = newset + (setlen - 2);                         \
-       }                                                               \
-       set = addcmd(set, (a), (b), (c), (d))
-
-#define        STANDARD_BITS   (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
-
-void *
-setmode(p)
-       register char *p;
-{
-       register int perm, who;
-       register char op;
-       BITCMD *set, *saveset, *endset;
-       sigset_t sigset, sigoset;
-       mode_t mask;
-       int equalopdone, permXbits, setlen;
-
-       if (!*p)
-               return (NULL);
-
-       /*
-        * Get a copy of the mask for the permissions that are mask relative.
-        * Flip the bits, we want what's not set.  Since it's possible that
-        * the caller is opening files inside a signal handler, protect them
-        * as best we can.
-        */
-       sigfillset(&sigset);
-        (void)sigprocmask(SIG_BLOCK, &sigset, &sigoset);
-       (void)umask(mask = umask(0));
-       mask = ~mask;
-        (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
-
-       setlen = SET_LEN + 2;
-       
-       if ((set = malloc((unsigned int)(sizeof(BITCMD) * setlen))) == NULL)
-               return (NULL);
-       saveset = set;
-       endset = set + (setlen - 2);
-
-       /*
-        * If an absolute number, get it and return; disallow non-octal digits
-        * or illegal bits.
-        */
-       if (isdigit(*p)) {
-               perm = (mode_t)strtol(p, NULL, 8);
-               if (perm & ~(STANDARD_BITS|S_ISTXT)) {
-                       free(saveset);
-                       return (NULL);
-               }
-               while (*++p)
-                       if (*p < '0' || *p > '7') {
-                               free(saveset);
-                               return (NULL);
-                       }
-               ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
-               return (saveset);
-       }
-
-       /*
-        * Build list of structures to set/clear/copy bits as described by
-        * each clause of the symbolic mode.
-        */
-       for (;;) {
-               /* First, find out which bits might be modified. */
-               for (who = 0;; ++p) {
-                       switch (*p) {
-                       case 'a':
-                               who |= STANDARD_BITS;
-                               break;
-                       case 'u':
-                               who |= S_ISUID|S_IRWXU;
-                               break;
-                       case 'g':
-                               who |= S_ISGID|S_IRWXG;
-                               break;
-                       case 'o':
-                               who |= S_IRWXO;
-                               break;
-                       default:
-                               goto getop;
-                       }
-               }
-
-getop:         if ((op = *p++) != '+' && op != '-' && op != '=') {
-                       free(saveset);
-                       return (NULL);
-               }
-               if (op == '=')
-                       equalopdone = 0;
-
-               who &= ~S_ISTXT;
-               for (perm = 0, permXbits = 0;; ++p) {
-                       switch (*p) {
-                       case 'r':
-                               perm |= S_IRUSR|S_IRGRP|S_IROTH;
-                               break;
-                       case 's':
-                               /* If only "other" bits ignore set-id. */
-                               if (who & ~S_IRWXO)
-                                       perm |= S_ISUID|S_ISGID;
-                               break;
-                       case 't':
-                               /* If only "other" bits ignore sticky. */
-                               if (who & ~S_IRWXO) {
-                                       who |= S_ISTXT;
-                                       perm |= S_ISTXT;
-                               }
-                               break;
-                       case 'w':
-                               perm |= S_IWUSR|S_IWGRP|S_IWOTH;
-                               break;
-                       case 'X':
-                               permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
-                               break;
-                       case 'x':
-                               perm |= S_IXUSR|S_IXGRP|S_IXOTH;
-                               break;
-                       case 'u':
-                       case 'g':
-                       case 'o':
-                               /*
-                                * When ever we hit 'u', 'g', or 'o', we have
-                                * to flush out any partial mode that we have,
-                                * and then do the copying of the mode bits.
-                                */
-                               if (perm) {
-                                       ADDCMD(op, who, perm, mask);
-                                       perm = 0;
-                               }
-                               if (op == '=')
-                                       equalopdone = 1;
-                               if (op == '+' && permXbits) {
-                                       ADDCMD('X', who, permXbits, mask);
-                                       permXbits = 0;
-                               }
-                               ADDCMD(*p, who, op, mask);
-                               break;
-
-                       default:
-                               /*
-                                * Add any permissions that we haven't already
-                                * done.
-                                */
-                               if (perm || (op == '=' && !equalopdone)) {
-                                       if (op == '=')
-                                               equalopdone = 1;
-                                       ADDCMD(op, who, perm, mask);
-                                       perm = 0;
-                               }
-                               if (permXbits) {
-                                       ADDCMD('X', who, permXbits, mask);
-                                       permXbits = 0;
-                               }
-                               goto apply;
-                       }
-               }
-
-apply:         if (!*p)
-                       break;
-               if (*p != ',')
-                       goto getop;
-               ++p;
-       }
-       set->cmd = 0;
-#ifdef SETMODE_DEBUG
-       (void)printf("Before compress_mode()\n");
-       dumpmode(saveset);
-#endif
-       compress_mode(saveset);
-#ifdef SETMODE_DEBUG
-       (void)printf("After compress_mode()\n");
-       dumpmode(saveset);
-#endif
-       return (saveset);
-}
-
-static BITCMD *
-addcmd(set, op, who, oparg, mask)
-       BITCMD *set;
-       register int oparg, who;
-       register int op;
-       unsigned int mask;
-{
-       switch (op) {
-       case '=':
-               set->cmd = '-';
-               set->bits = who ? who : STANDARD_BITS;
-               set++;
-
-               op = '+';
-               /* FALLTHROUGH */
-       case '+':
-       case '-':
-       case 'X':
-               set->cmd = op;
-               set->bits = (who ? who : mask) & oparg;
-               break;
-
-       case 'u':
-       case 'g':
-       case 'o':
-               set->cmd = op;
-               if (who) {
-                       set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
-                                   ((who & S_IRGRP) ? CMD2_GBITS : 0) |
-                                   ((who & S_IROTH) ? CMD2_OBITS : 0);
-                       set->bits = ~0;
-               } else {
-                       set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
-                       set->bits = mask;
-               }
-       
-               if (oparg == '+')
-                       set->cmd2 |= CMD2_SET;
-               else if (oparg == '-')
-                       set->cmd2 |= CMD2_CLR;
-               else if (oparg == '=')
-                       set->cmd2 |= CMD2_SET|CMD2_CLR;
-               break;
-       }
-       return (set + 1);
-}
-
-#ifdef SETMODE_DEBUG
-static void
-dumpmode(set)
-       register BITCMD *set;
-{
-       for (; set->cmd; ++set)
-               (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
-                   set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
-                   set->cmd2 & CMD2_CLR ? " CLR" : "",
-                   set->cmd2 & CMD2_SET ? " SET" : "",
-                   set->cmd2 & CMD2_UBITS ? " UBITS" : "",
-                   set->cmd2 & CMD2_GBITS ? " GBITS" : "",
-                   set->cmd2 & CMD2_OBITS ? " OBITS" : "");
-}
-#endif
-
-/*
- * Given an array of bitcmd structures, compress by compacting consecutive
- * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
- * 'g' and 'o' commands continue to be separate.  They could probably be 
- * compacted, but it's not worth the effort.
- */
-static void
-compress_mode(set)
-       register BITCMD *set;
-{
-       register BITCMD *nset;
-       register int setbits, clrbits, Xbits, op;
-
-       for (nset = set;;) {
-               /* Copy over any 'u', 'g' and 'o' commands. */
-               while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
-                       *set++ = *nset++;
-                       if (!op)
-                               return;
-               }
-
-               for (setbits = clrbits = Xbits = 0;; nset++) {
-                       if ((op = nset->cmd) == '-') {
-                               clrbits |= nset->bits;
-                               setbits &= ~nset->bits;
-                               Xbits &= ~nset->bits;
-                       } else if (op == '+') {
-                               setbits |= nset->bits;
-                               clrbits &= ~nset->bits;
-                               Xbits &= ~nset->bits;
-                       } else if (op == 'X')
-                               Xbits |= nset->bits & ~setbits;
-                       else
-                               break;
-               }
-               if (clrbits) {
-                       set->cmd = '-';
-                       set->cmd2 = 0;
-                       set->bits = clrbits;
-                       set++;
-               }
-               if (setbits) {
-                       set->cmd = '+';
-                       set->cmd2 = 0;
-                       set->bits = setbits;
-                       set++;
-               }
-               if (Xbits) {
-                       set->cmd = 'X';
-                       set->cmd2 = 0;
-                       set->bits = Xbits;
-                       set++;
-               }
-       }
-}
-
-/*
- * $PchId: setmode.c,v 1.3 2006/05/23 11:57:34 philip Exp $
- */
diff --git a/minix/commands/ash/trap.c b/minix/commands/ash/trap.c
deleted file mode 100644 (file)
index 56dc857..0000000
+++ /dev/null
@@ -1,568 +0,0 @@
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)trap.c     8.5 (Berkeley) 6/5/95";
-#endif
-#endif /* not lint */
-/*
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/bin/sh/trap.c,v 1.29 2004/04/06 20:06:51 markm Exp $");
-*/
-
-#include <signal.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "shell.h"
-#include "main.h"
-#include "nodes.h"     /* for other headers */
-#include "eval.h"
-#include "jobs.h"
-#include "show.h"
-#include "options.h"
-#include "syntax.h"
-#include "output.h"
-#include "memalloc.h"
-#include "error.h"
-#include "trap.h"
-#include "mystring.h"
-#if !defined(NO_HISTORY)
-#include "myhistedit.h"
-#endif
-#include "builtins.h"
-
-typedef void (*sig_T)(int);
-
-/*
- * Sigmode records the current value of the signal handlers for the various
- * modes.  A value of zero means that the current handler is not known.
- * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
- */
-
-#define S_DFL 1                        /* default signal handling (SIG_DFL) */
-#define S_CATCH 2              /* signal is caught */
-#define S_IGN 3                        /* signal is ignored (SIG_IGN) */
-#define S_HARD_IGN 4           /* signal is ignored permanently */
-#define S_RESET 5              /* temporary - to reset a hard ignored sig */
-
-
-MKINIT char sigmode[_NSIG];    /* current value of signal */
-int pendingsigs;               /* indicates some signal received */
-int is_interactive= -1;                /* Shell is interactive */
-int in_dotrap;                 /* do we execute in a trap handler? */
-static char *volatile trap[_NSIG];     /* trap handler commands */
-static volatile sig_atomic_t gotsig[_NSIG]; 
-                               /* indicates specified signal received */
-static int ignore_sigchld;     /* Used while handling SIGCHLD traps. */
-volatile sig_atomic_t gotwinch;
-
-static int sigstring_to_signum (char *);
-static void printsignals (void);
-static int getsigaction(int, sig_T *);
-static void onsig (int);
-#ifdef NO_SIGINTERRUPT
-static int siginterrupt (int,int);
-#endif
-static char *strsigname (int);
-
-
-/*
- * Map a string to a signal number.
- */
-static int
-sigstring_to_signum(char *sig)
-{
-
-       if (is_number(sig)) {
-               int signo;
-
-               signo = atoi(sig);
-               return ((signo >= 0 && signo < _NSIG) ? signo : (-1));
-       } else if (strcasecmp(sig, "exit") == 0) {
-               return (0);
-       } else {
-               int n;
-
-               if (strncasecmp(sig, "sig", 3) == 0)
-                       sig += 3;
-               for (n = 1; n < _NSIG; n++)
-                       if (strcasecmp(strsigname(n), sig) == 0)
-                               return (n);
-       }
-       return (-1);
-}
-
-
-/*
- * Print a list of valid signal names.
- */
-static void
-printsignals(void)
-{
-       int n, outlen;
-
-       outlen = 0;
-       for (n = 1; n < _NSIG; n++) {
-               if (strsigname(n)) {
-                       out1fmt("%s", strsigname(n));
-                       outlen += strlen(strsigname(n));
-               } else {
-                       out1fmt("%d", n);
-                       outlen += 3;    /* good enough */
-               }
-               ++outlen;
-               if (outlen > 70 || n == _NSIG - 1) {
-                       out1str("\n");
-                       outlen = 0;
-               } else {
-                       out1c(' ');
-               }
-       }
-}
-
-
-/*
- * The trap builtin.
- */
-int
-trapcmd(int argc, char **argv)
-{
-       char *action;
-       int signo;
-
-       if (argc <= 1) {
-               for (signo = 0 ; signo < _NSIG ; signo++) {
-                       if (trap[signo] != NULL) {
-                               if (signo == 0) {
-                                       out1fmt("trap -- '%s' %s\n",
-                                           trap[signo], "exit");
-                               } else if (strsigname(signo)) {
-                                       out1fmt("trap -- '%s' %s\n",
-                                           trap[signo], strsigname(signo));
-                               } else {
-                                       out1fmt("trap -- '%s' %d\n",
-                                           trap[signo], signo);
-                               }
-                       }
-               }
-               return 0;
-       }
-       action = NULL;
-       if (*++argv && strcmp(*argv, "--") == 0)
-               argv++;
-       if (*argv && sigstring_to_signum(*argv) == -1) {
-               if ((*argv)[0] != '-') {
-                       action = *argv;
-                       argv++;
-               } else if ((*argv)[1] == '\0') {
-                       argv++;
-               } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
-                       printsignals();
-                       return 0;
-               } else {
-                       error("bad option %s", *argv);
-               }
-       }
-       while (*argv) {
-               if ((signo = sigstring_to_signum(*argv)) == -1)
-                       error("bad signal %s", *argv);
-               INTOFF;
-               if (action)
-                       action = savestr(action);
-               if (trap[signo])
-                       ckfree(trap[signo]);
-               trap[signo] = action;
-               if (signo != 0)
-                       setsignal(signo);
-               INTON;
-               argv++;
-       }
-       return 0;
-}
-
-
-/*
- * Clear traps on a fork.
- */
-void
-clear_traps(void)
-{
-       char *volatile *tp;
-
-       for (tp = trap ; tp <= &trap[_NSIG - 1] ; tp++) {
-               if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
-                       INTOFF;
-                       ckfree(*tp);
-                       *tp = NULL;
-                       if (tp != &trap[0])
-                               setsignal(tp - trap);
-                       INTON;
-               }
-       }
-}
-
-
-/*
- * Set the signal handler for the specified signal.  The routine figures
- * out what it should be set to.
- */
-void
-setsignal(int signo)
-{
-       int action;
-       sig_T sig, sigact = SIG_DFL;
-       char *t;
-
-       if ((t = trap[signo]) == NULL)
-               action = S_DFL;
-       else if (*t != '\0')
-               action = S_CATCH;
-       else
-               action = S_IGN;
-       if (action == S_DFL) {
-               switch (signo) {
-               case SIGINT:
-                       action = S_CATCH;
-                       break;
-               case SIGQUIT:
-#if DEBUG
-                       {
-                       extern int debug;
-
-                       if (debug)
-                               break;
-                       }
-#endif
-                       action = S_CATCH;
-                       break;
-               case SIGTERM:
-                       if (rootshell && iflag)
-                               action = S_IGN;
-                       break;
-#if JOBS
-               case SIGTSTP:
-               case SIGTTOU:
-                       if (rootshell && mflag)
-                               action = S_IGN;
-                       break;
-#endif
-#ifndef NO_HISTORY
-               case SIGWINCH:
-                       if (rootshell && iflag)
-                               action = S_CATCH;
-                       break;
-#endif
-               }
-       }
-
-       t = &sigmode[signo];
-       if (*t == 0) {
-               /*
-                * current setting unknown
-                */
-               if (!getsigaction(signo, &sigact)) {
-                       /*
-                        * Pretend it worked; maybe we should give a warning
-                        * here, but other shells don't. We don't alter
-                        * sigmode, so that we retry every time.
-                        */
-                       return;
-               }
-               if (sigact == SIG_IGN) {
-                       if (mflag && (signo == SIGTSTP ||
-                            signo == SIGTTIN || signo == SIGTTOU)) {
-                               *t = S_IGN;     /* don't hard ignore these */
-                       } else
-                               *t = S_HARD_IGN;
-               } else {
-                       *t = S_RESET;   /* force to be set */
-               }
-       }
-       if (*t == S_HARD_IGN || *t == action)
-               return;
-       switch (action) {
-               case S_DFL:     sigact = SIG_DFL;       break;
-               case S_CATCH:   sigact = onsig;         break;
-               case S_IGN:     sigact = SIG_IGN;       break;
-       }
-       *t = action;
-       sig = signal(signo, sigact);
-       if (sig != SIG_ERR && action == S_CATCH)
-               siginterrupt(signo, 1);
-}
-
-
-/*
- * Return the current setting for sig w/o changing it.
- */
-static int
-getsigaction(int signo, sig_T *sigact)
-{
-       struct sigaction sa;
-
-       if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
-               return 0;
-       *sigact = (sig_T) sa.sa_handler;
-       return 1;
-}
-
-
-/*
- * Ignore a signal.
- */
-void
-ignoresig(int signo)
-{
-
-       if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
-               signal(signo, SIG_IGN);
-       }
-       sigmode[signo] = S_HARD_IGN;
-}
-
-
-#ifdef mkinit
-INCLUDE <signal.h>
-INCLUDE "trap.h"
-
-SHELLPROC {
-       char *sm;
-
-       clear_traps();
-       for (sm = sigmode ; sm < sigmode + _NSIG ; sm++) {
-               if (*sm == S_IGN)
-                       *sm = S_HARD_IGN;
-       }
-}
-#endif
-
-
-/*
- * Signal handler.
- */
-static void
-onsig(int signo)
-{
-
-#ifndef BSD
-       signal(signo, onsig);
-#endif
-       if (signo == SIGINT && trap[SIGINT] == NULL) {
-               onint();
-               return;
-       }
-
-       if (signo != SIGCHLD || !ignore_sigchld)
-               gotsig[signo] = 1;
-       pendingsigs++;
-
-       /* If we are currently in a wait builtin, prepare to break it */
-       if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0)
-               breakwaitcmd = 1;
-       /* 
-        * If a trap is set, not ignored and not the null command, we need 
-        * to make sure traps are executed even when a child blocks signals.
-        */
-       if (Tflag &&
-           trap[signo] != NULL && 
-           ! trap[signo][0] == '\0' &&
-           ! (trap[signo][0] == ':' && trap[signo][1] == '\0'))
-               breakwaitcmd = 1;
-
-#ifndef NO_HISTORY
-       if (signo == SIGWINCH)
-               gotwinch = 1;
-#endif
-}
-
-
-/*
- * Called to execute a trap.  Perhaps we should avoid entering new trap
- * handlers while we are executing a trap handler.
- */
-void
-dotrap(void)
-{
-       int i;
-       int savestatus;
-
-       in_dotrap++;
-       for (;;) {
-               for (i = 1; i < _NSIG; i++) {
-                       if (gotsig[i]) {
-                               gotsig[i] = 0;
-                               if (trap[i]) {
-                                       /*
-                                        * Ignore SIGCHLD to avoid infinite
-                                        * recursion if the trap action does
-                                        * a fork.
-                                        */
-                                       if (i == SIGCHLD)
-                                               ignore_sigchld++;
-                                       savestatus = exitstatus;
-                                       evalstring(trap[i]);
-                                       exitstatus = savestatus;
-                                       if (i == SIGCHLD)
-                                               ignore_sigchld--;
-                               }
-                               break;
-                       }
-               }
-               if (i >= _NSIG)
-                       break;
-       }
-       in_dotrap--;
-       pendingsigs = 0;
-}
-
-
-/*
- * Controls whether the shell is interactive or not.
- */
-void
-setinteractive(int on)
-{
-       if (on == is_interactive)
-               return;
-       setsignal(SIGINT);
-       setsignal(SIGQUIT);
-       setsignal(SIGTERM);
-#ifndef NO_HISTORY
-       setsignal(SIGWINCH);
-#endif
-       is_interactive = on;
-}
-
-
-/*
- * Called to exit the shell.
- */
-void
-exitshell(int status)
-{
-       struct jmploc loc1, loc2;
-       char *p;
-
-       TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
-       if (setjmp(loc1.loc)) {
-               goto l1;
-       }
-       if (setjmp(loc2.loc)) {
-               goto l2;
-       }
-       handler = &loc1;
-       if ((p = trap[0]) != NULL && *p != '\0') {
-               trap[0] = NULL;
-               evalstring(p);
-       }
-l1:   handler = &loc2;                 /* probably unnecessary */
-       flushall();
-#if JOBS
-       setjobctl(0);
-#endif
-l2:   _exit(status);
-}
-
-#ifdef NO_SIGINTERRUPT
-static int siginterrupt(sig, flag)
-int sig;
-int flag;
-{
-       return 0;
-}
-#endif
-
-#ifdef __minix
-static char *strsigname(sig)
-int sig;
-{
-       switch(sig)
-       {
-       case 0:         return "Signal 0";      /*  0 */
-       case SIGHUP:    return "hup";           /*  1 */
-       case SIGINT:    return "int";           /*  2 */
-       case SIGQUIT:   return "quit";          /*  3 */
-       case SIGILL:    return "ill";           /*  4 */
-       case SIGTRAP:   return "trap";          /*  5 */
-       case SIGABRT:   return "abrt";          /*  6 */
-       case SIGBUS:    return "bus";           /*  7 */
-       case SIGFPE:    return "fpe";           /*  8 */
-       case SIGKILL:   return "kill";          /*  9 */
-       case SIGUSR1:   return "usr1";          /* 10 */
-       case SIGSEGV:   return "segv";          /* 11 */
-       case SIGUSR2:   return "usr2";          /* 12 */
-       case SIGPIPE:   return "pipe";          /* 13 */
-       case SIGALRM:   return "alrm";          /* 14 */
-       case SIGTERM:   return "term";          /* 15 */
-       case SIGEMT:    return "emt";           /* 16 */
-       case SIGCHLD:   return "chld";          /* 17 */
-       case SIGCONT:   return "cont";          /* 18 */
-       case SIGSTOP:   return "stop";          /* 19 */
-       case SIGTSTP:   return "tstp";          /* 20 */
-       case SIGTTIN:   return "ttin";          /* 21 */
-       case SIGTTOU:   return "ttou";          /* 22 */
-       case SIGWINCH:  return "winch";         /* 23 */
-       case SIGVTALRM: return "vtalrm";        /* 24 */
-       case SIGPROF:   return "prof";          /* 25 */
-       default:        return "Signal n";
-       }
-}
-#else
-static char *strsigname(sig)
-int sig;
-{
-       return (char *)sys_signame[sig];
-}
-#endif
-
-#ifdef __minix
-#include "signames.h"
-char *strsiglist(sig)
-int sig;
-{
-       if (sig > MAXSIG)
-               return NULL;
-       return sigmesg[sig];
-}
-#else
-char *strsiglist(sig)
-int sig;
-{
-       return (char *)sys_siglist[sig];
-}
-#endif
-
-/*
- * $PchId: trap.c,v 1.7 2006/05/23 11:56:21 philip Exp $
- */
index 3e2a7f448f95fe5f62be6d67cb43d0d3ca869f3a..84a732a8baf9f22d18c62f555ac71e1f7d488be2 100644 (file)
@@ -48,7 +48,7 @@ dir.procfs:=  minix/fs/procfs
 PROGRAMS+=             service
 dir.service:=  minix/commands/service
 PROGRAMS+=             sh
-dir.sh:=       minix/commands/ash
+dir.sh:=       bin/sh
 PROGRAMS+=             sysenv
 dir.sysenv:=   minix/commands/sysenv
 PROGRAMS+=             umount
index 8f8b8e14c011729560dfbc5fdb330800b9b39c43..d2fb8f240d65c07d4aaee91b4e350fd7198e6d88 100644 (file)
@@ -1,4 +1,4 @@
-MAN=   ash.1 at.1 \
+MAN=   at.1 \
        bsfilt.1 cawf.1 chgrp.1 \
        cmp.1 compress.1 \
        crc.1 crontab.1 dd.1 \
@@ -21,33 +21,6 @@ MAN= ash.1 at.1 \
        uud.1 uue.1 vol.1 \
        yap.1 linkfarm.1 pkg_view.1
 
-MLINKS += ash.1 sh.1
-MLINKS += ash.1 ..1
-MLINKS += ash.1 break.1
-MLINKS += ash.1 case.1
-MLINKS += ash.1 cd.1
-MLINKS += ash.1 command.1
-MLINKS += ash.1 continue.1
-MLINKS += ash.1 eval.1
-MLINKS += ash.1 exec.1
-MLINKS += ash.1 exit.1
-MLINKS += ash.1 export.1
-MLINKS += ash.1 for.1
-MLINKS += ash.1 getopts.1
-MLINKS += ash.1 hash.1
-MLINKS += ash.1 if.1
-MLINKS += ash.1 jobs.1
-MLINKS += ash.1 local.1
-MLINKS += ash.1 read.1
-MLINKS += ash.1 readonly.1
-MLINKS += ash.1 return.1
-MLINKS += ash.1 set.1
-MLINKS += ash.1 setvar.1
-MLINKS += ash.1 shift.1
-MLINKS += ash.1 trap.1
-MLINKS += ash.1 umask.1
-MLINKS += ash.1 unset.1
-MLINKS += ash.1 wait.1
 MLINKS += compress.1 uncompress.1
 MLINKS += svc.1 ci.1
 MLINKS += svc.1 co.1
diff --git a/minix/man/man1/ash.1 b/minix/man/man1/ash.1
deleted file mode 100644 (file)
index 2f237ac..0000000
+++ /dev/null
@@ -1,1131 +0,0 @@
-.\" Copyright (c) 1991 The Regents of the University of California.
-.\" All rights reserved.
-.\"
-.\" This code is derived from software contributed to Berkeley by
-.\" Kenneth Almquist.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\"    notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\"    notice, this list of conditions and the following disclaimer in the
-.\"    documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\"    must display the following acknowledgement:
-.\"    This product includes software developed by the University of
-.\"    California, Berkeley and its contributors.
-.\" 4. Neither the name of the University nor the names of its contributors
-.\"    may be used to endorse or promote products derived from this software
-.\"    without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\"    @(#)sh.1        5.1 (Berkeley) 3/7/91
-.\"
-.TH SH 1 "March 7, 1991"
-.UC 7
-.de h \" subheading
-.sp
-.ti -0.3i
-.B "\\$1"
-.PP
-..
-.de d \" begin display
-.sp
-.in +4
-.nf
-..
-.de e \" end display
-.in -4
-.fi
-.sp
-..
-.de c \" command, etc.
-.br
-.HP 3
-\fB\\$1\fR
-.br
-..
-.de b \" begin builtin command
-.HP 3
-.B \\$1
-..
-.SH NAME
-ash, sh, bigsh, ., break, case, cd, command, continue, eval, exec, exit, export, for, getopts, hash, if, jobs, local, read, readonly, return, set, setvar, shift, trap, umask, unset, wait, while \- a shell
-.SH SYNOPSIS
-.B ash
-[
-.B -efIijnsxz
-] [
-.B +efIijnsxz
-] [
-.B -c
-.I command
-] [
-.I arg
-] ...
-.SH COPYRIGHT
-Copyright 1989 by Kenneth Almquist.
-.SH DESCRIPTION
-.I Ash
-is a version of
-.I sh
-with features similar to those of the System V shell.
-This manual page lists all the features of
-.I ash
-but concentrates on the ones not in other shells.
-.h "Invocation"
-If the
-.B -c
-options is given, then the shell executes the specified shell command.
-The
-.B -s
-flag cause the shell to read commands from the standard input (after
-executing any command specified with the
-.B -c
-option.
-If neither the
-.B -s
-or
-.B -c
-options are set, then the first
-.I arg
-is taken as the name of a file to read commands from.
-If this is impossible because there are no arguments following
-the options, then
-.I ash
-will set the
-.B -s
-flag and will read commands from the standard input.
-.PP
-The shell sets the initial value of the positional parameters from the
-.IR arg s
-remaining after any
-.I arg
-used as the name of a file of commands is deleted.
-.PP
-The flags (other than
-.BR -c )
-are set by preceding them with ``-'' and cleared by preceding them
-with ``+''; see the
-.I set
-builtin command for a list of flags.
-If no value is specified for the
-.B -i
-flag, the
-.B -s
-flag is set, and the standard input and output of the shell
-are connected to terminals, then the
-.B -i
-flag will be set.
-If no value is specified for the
-.B -j
-flag, then the
-.B -j
-flag will be set if the
-.B -i
-flag is set.
-.PP
-When the shell is invoked with the
-.B -c
-option, it is good practice to include the
-.I -i
-flag if the command was entered interactively by a user.
-For compatibility with the System V shell, the
-.I -i
-option should come after the
-.B -c
-option.
-.PP
-If the first character of argument zero to the shell is ``-'',
-the shell is assumed to be a login shell, and the files
-.B /etc/profile
-and
-.B .profile
-are read if they exist.
-If the environment variable SHINIT is set on entry to the shell,
-the commands in SHINIT are normally parsed and executed.  SHINIT is
-not examined if the shell is a login shell, or if it the shell is running a
-shell procedure.   (A shell is considered to be running a shell
-procedure if neither the
-.B -s
-nor the
-.B -c
-options are set.)
-.PP
-In older versions of MINIX that did not have virtual memory, it was
-important for executables to have enough memory assigned to them. The
-.B bigsh
-binary was provided for shells that need much memory. This command is
-retained for backward compatibility and need not be used on MINIX 3.1.4
-and later.
-.h "Control Structures"
-A
-.I list
-is a sequence of zero or more commands separated by newlines,
-semicolons, or ampersands, and optionally terminated by one of these
-three characters.  (This differs from the System V shell, which
-requires a list to contain at least one command in most cases.)  The
-commands in a list are executed in the order they are written.
-If command is followed by an ampersand, the shell starts the command
-and immediately proceed onto the next command; otherwise it waits
-for the command to terminate before proceeding to the next one.
-.PP
-``&&'' and ``||'' are binary operators.
-``&&'' executes the first command, and then executes the second command
-iff the exit status of the first command is zero.  ``||'' is similar,
-but executes the second command iff the exit status of the first command
-is nonzero.  ``&&'' and ``||'' both have the same priority.
-.PP
-The ``|'' operator is a binary operator which feeds the standard output
-of the first command into the standard input of the second command.
-The exit status of the ``|'' operator is the exit status of the second
-command.  ``|'' has a higher priority than ``||'' or ``&&''.
-.PP
-An
-.I if
-command looks like
-.d
-\fBif\fR list
-\fBthen\fR     list
-.ti -\w'[ 'u
-[ \fBelif\fR list
-  \fBthen\fR   list ] ...
-.ti -\w'[ 'u
-[ \fBelse\fR   list ]
-\fBfi\fR
-.e
-.PP
-A
-.I while
-command looks like
-.d
-\fBwhile\fR list
-\fBdo\fR       list
-\fBdone\fR
-.e
-The two lists are executed repeatedly while the exit status of the first
-list is zero.  The
-.I until
-command is similar, but has the word
-.B until
-in place of
-.B while
- repeats until the exit status of the first list
-is zero.
-.PP
-The
-.I for
-command looks like
-.d
-\fBfor\fR variable \fBin\fR word...
-\fBdo\fR       list
-\fBdone\fR
-.e
-The words are expanded, and then the list is executed repeatedly with
-the variable set to each word in turn.
-.B do
-and
-.B done
-may be replaced with
-``{'' and ``}''.
-.PP
-The
-.I break
-and
-.I continue
-commands look like
-.d
-\fBbreak\fR [ num ]
-\fBcontinue\fR [ num ]
-.e
-.I Break
-terminates the
-.I num
-innermost
-.I for
-or
-.I while
-loops.
-.I Continue
-continues with the next iteration of the
-.IR num'th
-innermost loop.
-These are implemented as builtin commands.
-.PP
-The
-.I case
-command looks like
-.d
-\fBcase\fR word \fBin\fR
-pattern\fB)\fR list \fB;;\fR
-\&...
-\fBesac\fR
-.e
-The pattern can actually be one or more patterns (see
-.I Patterns
-below), separated by ``|'' characters.
-.PP
-Commands may be grouped by writing either
-.d
-\fB(\fRlist\fB)\fR
-.e
-or
-.d
-\fB{\fR list; \fB}\fR
-.e
-The first of these executes the commands in a subshell.
-.PP
-A function definition looks like
-.d
-name \fB( )\fR command
-.e
-A function definition is an executable statement; when executed it installs
-a function named
-.B name
-and returns an exit status of zero.
-The command is normally a list enclosed between ``{'' and ``}''.
-.PP
-Variables may be declared to be local to a function by using a
-.I local
-command.  This should appear as the first staement of a function,
-and looks like
-.d
-\fBlocal\fR [ variable | \fB-\fR ] ...
-.e
-.I Local
-is implemented as a builtin command.
-.PP
-When a variable is made local, it inherits the initial value and
-exported and readonly flags from the variable with the same name in the
-surrounding scope, if there is one.  Otherwise, the variable is
-initially unset.
-.I Ash
-uses dynamic scoping, so that if you make the variable
-.B x
-local to function
-.IR f ,
-which then calls function
-.IR g ,
-references to the variable
-.B x
-made inside
-.I g
-will refer to the variable
-.B x
-declared inside
-.IR f ,
-not to the global variable named
-.BR x .
-.PP
-The only special parameter that can be made local is ``\fB-\fR''.
-Making ``\fB-\fR'' local any shell options that are changed via the
-.I set
-command inside the function to be restored to their original values
-when the function returns.
-.PP
-The
-.I return
-command looks like
-.d
-\fBreturn\fR [ exitstatus ]
-.e
-It terminates the currently executing function.
-.I Return
-is implemented as a builtin command.
-.h "Simple Commands"
-A simple command is a sequence of words.  The execution of a simple
-command proceeds as follows.  First, the leading words of the form
-``name=value'' are stripped off and assigned to the environment of
-the command.  Second, the words are expanded.  Third, the first
-remaining word is taken as the command name that command is located.
-Fourth, any redirections are performed.  Fifth, the command is
-executed.  We look at these operations in reverse order.
-.PP
-The execution of the command varies with the type of command.
-There are three types of commands:  shell functions, builtin commands,
-and normal programs.
-.PP
-When a shell function is executed, all of the shell positional parameters
-(except $0, which remains unchanged) are set to the parameters to the shell
-function.  The variables which are explicitly placed in the environment
-of the command (by placing assignments to them before the function name)
-are made local to the function and are set to values given.
-Then the command given in the function definition is executed.
-The positional parameters are restored to their original values when
-the command completes.
-.PP
-Shell builtins are executed internally to the shell, without spawning
-a new process.
-.PP
-When a normal program is executed, the shell runs the program, passing
-the parameters and the environment to the program.  If the program is
-a shell procedure, the shell will interpret the program in a subshell.
-The shell will reinitialize itself in this case, so that the effect
-will be as if a new shell had been invoked to handle the shell procedure,
-except that the location of commands located in the parent shell will
-be remembered by the child.  If the program is a file beginning with
-``#!'', the remainder of the first line specifies an interpreter for
-the program.  The shell (or the operating system, under Berkeley UNIX)
-will run the interpreter in this case.  The arguments to the interpreter
-will consist of any arguments given on the first line of the program,
-followed by the name of the program, followed by the arguments passed
-to the program.
-.h "Redirection"
-Input/output redirections can be intermixed with the words in a simple
-command and can be placed following any of the other commands.  When
-redirection occurs, the shell saves the old values of the file descriptors
-and restores them when the command completes.  The ``<'', ``>'', and ``>>''
-redirections open a file for input, output, and appending, respectively.
-The ``<&digit'' and ``>&digit'' makes the input or output a duplicate
-of the file descriptor numbered by the digit.  If a minus sign is used
-in place of a digit, the standard input or standard output are closed.
-.PP
-The ``<<\ word'' redirection
-takes input from a
-.I here
-document.
-As the shell encounters ``<<'' redirections, it collects them.  The
-next time it encounters an unescaped newline, it reads the documents
-in turn.  The word following the ``<<'' specifies the contents of the
-line that terminates the document.  If none of the quoting methods
-('', "", or \e) are used to enter the word, then the document is treated
-like a word inside double quotes:  ``$'' and backquote are expanded
-and backslash can be used to escape these and to continue long lines.
-The word cannot contain any variable or command substitutions, and
-its length (after quoting) must be in the range of 1 to 79 characters.
-If ``<<-'' is used in place of ``<<'', then leading tabs are deleted
-from the lines of the document.  (This is to allow you do indent shell
-procedures containing here documents in a natural fashion.)
-.PP
-Any of the preceding redirection operators may be preceded by a single
-digit specifying the file descriptor to be redirected.  There cannot
-be any white space between the digit and the redirection operator.
-.h "Path Search"
-When locating a command, the shell first looks to see if it has a
-shell function by that name.  Then, if PATH does not contain an
-entry for "%builtin", it looks for a builtin command by that name.
-Finally, it searches each entry in PATH in turn for the command.
-.PP
-The value of the PATH variable should be a series of entries separated
-by colons.
-Each entry consists of a directory name, or a directory name followed
-by a flag beginning with a percent sign.
-The current directory should be indicated by an empty directory name.
-.PP
-If no percent sign is present, then the entry causes the shell to
-search for the command in the specified directory.  If the flag is
-``%builtin'' then the list of shell builtin commands is searched.
-If the flag is ``%func'' then the directory is searched for a file which
-is read as input to the shell.  This file should define a function
-whose name is the name of the command being searched for.
-.PP
-Command names containing a slash are simply executed without performing
-any of the above searches.
-.h "The Environment"
-The environment of a command is a set of name/value pairs.  When the
-shell is invoked, it reads these names and values, sets the shell
-variables with these names to the corresponding values, and marks
-the variables as exported.  The
-.I export
-command can be used to mark additional variables as exported.
-.PP
-The environment of a command is constructed by constructing name/value
-pairs from all the exported shell variables, and then modifying this
-set by the assignments which precede the command, if any.
-.h "Expansion"
-The process of evaluating words when a shell procedure is executed is
-called
-.IR expansion .
-Expansion consists of four steps:  variable substitution, command
-substitution, word splitting, and file name generation.  If a word
-is the expression following the word
-.B case
-in a case statement, the file name
-which follows a redirection symbol, or an assignment to the environment
-of a command, then the word cannot be split into multiple words.  In
-these cases, the last two steps of the expansion process are omitted.
-.h "Variable Substitution"
-To be written.
-.h "Command Substitution"
-.I Ash
-accepts two syntaxes for command substitution:
-.d
-`\fIlist\fR`
-.e
-and
-.d
-$(\fIlist\fR)
-.e
-Either of these may be included in a word.
-During the command substitution process, the command (syntactly a
-.IR list )
-will be executed and anything that the command writes to the standard
-output will be captured by the shell.  The final newline (if any) of
-the output will be deleted; the rest of the output will be substituted
-for the command in the word.
-.h "Word Splitting"
-When the value of a variable or the output of a command is substituted,
-the resulting text is subject to word splitting, unless the dollar sign
-introducing the variable or backquotes containing the text were enclosed
-in double quotes.  In addition, ``$@'' is subject to a special type of
-splitting, even in the presence of double quotes.
-.PP
-Ash uses two different splitting algorithms.  The normal approach, which
-is intended for splitting text separated by which space, is used if the
-first character of the shell variable IFS is a space.  Otherwise an alternative
-experimental algorithm, which is useful for splitting (possibly empty)
-fields separated by a separator character, is used.
-.PP
-When performing splitting, the shell scans the replacement text looking
-for a character (when IFS does not begin with a space) or a sequence of
-characters (when IFS does begin with a space), deletes the character or
-sequence of characters, and spits the word into two strings at that
-point.  When IFS begins with a space, the shell deletes either of the
-strings if they are null.  As a special case, if the word containing
-the replacement text is the null string, the word is deleted.
-.PP
-The variable ``$@'' is special in two ways.  First, splitting takes
-place between the positional parameters, even if the text is enclosed
-in double quotes.  Second, if the word containing the replacement
-text is the null string and there are no positional parameters, then
-the word is deleted.  The result of these rules is that "$@" is
-equivalent to "$1" "$2" ... "$\fIn\fR", where \fIn\fR is the number of
-positional parameters.  (Note that this differs from the System V shell.
-The System V documentation claims that "$@" behaves this way; in fact
-on the System V shell "$@" is equivalent to "" when there are no
-positional paramteters.)
-.h "File Name Generation"
-Unless the
-.B -f
-flag is set, file name generation is performed after word splitting is
-complete.  Each word is viewed as a series of patterns, separated by
-slashes.  The process of expansion replaces the word with the names of
-all existing files whose names can be formed by replacing each pattern
-with a string that matches the specified pattern.  There are two
-restrictions on this:  first, a pattern cannot match a string containing
-a slash, and second, a pattern cannot match a string starting with a
-period unless the first character of the pattern is a period.
-.PP
-If a word fails to match any files and the
-.B -z
-flag is not set, then the word will be left unchanged (except that the
-meta-characters will be converted to normal characters).  If the
-.B -z
-flag is set, then the word is only left unchanged if none
-of the patterns contain a character that can match anything besides
-itself.  Otherwise the
-.B -z
-flag forces the word to be replaced with the names of the files that it
-matches, even if there are zero names.
-.h "Patterns"
-A
-.I pattern
-consists of normal characters, which match themselves, and meta-characters.
-The meta-characters are ``!'', ``*'', ``?'', and ``[''.  These characters lose
-there special meanings if they are quoted.  When command or variable
-substitution is performed and the dollar sign or back quotes are not
-double quoted, the value of the variable or the output of the command
-is scanned for these characters and they are turned into meta-characters.
-.PP
-Two exclamation points at the beginning of a pattern function as a ``not''
-operator, causing the pattern to match any string that the remainder of
-the pattern does
-.I not
-match.  Other occurances of exclamation points in a pattern match
-exclamation points.  Two exclamation points are required rather than one
-to decrease the incompatibility with the System V shell (which does not
-treat exclamation points specially).
-.PP
-An asterisk (``*'') matches any string of characters.
-A question mark matches any single character.
-A left bracket (``['') introduces a character class.  The end of the
-character class is indicated by a ``]''; if the ``]'' is missing then
-the ``['' matches a ``['' rather than introducing a character class.
-A character class matches any of the characters between the square
-brackets.  A range of characters may be specified using a minus sign.
-The character class may be complemented by making an exclamation point
-the first character of the character class.
-.PP
-To include a ``]'' in a character class, make it the first character listed
-(after the ``!'', if any).
-To include a minus sign, make it the first or last character listed.
-.h "The /u Directory"
-By convention, the name ``/u/user'' refers to the home directory of the
-specified user.  There are good reasons why this feature should be supported
-by the file system (using a feature such as symbolic links) rather than
-by the shell, but
-.I ash
-is capable of performing this mapping if the file system doesn't.
-If the mapping is done by
-.IR ash ,
-setting the
-.B -f
-flag will turn it off.
-.h "Character Set"
-.I Ash
-silently discards nul characters.  Any other character will be handled
-correctly by
-.IR ash ,
-including characters with the high order bit set.
-.h "Job Names and Job Control"
-The term
-.I job
-refers to a process created by a shell command, or in the case of a
-pipeline, to the set of processes in the pipeline.  The ways to refer
-to a job are:
-.d
-%\fInumber\fR
-%\fIstring\fR
-%%
-\fIprocess_id\fR
-.e
-The first form identifies a job by job number.
-When a command is run,
-.I ash
-assigns it a job number
-(the lowest unused number is assigned).
-The second form identifies a job by giving a prefix of the command used
-to create the job.  The prefix must be unique.  If there is only one job,
-then the null prefix will identify the job, so you can refer to the job
-by writing ``%''.  The third form refers to the \fIcurrent job\fR.  The
-current job is the last job to be stopped while it was in the foreground.
-(See the next paragraph.)  The last form identifies a job by giving the
-process id of the last process in the job.
-.PP
-If the operating system that
-.I ash
-is running on supports job control,
-.I ash
-will allow you to use it.
-In this case, typing the suspend character (typically ^Z) while running
-a command will return you to
-.I ash
-and will make the suspended command the current job.  You can then continue
-the job in the background by typing
-.IR bg ,
-or you can continue it in the foreground by typing
-.IR fg .
-.h "Atty"
-If the shell variable ATTY is set, and the shell variable TERM is not
-set to ``emacs'', then \fIash\fR generates appropriate escape sequences
-to talk to
-.IR atty (1).
-.h "Exit Statuses"
-By tradition, an exit status of zero means that a command has succeeded
-and a nonzero exit status indicates that the command failed.  This is
-better than no convention at all, but in practice it is extremely useful
-to allow commands that succeed to use the exit status to return information
-to the caller.  A variety of better conventions have been proposed, but
-none of them has met with universal approval.  The convention used by
-\fIash\fR and all the programs included in the \fIash\fR distribution is
-as follows:
-.ta 1i 2i
-.nf
-       0       Success.
-       1       Alternate success.
-       2       Failure.
-       129-... Command terminated by a signal.
-.fi
-The \fIalternate success\fR return is used by commands to indicate various
-conditions which are not errors but which can, with a little imagination,
-be conceived of as less successful than plain success.  For example,
-.I test
-returns 1 when the tested condition is false and
-.I getopts
-returns 1 when there are no more options.
-Because this convention is not used universally, the
-.B -e
-option of
-.I ash
-causes the shell to exit when a command returns 1 even though that
-contradicts the convention described here.
-.PP
-When a command is terminated by a signal, the uses 128 plus the signal
-number as the exit code for the command.
-.h "Builtin Commands"
-This concluding section lists the builtin commands which are builtin
-because they need to perform some operation that can't be performed by a
-separate process.  In addition to these, there are several other commands
-.RI ( catf ,
-.IR echo ,
-.IR expr ,
-.IR line ,
-.IR nlecho ,
-.IR test ,
-.RI  `` : '',
-and
-.IR true )
-which can optionally be compiled into the shell.  The builtin
-commands described below that accept options use the System V Release 2
-.IR getopt (3)
-syntax.
-.sp
-.b bg
-[
-.I job
-] ...
-.br
-Continue the specified jobs (or the current job if no jobs are given)
-in the background.
-This command is only available on systems with Bekeley job control.
-.b command
-.IR "command arg" ...
-.br
-Execute the specified builtin command.  (This is useful when you have a
-shell function with the same name as a builtin command.)
-.b cd
-[
-.I directory
-]
-.br
-Switch to the specified directory (default $HOME).
-If the an entry for CDPATH appears in the environment of the cd command
-or the shell variable CDPATH is set and the directory name does not
-begin with a slash, then the directories listed in CDPATH will be
-searched for the specified directory.  The format of CDPATH is the
-same as that of PATH.
-In an interactive shell, the cd command will print out the name of the
-directory that it actually switched to if this is different from the
-name that the user gave.  These may be different either because
-the CDPATH mechanism was used or because a symbolic link was crossed.
-.\" .b ".\fI\h'0.1i'file"
-.\" Cawf can't do \h'0.1i'
-.b .
-.I file
-.br
-The commands in the specified file are read and executed by the shell.
-A path search is not done to find the file because the directories in
-PATH generally contain files that are intended to be executed, not read.
-.b eval
-.IR string ...
-.br
-The strings are parsed as shell commands and executed.
-(This differs from the System V shell, which concatenates the arguments
-(separated by spaces) and parses the result as a single command.)
-.b exec
-[
-.IR "command arg" ...
-]
-.br
-Unless
-.I command
-is omitted,
-the shell process is replaced with the specified program (which must be a real
-program, not a shell builtin or function).
-Any redirections on the exec command are marked as permanent, so that they
-are not undone when the exec command finishes.
-If the command is not found, the exec command causes the shell to exit.
-.b exit
-[
-.I exitstatus
-]
-.br
-Terminate the shell process.  If
-.I exitstatus
-is given it is used as the
-exit status of the shell; otherwise the exit status of the preceding
-command is used.
-.b export
-.IR name ...
-.br
-The specified names are exported so that they will appear in the environment
-of subsequent commands.  The only way to un-export a variable is to unset it.
-.I Ash
-allows the value of a variable to be set at the same time it is exported
-by writing
-.d
-\fBexport\fR name=value
-.e
-With no arguments the export command lists the names of all exported variables.
-.b fg
-[
-.I job
-]
-.br
-Move the specified job or the current job to the foreground.
-This command is only available on systems with Bekeley job control.
-.b getopts
-.I optstring
-.I var
-.br
-The System V
-.I getopts
-command.
-.b hash
-.B -rv
-.IR command ...
-.br
-The shell maintains a hash table which remembers the locations of
-commands.  With no arguments whatsoever, the hash command prints
-out the contents of this table.  Entries which have not been looked
-at since the last
-.I cd
-command are marked with an asterisk; it is possible for these entries
-to be invalid.
-.sp
-With arguments, the hash command removes the specified commands from
-the hash table (unless they are functions) and then locates them.
-With the
-.B -v
-option,
-.I hash
-prints the locations of the commands as it finds them.
-The
-.B -r
-option causes the
-.I hash
-command to delete all the entries in the hash table except for
-functions.
-.b jobid
-[
-.I job
-]
-.br
-Print the process id's of the processes in the job.  If the job argument
-is omitted, use the current job.
-.b jobs
-.br
-This command lists out all the background processes which are children
-of the current shell process.
-.b pwd
-.br
-Print the current directory.  The builtin command may differ from the
-program of the same name because the builtin command remembers what
-the current directory is rather than recomputing it each time.  This
-makes it faster.  However, if the current directory is renamed, the
-builtin version of pwd will continue to print the old name for the
-directory.
-.b read
-[
-.B -p
-.I prompt
-]
-[
-.B -e
-]
-.IR variable ...
-.br
-The prompt is printed if the
-.B -p
-option is specified and the standard input is a terminal.  Then a
-line is read from the standard input.  The trailing newline is deleted
-from the line and the line is split as described
-in the section on word splitting above, and the pieces are assigned to
-the variables in order.  If there are more pieces than variables, the
-remaining pieces (along with the characters in IFS that separated them)
-are assigned to the last variable.  If there are more variables than
-pieces, the remaining variables are assigned the null string.
-.sp
-The
-.B -e
-option causes any backslashes in the input to be treated specially.
-If a backslash is followed by a newline, the backslash and the newline
-will be deleted.  If a backslash is followed by any other character,
-the backslash will be deleted and the following character will be treated
-as though it were not in IFS, even if it is.
-.b readonly
-.IR name ...
-.br
-The specified names are marked as read only, so that they cannot be
-subsequently modified or unset.
-.I Ash
-allows the value of a variable to be set at the same time it is marked
-read only by writing
-.d
-\fBreadonly\fR name=value
-.e
-With no arguments the readonly command lists the names of all
-read only variables.
-.b set
-[
-{
-.BI - options
-|
-.BI + options
-|
-.B --
-}
-]
-.IR arg ...
-.br
-The
-.I set
-command performs three different functions.
-.sp
-With no arguments, it lists the values of all shell variables.
-.sp
-If options are given, it sets the specified option flags, or clears
-them if the option flags are introduced with a
-.B +
-rather than a
-.BR - .
-Only the first argument to
-.I set
-can contain options.
-The possible options are:
-.sp
-.ta 0.4i
-.in +0.4i
-.ti -0.4i
-\fB-e\fR       Causes the shell to exit when a command terminates with
-a nonzero exit status, except when the exit status of the command is
-explicitly tested.  The exit status of a command is considered to be
-explicitly tested if the command is used to control an
-.IR if ,
-.IR elif ,
-.IR while ,
-or
-.IR until ;
-or if the command is the left hand operand of an ``&&'' or ``||''
-operator.
-.sp
-.ti -0.4i
-\fB-f\fR       Turn off file name generation.
-.sp
-.ti -0.4i
-\fB-I\fR       Cause the shell to ignore end of file conditions.
-(This doesn't apply when the shell a script sourced using the ``.''
-command.)  The shell will in fact exit if it gets 50 eof's in a
-row.
-.sp
-.ti -0.4i
-\fB-i\fR       Make the shell interactive.  This causes the shell to
-prompt for input, to trap interrupts, to ignore quit and terminate signals,
-and to return to the main command loop rather than exiting on error.
-.sp
-.ti -0.4i
-\fB-j\fR       Turns on Berkeley job control, on systems that support it.
-When the shell starts up, the
-.B -j
-is set by default if the
-.B -i
-flag is set.
-.sp
-.ti -0.4i
-\fB-n\fR       Causes the shell to read commands but not execute them.
-(This is marginally useful for checking the syntax of scripts.)
-.sp
-.ti -0.4i
-\fB-s\fR       If this flag is set when the shell starts up, the shell
-reads commands from its standard input.  The shell doesn't examine the
-value of this flag any other time.
-.sp
-.ti -0.4i
-\fB-x\fR       If this flag is set, the shell will print out each
-command before executing it.
-.sp
-.ti -0.4i
-\fB-z\fR       If this flag is set, the file name generation process
-may generate zero files.  If it is not set, then a pattern which does
-not match any files will be replaced by a quoted version of the pattern.
-.in -0.4i
-.sp
-The third use of the set command is to set the values of the shell's
-positional parameters to the specified
-.IR args .
-To change the positional parameters without changing any options,
-use ``\fB--\fR'' as the first argument to
-.IR set .
-If no args are present, the set command will leave the value of the
-positional parameters unchanged, so to set the positional parameters
-to set of values that may be empty, execute the command
-.d
-shift $#
-.e
-first to clear out the old values of the positional parameters.
-.b setvar
-.I variable
-.I value
-.br
-Assigns
-.I value
-to
-.IR variable .
-(In general it is better to write
-.I variable=value
-rather than using
-.IR setvar .
-.I Setvar
-is intended to be used in functions that assign values to variables whose
-names are passed as parameters.)
-.b shift
-[
-.I n
-]
-.br
-Shift the positional parameters
-.I n
-times.
-A shift sets the value of $1 to the value of $2, the value of $2 to
-the value of $3, and so on, decreasing the value of $# by one.
-If there are zero positional parameters, shifting doesn't do anything.
-.b trap
-[
-.I action
-]
-.IR signal ...
-.br
-Cause the shell to parse and execute
-.I action
-when any of the specified signals are received.
-The signals are specified by signal number.
-.I Action
-may be null or omitted;
-the former causes the specified signal to be ignored and the latter
-causes the default action to be taken.
-When the shell forks off a subshell, it resets trapped (but not ignored)
-signals to the default action.
-The trap command has no effect on signals that were ignored on entry
-to the shell.
-.b umask
-[
-.I mask
-]
-.br
-Set the value of umask (see
-.IR umask (2))
-to the specified octal value.  If the argument is omitted, the umask
-value is printed.
-.b unset
-.IR name ...
-.br
-The specified variables and functions are unset and unexported.
-If a given name corresponds to both a variable and a function, both the
-variable and the function are unset.
-.b wait
-[
-.I job
-]
-.br
-Wait for the specified job to complete and return the exit status of the
-last process in the job.  If the argument is omitted, wait for all jobs
-to complete and the return an exit status of zero.
-.SH EXAMPLES
-The following function redefines the \fIcd\fR command:
-.d
-cd() {
-       if command cd "$@"
-       then    if test -f .enter
-               then    . .enter
-               else    return 0
-               fi
-       fi
-}
-.e
-This function causes the file ``.enter'' to be read when you enter a
-directory, if it exists.  The \fIcommand\fR command is used to access the
-real \fIcd\fR command.  The ``return 0'' ensures that the function will
-return an exit status of zero if it successfully changes to a directory
-that does not contain a ``.enter'' file.  Redefining existing commands
-is not always a good idea, but this example shows that you can do it if
-you want to.
-.PP
-The suspend function distributed with
-.I ash
-looks like
-.d
-# Copyright (C) 1989 by Kenneth Almquist.  All rights reserved.
-# This file is part of ash, which is distributed under the terms
-# specified by the Ash General Public License.
-
-suspend() {
-       local -
-       set +j
-       kill -TSTP 0
-}
-.e
-This turns off job control and then sends a stop signal to the current
-process group, which suspends the shell.  (When job control is turned
-on, the shell ignores the TSTP signal.)  Job control will be turned back
-on when the function returns because ``-'' is local to the function.
-As an example of what \fInot\fR to do, consider an earlier version of
-\fIsuspend\fR:
-.d
-suspend() {
-       suspend_flag=$-
-       set +j
-       kill -TSTP 0
-       set -$suspend_flag
-}
-.e
-There are two problems with this.  First, \fBsuspend_flag\fR is a global
-variable rather than a local one, which will cause problems in the
-(unlikely) circumstance that the user is using that variable for some
-other purpose.  Second, consider what happens if shell received an interrupt
-signal after it executes the first \fIset\fR command but before it executes
-the second one.  The interrupt signal will abort the shell function, so
-that the second \fIset\fR command will never be executed and job control
-will be left off.  The first version of \fIsuspend\fR avoids this problem
-by turning job control off only in a local copy of the shell options.  The
-local copy of the shell options is discarded when the function is terminated,
-no matter how it is terminated.
-.SH HINTS
-Shell variables can be used to provide abbreviations for things which
-you type frequently.  For example, I set
-.br
-.\" \h'1i'export h=$HOME
-.\" Cawf can't do \h'1i'
-.in +1i
-export h=$HOME
-.in -1i
-.br
-in my .profile so that I can type the name of my home directory simply
-by typing ``$h''.
-.PP
-When writing shell procedures, try not to make assumptions about what is
-imported from the environment.  Explicitly unset or initialize all variables,
-rather than assuming they will be unset.  If you use cd, it is a good idea
-to unset CDPATH.
-.PP
-People sometimes use ``<&-'' or ``>&-'' to provide no input to a command
-or to discard the output of a command.  A better way to do this is
-to redirect the input or output of the command to
-.BR /dev/null .
-.PP
-Word splitting and file name generation are performed by default,
-and you have to explicitly use double quotes to suppress it.  This is
-backwards, but you can learn to live with it.  Just get in the habit of
-writing double quotes around variable and command substitutions, and
-omit them only when you really want word splitting and file name generation.
-If you want word splitting but not file name generation, use the
-.B -f
-option.
-.SH AUTHORS
-Kenneth Almquist
-.SH "SEE ALSO"
-echo(1), expr(1), line(1), pwd(1), true(1).
-.SH BUGS
-When command substitution occurs inside a here document, the commands inside
-the here document are run with their standard input closed.  For example,
-the following will not work because the standard input of the
-.I line
-command will be closed when the command is run:
-.d
-cat <<-!
-Line 1: $(line)
-Line 2: $(line)
-!
-.e
-.PP
-Unsetting a function which is currently being executed may cause strange
-behavior.
-.PP
-The shell syntax allows a here document to be terminated by an end of file
-as well as by a line containing the terminator word which follows the ``<<''.
-What this means is that if you mistype the terminator line, the shell
-will silently swallow up the rest of your shell script and stick it
-in the here document.
-.\" several minor typos corrected -- ASW 2005-01-15
index 96fdf1833fa47aed27ee803cb5c5a8daeff6a4e7..cbc13451e53ddfa40f1b4b83268754c49d9fed3e 100755 (executable)
@@ -142,7 +142,7 @@ vndconfig vnd0 image0 || bomb "unable to configure vnd0"
 # Invoke the blocktest test set to test various other aspects.
 vndconfig -S vnd0 image0 || bomb "unable to configure vnd0"
 cd ../blocktest
-. support.sh
+. ./support.sh
 block_test /dev/vnd0 \
   "rw,min_read=1,min_write=1,element=1,max=16777216,nocontig,silent" || \
   bomb "blocktest test set failed"