diff options
author | Matthew Turk <satai@gentoo.org> | 2003-02-09 09:36:31 +0000 |
---|---|---|
committer | Matthew Turk <satai@gentoo.org> | 2003-02-09 09:36:31 +0000 |
commit | bb490d1e512c36fba93fefe22ce06a5ac84ae186 (patch) | |
tree | f103e8fa495b349fc6891d09c9dd972f9fe8c9cb /app-shells | |
parent | New pre-release version. (diff) | |
download | historical-bb490d1e512c36fba93fefe22ce06a5ac84ae186.tar.gz historical-bb490d1e512c36fba93fefe22ce06a5ac84ae186.tar.bz2 historical-bb490d1e512c36fba93fefe22ce06a5ac84ae186.zip |
Ash, the netbsd shell. Closes 15319 -- thanks to Tavis Ormandy!
Diffstat (limited to 'app-shells')
-rw-r--r-- | app-shells/ash/ChangeLog | 8 | ||||
-rw-r--r-- | app-shells/ash/ash-1.6.ebuild | 46 | ||||
-rw-r--r-- | app-shells/ash/files/dash-ash-hetio-yacc.diff | 17336 | ||||
-rw-r--r-- | app-shells/ash/files/digest-ash-1.6 | 1 |
4 files changed, 17391 insertions, 0 deletions
diff --git a/app-shells/ash/ChangeLog b/app-shells/ash/ChangeLog new file mode 100644 index 000000000000..90d71f3d179d --- /dev/null +++ b/app-shells/ash/ChangeLog @@ -0,0 +1,8 @@ +# ChangeLog for <CATEGORY>/<PACKAGE_NAME> +# Copyright 2002-2003 Gentoo Technologies, Inc.; Distributed under the GPL v2 +# $Header: /var/cvsroot/gentoo-x86/app-shells/ash/ChangeLog,v 1.1 2003/02/09 09:36:30 satai Exp $ + +*ash-1.6 (09 Feb 2003) + + 09 Feb 2003; Matthew Turk <satai@gentoo.org> : + Initial import. Ebuild submitted by Tavis Ormandy <taviso@sdf.lonestar.org> diff --git a/app-shells/ash/ash-1.6.ebuild b/app-shells/ash/ash-1.6.ebuild new file mode 100644 index 000000000000..cd510ba8880e --- /dev/null +++ b/app-shells/ash/ash-1.6.ebuild @@ -0,0 +1,46 @@ +# Copyright 1999-2003 Gentoo Technologies, Inc. +# Distributed under the terms of the GNU General Public License v2 +# $Header: /var/cvsroot/gentoo-x86/app-shells/ash/ash-1.6.ebuild,v 1.1 2003/02/09 09:36:31 satai Exp $ + +inherit eutils + +DESCRIPTION="NetBSD's lightweight bourne shell" +HOMEPAGE="http://cvsweb.netbsd.org/bsdweb.cgi/src/bin/sh/" +SRC_URI="ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-release-1-6/tar_files/src/bin.tar.gz" +LICENSE="BSD" +SLOT="0" +KEYWORDS="~alpha ~x86" +IUSE="" +DEPEND="virtual/glibc + sys-devel/pmake + sys-apps/sed + dev-util/yacc" +S=${WORKDIR}/bin_NetBSD-1.6release/src/bin/sh + +src_unpack() { + mkdir ${WORKDIR}/bin_NetBSD-1.6release + (cd ${WORKDIR}/bin_NetBSD-1.6release; tar zxv --no-same-owner \ + -f ${DISTDIR}/bin.tar.gz src/bin/sh) + epatch ${FILESDIR}/dash-ash-hetio-yacc.diff +} +src_compile() { + cd ${S} + # pmake name conflicts, use full path + /usr/bin/pmake CFLAGS:="-Wall -DBSD=1 -D_GNU_SOURCE -DGLOB_BROKEN \ + -DHAVE_VASPRINTF=1 -DIFS_BROKEN -DGCC_BROKEN_NG -D__COPYRIGHT\(x\)=\ + -D__RCSID\(x\)= -D_DIAGASSERT\(x\)= -g -O2 -fstrict-aliasing ${CFLAGS}" \ + YACC:="sh ${S}/yaccfe.sh" || die "pmake failed" + cd - +} + +src_install() { + install -D -g root -m 0755 -o root -s ${S}/sh ${D}/bin/ash || { + die "install failed." + } + install -D -g root -m 0644 -o root ${S}/sh.1 ${D}/usr/man/man1/ash.1 || { + die "install failed." + } + gzip ${D}/usr/man/man1/ash.1 + dosym /usr/man/man1/ash.1.gz /usr/man/man1/sh.1.gz +} + diff --git a/app-shells/ash/files/dash-ash-hetio-yacc.diff b/app-shells/ash/files/dash-ash-hetio-yacc.diff new file mode 100644 index 000000000000..f9513d835fc4 --- /dev/null +++ b/app-shells/ash/files/dash-ash-hetio-yacc.diff @@ -0,0 +1,17336 @@ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/alias.c bin_NetBSD-1.6release/src/bin/sh/alias.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/alias.c 1998-05-20 12:07:30.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/alias.c 2003-02-08 14:35:42.000000000 +0000 +@@ -60,8 +60,9 @@ + struct alias *atab[ATABSIZE]; + + STATIC void setalias __P((char *, char *)); +-STATIC int unalias __P((char *)); +-STATIC struct alias **hashalias __P((char *)); ++STATIC struct alias **hashalias __P((const char *)); ++STATIC struct alias *freealias __P((struct alias *)); ++STATIC struct alias **__lookupalias __P((const char *)); + + STATIC + void +@@ -70,110 +71,58 @@ + { + struct alias *ap, **app; + +- app = hashalias(name); +- for (ap = *app; ap; ap = ap->next) { +- if (equal(name, ap->name)) { ++ app = __lookupalias(name); ++ ap = *app; + INTOFF; ++ if (ap) { ++ if (!(ap->flag & ALIASINUSE)) { + ckfree(ap->val); +- ap->val = savestr(val); +- INTON; +- return; +- } + } ++ ap->val = savestr(val); ++ ap->flag &= ~ALIASDEAD; ++ } else { + /* not found */ +- INTOFF; + ap = ckmalloc(sizeof (struct alias)); + ap->name = savestr(name); +- /* +- * XXX - HACK: in order that the parser will not finish reading the +- * alias value off the input before processing the next alias, we +- * dummy up an extra space at the end of the alias. This is a crock +- * and should be re-thought. The idea (if you feel inclined to help) +- * is to avoid alias recursions. The mechanism used is: when +- * 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 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 +- * H A C K is that we add a little fluff after the alias value +- * so that the string will not be exhausted. This is a good +- * idea ------- ***NOT*** +- */ +-#ifdef notyet + ap->val = savestr(val); +-#else /* hack */ +- { +- int len = strlen(val); +- ap->val = ckmalloc(len + 2); +- memcpy(ap->val, val, len); +- ap->val[len] = ' '; /* fluff */ +- ap->val[len+1] = '\0'; +- } +-#endif +- ap->next = *app; ++ ap->flag = 0; ++ ap->next = 0; + *app = ap; ++ } + INTON; + } + +-STATIC int ++int + unalias(name) + char *name; + { +- struct alias *ap, **app; ++ struct alias **app; + +- app = hashalias(name); ++ app = __lookupalias(name); + +- for (ap = *app; ap; app = &(ap->next), ap = ap->next) { +- if (equal(name, ap->name)) { +- /* +- * if the alias is currently in use (i.e. its +- * buffer is being used by the input routine) we +- * just null out the name instead of freeing it. +- * We could clear it out later, but this situation +- * is so rare that it hardly seems worth it. +- */ +- if (ap->flag & ALIASINUSE) +- *ap->name = '\0'; +- else { ++ if (*app) { + INTOFF; +- *app = ap->next; +- ckfree(ap->name); +- ckfree(ap->val); +- ckfree(ap); ++ *app = freealias(*app); + INTON; +- } + return (0); + } +- } + + return (1); + } + +-#ifdef mkinit +-MKINIT void rmaliases __P((void)); +- +-SHELLPROC { +- rmaliases(); +-} +-#endif +- + void + rmaliases() { +- struct alias *ap, *tmp; ++ struct alias *ap, **app; + int i; + + INTOFF; + for (i = 0; i < ATABSIZE; i++) { +- ap = atab[i]; +- atab[i] = NULL; +- while (ap) { +- ckfree(ap->name); +- ckfree(ap->val); +- tmp = ap; +- ap = ap->next; +- ckfree(tmp); ++ app = &atab[i]; ++ for (ap = *app; ap; ap = *app) { ++ *app = freealias(*app); ++ if (ap == *app) { ++ app = &ap->next; ++ } + } + } + INTON; +@@ -181,20 +130,14 @@ + + struct alias * + lookupalias(name, check) +- char *name; ++ const char *name; + int check; + { +- struct alias *ap = *hashalias(name); ++ struct alias *ap = *__lookupalias(name); + +- for (; ap; ap = ap->next) { +- if (equal(name, ap->name)) { +- if (check && (ap->flag & ALIASINUSE)) ++ if (check && ap && (ap->flag & ALIASINUSE)) + return (NULL); + return (ap); +- } +- } +- +- return (NULL); + } + + /* +@@ -214,18 +157,17 @@ + + for (i = 0; i < ATABSIZE; i++) + for (ap = atab[i]; ap; ap = ap->next) { +- if (*ap->name != '\0') +- out1fmt("alias %s=%s\n", ap->name, ap->val); ++ printalias(ap); + } + return (0); + } + while ((n = *++argv) != NULL) { + 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); ++ if ((ap = *__lookupalias(n)) == NULL) { ++ outfmt(out2, "%s: %s not found\n", "alias", n); + ret = 1; + } else +- out1fmt("alias %s=%s\n", n, ap->val); ++ printalias(ap); + } + else { + *v++ = '\0'; +@@ -249,15 +191,19 @@ + return (0); + } + } +- for (i = 0; *argptr; argptr++) +- i = unalias(*argptr); ++ for (i = 0; *argptr; argptr++) { ++ if (unalias(*argptr)) { ++ outfmt(out2, "%s: %s not found\n", "unalias", *argptr); ++ i = 1; ++ } ++ } + + return (i); + } + + STATIC struct alias ** + hashalias(p) +- char *p; ++ const char *p; + { + unsigned int hashval; + +@@ -266,3 +212,37 @@ + hashval+= *p++; + return &atab[hashval % ATABSIZE]; + } ++ ++STATIC struct alias * ++freealias(struct alias *ap) { ++ struct alias *next; ++ ++ if (ap->flag & ALIASINUSE) { ++ ap->flag |= ALIASDEAD; ++ return ap; ++ } ++ ++ next = ap->next; ++ ckfree(ap->name); ++ ckfree(ap->val); ++ ckfree(ap); ++ return next; ++} ++ ++void ++printalias(const struct alias *ap) { ++ out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); ++} ++ ++STATIC struct alias ** ++__lookupalias(const char *name) { ++ struct alias **app = hashalias(name); ++ ++ for (; *app; app = &(*app)->next) { ++ if (equal(name, (*app)->name)) { ++ break; ++ } ++ } ++ ++ return app; ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/alias.h bin_NetBSD-1.6release/src/bin/sh/alias.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/alias.h 1995-10-14 00:43:54.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/alias.h 2003-02-08 14:35:42.000000000 +0000 +@@ -39,6 +39,7 @@ + */ + + #define ALIASINUSE 1 ++#define ALIASDEAD 2 + + struct alias { + struct alias *next; +@@ -47,7 +48,9 @@ + int flag; + }; + +-struct alias *lookupalias __P((char *, int)); ++struct alias *lookupalias __P((const char *, int)); + int aliascmd __P((int, char **)); + int unaliascmd __P((int, char **)); + void rmaliases __P((void)); ++int unalias __P((char *)); ++void printalias __P((const struct alias *)); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/arith_lex.l bin_NetBSD-1.6release/src/bin/sh/arith_lex.l +--- bin_NetBSD-1.6release.orig/src/bin/sh/arith_lex.l 1999-02-05 12:04:50.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/arith_lex.l 2003-02-08 14:35:42.000000000 +0000 +@@ -52,7 +52,7 @@ + #include "expand.h" + + extern int yylval; +-extern char *arith_buf, *arith_startbuf; ++extern const char *arith_buf, *arith_startbuf; + #undef YY_INPUT + #define YY_INPUT(buf,result,max) \ + result = (*buf = *arith_buf++) ? 1 : YY_NULL; +@@ -84,7 +84,7 @@ + "-" { return(ARITH_SUB); } + "~" { return(ARITH_BNOT); } + "!" { return(ARITH_NOT); } +-. { error("arith: syntax error: \"%s\"\n", arith_startbuf); } ++. { error("arith: syntax error: \"%s\"", arith_startbuf); } + %% + + void +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/arith.y bin_NetBSD-1.6release/src/bin/sh/arith.y +--- bin_NetBSD-1.6release.orig/src/bin/sh/arith.y 2001-02-05 11:15:29.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/arith.y 2003-02-08 14:35:42.000000000 +0000 +@@ -55,6 +55,7 @@ + + const char *arith_buf, *arith_startbuf; + ++int yyparse __P((void)); + void yyerror __P((const char *)); + #ifdef TESTARITH + int main __P((int , char *[])); +@@ -84,8 +85,8 @@ + + + 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_OR expr = { $$ = $1 || $3; } ++ | expr ARITH_AND expr = { $$ = $1 && $3; } + | expr ARITH_BOR expr = { $$ = $1 | $3; } + | expr ARITH_BXOR expr = { $$ = $1 ^ $3; } + | expr ARITH_BAND expr = { $$ = $1 & $3; } +@@ -166,7 +167,7 @@ + p = grabstackstr(concat); + } + } else +- p = ""; ++ p = nullstr; + + i = arith(p); + +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/arith_yylex.c bin_NetBSD-1.6release/src/bin/sh/arith_yylex.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/arith_yylex.c 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/arith_yylex.c 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,162 @@ ++/* $Id: dash-ash-hetio-yacc.diff,v 1.1 2003/02/09 09:36:31 satai Exp $ */ ++ ++/*- ++ * Copyright (c) 2002 ++ * Herbert Xu. ++ * 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 <stdlib.h> ++#include "arith.h" ++#include "expand.h" ++#include "error.h" ++ ++extern int yylval; ++extern const char *arith_buf, *arith_startbuf; ++ ++int ++yylex() ++{ ++ int value; ++ const char *buf = arith_buf; ++ ++ for (;;) { ++ switch (*buf) { ++ case ' ': ++ case '\t': ++ case '\n': ++ buf++; ++ continue; ++ default: ++err: ++ error("arith: syntax error: \"%s\"", arith_startbuf); ++ /* NOTREACHED */ ++ case '0': ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ case '8': ++ case '9': ++ yylval = strtol(buf, (char **) &arith_buf, 0); ++ return ARITH_NUM; ++ case '=': ++ if (*++buf != '=') { ++ goto err; ++ } ++ value = ARITH_EQ; ++ break; ++ case '>': ++ switch (*++buf) { ++ case '=': ++ value = ARITH_GE; ++ break; ++ case '>': ++ value = ARITH_RSHIFT; ++ break; ++ default: ++ value = ARITH_GT; ++ goto out; ++ } ++ break; ++ case '<': ++ switch (*++buf) { ++ case '=': ++ value = ARITH_LE; ++ break; ++ case '<': ++ value = ARITH_LSHIFT; ++ break; ++ default: ++ value = ARITH_LT; ++ goto out; ++ } ++ break; ++ case '|': ++ if (*++buf != '|') { ++ value = ARITH_BOR; ++ goto out; ++ } ++ value = ARITH_OR; ++ break; ++ case '&': ++ if (*++buf != '&') { ++ value = ARITH_BAND; ++ goto out; ++ } ++ value = ARITH_AND; ++ break; ++ case '!': ++ if (*++buf != '=') { ++ value = ARITH_NOT; ++ goto out; ++ } ++ value = ARITH_NE; ++ break; ++ case 0: ++ value = 0; ++ goto out; ++ case '(': ++ value = ARITH_LPAREN; ++ break; ++ case ')': ++ value = ARITH_RPAREN; ++ break; ++ case '*': ++ value = ARITH_MUL; ++ break; ++ case '/': ++ value = ARITH_DIV; ++ break; ++ case '%': ++ value = ARITH_REM; ++ break; ++ case '+': ++ value = ARITH_ADD; ++ break; ++ case '-': ++ value = ARITH_SUB; ++ break; ++ case '~': ++ value = ARITH_BNOT; ++ break; ++ } ++ break; ++ } ++ ++ buf++; ++out: ++ arith_buf = buf; ++ return value; ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/assignbltins.def bin_NetBSD-1.6release/src/bin/sh/assignbltins.def +--- bin_NetBSD-1.6release.orig/src/bin/sh/assignbltins.def 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/assignbltins.def 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,4 @@ ++alias ++export ++local ++readonly +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/bltin/bltin.h bin_NetBSD-1.6release/src/bin/sh/bltin/bltin.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/bltin/bltin.h 1997-07-05 12:12:37.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/bltin/bltin.h 2003-02-08 14:35:42.000000000 +0000 +@@ -47,7 +47,10 @@ + #include "../shell.h" + #include "../mystring.h" + #ifdef SHELL ++#include "../error.h" ++#include "../memalloc.h" + #include "../output.h" ++#ifndef USE_GLIBC_STDIO + #define stdout out1 + #define stderr out2 + #define printf out1fmt +@@ -56,12 +59,9 @@ + #define fprintf outfmt + #define fputs outstr + #define fflush flushout ++#define ferror outerr ++#endif + #define INITARGS(argv) +-#define warnx(a, b, c) { \ +- char buf[64]; \ +- (void)snprintf(buf, sizeof(buf), a, b, c); \ +- error("%s", buf); \ +-} + + #else + #undef NULL +@@ -70,8 +70,6 @@ + #define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else + #endif + +-pointer stalloc __P((int)); +-void error __P((char *, ...)); + int echocmd __P((int, char **)); + + +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/bltin/echo.c bin_NetBSD-1.6release/src/bin/sh/bltin/echo.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/bltin/echo.c 1996-11-03 12:06:22.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/bltin/echo.c 2003-02-08 14:35:42.000000000 +0000 +@@ -44,64 +44,48 @@ + + #define main echocmd + ++#ifdef USE_GLIBC_STDIO ++#include <stdio.h> ++ ++#include "../mystring.h" ++#else + #include "bltin.h" ++#endif + +-/* #define eflag 1 */ ++int print_escape_str(const char *); + + int +-main(argc, argv) char **argv; { +- register char **ap; +- register char *p; +- register char c; +- int count; ++main(int argc, char **argv) { + int nflag = 0; +-#ifndef eflag +- int eflag = 0; +-#endif ++ int c = ' '; + +- ap = argv; +- if (argc) +- ap++; +- if ((p = *ap) != NULL) { +- if (equal(p, "-n")) { +- nflag++; +- ap++; +- } else if (equal(p, "-e")) { +-#ifndef eflag +- eflag++; +-#endif +- ap++; ++ argv++; ++ if (*argv && equal(*argv, "-n")) { ++ argv++; ++ nflag = 1; + } ++ ++ if (!*argv) { ++ goto end; + } +- while ((p = *ap++) != NULL) { +- while ((c = *p++) != '\0') { +- if (c == '\\' && eflag) { +- switch (*p++) { +- case 'b': c = '\b'; break; +- case 'c': return 0; /* exit */ +- case 'f': c = '\f'; break; +- case 'n': c = '\n'; break; +- case 'r': c = '\r'; break; +- case 't': c = '\t'; break; +- case 'v': c = '\v'; break; +- case '\\': break; /* c = '\\' */ +- case '0': +- c = 0; +- count = 3; +- while (--count >= 0 && (unsigned)(*p - '0') < 8) +- c = (c << 3) + (*p++ - '0'); ++ ++ do { ++ if (print_escape_str(*argv)) { + break; +- default: +- p--; ++ } ++ if (!*++argv) { ++end: ++ if (nflag) { + break; + } ++ c = '\n'; + } + putchar(c); +- } +- if (*ap) +- putchar(' '); +- } +- if (! nflag) +- putchar('\n'); ++ } while (c == ' '); ++#ifdef SHELL + return 0; ++#else ++ fflush(stdout); ++ return ferror(stdout); ++#endif + } +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/bltin/printf.1 bin_NetBSD-1.6release/src/bin/sh/bltin/printf.1 +--- bin_NetBSD-1.6release.orig/src/bin/sh/bltin/printf.1 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/bltin/printf.1 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,281 @@ ++.\" $NetBSD: printf.1,v 1.15 2002/02/08 01:36:31 ross Exp $ ++.\" ++.\" Copyright (c) 1989, 1990, 1993 ++.\" The Regents of the University of California. All rights reserved. ++.\" ++.\" This code is derived from software contributed to Berkeley by ++.\" the Institute of Electrical and Electronics Engineers, 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. ++.\" ++.\" from: @(#)printf.1 8.1 (Berkeley) 6/6/93 ++.\" ++.Dd November 5, 1993 ++.Dt PRINTF 1 ++.Os ++.Sh NAME ++.Nm printf ++.Nd formatted output ++.Sh SYNOPSIS ++.Nm ++.Ar format ++.Op Ar arguments ... ++.Sh DESCRIPTION ++.Nm ++formats and prints its arguments, after the first, under control ++of the ++.Ar format . ++The ++.Ar format ++is a character string which contains three types of objects: plain characters, ++which are simply copied to standard output, character escape sequences which ++are converted and copied to the standard output, and format specifications, ++each of which causes printing of the next successive ++.Ar argument . ++.Pp ++The ++.Ar arguments ++after the first are treated as strings if the corresponding format is ++either ++.Cm b , ++.Cm c ++or ++.Cm s ; ++otherwise it is evaluated as a C constant, with the following extensions: ++.Pp ++.Bl -bullet -offset indent -compact ++.It ++A leading plus or minus sign is allowed. ++.It ++If the leading character is a single or double quote, the value is the ++.Tn ASCII ++code of the next character. ++.El ++.Pp ++The format string is reused as often as necessary to satisfy the ++.Ar arguments . ++Any extra format specifications are evaluated with zero or the null ++string. ++.Pp ++Character escape sequences are in backslash notation as defined in ++.St -ansiC . ++The characters and their meanings ++are as follows: ++.Bl -tag -width Ds -offset indent ++.It Cm \ee ++Write an \*[Lt]escape\*[Gt] character. ++.It Cm \ea ++Write a \*[Lt]bell\*[Gt] character. ++.It Cm \eb ++Write a \*[Lt]backspace\*[Gt] character. ++.It Cm \ef ++Write a \*[Lt]form-feed\*[Gt] character. ++.It Cm \en ++Write a \*[Lt]new-line\*[Gt] character. ++.It Cm \er ++Write a \*[Lt]carriage return\*[Gt] character. ++.It Cm \et ++Write a \*[Lt]tab\*[Gt] character. ++.It Cm \ev ++Write a \*[Lt]vertical tab\*[Gt] character. ++.It Cm \e\' ++Write a \*[Lt]single quote\*[Gt] character. ++.It Cm \e\e ++Write a backslash character. ++.It Cm \e Ns Ar num ++Write an 8-bit character whose ++.Tn ASCII ++value is the 1-, 2-, or 3-digit ++octal number ++.Ar num . ++.El ++.Pp ++Each format specification is introduced by the percent character ++(``%''). ++The remainder of the format specification includes, ++in the following order: ++.Bl -tag -width Ds ++.It "Zero or more of the following flags:" ++.Bl -tag -width Ds ++.It Cm # ++A `#' character ++specifying that the value should be printed in an ``alternative form''. ++For ++.Cm c , ++.Cm d , ++and ++.Cm s , ++formats, this option has no effect. For the ++.Cm o ++formats the precision of the number is increased to force the first ++character of the output string to a zero. For the ++.Cm x ++.Pq Cm X ++format, a non-zero result has the string ++.Li 0x ++.Pq Li 0X ++prepended to it. For ++.Cm e , ++.Cm E , ++.Cm f , ++.Cm g , ++and ++.Cm G , ++formats, the result will always contain a decimal point, even if no ++digits follow the point (normally, a decimal point only appears in the ++results of those formats if a digit follows the decimal point). For ++.Cm g ++and ++.Cm G ++formats, trailing zeros are not removed from the result as they ++would otherwise be; ++.It Cm \&\- ++A minus sign `\-' which specifies ++.Em left adjustment ++of the output in the indicated field; ++.It Cm \&+ ++A `+' character specifying that there should always be ++a sign placed before the number when using signed formats. ++.It Sq \&\ \& ++A space specifying that a blank should be left before a positive number ++for a signed format. A `+' overrides a space if both are used; ++.It Cm \&0 ++A zero `0' character indicating that zero-padding should be used ++rather than blank-padding. A `\-' overrides a `0' if both are used; ++.El ++.It "Field Width:" ++An optional digit string specifying a ++.Em field width ; ++if the output string has fewer characters than the field width it will ++be blank-padded on the left (or right, if the left-adjustment indicator ++has been given) to make up the field width (note that a leading zero ++is a flag, but an embedded zero is part of a field width); ++.It Precision : ++An optional period, ++.Sq Cm \&.\& , ++followed by an optional digit string giving a ++.Em precision ++which specifies the number of digits to appear after the decimal point, ++for ++.Cm e ++and ++.Cm f ++formats, or the maximum number of characters to be printed ++from a string; if the digit string is missing, the precision is treated ++as zero; ++.It Format : ++A character which indicates the type of format to use (one of ++.Cm diouxXfwEgGbcs ) . ++.El ++.Pp ++A field width or precision may be ++.Sq Cm \&* ++instead of a digit string. ++In this case an ++.Ar argument ++supplies the field width or precision. ++.Pp ++The format characters and their meanings are: ++.Bl -tag -width Fl ++.It Cm diouXx ++The ++.Ar argument ++is printed as a signed decimal (d or i), unsigned octal, unsigned decimal, ++or unsigned hexadecimal (X or x), respectively. ++.It Cm f ++The ++.Ar argument ++is printed in the style ++.Sm off ++.Pf [\-]ddd Cm \&. No ddd ++.Sm on ++where the number of d's ++after the decimal point is equal to the precision specification for ++the argument. ++If the precision is missing, 6 digits are given; if the precision ++is explicitly 0, no digits and no decimal point are printed. ++.It Cm eE ++The ++.Ar argument ++is printed in the style ++.Sm off ++.Pf [\-]d Cm \&. No ddd Cm e No \\*(Pmdd ++.Sm on ++where there ++is one digit before the decimal point and the number after is equal to ++the precision specification for the argument; when the precision is ++missing, 6 digits are produced. ++An upper-case E is used for an `E' format. ++.It Cm gG ++The ++.Ar argument ++is printed in style ++.Cm f ++or in style ++.Cm e ++.Pq Cm E ++whichever gives full precision in minimum space. ++.It Cm b ++Characters from the string ++.Ar argument ++are printed with backslash-escape sequences expanded. ++.It Cm c ++The first character of ++.Ar argument ++is printed. ++.It Cm s ++Characters from the string ++.Ar argument ++are printed until the end is reached or until the number of characters ++indicated by the precision specification is reached; however if the ++precision is 0 or missing, all characters in the string are printed. ++.It Cm \&% ++Print a `%'; no argument is used. ++.El ++.Pp ++In no case does a non-existent or small field width cause truncation of ++a field; padding takes place only if the specified field width exceeds ++the actual width. ++.Sh EXIT STATUS ++.Nm ++exits 0 on success, 1 on failure. ++.Sh SEE ALSO ++.Xr echo 1 , ++.Xr printf 3 , ++.Xr printf 9 ++.Sh STANDARDS ++The ++.Nm ++utility conforms to ++.St -p1003.2-92 . ++.Sh BUGS ++Since the floating point numbers are translated from ++.Tn ASCII ++to floating-point and ++then back again, floating-point precision may be lost. +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/bltin/printf.c bin_NetBSD-1.6release/src/bin/sh/bltin/printf.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/bltin/printf.c 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/bltin/printf.c 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,532 @@ ++/* $NetBSD: printf.c,v 1.24 2002/06/14 11:32:15 tron Exp $ */ ++ ++/* ++ * Copyright (c) 1989, 1993 ++ * The Regents of the University of California. 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. 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. ++ */ ++ ++#include <sys/cdefs.h> ++#ifndef lint ++#if !defined(BUILTIN) && !defined(SHELL) ++__COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\ ++ The Regents of the University of California. All rights reserved.\n"); ++#endif ++#endif ++ ++#ifndef lint ++#if 0 ++static char sccsid[] = "@(#)printf.c 8.2 (Berkeley) 3/22/95"; ++#else ++__RCSID("$NetBSD: printf.c,v 1.24 2002/06/14 11:32:15 tron Exp $"); ++#endif ++#endif /* not lint */ ++ ++#include <sys/types.h> ++ ++#include <ctype.h> ++#include <err.h> ++#include <errno.h> ++#include <inttypes.h> ++#include <limits.h> ++#include <locale.h> ++#include <stdarg.h> ++#ifndef SHELL ++#include <stdio.h> ++#endif ++#include <stdlib.h> ++#include <string.h> ++#include <unistd.h> ++ ++int print_escape_str(const char *); ++static size_t print_escape(const char *); ++ ++static int getchr(void); ++static double getdouble(void); ++static intmax_t getintmax(void); ++static uintmax_t getuintmax __P ((void)); ++static char *getstr(void); ++static char *mklong(const char *, int); ++static void check_conversion(const char *, const char *); ++static void usage(void); ++ ++static int rval; ++static char **gargv; ++ ++#ifdef BUILTIN ++int progprintf(int, char **); ++#else ++int main(int, char **); ++#endif ++ ++#define isodigit(c) ((c) >= '0' && (c) <= '7') ++#define octtobin(c) ((c) - '0') ++#define hextobin(c) ((c) >= 'A' && (c) <= 'F' ? c - 'A' + 10 : (c) >= 'a' && (c) <= 'f' ? c - 'a' + 10 : c - '0') ++ ++#ifdef SHELL ++#define main printfcmd ++#include "bltin.h" ++#else ++#define nullstr "" ++#endif ++ ++#define PF(f, func) { \ ++ switch (param - array) { \ ++ case 0: \ ++ (void)printf(f, func); \ ++ break; \ ++ case 1: \ ++ (void)printf(f, array[0], func); \ ++ break; \ ++ default: \ ++ (void)printf(f, array[0], array[1], func); \ ++ break; \ ++ } \ ++} ++ ++int ++#ifdef BUILTIN ++progprintf(int argc, char **argv) ++#else ++main(int argc, char **argv) ++#endif ++{ ++ char *fmt; ++ char *format; ++ ++#if !defined(SHELL) && !defined(BUILTIN) ++ (void)setlocale (LC_ALL, ""); ++#endif ++ ++ if (--argc < 1) { ++ usage(); ++ return (1); ++ } ++ ++ format = *++argv; ++ gargv = ++argv; ++ ++#define SKIP1 "#-+ 0" ++#define SKIP2 "*0123456789" ++ do { ++ /* ++ * Basic algorithm is to scan the format string for conversion ++ * specifications -- once one is found, find out if the field ++ * width or precision is a '*'; if it is, gather up value. ++ * Note, format strings are reused as necessary to use up the ++ * provided arguments, arguments of zero/null string are ++ * provided to use up the format string. ++ */ ++ ++ /* find next format specification */ ++ for (fmt = format; *fmt; fmt++) { ++ switch (*fmt) { ++ case '%': { ++ char *start; ++ char convch, nextch; ++ int array[2]; ++ int *param; ++ ++ start = fmt++; ++ ++ if (*fmt == '%') { ++ (void)putchar('%'); ++ break; ++ } else if (*fmt == 'b') { ++ char *p = getstr(); ++ if (print_escape_str(p)) { ++ return (rval); ++ } ++ break; ++ } ++ ++ param = array; ++ ++ /* skip to field width */ ++ fmt += strspn(fmt, SKIP1); ++ if (*fmt == '*') ++ *param++ = getintmax(); ++ ++ /* skip to possible '.', get following precision */ ++ fmt += strspn(fmt, SKIP2); ++ if (*fmt == '.') ++ ++fmt; ++ if (*fmt == '*') ++ *param++ = getintmax(); ++ ++ fmt += strspn(fmt, SKIP2); ++ if (!*fmt) { ++ warnx ("missing format character"); ++ return(1); ++ } ++ ++ convch = *fmt; ++ nextch = *(fmt + 1); ++ *(fmt + 1) = '\0'; ++ switch(convch) { ++ case 'c': { ++ char p = getchr(); ++ PF(start, p); ++ break; ++ } ++ case 's': { ++ char *p = getstr(); ++ PF(start, p); ++ break; ++ } ++ case 'd': ++ case 'i': { ++ char *f = mklong(start, convch); ++ intmax_t p = getintmax(); ++ PF(f, p); ++ break; ++ } ++ case 'o': ++ case 'u': ++ case 'x': ++ case 'X': { ++ char *f = mklong(start, convch); ++ uintmax_t p = getuintmax(); ++ PF(f, p); ++ break; ++ } ++ case 'e': ++ case 'E': ++ case 'f': ++ case 'g': ++ case 'G': { ++ double p = getdouble(); ++ PF(start, p); ++ break; ++ } ++ default: ++ warnx ("%s: invalid directive", start); ++ return(1); ++ } ++ *(fmt + 1) = nextch; ++ break; ++ } ++ ++ case '\\': ++ fmt += print_escape(fmt); ++ break; ++ ++ default: ++ (void)putchar(*fmt); ++ break; ++ } ++ } ++ } while (gargv > argv && *gargv); ++ ++#ifdef SHELL ++ return (rval); ++#else ++ fflush(stdout); ++ return (rval ? rval : ferror(stdout)); ++#endif ++} ++ ++ ++/* ++ * Print SysV echo(1) style escape string ++ * Halts processing string and returns 1 if a \c escape is encountered. ++ */ ++int ++print_escape_str(const char *str) ++{ ++ char value; ++ char c; ++ ++ for (; (value = *str); str++) { ++ if (value == '\\') { ++ c = *++str; ++ /* ++ * %b string octal constants are not like those in C. ++ * They start with a \0, and are followed by 0, 1, 2, ++ * or 3 octal digits. ++ */ ++ if (c == '0') { ++ unsigned j; ++ unsigned char i; ++ i = 3; ++ j = 0; ++ do { ++ unsigned k = octtobin(*++str); ++ if (k > 7) { ++ str--; ++ break; ++ } ++ j <<= 3; ++ j += k; ++ } while (--i); ++ value = j; ++ } else if (c == 'c') { ++ return 1; ++ } else { ++ str--; ++ str += print_escape(str); ++ continue; ++ } ++ } ++ putchar(value); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Print "standard" escape characters ++ */ ++static size_t ++print_escape(const char *str) ++{ ++ const char *start = str; ++ int value; ++ size_t c = 1; ++ ++ str++; ++ ++ switch (*str) { ++ case '0': case '1': case '2': case '3': ++ case '4': case '5': case '6': case '7': ++ for (c = 4, value = 0; --c && isodigit(*str); str++) { ++ value <<= 3; ++ value += octtobin(*str); ++ } ++ c = str - start - 1; ++ break; ++ ++#ifdef notrequired ++ case 'x': ++ str++; ++ for (value = 0; isxdigit((unsigned char)*str); str++) { ++ value <<= 4; ++ value += hextobin(*str); ++ } ++ if (value > UCHAR_MAX) { ++ warnx ("escape sequence out of range for character"); ++ rval = 1; ++ } ++ c = str - start - 1; ++ break; ++#endif ++ ++ case '\\': /* backslash */ ++ value = '\\'; ++ break; ++ ++#ifdef notrequired ++ case '\'': /* single quote */ ++ value = '\''; ++ break; ++ ++ case '"': /* double quote */ ++ value = '"'; ++ break; ++#endif ++ ++ case 'a': /* alert */ ++ value = '\a'; ++ break; ++ ++ case 'b': /* backspace */ ++ value = '\b'; ++ break; ++ ++#ifdef notrequired ++ case 'e': /* escape */ ++#ifdef __GNUC__ ++ value = '\e'; ++#else ++ value = 033; ++#endif ++ break; ++#endif ++ ++ case 'f': /* form-feed */ ++ value = '\f'; ++ break; ++ ++ case 'n': /* newline */ ++ value = '\n'; ++ break; ++ ++ case 'r': /* carriage-return */ ++ value = '\r'; ++ break; ++ ++ case 't': /* tab */ ++ value = '\t'; ++ break; ++ ++ case 'v': /* vertical-tab */ ++ value = '\v'; ++ break; ++ ++ default: ++#if 0 ++ value = *str; ++ warnx("unknown escape sequence `\\%c'", *str); ++ rval = 1; ++#else ++ value = '\\'; ++ c = 0; ++#endif ++ break; ++ } ++ ++ putchar(value); ++ return c; ++} ++ ++static char * ++mklong(const char *str, int ch) ++{ ++ static char copy[64]; ++ size_t len; ++ ++ len = strlen(str) + 2; ++ (void)memmove(copy, str, len - 3); ++ copy[len - 3] = 'j'; ++ copy[len - 2] = ch; ++ copy[len - 1] = '\0'; ++ return (copy); ++} ++ ++static int ++getchr(void) ++{ ++ int val = 0; ++ ++ if (*gargv) ++ val = **gargv++; ++ return val; ++} ++ ++static char * ++getstr(void) ++{ ++ char *val = nullstr; ++ ++ if (*gargv) ++ val = *gargv++; ++ return val; ++} ++ ++static intmax_t ++getintmax(void) ++{ ++ intmax_t val = 0; ++ char *ep; ++ const char *arg = *gargv; ++ ++ if (!arg) ++ goto out; ++ ++ gargv++; ++ ++ val = (unsigned char) arg[1]; ++ if (*arg == '\"' || *arg == '\'') ++ goto out; ++ ++ errno = 0; ++ val = strtoimax(arg, &ep, 0); ++ check_conversion(arg, ep); ++out: ++ return val; ++} ++ ++static uintmax_t ++getuintmax(void) ++{ ++ uintmax_t val = 0; ++ char *ep; ++ const char *arg = *gargv; ++ ++ if (!arg) ++ goto out; ++ ++ gargv++; ++ ++ val = (unsigned char) arg[1]; ++ if (*arg == '\"' || *arg == '\'') ++ goto out; ++ ++ errno = 0; ++ val = strtoumax(arg, &ep, 0); ++ check_conversion(arg, ep); ++out: ++ return val; ++} ++ ++static double ++getdouble(void) ++{ ++ double val = 0; ++ char *ep; ++ const char *arg = *gargv; ++ ++ if (!arg) ++ goto out; ++ ++ gargv++; ++ ++ if (*arg == '\"' || *arg == '\'') { ++ val = (unsigned char) arg[1]; ++ goto out; ++ } ++ ++ errno = 0; ++ val = strtod(arg, &ep); ++ check_conversion(arg, ep); ++out: ++ return val; ++} ++ ++static void ++check_conversion(const char *s, const char *ep) ++{ ++ if (*ep) { ++ if (ep == s) ++ warnx ("%s: expected numeric value", s); ++ else ++ warnx ("%s: not completely converted", s); ++ rval = 1; ++ } else if (errno == ERANGE) { ++ warnx ("%s: %s", s, strerror(ERANGE)); ++ rval = 1; ++ } ++} ++ ++static void ++usage(void) ++{ ++ (void)fprintf(stderr, "usage: printf format [arg ...]\n"); ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/bltin/test.1 bin_NetBSD-1.6release/src/bin/sh/bltin/test.1 +--- bin_NetBSD-1.6release.orig/src/bin/sh/bltin/test.1 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/bltin/test.1 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,312 @@ ++.\" $NetBSD: test.1,v 1.17 2002/02/08 01:22:01 ross 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 ++.\" the Institute of Electrical and Electronics Engineers, 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. ++.\" ++.\" @(#)test.1 8.1 (Berkeley) 5/31/93 ++.\" ++.Dd May 31, 1993 ++.Dt TEST 1 ++.Os ++.Sh NAME ++.Nm test , ++.Nm \&[ ++.Nd condition evaluation utility ++.Sh SYNOPSIS ++.Nm test ++.Ar expression ++.Nm \&[ ++.Ar expression Cm ] ++.Sh DESCRIPTION ++The ++.Nm test ++utility evaluates the expression and, if it evaluates ++to true, returns a zero (true) exit status; otherwise ++it returns 1 (false). ++If there is no expression, test also ++returns 1 (false). ++.Pp ++All operators and flags are separate arguments to the ++.Nm test ++utility. ++.Pp ++The following primaries are used to construct expression: ++.Bl -tag -width Ar ++.It Fl b Ar file ++True if ++.Ar file ++exists and is a block special ++file. ++.It Fl c Ar file ++True if ++.Ar file ++exists and is a character ++special file. ++.It Fl d Ar file ++True if ++.Ar file ++exists and is a directory. ++.It Fl e Ar file ++True if ++.Ar file ++exists (regardless of type). ++.It Fl f Ar file ++True if ++.Ar file ++exists and is a regular file. ++.It Fl g Ar file ++True if ++.Ar file ++exists and its set group ID flag ++is set. ++.It Fl h Ar file ++True if ++.Ar file ++exists and is a symbolic link. ++.It Fl k Ar file ++True if ++.Ar file ++exists and its sticky bit is set. ++.It Fl n Ar string ++True if the length of ++.Ar string ++is nonzero. ++.It Fl p Ar file ++True if ++.Ar file ++is a named pipe ++.Po Tn FIFO Pc . ++.It Fl r Ar file ++True if ++.Ar file ++exists and is readable. ++.It Fl s Ar file ++True if ++.Ar file ++exists and has a size greater ++than zero. ++.It Fl t Ar file_descriptor ++True if the file whose file descriptor number ++is ++.Ar file_descriptor ++is open and is associated with a terminal. ++.It Fl u Ar file ++True if ++.Ar file ++exists and its set user ID flag ++is set. ++.It Fl w Ar file ++True if ++.Ar file ++exists and is writable. ++True ++indicates only that the write flag is on. ++The file is not writable on a read-only file ++system even if this test indicates true. ++.It Fl x Ar file ++True if ++.Ar file ++exists and is executable. ++True ++indicates only that the execute flag is on. ++If ++.Ar file ++is a directory, true indicates that ++.Ar file ++can be searched. ++.It Fl z Ar string ++True if the length of ++.Ar string ++is zero. ++.It Fl L Ar file ++True if ++.Ar file ++exists and is a symbolic link. ++This operator is retained for compatibility with previous versions of ++this program. Do not rely on its existence; use ++.Fl h ++instead. ++.It Fl O Ar file ++True if ++.Ar file ++exists and its owner matches the effective user id of this process. ++.It Fl G Ar file ++True if ++.Ar file ++exists and its group matches the effective group id of this process. ++.It Fl S Ar file ++True if ++.Ar file ++exists and is a socket. ++.It Ar file1 Fl nt Ar file2 ++True if ++.Ar file1 ++exists and is newer than ++.Ar file2 . ++.It Ar file1 Fl ot Ar file2 ++True if ++.Ar file1 ++exists and is older than ++.Ar file2 . ++.It Ar file1 Fl ef Ar file2 ++True if ++.Ar file1 ++and ++.Ar file2 ++exist and refer to the same file. ++.It Ar string ++True if ++.Ar string ++is not the null ++string. ++.It Ar \&s\&1 Cm \&= Ar \&s\&2 ++True if the strings ++.Ar \&s\&1 ++and ++.Ar \&s\&2 ++are identical. ++.It Ar \&s\&1 Cm \&!= Ar \&s\&2 ++True if the strings ++.Ar \&s\&1 ++and ++.Ar \&s\&2 ++are not identical. ++.It Ar \&s\&1 Cm \&\*[Lt] Ar \&s\&2 ++True if string ++.Ar \&s\&1 ++comes before ++.Ar \&s\&2 ++based on the ASCII value of their characters. ++.It Ar \&s\&1 Cm \&\*[Gt] Ar \&s\&2 ++True if string ++.Ar \&s\&1 ++comes after ++.Ar \&s\&2 ++based on the ASCII value of their characters. ++.It Ar \&n\&1 Fl \&eq Ar \&n\&2 ++True if the integers ++.Ar \&n\&1 ++and ++.Ar \&n\&2 ++are algebraically ++equal. ++.It Ar \&n\&1 Fl \&ne Ar \&n\&2 ++True if the integers ++.Ar \&n\&1 ++and ++.Ar \&n\&2 ++are not ++algebraically equal. ++.It Ar \&n\&1 Fl \> Ar \&n\&2 ++True if the integer ++.Ar \&n\&1 ++is algebraically ++greater than the integer ++.Ar \&n\&2 . ++.It Ar \&n\&1 Fl \&ge Ar \&n\&2 ++True if the integer ++.Ar \&n\&1 ++is algebraically ++greater than or equal to the integer ++.Ar \&n\&2 . ++.It Ar \&n\&1 Fl \< Ar \&n\&2 ++True if the integer ++.Ar \&n\&1 ++is algebraically less ++than the integer ++.Ar \&n\&2 . ++.It Ar \&n\&1 Fl \&le Ar \&n\&2 ++True if the integer ++.Ar \&n\&1 ++is algebraically less ++than or equal to the integer ++.Ar \&n\&2 . ++.El ++.Pp ++These primaries can be combined with the following operators: ++.Bl -tag -width Ar ++.It Cm \&! Ar expression ++True if ++.Ar expression ++is false. ++.It Ar expression1 Fl a Ar expression2 ++True if both ++.Ar expression1 ++and ++.Ar expression2 ++are true. ++.It Ar expression1 Fl o Ar expression2 ++True if either ++.Ar expression1 ++or ++.Ar expression2 ++are true. ++.It Cm \&( Ns Ar expression Ns Cm \&) ++True if expression is true. ++.El ++.Pp ++The ++.Fl a ++operator has higher precedence than the ++.Fl o ++operator. ++.Sh GRAMMAR AMBIGUITY ++The ++.Nm test ++grammar is inherently ambiguous. In order to assure a degree of consistency, ++the cases described in ++.St -p1003.2 ++section 4.62.4, ++are evaluated consistently according to the rules specified in the ++standards document. All other cases are subject to the ambiguity in the ++command semantics. ++.Sh EXIT STATUS ++The ++.Nm test ++utility exits with one of the following values: ++.Bl -tag -width Ds ++.It 0 ++expression evaluated to true. ++.It 1 ++expression evaluated to false or expression was ++missing. ++.It \*[Gt]1 ++An error occurred. ++.El ++.Sh STANDARDS ++The ++.Nm test ++utility implements a superset of the ++.St -p1003.2 ++specification. +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/bltin/test.c bin_NetBSD-1.6release/src/bin/sh/bltin/test.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/bltin/test.c 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/bltin/test.c 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,545 @@ ++/* $NetBSD: test.c,v 1.25 2002/05/25 23:12:16 wiz Exp $ */ ++ ++/* ++ * test(1); version 7-like -- author Erik Baalbergen ++ * modified by Eric Gisin to be used as built-in. ++ * modified by Arnold Robbins to add SVR3 compatibility ++ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). ++ * modified by J.T. Conklin for NetBSD. ++ * ++ * This program is in the Public Domain. ++ */ ++ ++#include <sys/cdefs.h> ++#ifndef lint ++__RCSID("$NetBSD: test.c,v 1.25 2002/05/25 23:12:16 wiz Exp $"); ++#endif ++ ++#include <sys/stat.h> ++#include <sys/types.h> ++ ++#include <ctype.h> ++#include <err.h> ++#include <errno.h> ++#include <stdlib.h> ++#include <string.h> ++#include <unistd.h> ++#include <stdarg.h> ++#include "bltin.h" ++ ++/* test(1) accepts the following grammar: ++ oexpr ::= aexpr | aexpr "-o" oexpr ; ++ aexpr ::= nexpr | nexpr "-a" aexpr ; ++ nexpr ::= primary | "!" primary ++ primary ::= unary-operator operand ++ | operand binary-operator operand ++ | operand ++ | "(" oexpr ")" ++ ; ++ unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| ++ "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; ++ ++ binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| ++ "-nt"|"-ot"|"-ef"; ++ operand ::= <any legal UNIX file name> ++*/ ++ ++enum token { ++ EOI, ++ FILRD, ++ FILWR, ++ FILEX, ++ FILEXIST, ++ FILREG, ++ FILDIR, ++ FILCDEV, ++ FILBDEV, ++ FILFIFO, ++ FILSOCK, ++ FILSYM, ++ FILGZ, ++ FILTT, ++ FILSUID, ++ FILSGID, ++ FILSTCK, ++ FILNT, ++ FILOT, ++ FILEQ, ++ FILUID, ++ FILGID, ++ STREZ, ++ STRNZ, ++ STREQ, ++ STRNE, ++ STRLT, ++ STRGT, ++ INTEQ, ++ INTNE, ++ INTGE, ++ INTGT, ++ INTLE, ++ INTLT, ++ UNOT, ++ BAND, ++ BOR, ++ LPAREN, ++ RPAREN, ++ OPERAND ++}; ++ ++enum token_types { ++ UNOP, ++ BINOP, ++ BUNOP, ++ BBINOP, ++ PAREN ++}; ++ ++static struct t_op { ++ const char *op_text; ++ short op_num, op_type; ++} const ops [] = { ++ {"-r", FILRD, UNOP}, ++ {"-w", FILWR, UNOP}, ++ {"-x", FILEX, UNOP}, ++ {"-e", FILEXIST,UNOP}, ++ {"-f", FILREG, UNOP}, ++ {"-d", FILDIR, UNOP}, ++ {"-c", FILCDEV,UNOP}, ++ {"-b", FILBDEV,UNOP}, ++ {"-p", FILFIFO,UNOP}, ++ {"-u", FILSUID,UNOP}, ++ {"-g", FILSGID,UNOP}, ++ {"-k", FILSTCK,UNOP}, ++ {"-s", FILGZ, UNOP}, ++ {"-t", FILTT, UNOP}, ++ {"-z", STREZ, UNOP}, ++ {"-n", STRNZ, UNOP}, ++ {"-h", FILSYM, UNOP}, /* for backwards compat */ ++ {"-O", FILUID, UNOP}, ++ {"-G", FILGID, UNOP}, ++ {"-L", FILSYM, UNOP}, ++ {"-S", FILSOCK,UNOP}, ++ {"=", STREQ, BINOP}, ++ {"!=", STRNE, BINOP}, ++ {"<", STRLT, BINOP}, ++ {">", STRGT, BINOP}, ++ {"-eq", INTEQ, BINOP}, ++ {"-ne", INTNE, BINOP}, ++ {"-ge", INTGE, BINOP}, ++ {"-gt", INTGT, BINOP}, ++ {"-le", INTLE, BINOP}, ++ {"-lt", INTLT, BINOP}, ++ {"-nt", FILNT, BINOP}, ++ {"-ot", FILOT, BINOP}, ++ {"-ef", FILEQ, BINOP}, ++ {"!", UNOT, BUNOP}, ++ {"-a", BAND, BBINOP}, ++ {"-o", BOR, BBINOP}, ++ {"(", LPAREN, PAREN}, ++ {")", RPAREN, PAREN}, ++ {0, 0, 0} ++}; ++ ++static char **t_wp; ++static struct t_op const *t_wp_op; ++ ++static void syntax(const char *, const char *); ++static int oexpr(enum token); ++static int aexpr(enum token); ++static int nexpr(enum token); ++static int primary(enum token); ++static int binop(void); ++static int filstat(char *, enum token); ++static enum token t_lex(char *); ++static int isoperand(void); ++static int getn(const char *); ++static int newerf(const char *, const char *); ++static int olderf(const char *, const char *); ++static int equalf(const char *, const char *); ++static int test_eaccess(const char *, int); ++static int bash_group_member(gid_t); ++ ++#ifndef SHELL ++static void error(const char *, ...) __attribute__((__noreturn__)); ++ ++static void ++error(const char *msg, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, msg); ++ verrx(2, msg, ap); ++ /*NOTREACHED*/ ++ va_end(ap); ++} ++#endif ++ ++#ifdef SHELL ++int testcmd(int, char **); ++ ++int ++testcmd(int argc, char **argv) ++#else ++int main(int, char *[]); ++ ++int ++main(int argc, char *argv[]) ++#endif ++{ ++ int res; ++ ++#ifndef SHELL ++ setprogname(argv[0]); ++#endif ++ if (strcmp(argv[0], "[") == 0) { ++ if (strcmp(argv[--argc], "]")) ++ error("missing ]"); ++ argv[argc] = NULL; ++ } ++ ++ if (argc < 2) ++ return 1; ++ ++ t_wp = &argv[1]; ++ res = !oexpr(t_lex(*t_wp)); ++ ++ if (*t_wp != NULL && *++t_wp != NULL) ++ syntax(*t_wp, "unexpected operator"); ++ ++ return res; ++} ++ ++static void ++syntax(const char *op, const char *msg) ++{ ++ if (op && *op) ++ error("%s: %s", op, msg); ++ else ++ error("%s", msg); ++} ++ ++static int ++oexpr(enum token n) ++{ ++ int res; ++ ++ res = aexpr(n); ++ if (t_lex(*++t_wp) == BOR) ++ return oexpr(t_lex(*++t_wp)) || res; ++ t_wp--; ++ return res; ++} ++ ++static int ++aexpr(enum token n) ++{ ++ int res; ++ ++ res = nexpr(n); ++ if (t_lex(*++t_wp) == BAND) ++ return aexpr(t_lex(*++t_wp)) && res; ++ t_wp--; ++ return res; ++} ++ ++static int ++nexpr(enum token n) ++{ ++ if (n == UNOT) ++ return !nexpr(t_lex(*++t_wp)); ++ return primary(n); ++} ++ ++static int ++primary(enum token n) ++{ ++ enum token nn; ++ int res; ++ ++ if (n == EOI) ++ return 0; /* missing expression */ ++ if (n == LPAREN) { ++ if ((nn = t_lex(*++t_wp)) == RPAREN) ++ return 0; /* missing expression */ ++ res = oexpr(nn); ++ if (t_lex(*++t_wp) != RPAREN) ++ syntax(NULL, "closing paren expected"); ++ return res; ++ } ++ if (t_wp_op && t_wp_op->op_type == UNOP) { ++ /* unary expression */ ++ if (*++t_wp == NULL) ++ syntax(t_wp_op->op_text, "argument expected"); ++ switch (n) { ++ case STREZ: ++ return strlen(*t_wp) == 0; ++ case STRNZ: ++ return strlen(*t_wp) != 0; ++ case FILTT: ++ return isatty(getn(*t_wp)); ++ default: ++ return filstat(*t_wp, n); ++ } ++ } ++ ++ if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { ++ return binop(); ++ } ++ ++ return strlen(*t_wp) > 0; ++} ++ ++static int ++binop(void) ++{ ++ const char *opnd1, *opnd2; ++ struct t_op const *op; ++ ++ opnd1 = *t_wp; ++ (void) t_lex(*++t_wp); ++ op = t_wp_op; ++ ++ if ((opnd2 = *++t_wp) == (char *)0) ++ syntax(op->op_text, "argument expected"); ++ ++ switch (op->op_num) { ++ case STREQ: ++ return strcmp(opnd1, opnd2) == 0; ++ case STRNE: ++ return strcmp(opnd1, opnd2) != 0; ++ case STRLT: ++ return strcmp(opnd1, opnd2) < 0; ++ case STRGT: ++ return strcmp(opnd1, opnd2) > 0; ++ case INTEQ: ++ return getn(opnd1) == getn(opnd2); ++ case INTNE: ++ return getn(opnd1) != getn(opnd2); ++ case INTGE: ++ return getn(opnd1) >= getn(opnd2); ++ case INTGT: ++ return getn(opnd1) > getn(opnd2); ++ case INTLE: ++ return getn(opnd1) <= getn(opnd2); ++ case INTLT: ++ return getn(opnd1) < getn(opnd2); ++ case FILNT: ++ return newerf (opnd1, opnd2); ++ case FILOT: ++ return olderf (opnd1, opnd2); ++ case FILEQ: ++ return equalf (opnd1, opnd2); ++ default: ++ abort(); ++ /* NOTREACHED */ ++ } ++} ++ ++static int ++filstat(char *nm, enum token mode) ++{ ++ struct stat64 s; ++ ++ if (mode == FILSYM ? lstat64(nm, &s) : stat64(nm, &s)) ++ return 0; ++ ++ switch (mode) { ++ case FILRD: ++ return test_eaccess(nm, R_OK) == 0; ++ case FILWR: ++ return test_eaccess(nm, W_OK) == 0; ++ case FILEX: ++ return test_eaccess(nm, X_OK) == 0; ++ case FILEXIST: ++ return 1; ++ case FILREG: ++ return S_ISREG(s.st_mode); ++ case FILDIR: ++ return S_ISDIR(s.st_mode); ++ case FILCDEV: ++ return S_ISCHR(s.st_mode); ++ case FILBDEV: ++ return S_ISBLK(s.st_mode); ++ case FILFIFO: ++ return S_ISFIFO(s.st_mode); ++ case FILSOCK: ++ return S_ISSOCK(s.st_mode); ++ case FILSYM: ++ return S_ISLNK(s.st_mode); ++ case FILSUID: ++ return (s.st_mode & S_ISUID) != 0; ++ case FILSGID: ++ return (s.st_mode & S_ISGID) != 0; ++ case FILSTCK: ++ return (s.st_mode & S_ISVTX) != 0; ++ case FILGZ: ++ return s.st_size > (off_t)0; ++ case FILUID: ++ return s.st_uid == geteuid(); ++ case FILGID: ++ return s.st_gid == getegid(); ++ default: ++ return 1; ++ } ++} ++ ++static enum token ++t_lex(char *s) ++{ ++ struct t_op const *op; ++ ++ op = ops; ++ ++ if (s == 0) { ++ t_wp_op = (struct t_op *)0; ++ return EOI; ++ } ++ while (op->op_text) { ++ if (strcmp(s, op->op_text) == 0) { ++ if ((op->op_type == UNOP && isoperand()) || ++ (op->op_num == LPAREN && *(t_wp+1) == 0)) ++ break; ++ t_wp_op = op; ++ return op->op_num; ++ } ++ op++; ++ } ++ t_wp_op = (struct t_op *)0; ++ return OPERAND; ++} ++ ++static int ++isoperand(void) ++{ ++ struct t_op const *op; ++ char *s, *t; ++ ++ op = ops; ++ if ((s = *(t_wp+1)) == 0) ++ return 1; ++ if ((t = *(t_wp+2)) == 0) ++ return 0; ++ while (op->op_text) { ++ if (strcmp(s, op->op_text) == 0) ++ return op->op_type == BINOP && ++ (t[0] != ')' || t[1] != '\0'); ++ op++; ++ } ++ return 0; ++} ++ ++/* atoi with error detection */ ++static int ++getn(const char *s) ++{ ++ char *p; ++ long r; ++ ++ errno = 0; ++ r = strtol(s, &p, 10); ++ ++ if (errno != 0) ++ error("%s: out of range", s); ++ ++ while (isspace((unsigned char)*p)) ++ p++; ++ ++ if (*p) ++ error("%s: bad number", s); ++ ++ return (int) r; ++} ++ ++static int ++newerf (const char *f1, const char *f2) ++{ ++ struct stat b1, b2; ++ ++ return (stat (f1, &b1) == 0 && ++ stat (f2, &b2) == 0 && ++ b1.st_mtime > b2.st_mtime); ++} ++ ++static int ++olderf (const char *f1, const char *f2) ++{ ++ struct stat b1, b2; ++ ++ return (stat (f1, &b1) == 0 && ++ stat (f2, &b2) == 0 && ++ b1.st_mtime < b2.st_mtime); ++} ++ ++static int ++equalf (const char *f1, const char *f2) ++{ ++ struct stat b1, b2; ++ ++ return (stat (f1, &b1) == 0 && ++ stat (f2, &b2) == 0 && ++ b1.st_dev == b2.st_dev && ++ b1.st_ino == b2.st_ino); ++} ++ ++/* Do the same thing access(2) does, but use the effective uid and gid, ++ and don't make the mistake of telling root that any file is ++ executable. */ ++static int ++test_eaccess(const char *path, int mode) ++{ ++ struct stat64 st; ++ int euid = geteuid(); ++ ++ if (stat64(path, &st) < 0) ++ return (-1); ++ ++ if (euid == 0) { ++ /* Root can read or write any file. */ ++ if (mode != X_OK) ++ return (0); ++ ++ /* Root can execute any file that has any one of the execute ++ bits set. */ ++ if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) ++ return (0); ++ } ++ ++ if (st.st_uid == euid) /* owner */ ++ mode <<= 6; ++ else if (bash_group_member(st.st_gid)) ++ mode <<= 3; ++ ++ if (st.st_mode & mode) ++ return (0); ++ ++ return (-1); ++} ++ ++/* Return non-zero if GID is one that we have in our groups list. */ ++static int ++bash_group_member(gid_t gid) ++{ ++ register int i; ++ gid_t *group_array; ++ int ngroups; ++ ++ /* Short-circuit if possible, maybe saving a call to getgroups(). */ ++ if (gid == getgid() || gid == getegid()) ++ return (1); ++ ++ ngroups = getgroups(0, NULL); ++#ifdef SHELL ++ group_array = stalloc(ngroups * sizeof(gid_t)); ++#else ++ group_array = alloca(ngroups * sizeof(gid_t)); ++#endif ++ getgroups(ngroups, group_array); ++ ++ /* Search through the list looking for GID. */ ++ for (i = 0; i < ngroups; i++) ++ if (gid == group_array[i]) ++ return (1); ++ ++ return (0); ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/bltin/times.c bin_NetBSD-1.6release/src/bin/sh/bltin/times.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/bltin/times.c 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/bltin/times.c 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (c) 1999 Herbert Xu <herbert@debian.org> ++ * This file contains code for the times builtin. ++ * $Id: dash-ash-hetio-yacc.diff,v 1.1 2003/02/09 09:36:31 satai Exp $ ++ */ ++ ++#include <sys/times.h> ++#include <unistd.h> ++#ifdef USE_GLIBC_STDIO ++#include <stdio.h> ++#else ++#include "bltin.h" ++#endif ++ ++#define main timescmd ++ ++int main() { ++ struct tms buf; ++ long int clk_tck = sysconf(_SC_CLK_TCK); ++ ++ times(&buf); ++ printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", ++ (int) (buf.tms_utime / clk_tck / 60), ++ ((double) buf.tms_utime) / clk_tck, ++ (int) (buf.tms_stime / clk_tck / 60), ++ ((double) buf.tms_stime) / clk_tck, ++ (int) (buf.tms_cutime / clk_tck / 60), ++ ((double) buf.tms_cutime) / clk_tck, ++ (int) (buf.tms_cstime / clk_tck / 60), ++ ((double) buf.tms_cstime) / clk_tck); ++ return 0; ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/builtins.def bin_NetBSD-1.6release/src/bin/sh/builtins.def +--- bin_NetBSD-1.6release.orig/src/bin/sh/builtins.def 2000-04-10 12:02:58.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/builtins.def 2003-02-08 14:35:42.000000000 +0000 +@@ -49,12 +49,13 @@ + # + # NOTE: bltincmd must come first! + +-bltincmd command ++bltincmd builtin + #alloccmd alloc + bgcmd -j bg + breakcmd break continue + #catfcmd catf + cdcmd cd chdir ++commandcmd command + dotcmd . + echocmd echo + evalcmd eval +@@ -68,12 +69,13 @@ + fgcmd -j fg + getoptscmd getopts + hashcmd hash +-jobidcmd jobid ++#jobidcmd jobid + jobscmd jobs ++killcmd -j kill + #linecmd line + localcmd local + #nlechocmd nlecho +-#printfcmd printf ++printfcmd printf + pwdcmd pwd + readcmd read + returncmd return +@@ -91,3 +93,4 @@ + aliascmd alias + ulimitcmd ulimit + testcmd test [ ++timescmd times +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/cd.c bin_NetBSD-1.6release/src/bin/sh/cd.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/cd.c 2001-11-15 11:08:17.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/cd.c 2003-02-08 14:35:42.000000000 +0000 +@@ -70,13 +70,33 @@ + #include "show.h" + #include "cd.h" + +-STATIC int docd __P((char *, int)); +-STATIC char *getcomponent __P((void)); +-STATIC void updatepwd __P((char *)); ++#define CD_PHYSICAL 1 ++#define CD_PRINT 2 + +-char *curdir = NULL; /* current working directory */ +-char *prevdir; /* previous working directory */ +-STATIC char *cdcomppath; ++STATIC int docd __P((const char *, int)); ++STATIC const char *updatepwd __P((const char *)); ++STATIC char *getpwd __P((void)); ++STATIC int cdopt __P((void)); ++ ++STATIC char *curdir = nullstr; /* current working directory */ ++STATIC char *physdir = nullstr; /* physical working directory */ ++ ++STATIC int ++cdopt() ++{ ++ int flags = 0; ++ int i, j; ++ ++ j = 'L'; ++ while ((i = nextopt("LP"))) { ++ if (i != j) { ++ flags ^= CD_PHYSICAL; ++ j = i; ++ } ++ } ++ ++ return flags; ++} + + int + cdcmd(argc, argv) +@@ -85,296 +105,218 @@ + { + const char *dest; + const char *path; +- char *p; ++ const char *p; ++ char c; + struct stat statb; +- int print = 0; ++ int flags; + +- nextopt(nullstr); +- if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME", 1)) == NULL) +- error("HOME not set"); +- if (*dest == '\0') +- dest = "."; +- if (dest[0] == '-' && dest[1] == '\0') { +- dest = prevdir ? prevdir : curdir; +- print = 1; +- if (dest) +- print = 1; +- else +- dest = "."; ++ flags = cdopt(); ++ dest = *argptr; ++ if (!dest) ++ dest = bltinlookup(homestr); ++ else if (dest[0] == '-' && dest[1] == '\0') { ++ dest = bltinlookup("OLDPWD"); ++ flags |= CD_PRINT; ++ goto step7; + } +- if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL) +- path = nullstr; +- while ((p = padvance(&path, dest)) != NULL) { +- if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { +- if (!print) { +- /* +- * XXX - rethink +- */ +- if (p[0] == '.' && p[1] == '/' && p[2] != '\0') +- p += 2; +- print = strcmp(p, dest); ++ if (!dest) ++ dest = nullstr; ++ if (*dest == '/') ++ goto step7; ++ if (*dest == '.') { ++ c = dest[1]; ++dotdot: ++ switch (c) { ++ case '\0': ++ case '/': ++ goto step6; ++ case '.': ++ c = dest[2]; ++ if (c != '.') ++ goto dotdot; + } +- if (docd(p, print) >= 0) +- return 0; +- + } ++ if (!*dest) ++ dest = "."; ++ if (!(path = bltinlookup("CDPATH"))) { ++step6: ++step7: ++ p = dest; ++ goto docd; ++ } ++ do { ++ c = *path; ++ p = padvance(&path, dest); ++ if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { ++ if (c && c != ':') ++ flags |= CD_PRINT; ++docd: ++ if (!docd(p, flags)) ++ goto out; ++ break; + } ++ } while (path); + error("can't cd to %s", dest); + /* NOTREACHED */ ++out: ++ if (flags & CD_PRINT) ++ out1fmt(snlfmt, curdir); ++ return 0; + } + + + /* +- * Actually do the chdir. In an interactive shell, print the +- * directory name if "print" is nonzero. ++ * Actually do the chdir. We also call hashcd to let the routines in exec.c ++ * know that the current directory has changed. + */ + + STATIC int +-docd(dest, print) +- char *dest; +- int print; ++docd(const char *dest, int flags) + { +- char *p; +- char *q; +- char *component; +- struct stat statb; +- int first; +- int badstat; +- +- TRACE(("docd(\"%s\", %d) called\n", dest, print)); ++ const char *dir = 0; ++ int err; + +- /* +- * Check each component of the path. If we find a symlink or +- * something we can't stat, clear curdir to force a getcwd() +- * next time we get the value of the current directory. +- */ +- badstat = 0; +- cdcomppath = stalloc(strlen(dest) + 1); +- scopy(dest, cdcomppath); +- STARTSTACKSTR(p); +- if (*dest == '/') { +- STPUTC('/', p); +- cdcomppath++; +- } +- first = 1; +- while ((q = getcomponent()) != NULL) { +- if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) +- continue; +- if (! first) +- STPUTC('/', p); +- first = 0; +- component = q; +- while (*q) +- STPUTC(*q++, p); +- if (equal(component, "..")) +- continue; +- STACKSTRNUL(p); +- if ((lstat(stackblock(), &statb) < 0) +- || (S_ISLNK(statb.st_mode))) { +- /* print = 1; */ +- badstat = 1; +- break; +- } +- } ++ TRACE(("docd(\"%s\", %d) called\n", dest, flags)); + + INTOFF; +- if (chdir(dest) < 0) { +- INTON; +- return -1; ++ if (!(flags & CD_PHYSICAL)) { ++ dir = updatepwd(dest); ++ if (dir) ++ dest = dir; + } +- updatepwd(badstat ? NULL : dest); ++ err = chdir(dest); ++ if (err) ++ goto out; ++ setpwd(dir, 1); ++ hashcd(); ++out: + INTON; +- if (print && iflag && curdir) +- out1fmt("%s\n", curdir); +- 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() { +- char *p; +- char *start; +- +- if ((p = cdcomppath) == NULL) +- return NULL; +- start = cdcomppath; +- while (*p != '/' && *p != '\0') +- p++; +- if (*p == '\0') { +- cdcomppath = NULL; +- } else { +- *p++ = '\0'; +- cdcomppath = p; +- } +- return start; ++ return err; + } + + +- + /* + * 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. ++ * cd command. + */ + +-STATIC void +-updatepwd(dir) +- char *dir; +- { ++STATIC const char * ++updatepwd(const char *dir) ++{ + char *new; + char *p; ++ char *cdcomppath; ++ const char *lim; + +- hashcd(); /* update command hash table */ +- +- /* +- * If our argument is NULL, we don't know the current directory +- * any more because we traversed a symbolic link or something +- * we couldn't stat(). +- */ +- if (dir == NULL || curdir == NULL) { +- if (prevdir) +- ckfree(prevdir); +- INTOFF; +- prevdir = curdir; +- curdir = NULL; +- getpwd(); +- setvar("PWD", curdir, VEXPORT); +- INTON; +- return; +- } +- cdcomppath = stalloc(strlen(dir) + 1); +- scopy(dir, cdcomppath); ++ cdcomppath = sstrdup(dir); + STARTSTACKSTR(new); + if (*dir != '/') { +- p = curdir; +- while (*p) +- STPUTC(*p++, new); +- if (p[-1] == '/') ++ if (curdir == nullstr) ++ return 0; ++ new = stputs(curdir, new); ++ } ++ new = makestrspace(strlen(dir) + 2, new); ++ lim = stackblock() + 1; ++ if (*dir != '/') { ++ if (new[-1] != '/') ++ USTPUTC('/', new); ++ if (new > lim && *lim == '/') ++ lim++; ++ } else { ++ USTPUTC('/', new); ++ cdcomppath++; ++ if (dir[1] == '/' && dir[2] != '/') { ++ USTPUTC('/', new); ++ cdcomppath++; ++ lim++; ++ } ++ } ++ p = strtok(cdcomppath, "/"); ++ while (p) { ++ switch(*p) { ++ case '.': ++ if (p[1] == '.' && p[2] == '\0') { ++ while (new > lim) { + STUNPUTC(new); ++ if (new[-1] == '/') ++ break; + } +- while ((p = getcomponent()) != NULL) { +- if (equal(p, "..")) { +- while (new > stackblock() && (STUNPUTC(new), *new) != '/'); +- } else if (*p != '\0' && ! equal(p, ".")) { +- STPUTC('/', new); +- while (*p) +- STPUTC(*p++, new); ++ break; ++ } else if (p[1] == '\0') ++ break; ++ /* fall through */ ++ default: ++ new = stputs(p, new); ++ USTPUTC('/', new); + } ++ p = strtok(0, "/"); + } +- if (new == stackblock()) +- STPUTC('/', new); +- STACKSTRNUL(new); +- INTOFF; +- if (prevdir) +- ckfree(prevdir); +- prevdir = curdir; +- curdir = savestr(stackblock()); +- setvar("PWD", curdir, VEXPORT); +- INTON; ++ if (new > lim) ++ STUNPUTC(new); ++ *new = 0; ++ return stackblock(); + } + + ++#define MAXPWD 256 ++ ++/* ++ * Find out what the current directory is. If we already know the current ++ * directory, this routine returns immediately. ++ */ ++inline ++STATIC char * ++getpwd() ++{ ++ char *dir = getcwd(0, 0); ++ return dir ? dir : nullstr; ++} + + int + pwdcmd(argc, argv) + int argc; + char **argv; + { +- getpwd(); +- out1str(curdir); +- out1c('\n'); ++ int flags; ++ const char *dir = curdir; ++ ++ flags = cdopt(); ++ if (flags) { ++ if (physdir == nullstr) ++ setpwd(dir, 0); ++ dir = physdir; ++ } ++ out1fmt(snlfmt, dir); + return 0; + } + +- +- +- +-#define MAXPWD 256 +- +-/* +- * Find out what the current directory is. If we already know the current +- * directory, this routine returns immediately. +- */ + void +-getpwd() ++setpwd(const char *val, int setold) + { +- char buf[MAXPWD]; +- +- if (curdir) +- return; +- /* +- * 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) ++ char *oldcur, *dir; + +- if (getcwd(buf, sizeof(buf)) == NULL) { +- char *pwd = getenv("PWD"); +- struct stat stdot, stpwd; ++ oldcur = dir = curdir; + +- 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; +- } +- error("getcwd() failed: %s", strerror(errno)); ++ if (setold) { ++ setvar("OLDPWD", oldcur, VEXPORT); + } +- curdir = savestr(buf); +-#else +- { +- char *p; +- int i; +- int status; +- struct job *jp; +- int pip[2]; +- + INTOFF; +- if (pipe(pip) < 0) +- error("Pipe call failed"); +- jp = makejob((union node *)NULL, 1); +- if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) { +- (void) close(pip[0]); +- if (pip[1] != 1) { +- close(1); +- copyfd(pip[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 = buf; +- while ((i = read(pip[0], p, buf + MAXPWD - p)) > 0 +- || (i == -1 && errno == EINTR)) { +- if (i > 0) +- p += i; ++ if (physdir != nullstr) { ++ if (physdir != oldcur) ++ free(physdir); ++ physdir = nullstr; + } +- (void) close(pip[0]); +- pip[0] = -1; +- status = waitforjob(jp); +- if (status != 0) +- error((char *)0); +- if (i < 0 || p == buf || p[-1] != '\n') +- error("pwd command failed"); +- p[-1] = '\0'; ++ if (oldcur == val || !val) { ++ char *s = getpwd(); ++ physdir = s; ++ if (!val) ++ dir = s; ++ } else ++ dir = savestr(val); ++ if (oldcur != dir && oldcur != nullstr) { ++ free(oldcur); + } +- curdir = savestr(buf); ++ curdir = dir; + INTON; +-#endif ++ setvar("PWD", dir, VEXPORT); + } +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/cd.h bin_NetBSD-1.6release/src/bin/sh/cd.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/cd.h 1997-07-05 12:12:27.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/cd.h 2003-02-08 14:35:42.000000000 +0000 +@@ -34,6 +34,6 @@ + * + */ + +-void getpwd __P((void)); + int cdcmd __P((int, char **)); + int pwdcmd __P((int, char **)); ++void setpwd __P((const char *, int)); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/ash.dirs bin_NetBSD-1.6release/src/bin/sh/debian/ash.dirs +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/ash.dirs 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/ash.dirs 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,2 @@ ++bin ++usr/share/man/man1 +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/ash.postinst bin_NetBSD-1.6release/src/bin/sh/debian/ash.postinst +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/ash.postinst 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/ash.postinst 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,54 @@ ++#!/bin/sh ++# ++# post-install script for the Debian GNU/Linux ash package ++# ++# $Id: dash-ash-hetio-yacc.diff,v 1.1 2003/02/09 09:36:31 satai Exp $ ++ ++set -e ++ ++check_divert() { ++ div=$(dpkg-divert --list $1) ++ distrib=${3:-$1.distrib} ++ case $div in ++ '' | *by\ dash) ++ ;; ++ *by\ ash) ++ dst=${div% by ash} ++ dst=${dst##* to } ++ ++ # Work around dpkg-divert bug. ++ if [ -e "$dst" ]; then ++ mv "$dst" "$dst.ash-tmp" ++ fi ++ dpkg-divert --remove $1 ++ if [ -e "$dst.ash-tmp" ]; then ++ mv "$dst.ash-tmp" "$dst" ++ fi ++ ++ dpkg-divert --package dash --divert $distrib --add $1 ++ if [ "$dst" != $distrib ] && [ -e "$dst" ]; then ++ mv "$dst" $distrib ++ fi ++ ln -sf $2 $1 ++ ;; ++ *) ++ d=${1%/*} ++ if ++ [ -h $1 ] && [ -f $1 ] && [ -f $d/$4 ] && ++ cmp $1 $d/$4 ++ then ++ ln -sf $2 $1 ++ fi ++ ;; ++ esac ++} ++ ++dcv='dpkg --compare-versions' ++ ++if [ "$1" = configure ] && [ -n "$2" ] && $dcv "$2" lt 0.4.3; then ++ check_divert /bin/sh dash '' ash ++ check_divert /usr/share/man/man1/sh.1.gz dash.1.gz \ ++ /usr/share/man/man1/sh.distrib.1.gz ash.1.gz ++fi ++ ++#DEBHELPER# +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/bsdyacc bin_NetBSD-1.6release/src/bin/sh/debian/bsdyacc +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/bsdyacc 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/bsdyacc 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,20 @@ ++#!/bin/sh -e ++ ++if echo "$@" | grep -q -- -o; then ++ OUTPUT=$(echo "$@" | ++ sed 's/.*-o[[:blank:]]\+\([^[:blank:]]\+\)\.c.*/\1/') ++ OPTIONS=$(echo "$@" | ++ sed 's/\(.*\)-o[[:blank:]]\+[^[:blank:]]\+\(.*\)/\1\2/') ++ NEW=1 ++else ++ OUTPUT=$(echo "$@" | ++ sed -e 's/.*[[:blank:]]\+\([^[:blank:]]\+\)\.y.*/\1/') ++ OPTIONS="$@" ++ NEW=0 ++fi ++ ++byacc $OPTIONS ++if [ $NEW = 1 ]; then ++ mv y.tab.c $OUTPUT.c ++fi ++mv y.tab.h $OUTPUT.h +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/changelog bin_NetBSD-1.6release/src/bin/sh/debian/changelog +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/changelog 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/changelog 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,868 @@ ++dash (0.4.10) unstable; urgency=low ++ ++ * Fixed redirection fd leak when execing. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 19 Jan 2003 13:25:41 +1100 ++ ++dash (0.4.9) unstable; urgency=low ++ ++ * Reset exitstatus in evalsubshell if backgnd is true. ++ * Fixed glibc glob syntax error in expand.c. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 11 Jan 2003 16:04:02 +1100 ++ ++dash (0.4.8) unstable; urgency=low ++ ++ * Removed backgnd flag from ncmd due to previous redirection change. ++ * Set lim after the stack stablises in updatepwd (closes: #173884). ++ * Do not clobber the exitstatus after redirection. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 23 Dec 2002 19:50:06 +1100 ++ ++dash (0.4.7) unstable; urgency=low ++ ++ * Merged clearredir with reset code in redir.c. ++ * Redirect before command search in evalcommand (closes: #168862). ++ * Build binary-all packages in binary-indep (closes: #173191). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 21 Dec 2002 13:52:37 +1100 ++ ++dash (0.4.6) unstable; urgency=low ++ ++ * Restored code for leaving job control. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 8 Dec 2002 15:21:58 +1100 ++ ++dash (0.4.5) unstable; urgency=low ++ ++ * Optimised doformat so that vsnprintf is usually called only once. ++ * Reset redirlist in clearredir so that popredir can work (closes: #170247). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 23 Nov 2002 22:09:59 +1100 ++ ++dash (0.4.4) unstable; urgency=low ++ ++ * Fixed duplicate define warnings in init.c. ++ * Set debhelper compat to 4. ++ * Vanishing mail boxes no longer elicit "you have mail" messages. ++ * Function redirection errors no longer abort the shell. ++ * Fixed potential memory leak in redirect. ++ * Only allocate memory if necessary in redirect. ++ * Reap dead here documents. ++ * Do not strdup default values of static shell variables. ++ * Removed unnecessary setprompt(0) calls. ++ * Read in BUFSIZ chunks rather than BUFSIZ - 1. ++ * Documented undefined escape behaviour for echo(1) (closes: #167893). ++ * Do va_copy when we use a va_list twice (closes: #169503). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 20 Nov 2002 19:48:31 +1100 ++ ++dash (0.4.3) unstable; urgency=low ++ ++ * Added manual entry for PPID. ++ * Exporting an unset variable no longer causes it to be set. ++ * Fixed fd0 redirection in asynchronous lists. ++ * Only stat if necessary in cdcmd (see #42880). ++ * Removed extra newline in error message in arith lexer. ++ * Set heredoclist to 0 ASAP in parseheredoc. ++ * Removed BSD advertising clause from copyright file. ++ * Check non-ash diversions as well in dash.postinst. ++ * Duplicated diversion checking in ash.postinst (closes: #166441). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 26 Oct 2002 21:28:33 +1000 ++ ++dash (0.4.2) unstable; urgency=low ++ ++ * Give benefits of dash in templates (closes: #161527). ++ * Fixed signed/unsigned on result of xwrite (closes: #161606). ++ * Removed support for SIG prefixes in kill and trap. ++ * Added -- processing in trap. ++ * Dropped use of unset in postinst (closes: 161868). ++ * Fixed printf(1) %* processing on bad integers and zero. ++ * Use stat64 in test(1). ++ * Allocate group_array with stalloc in test(1). ++ * Disabled alias checking after a pattern in a case statement. ++ * Wait now returns 128 + last trapped signal. ++ * Printf now keeps going after errors. ++ * Empty non-trivial parameter expansions are now removed correctly. ++ * Call reset() before exitshell() is called. This fixes the bug where ++ returning an error from a function running under set -e caused the exit ++ trap to be taken with evalskip set. ++ * Fixed quoting of empty strings in single_quote(). ++ * Show line numbers on all errors. ++ * Function names must be valid identifiers. ++ * Removed unused dependency on groff. ++ * Fixed race condition before entering a function. ++ * Fixed getopts initialisation for functions. ++ * Added memory barriers in INT macros. ++ * Banned empty compound lists in most places. ++ * Keep usage counters on functions (closes: #164234). ++ * Updated copyright file. ++ * Check evalskip in evalstring (closes: #165056). ++ * Merged changes from NetBSD 1.6: ++ . Added intmax support in printf(1). ++ . Implemented set -u. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 19 Oct 2002 14:23:11 +1000 ++ ++dash (0.4.1) unstable; urgency=low ++ ++ * Removed extra new line in command -v output for aliases. ++ * Removed alais prefix in the output of alias. ++ * Recognise octal and hex numbers in arith expansion (closes: #151449). ++ * Added sh(1) entries for echo, printf and test (closes: #156446). ++ * Renamed to dash --- the Debian Almquist Shell. ++ * Cleaned up rules file (Matej Vela). ++ * Check mtime instead of size in chkmail per POSIX. ++ * Added support for LFS (closes: #157884). ++ * Added SuS options to cd and pwd (closes: #145828). ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 13 Sep 2002 20:35:06 +1000 ++ ++ash (0.3.8-38) unstable; urgency=low ++ ++ * Turned pre-dependency to dependency in udeb since the former is not allowed ++ (closes: #143749). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 28 Apr 2002 11:59:05 +1000 ++ ++ash (0.3.8-37) unstable; urgency=low ++ ++ * Added Japanese debconf translation (Tomohiro KUBOTA, closes: #137431). ++ * Added missing escapes in manual page (Aaron Schrab, closes: #137966). ++ * Added Russian debconf translation (Ilgiz Kalmetev, closes: #137618). ++ * Fixed trap(1) documentation (closes: #140973). ++ * Do not abort if getcwd fails. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 3 Apr 2002 20:58:09 +1000 ++ ++ash (0.3.8-36) unstable; urgency=low ++ ++ * Added library dependency for ash-udeb. ++ * Handle null case statements correctly. ++ * Fixed alias expansions in case statements (NetBSD). ++ * Disabled unused jobid command. ++ * Corrected documentation about shifting too much. ++ * Added French debconf translation (Denis Barbier, closes: #134625). ++ * Updated Spanish debconf translation (Carlos Valdivia, closes: #136366). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 2 Mar 2002 18:31:22 +1100 ++ ++ash (0.3.8-35) unstable; urgency=low ++ ++ * Moved PWD initialisation into var.c (closes: #124032). ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 24 Dec 2001 09:34:55 +1100 ++ ++ash (0.3.8-34) unstable; urgency=low ++ ++ * NSEMI must be NOR + 1. ++ * Set exitstatus to zero before evaluating cases (closes: #124066). ++ * Explicitly set default answer of the ash/sh question to false so that ++ people whose debconf priority is set to low and who keeps banging on their ++ keyboards don't accidently end up with ash as /bin/sh. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 21 Dec 2001 20:30:49 +1100 ++ ++ash (0.3.8-33) unstable; urgency=low ++ ++ * Added missing inclusion of bltin.h in bltin/times.c. ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 13 Dec 2001 18:46:07 +1100 ++ ++ash (0.3.8-32) unstable; urgency=low ++ ++ * Back slashes in expansions are now escaped (closes: #121516). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 28 Nov 2001 20:15:01 +1100 ++ ++ash (0.3.8-31) unstable; urgency=low ++ ++ * Made sure all back slashes are escaped. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 26 Nov 2001 19:10:27 +1100 ++ ++ash (0.3.8-30) unstable; urgency=low ++ ++ * Restored fnmatch(3) code. ++ * Treat escaped slashes correctly while globbing. ++ * Restored missing EV_EXIT check in evalcommand (closes: #120364). ++ * Fixed stack corruption in _rmescapes. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 25 Nov 2001 17:51:19 +1100 ++ ++ash (0.3.8-29) unstable; urgency=low ++ ++ * Added missing va_end in fmtstr (NetBSD). ++ * Removed shellproc crap. ++ * Updated Swedish debconf translation (Mikael Hedin, closes: #116097). ++ * Updated German debconf translation (Andreas Metzler, closes: #117160). ++ * Break now treats illegal numbers according to SuS. ++ * Errors in special builtins now rise to the top. ++ * Normal redirection errors no longer abort the shell. ++ * Functions now have the same variable assignment properties as special ++ builtins. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 3 Nov 2001 11:36:36 +1100 ++ ++ash (0.3.8-28) unstable; urgency=low ++ ++ * Local variables are now unset properly in shprocvar() (closes: #114917). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 13 Oct 2001 14:07:21 +1000 ++ ++ash (0.3.8-27) unstable; urgency=low ++ ++ * Kill no longer aborts if it fails to kill someone. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 30 Sep 2001 22:20:36 +1000 ++ ++ash (0.3.8-26) unstable; urgency=low ++ ++ * The sh.1.gz diversion now agrees with reality (closes: #113831). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 29 Sep 2001 08:43:27 +1000 ++ ++ash (0.3.8-25) unstable; urgency=low ++ ++ * Only read ENV if the shell is interactive (closes: #110421). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 29 Aug 2001 19:18:53 +1000 ++ ++ash (0.3.8-24) unstable; urgency=low ++ ++ * Handle SIGINT when waiting even if there is no trap (closes: #107699). ++ * Protect all makejob/forkshell/waitforjobs sequences from SIGINT. ++ * Work around gcc bug that generates bad ..ng references (closes: #107994). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 8 Aug 2001 20:28:28 +1000 ++ ++ash (0.3.8-23) unstable; urgency=low ++ ++ * Fixed fence post error in scanleft (closes: #107229). ++ * Removed stunalloc in expname as it interferes with addfname. ++ * Fixed CTLESC skipping in scanright. ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 2 Aug 2001 20:06:00 +1000 ++ ++ash (0.3.8-22) unstable; urgency=low ++ ++ * Fixed trailing back slash bug in echo/printf (closes: #106693). ++ * Some quoted's are meant to be quotes. ++ * Added Brazilian translation (Andre Luis Lopes, closes: #107041). ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 30 Jul 2001 20:21:52 +1000 ++ ++ash (0.3.8-21) unstable; urgency=low ++ ++ * Fixed EV_EXIT/redirection bugs that caused core dumps. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 28 Jul 2001 17:03:28 +1000 ++ ++ash (0.3.8-20) unstable; urgency=low ++ ++ * Don't save fd2 if job control is turned off. ++ * Don't push redirections when EV_EXIT is set. ++ * Fixed assignment recognition in the presence of back ticks. ++ * Combined checkkwd and checkalias. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 27 Jul 2001 22:29:41 +1000 ++ ++ash (0.3.8-19) unstable; urgency=low ++ ++ * Recompute strings after growing in subevalvar (closes: #106050). ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 23 Jul 2001 21:16:50 +1000 ++ ++ash (0.3.8-18) unstable; urgency=low ++ ++ * Added more space optimisations for udeb on i386. ++ * Set stack mark in patmatch (closes: #106050). ++ * Fixed theoretical bug in expari. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 21 Jul 2001 20:08:15 +1000 ++ ++ash (0.3.8-17) unstable; urgency=low ++ ++ * Don't complain about unknown escape codes in echo and printf ++ (closes: #105659). ++ * Updated build-time dependency on groff-base (closes: #105612). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 18 Jul 2001 19:33:20 +1000 ++ ++ash (0.3.8-16) unstable; urgency=low ++ ++ * Fixed backslash bug in new pattern matching code. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 16 Jul 2001 21:47:39 +1000 ++ ++ash (0.3.8-15) unstable; urgency=low ++ ++ * Added Swedish translation of templates (Martin Sjögren, closes: #103158). ++ * Restored escape code support in echo. ++ * Removed assignment builtins since it is at best undefined by the SuS and ++ also can't be implemented consistently. ++ * Removed extraneous volatile modifier (closes: #104518). ++ * General overhaul of word expansion (closes: #96588). ++ * Redirection prefixes no longer stop assignments from being recognised. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 15 Jul 2001 17:27:03 +1000 ++ ++ash (0.3.8-14) unstable; urgency=low ++ ++ * Divert sh.1.gz to sh.distrib.1.gz (closes: #102251). ++ * Added HETIO support for ^D and ^U (Aaron Lehmann, closes: #102215). ++ * Added Spaniash translation of debconf templates (Carlos Valdivia Yagüe, ++ closes: #103040). ++ * Added versioned build-time dependency on groff. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 2 Jul 2001 19:32:03 +1000 ++ ++ash (0.3.8-13) unstable; urgency=low ++ ++ * Fixed a bug where errors in pipelines which are part of andor lists were ++ not ignored when -e is in effect. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 25 Jun 2001 19:40:27 +1000 ++ ++ash (0.3.8-12) unstable; urgency=low ++ ++ * Rewrote arith_lex.l in C (Aaron Lehmann, closes: #101741). ++ * && and || in arithmetic expansions now return either 0 or 1. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 24 Jun 2001 20:14:29 +1000 ++ ++ash (0.3.8-11) unstable; urgency=low ++ ++ * Check for NULL argument in evaltree() (closes: #98865, #98867). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 27 May 2001 17:53:14 +1000 ++ ++ash (0.3.8-10) unstable; urgency=low ++ ++ * Use /bin/ash in postinst to sidestep bugs in other shells (closes: #98739). ++ * Exit status is now tested on non-negated pipelines (closes: #98736). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 26 May 2001 23:56:07 +1000 ++ ++ash (0.3.8-9) unstable; urgency=medium ++ ++ * IFS is now fetched using bltinlookup() again in read (closes: #98343). ++ * Divert sh(1) man page as well as /bin/sh (closes: #98525). ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 25 May 2001 20:30:06 +1000 ++ ++ash (0.3.8-8) unstable; urgency=low ++ ++ * Fixed diversion removal in prerm (duh, closes: #98031). ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 21 May 2001 20:52:48 +1000 ++ ++ash (0.3.8-7) unstable; urgency=low ++ ++ * Fixed diversion test in prerm (closes: #98031). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 20 May 2001 12:30:53 +1000 ++ ++ash (0.3.8-6) unstable; urgency=low ++ ++ * Make sure that fd2 is closed when clearing redirects (closes: #96619). ++ * Fixed memory corruption in stunalloc(). ++ * The output of export/readonly/set is now correctly quoted. ++ * Fixed newline eating bug in expbackq(). ++ * Set OLDPWD. ++ * Removed ash-medium as neither bf or di uses it. ++ * Wait now waits for all its argument rather than the first one. ++ * Wait will exit with 129 when interrupted by a signal for a which a trap has ++ been set. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 18 May 2001 21:51:41 +1000 ++ ++ash (0.3.8-5) unstable; urgency=low ++ ++ * Added German translation to template file (Sebastian Feltel, ++ closes: #96203). ++ * Added missing initialisation in setalias() (closes: #95433). ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 4 May 2001 20:54:31 +1000 ++ ++ash (0.3.8-4) unstable; urgency=low ++ ++ * Disabled fnmatch code as fnmatch(3) in glibc is broken. ++ * Fixed echo example in man page (Kalle Olavi Niemitalo, closes: #96014). ++ * Fixed trailing semicolon bug with eval (NetBSD). ++ * Fixed globbing inconsistency with broken symlinks (NetBSD). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 2 May 2001 22:57:16 +1000 ++ ++ash (0.3.8-3) unstable; urgency=low ++ ++ * Work around broken autoconf scripts (closes: #95430). ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 1 May 2001 18:27:50 +1000 ++ ++ash (0.3.8-2) unstable; urgency=low ++ ++ * Save checkalias before calling xxreadtoken() (closes: #95628). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 29 Apr 2001 17:36:01 +1000 ++ ++ash (0.3.8-1) unstable; urgency=low ++ ++ * NetBSD-current version as of 20010316. ++ * Removed code that sets IFS. ++ * Fixed memory leak with PWD. ++ * Set PPID. ++ * Fixed inconsistencies in alias expansion. ++ * Restored original output code. ++ * Enabled fnmatch code again. ++ * Added builtin printf. ++ * Offer to divert /bin/sh (closes: #70462). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 25 Apr 2001 22:32:39 +1000 ++ ++ash (0.3.7-16) unstable; urgency=low ++ ++ * Fixed incorrect default IFS in readcmd (closes: #88950). ++ * Added missing return in hashcmd. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 9 Mar 2001 20:44:40 +1100 ++ ++ash (0.3.7-15) unstable; urgency=low ++ ++ * Unknown escape codes are now prnted literally by echo (closes: #82869). ++ * Made hetio_read_input() fail if fd is not stdin. ++ * Some uses of VSQUOTE were really meant to be quotes (closes: #88777). ++ * Build different ashes in different subdirectories. ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 8 Mar 2001 21:32:28 +1100 ++ ++ash (0.3.7-14) unstable; urgency=low ++ ++ * Removed predependency from udeb (closes: #81995). ++ * Added /bin/sh symlink to udeb (closes: #81967). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 13 Jan 2001 15:23:21 +1100 ++ ++ash (0.3.7-13) unstable; urgency=low ++ ++ * Renamed the udeb to ash-udeb. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 20 Dec 2000 19:32:34 +1100 ++ ++ash (0.3.7-12) unstable; urgency=low ++ ++ * Added support for udebs (Randolph Chung, closes: #79237). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 16 Dec 2000 13:53:28 +1100 ++ ++ash (0.3.7-11) unstable; urgency=low ++ ++ * Preserve the previous exit status upon entering a function ++ (closes: #78374). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 3 Dec 2000 13:34:27 +1100 ++ ++ash (0.3.7-10) unstable; urgency=low ++ ++ * Merged changes for GNU from Igor Khavkine. ++ * Minimise the number of sigactions. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 3 Nov 2000 20:31:52 +1100 ++ ++ash (0.3.7-9) unstable; urgency=low ++ ++ * Predepend on the libraries. ++ * Always save fd 2 when it is redirected (closes: #75302). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 22 Oct 2000 08:40:40 +1100 ++ ++ash (0.3.7-8) unstable; urgency=high ++ ++ * More redirection fixes (closes: #73613). ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 5 Oct 2000 18:22:17 +1100 ++ ++ash (0.3.7-7) unstable; urgency=high ++ ++ * Added missing break in redirection code (closes: #72956). ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 3 Oct 2000 07:58:04 +1100 ++ ++ash (0.3.7-6) unstable; urgency=low ++ ++ * command -[vV] no longer displays an error message on stdout. ++ * Redirecting to /proc/self/fd/* now works (closes: #72852). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 1 Oct 2000 12:56:39 +1100 ++ ++ash (0.3.7-5) unstable; urgency=low ++ ++ * Implemented set -a. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 30 Sep 2000 16:00:33 +1100 ++ ++ash (0.3.7-4) unstable; urgency=low ++ ++ * Added build-time dependency on debhelper (closes: #69920). ++ * Extended maximum length of arithmetic expansions to match 32-bit integers. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 20 Sep 2000 14:28:16 +1100 ++ ++ash (0.3.7-3) unstable; urgency=low ++ ++ * Switch to the old globbing code since glob(3) is hopelessly broken ++ (closes: #69455). ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 21 Aug 2000 20:37:15 +1000 ++ ++ash (0.3.7-2) unstable; urgency=low ++ ++ * Call glob(3) with GLOB_NOMAGIC (ouch). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 6 Aug 2000 17:47:08 +1000 ++ ++ash (0.3.7-1) unstable; urgency=low ++ ++ * NetBSD-current version as of 20000729. ++ * Use fnmatch(3) and glob(3). ++ * Fixed the use of backslashes in the pattern in parameter substitutions, ++ hopefully for the last time. ++ * Applied HETIO patch and built ash.medium (closes: #50788). Will do ash.big ++ when readline is fixed so that it doesn't leak anymore. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 4 Aug 2000 21:36:44 +1000 ++ ++ash (0.3.6-5) unstable; urgency=low ++ ++ * Fixed manpage entry for read with patch from Kevin Ryde (closes: #62500). ++ * Fixed a file descriptor leak for pipelines. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 19 Apr 2000 18:56:20 +1000 ++ ++ash (0.3.6-4) unstable; urgency=low ++ ++ * Fixed the case of an empty command with redirections. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 7 Apr 2000 12:07:18 +1000 ++ ++ash (0.3.6-3) unstable; urgency=low ++ ++ * ! is now recognised correctly. ++ * Ash is now more strict on the syntax, e.g., a lone ! is no longer accepted ++ as an alternative to ! true. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 7 Apr 2000 10:46:06 +1000 ++ ++ash (0.3.6-2) unstable; urgency=low ++ ++ * Fixed a problem with fmtstr() which broke getopts. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 2 Apr 2000 10:49:26 +1000 ++ ++ash (0.3.6-1) unstable; urgency=low ++ ++ * NetBSD-current version as of 20000326. ++ * Added a Build-Depends on groff (closes: #61041). ++ * Implemented noclobber (closes: #59028). ++ * Rewrote output.c to use stream IO. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 1 Apr 2000 19:24:31 +1000 ++ ++ash (0.3.5-10) frozen unstable; urgency=low ++ ++ * Don't stat mail boxes in non-interactive mode (closes: #59213). ++ * Added an fflush(stdout) to the times builtin (closes: #59027). ++ * Documented the times builtin. ++ * Added source depends. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 18 Mar 2000 18:58:44 +1100 ++ ++ash (0.3.5-9) unstable; urgency=low ++ ++ * Double quotes inside paramater substitutions inside double quotes are now ++ ignored as in bash (the originial behaviour was POSIX compliant too but ++ IMHO this one makes a little bit more sense). ++ This one broke mwm (but it was actually mwm's fault). ++ * Corrected backslash/CTLESC treatment for patterns in parameter ++ substitutions. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 6 Nov 1999 18:13:19 +1100 ++ ++ash (0.3.5-8) unstable; urgency=low ++ ++ * Replaced use of echo -n in manual page with escape codes. ++ * Made FHS compliant (closes: #47978). ++ * Restored echo's option processing ability. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 22 Oct 1999 10:20:58 +1000 ++ ++ash (0.3.5-7) unstable; urgency=low ++ ++ * echo no longer supports options. ++ * Don't quote patterns inside parameter substitutions enclosed by double ++ quotes (closes: #47842). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 20 Oct 1999 20:28:14 +1000 ++ ++ash (0.3.5-6) unstable; urgency=low ++ ++ * Use getcwd() instead of /bin/pwd -- Zack Weinberg (closes: #46981). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 10 Oct 1999 16:31:49 +1000 ++ ++ash (0.3.5-5) unstable; urgency=low ++ ++ * Only test for -e on simple commands (fixes #44559). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 8 Sep 1999 22:18:27 +1000 ++ ++ash (0.3.5-4) unstable; urgency=low ++ ++ * Don't wait for stopped children if job control is disabled (fixes #42814). ++ * Allow an option '(' in a case statement (fixes #42364). ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 12 Aug 1999 23:30:30 +1000 ++ ++ash (0.3.5-3) unstable; urgency=low ++ ++ * OK, the fix to the esoteric problem in 0.3.5-1 actually breaks VSASSIGN ++ and VSQUESTION, they should work properly now (fixes #41327). ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 15 Jul 1999 22:47:13 +1000 ++ ++ash (0.3.5-2) unstable; urgency=low ++ ++ * PATH search and execution is now correct. ++ * hash no longer shows builtins. ++ * Added kill builtin. ++ * New description from James R. van Zandt reformatted by Josip Rodin. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 12 Jul 1999 18:51:42 +1000 ++ ++ash (0.3.5-1) unstable; urgency=low ++ ++ * New upstream release. ++ * Adapted to new pmake (fixes #38737). ++ * Fixed behvaiour of backslashes preceding a closing brace for a parameter ++ substituion inside double quotes (even bash messes this one up :). ++ * Fixed command (fixes #34639). ++ * Fixed a pipe bug where stdin may be wrongly closed (fixes #35452). ++ * Revamped getopts (fixes #39694). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 4 Jul 1999 12:19:01 +1000 ++ ++ash (0.3.4-7) unstable; urgency=low ++ ++ * Fixed a glibc 2.1 compatitibility problem. ++ * Fixed a PWD inconsistency that stuffed up the kernel compilation. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 17 May 1999 23:14:57 +1000 ++ ++ash (0.3.4-6) unstable; urgency=low ++ ++ * Fixed incorrect -e test due to the last bug fix (fixes #26509). ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 8 Sep 1998 10:02:46 +1000 ++ ++ash (0.3.4-5) unstable; urgency=low ++ ++ * Use test_eaccess from bash instead of access(2) (fixes #26110). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 26 Aug 1998 21:22:49 +1000 ++ ++ash (0.3.4-4) unstable; urgency=low ++ ++ * Only upload to unstable. ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 5 May 1998 18:01:02 +1000 ++ ++ash (0.3.4-3) frozen unstable; urgency=low ++ ++ * Applied sparc patch (fixes #21562). ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 1 May 1998 19:48:13 +1000 ++ ++ash (0.3.4-2) frozen unstable; urgency=low ++ ++ * Fixed the incorrect trap fixes (fixes #20363). ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 16 Apr 1998 21:07:10 +1000 ++ ++ash (0.3.4-1) unstable; urgency=low ++ ++ * New upstream release. ++ * Reverted word splitting change in 0.3.2-1 since the fix was broken and ++ major work (the quote removal is done too quickly at the moment) is needed ++ to fix it properly. ++ * Fixed more trap noncompliance. ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 19 Mar 1998 22:59:12 +1100 ++ ++ash (0.3.2-5) unstable; urgency=low ++ ++ * Fixed a bug when doing pattern matching in parameter expansions. ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 10 Mar 1998 21:25:40 +1100 ++ ++ash (0.3.2-4) unstable; urgency=low ++ ++ * Allow ] to be quoted in bracket expressions (fixes #17533). ++ * Move dh_fixperms to second last spot (fixes #18267). ++ * Don't do field splitting in evalfor. ++ ++ -- Herbert Xu <herbert@debian.org> Tue, 17 Feb 1998 13:32:09 +1100 ++ ++ash (0.3.2-3) unstable; urgency=low ++ ++ * Fixed stupid core dump. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 11 Feb 1998 21:33:55 +1100 ++ ++ash (0.3.2-2) unstable; urgency=low ++ ++ * Hack for special builtins (fixes #18055). ++ * Hack for command. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 11 Feb 1998 21:19:46 +1100 ++ ++ash (0.3.2-1) unstable; urgency=low ++ ++ * NetBSD-current version as of 19980209. ++ * Fixed a word splitting problem after parameter expansion thanks to Alexey ++ Marinichev. ++ * Converted to debhelper (fixes #14612, #15005). ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 9 Feb 1998 16:53:48 +1100 ++ ++ash (0.3.1-20) unstable; urgency=low ++ ++ * Fixed -e problem with eval. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 7 Dec 1997 20:19:00 +1100 ++ ++ash (0.3.1-19) unstable; urgency=low ++ ++ * Fixed -e problem with command substitution. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 7 Dec 1997 19:44:49 +1100 ++ ++ash (0.3.1-18) unstable; urgency=low ++ ++ * Do not link with ncurses (#15485). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 30 Nov 1997 12:00:11 +1100 ++ ++ash (0.3.1-17) unstable; urgency=low ++ ++ * Set PATH like bash (#15238). ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 26 Nov 1997 16:17:27 +1100 ++ ++ash (0.3.1-16) unstable; urgency=low ++ ++ * Fixed incorrect assignment builtin code. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 24 Nov 1997 16:19:10 +1100 ++ ++ash (0.3.1-15) unstable; urgency=low ++ ++ * hash now returns error codes (needed by the Linux kernel). ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 23 Nov 1997 21:37:08 +1100 ++ ++ash (0.3.1-14) unstable; urgency=low ++ ++ * Disabled word-splitting for assignment builtins. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 23 Nov 1997 12:45:15 +1100 ++ ++ash (0.3.1-13) unstable; urgency=low ++ ++ * ! is now recognised even after &&/||. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 21 Nov 1997 22:09:05 +1100 ++ ++ash (0.3.1-12) unstable; urgency=low ++ ++ * More fixes to the handling of SIGINT when forking. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 14 Nov 1997 15:14:32 +1100 ++ ++ash (0.3.1-11) unstable; urgency=low ++ ++ * Ignore SIGINT when forking non-interactively. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 3 Nov 1997 12:00:02 +1100 ++ ++ash (0.3.1-10) unstable; urgency=low ++ ++ * echo now handles options correctly. ++ * echo nolonger returns 0 if erorrs occured while writing to stdout. ++ * New code from GNU echo merged. ++ * Error messages from test now work. ++ ++ -- Herbert Xu <herbert@debian.org> Wed, 8 Oct 1997 21:47:13 +1000 ++ ++ash (0.3.1-9) unstable; urgency=low ++ ++ * ! is recognised at pipeline level like bash. ++ ++ -- Herbert Xu <herbert@debian.org> Mon, 15 Sep 1997 23:13:45 +1000 ++ ++ash (0.3.1-8) unstable; urgency=medium ++ ++ * Old patch regarding SIGCHLD in again. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 31 Aug 1997 11:20:27 +1000 ++ ++ash (0.3.1-7) unstable; urgency=low ++ ++ * /bin/sh -e is behaving even better now (for loops within conditionals). ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 23 Aug 1997 22:08:19 +1000 ++ ++ash (0.3.1-6) unstable; urgency=low ++ ++ * /bin/sh -e is behaving better now. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 23 Aug 1997 13:16:26 +1000 ++ ++ash (0.3.1-5) unstable; urgency=low ++ ++ * hash -v /dir/command doesn't coredump anymore. ++ * type /dir/command now works correctly. ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 1 Aug 1997 20:48:19 +1000 ++ ++ash (0.3.1-4) unstable; urgency=low ++ ++ * trap now understands symbolic signal names. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 26 Jul 1997 14:04:46 +1000 ++ ++ash (0.3.1-3) unstable; urgency=low ++ ++ * Added the builtin test command. ++ ++ -- Herbert Xu <herbert@debian.org> Sun, 20 Jul 1997 15:00:14 +1000 ++ ++ash (0.3.1-2) unstable; urgency=medium ++ ++ * Fixed a coredump involving $*. ++ ++ -- Herbert Xu <herbert@debian.org> Sat, 19 Jul 1997 12:03:02 +1000 ++ ++ash (0.3.1-1) unstable; urgency=medium ++ ++ * NetBSD-current version as of 19970715. ++ * Fixed a "use after free" bug (#11294). ++ ++ -- Herbert Xu <herbert@debian.org> Fri, 18 Jul 1997 13:48:09 +1000 ++ ++ash (0.3-1) unstable; urgency=low ++ ++ * Initial Release. ++ ++ -- Herbert Xu <herbert@debian.org> Thu, 19 Jun 1997 19:29:16 +1000 ++ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/compat bin_NetBSD-1.6release/src/bin/sh/debian/compat +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/compat 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/compat 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1 @@ ++4 +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/control bin_NetBSD-1.6release/src/bin/sh/debian/control +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/control 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/control 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,53 @@ ++Source: dash ++Section: shells ++Priority: optional ++Maintainer: Herbert Xu <herbert@debian.org> ++Build-Depends: byacc, debhelper (>= 4), pmake ++Standards-Version: 3.5.8 ++ ++Package: dash ++Architecture: any ++Pre-Depends: ${shlibs:Depends} ++Description: The Debian Almquist Shell ++ "dash" is a POSIX compliant shell that is much smaller than "bash". ++ We take advantage of that by making it the shell on the installation ++ root floppy, where space is at a premium. ++ . ++ It can be usefully installed as /bin/sh (because it executes scripts ++ somewhat faster than "bash"), or as the default shell either of root ++ or of a second user with a userid of 0 (because it depends on fewer ++ libraries, and is therefore less likely to be affected by an upgrade ++ problem or a disk failure). It is also useful for checking that a ++ script uses only POSIX syntax. ++ . ++ "bash" is a better shell for most users, since it has some nice ++ features absent from "dash", and is a required part of the system. ++ ++Package: dash-udeb ++Architecture: any ++Depends: ${shlibs:Depends} ++Section: debian-installer ++Priority: standard ++Description: The Debian Almquist Shell for boot floppies ++ "dash" is a POSIX compliant shell that is much smaller than "bash". ++ We take advantage of that by making it the shell on the installation ++ root floppy, where space is at a premium. ++ . ++ It can be usefully installed as /bin/sh (because it executes scripts ++ somewhat faster than "bash"), or as the default shell either of root ++ or of a second user with a userid of 0 (because it depends on fewer ++ libraries, and is therefore less likely to be affected by an upgrade ++ problem or a disk failure). It is also useful for checking that a ++ script uses only POSIX syntax. ++ . ++ "bash" is a better shell for most users, since it has some nice ++ features absent from "dash", and is a required part of the system. ++ ++Package: ash ++Architecture: all ++Pre-Depends: dash ++Description: Compatibility package for the Debian Almquist Shell ++ This package exists so that users of the "ash" package can upgrade to the ++ "dash" package which replaces the former. It includes the /bin/ash symlink. ++ You can remove this package if you do not use /bin/ash explicitly. ++ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/copyright bin_NetBSD-1.6release/src/bin/sh/debian/copyright +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/copyright 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/copyright 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,44 @@ ++This package was debianized by Mark W. Eichin eichin@kitten.gen.ma.us on ++Mon, 24 Feb 1997 16:00:16 -0500. ++ ++This package was re-ported from NetBSD and debianized by ++Herbert Xu herbert@debian.org on Thu, 19 Jun 1997 19:29:16 +1000. ++ ++It was downloaded from ftp.netbsd.org. ++ ++Copyright: ++ ++Copyright (c) 1989-1994 ++ The Regents of the University of California. All rights reserved. ++Copyright (c) 1997-2002 ++ Herbert Xu <herbert@debian.org> ++ ++This code is derived from software contributed to Berkeley by Kenneth Almquist. ++ ++Please refer to /usr/share/common-licenses/BSD for details. ++ ++mksignames.c: ++ ++This file is not directly linked with dash. However, its output is. ++ ++Copyright (C) 1992 Free Software Foundation, Inc. ++ ++This file is part of GNU Bash, the Bourne Again SHell. ++ ++Bash is free software; you can redistribute it and/or modify it under ++the terms of the GNU General Public License as published by the Free ++Software Foundation; either version 2, or (at your option) any later ++version. ++ ++Bash is distributed in the hope that it will be useful, but WITHOUT ANY ++WARRANTY; without even the implied warranty of MERCHANTABILITY or ++FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++for more details. ++ ++You should have received a copy of the GNU General Public License with ++your Debian GNU/Linux system, in /usr/share/common-licenses/GPL, or with the ++Debian GNU/Linux hello source package as the file COPYING. If not, ++write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ++Boston, MA 02111 USA. ++ ++$Id: dash-ash-hetio-yacc.diff,v 1.1 2003/02/09 09:36:31 satai Exp $ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.config bin_NetBSD-1.6release/src/bin/sh/debian/dash.config +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.config 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.config 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,39 @@ ++#!/bin/sh ++# ++# debconf script for the Debian GNU/Linux ash package ++# ++# $Id: dash-ash-hetio-yacc.diff,v 1.1 2003/02/09 09:36:31 satai Exp $ ++ ++set -e ++ ++. /usr/share/debconf/confmodule ++ ++db_version 2.0 ++ ++if [ "$1" = configure ] && [ -z "$2" ]; then ++ set +e ++ db_fget ash/sh seen ++ err=$? ++ set -e ++ ++ case $err in ++ 0) ++ if [ "$RET" = true ]; then ++ db_fset dash/sh seen true ++ db_get ash/sh ++ db_set dash/sh "$RET" ++ exit ++ fi ++ ;; ++ 10) ++ # ash/sh does not exist ++ ;; ++ *) ++ echo "db_fget exited with $err" >&2 ++ exit $err ++ ;; ++ esac ++fi ++ ++db_input low dash/sh || true ++db_go +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.dirs bin_NetBSD-1.6release/src/bin/sh/debian/dash.dirs +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.dirs 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.dirs 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,2 @@ ++bin ++usr/share/man/man1 +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.postinst bin_NetBSD-1.6release/src/bin/sh/debian/dash.postinst +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.postinst 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.postinst 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,81 @@ ++#!/bin/sh ++# ++# post-install script for the Debian GNU/Linux dash package ++# ++# $Id: dash-ash-hetio-yacc.diff,v 1.1 2003/02/09 09:36:31 satai Exp $ ++ ++set -e ++ ++check_divert() { ++ div=$(dpkg-divert --list $2) ++ distrib=${4:-$2.distrib} ++ case "$1" in ++ true) ++ if [ -z "$div" ]; then ++ dpkg-divert --package dash --divert $distrib --add $2 ++ cp -dp $2 $distrib ++ ln -sf $3 $2 ++ fi ++ ;; ++ false) ++ if [ -n "$div" ] && [ -z "${div%%*by dash}" ]; then ++ mv $distrib $2 ++ dpkg-divert --remove $2 ++ fi ++ ;; ++ ash) ++ case $div in ++ '') ++ ;; ++ *by\ ash) ++ dst=${div% by ash} ++ dst=${dst##* to } ++ ++ # Work around dpkg-divert bug. ++ if [ -e "$dst" ]; then ++ mv "$dst" "$dst.dash-tmp" ++ fi ++ dpkg-divert --remove $2 ++ if [ -e "$dst.dash-tmp" ]; then ++ mv "$dst.dash-tmp" "$dst" ++ fi ++ ++ dpkg-divert --package dash --divert $distrib --add $2 ++ if [ "$dst" != $distrib ] && [ -e "$dst" ]; then ++ mv "$dst" $distrib ++ fi ++ ln -sf $3 $2 ++ ;; ++ *) ++ d=${2%/*} ++ if ++ [ -h $2 ] && [ -f $2 ] && [ -f $d/$5 ] && ++ cmp $2 $d/$5 ++ then ++ ln -sf $3 $2 ++ fi ++ ;; ++ esac ++ esac ++} ++ ++debconf= ++if [ -f /usr/share/debconf/confmodule ]; then ++ . /usr/share/debconf/confmodule ++ debconf=yes ++fi ++ ++if [ "$1" = configure ] && [ -z "$2" ]; then ++ check_divert ash /bin/sh dash '' ash ++ check_divert ash /usr/share/man/man1/sh.1.gz dash.1.gz \ ++ /usr/share/man/man1/sh.distrib.1.gz ash.1.gz ++fi ++ ++if [ $debconf ]; then ++ db_get dash/sh ++ check_divert "$RET" /bin/sh dash ++ check_divert "$RET" /usr/share/man/man1/sh.1.gz dash.1.gz \ ++ /usr/share/man/man1/sh.distrib.1.gz ++fi ++ ++#DEBHELPER# +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.prerm bin_NetBSD-1.6release/src/bin/sh/debian/dash.prerm +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.prerm 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.prerm 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,24 @@ ++#!/bin/sh ++# ++# pre-removal script for the Debian GNU/Linux ash package ++# ++# $Id: dash-ash-hetio-yacc.diff,v 1.1 2003/02/09 09:36:31 satai Exp $ ++ ++set -e ++ ++remove_divert() { ++ div=$(dpkg-divert --list $1) ++ if [ -n "$div" ] && [ -z "${div%%*by dash}" ]; then ++ distrib=${div% by dash} ++ distrib=${distrib##* to } ++ mv $distrib $1 ++ dpkg-divert --remove $1 ++ fi ++} ++ ++if [ "$1" = remove ] || [ "$1" = deconfigure ]; then ++ remove_divert /bin/sh ++ remove_divert /usr/share/man/man1/sh.1.gz ++fi ++ ++#DEBHELPER# +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,10 @@ ++Template: dash/sh ++Type: boolean ++Default: false ++Description: Install dash as /bin/sh? ++ Bash is the default /bin/sh on a Debian system. However, since our policy ++ requires all shell scripts using /bin/sh to be POSIX compliant, any shell ++ that conforms to POSIX can serve as /bin/sh. Since dash is POSIX compliant, ++ it can be used as /bin/sh. You may wish to do this because dash is faster ++ and smaller than bash. ++ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.de bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.de +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.de 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.de 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,13 @@ ++Template: dash/sh ++Description: Install dash as /bin/sh? ++ Bash is the default /bin/sh on a Debian system. However, since our policy ++ requires all shell scripts using /bin/sh to be POSIX compliant, any shell ++ that conforms to POSIX can serve as /bin/sh. Since dash is POSIX compliant, ++ it can be used as /bin/sh. ++Description-de: dash als /bin/sh installieren? ++ Bash ist die Standard-Shell (/bin/sh) auf einem Debian-System. Da die ++ Debian-Policy von allen Shellscripts, die /bin/sh benutzen, ++ POSIX-Kompatibilität verlangt, kann für /bin/sh jede POSIX-kompatible Shell ++ benutzt werden. Dash ist POSIX-kompatibel und kann daher als /bin/sh verwendet ++ werden. ++ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.es bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.es +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.es 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.es 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,13 @@ ++Template: dash/sh ++Description: Install dash as /bin/sh? ++ Bash is the default /bin/sh on a Debian system. However, since our policy ++ requires all shell scripts using /bin/sh to be POSIX compliant, any shell ++ that conforms to POSIX can serve as /bin/sh. Since dash is POSIX compliant, ++ it can be used as /bin/sh. ++Description-es: ¿Instalar dash como /bin/sh? ++ Bash es el intérprte de comandos /bin/sh por defecto de los sistemas Debian. ++ Sin embargo, dado que nuestras normas obligan a que todos los scripts para el ++ intérprete de comandos se atengan a las normas POSIX, cualquier intérprete ++ compatible con POSIX puede servir como /bin/sh. Puesto que dash lo es, puede ++ usarse como /bin/sh. ++ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.fr bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.fr +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.fr 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.fr 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,12 @@ ++Template: dash/sh ++Description: Install dash as /bin/sh? ++ Bash is the default /bin/sh on a Debian system. However, since our policy ++ requires all shell scripts using /bin/sh to be POSIX compliant, any shell ++ that conforms to POSIX can serve as /bin/sh. Since dash is POSIX compliant, ++ it can be used as /bin/sh. ++Description-fr: Mettre un lien de /bin/sh vers dash ? ++ Sur un système Debian, /bin/sh est bash par défaut. Cependant, comme notre ++ charte impose que tous les scripts shells utilisant /bin/sh soient conformes ++ à la norme POSIX, /bin/sh peut être n'importe quel shell conforme à cette ++ norme. Et comme dash l'est, il peut servir de /bin/sh. ++ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.ja bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.ja +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.ja 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.ja 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,13 @@ ++Template: dash/sh ++Description: Install dash as /bin/sh? ++ Bash is the default /bin/sh on a Debian system. However, since our policy ++ requires all shell scripts using /bin/sh to be POSIX compliant, any shell ++ that conforms to POSIX can serve as /bin/sh. Since dash is POSIX compliant, ++ it can be used as /bin/sh. ++Description-ja: dash ¤ò /bin/sh ¤È¤·¤Æ¥¤¥ó¥¹¥È¡¼¥ë¤·¤Þ¤¹¤«? ++ Debian ¥·¥¹¥Æ¥à¤Ç¤Ï bash ¤¬¥Ç¥Õ¥©¥ë¥È¤Î /bin/sh ¤Ç¤¹¡£¤·¤«¤·¡¢Debian ++ ¤Î¥Ý¥ê¥·¡¼¤Ë¤è¤Ã¤Æ¡¢/bin/sh ¤òÍѤ¤¤ëÁ´¤Æ¤Î¥·¥§¥ë¥¹¥¯¥ê¥×¥È¤Ï POSIX ++ ½àµò¤Ç¤Ê¤±¤ì¤Ð¤Ê¤é¤Ê¤¤¤¿¤á¡¢POSIX ¤òËþ¤¿¤¹¥·¥§¥ë¤Ï¤É¤ì¤Ç¤â /bin/sh ++ ¤È¤Ê¤ë¤³¤È¤¬¤Ç¤¤Þ¤¹¡£dash ¤Ï POSIX ½àµò¤Ç¤¹¤Î¤Ç¡¢/bin/sh ¤È¤·¤Æ»È¤¦ ++ ¤³¤È¤¬¤Ç¤¤Þ¤¹¡£ ++ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.pt_BR bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.pt_BR +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.pt_BR 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.pt_BR 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,12 @@ ++Template: dash/sh ++Description: Install dash as /bin/sh? ++ Bash is the default /bin/sh on a Debian system. However, since our policy ++ requires all shell scripts using /bin/sh to be POSIX compliant, any shell ++ that conforms to POSIX can serve as /bin/sh. Since dash is POSIX compliant, ++ it can be used as /bin/sh. ++Description-pt_BR: Instalar dash como /bin/sh ? ++ Bash é o /bin/sh padrão em um sistema Debian. Porém, uma vez que nossa ++ política requer que todos os shell scripts usando /bin/sh sejam compatíveis ++ POSIX, qualquer shell que esteja em conformidade POSIX pode servir como ++ /bin/sh. Uma vez que dash é compatível POSIX, pode ser usado como /bin/sh. ++ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.ru bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.ru +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.ru 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.ru 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,13 @@ ++Template: dash/sh ++Description: Install dash as /bin/sh? ++ Bash is the default /bin/sh on a Debian system. However, since our policy ++ requires all shell scripts using /bin/sh to be POSIX compliant, any shell ++ that conforms to POSIX can serve as /bin/sh. Since dash is POSIX compliant, ++ it can be used as /bin/sh. ++Description-ru: õÓÔÁÎÏ×ÉÔØ dash ËÁË /bin/sh? ++ Bash - ÜÔÏ /bin/sh ÐÏ ÕÍÏÌÞÁÎÉÀ × ÓÉÓÔÅÍÅ Debian. ïÄÎÁËÏ, ÔÁË ËÁË ÎÁÛÁ ++ ÐÏÌÉÔÉËÁ ÔÒÅÂÕÅÔ, ÞÔÏÂÙ ×ÓÅ ÓÃÅÎÁÒÉÉ ÏÂÏÌÏÞËÉ, ÉÓÐÏÌØÚÕÀÝÉÅ /bin/sh, ++ ÂÙÌÉ ÓÏ×ÍÅÓÔÉÍÙÍÉ Ó POSIX, ÔÏ ÒÁÂÏÔÁÔØ ËÁË /bin/sh ÍÏÖÅÔ ÌÀÂÁÑ ++ ÏÂÏÌÏÞËÁ, ÓÏ×ÍÅÓÔÉÍÁÑ Ó POSIX. ôÁË ËÁË dash ÓÏ×ÍÅÓÔÉÍ Ó POSIX, ÔÏ ÏÎ ++ ÍÏÖÅÔ ÉÓÐÏÌØÚÏ×ÁÔØÓÑ ËÁË /bin/sh. ++ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.sv bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.sv +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash.templates.sv 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash.templates.sv 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,13 @@ ++Template: dash/sh ++Type: boolean ++Description: Install dash as /bin/sh? ++ Bash is the default /bin/sh on a Debian system. However, since our policy ++ requires all shell scripts using /bin/sh to be POSIX compliant, any shell ++ that conforms to POSIX can serve as /bin/sh. Since dash is POSIX compliant, ++ it can be used as /bin/sh. ++Description-sv: Installera dash som /bin/sh? ++ Bash är standardinställningen för /bin/sh på Debiansystem. Eftersom vår ++ policy kräver att alla script som använder /bin/sh måste vara ++ POSIX-kompatibla, kan vilket POSIX-kompatibelt skal som helst vara /bi/sh. Då ++ dash är POSIX-kompatibelt kan det användas som /bin/sh. ++ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash-udeb.dirs bin_NetBSD-1.6release/src/bin/sh/debian/dash-udeb.dirs +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/dash-udeb.dirs 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/dash-udeb.dirs 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1 @@ ++bin +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/debian/rules bin_NetBSD-1.6release/src/bin/sh/debian/rules +--- bin_NetBSD-1.6release.orig/src/bin/sh/debian/rules 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/debian/rules 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,101 @@ ++#!/usr/bin/make -f ++# $Id: dash-ash-hetio-yacc.diff,v 1.1 2003/02/09 09:36:31 satai Exp $ ++ ++# Uncomment this to turn on verbose mode. ++#export DH_VERBOSE=1 ++ ++# This has to be exported to make some magic below work. ++export DH_OPTIONS ++ ++DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH) ++ ++CDEF := \ ++ -Wall -DBSD=1 -DSMALL -D_GNU_SOURCE -DGLOB_BROKEN -DHAVE_VASPRINTF=1 \ ++ -DIFS_BROKEN -DGCC_BROKEN_NG \ ++ -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= -D_DIAGASSERT\(x\)= ++ ++OPT := -g -O2 -fstrict-aliasing ++OPTSM := -g -Os -fstrict-aliasing -fomit-frame-pointer -DREALLY_SMALL ++ ++ifeq ($(DEB_HOST_ARCH),i386) ++OPTSM += \ ++ -malign-loops=0 -malign-jumps=0 -malign-functions=0 \ ++ -mpreferred-stack-boundary=2 -DUSE_NORETURN ++endif ++ ++setup: setup-stamp ++setup-stamp: ++ rm -rf obj obj-udeb ++ mkdir obj obj-udeb ++ chmod u+x debian/bsdyacc ++ touch setup-stamp ++ ++build: setup-stamp ++ dh_testdir ++ ++ pmake CFLAGS:='$(CDEF) $(OPT)' \ ++ YACC:='$${.CURDIR}/debian/bsdyacc' ++ MAKEOBJDIR=obj-udeb pmake CFLAGS:='$(CDEF) $(OPTSM)' \ ++ YACC:='$${.CURDIR}/debian/bsdyacc' ++ ++clean: ++ dh_testdir ++ dh_testroot ++ rm -f setup-stamp ++ ++ rm -rf obj obj-udeb ++ ++ dh_clean ++ ++install: build ++ dh_testdir ++ dh_testroot ++ dh_clean -k ++ dh_installdirs ++ ++ install obj/sh debian/dash/bin/dash ++ install -m 644 sh.1 debian/dash/usr/share/man/man1/dash.1 ++ install obj-udeb/sh debian/dash-udeb/bin/dash ++ ln -s dash debian/dash-udeb/bin/sh ++ ln -s dash debian/ash/bin/ash ++ ln -s dash.1.gz debian/ash/usr/share/man/man1/ash.1.gz ++ ++# This single target is used to build all the packages, all at once, or ++# one at a time. So keep in mind: any options passed to commands here will ++# affect _all_ packages. Anything you want to only affect one package ++# should be put in another target, such as the install target. ++binary-common: ++ dh_testdir ++ dh_testroot ++ dh_installdebconf ++ dh_installdocs -Ndash-udeb ++ dh_installexamples ++ dh_installmenu ++ dh_installcron ++ dh_installchangelogs -Ndash-udeb ++ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) ++ dh_strip ++endif ++ dh_compress ++ dh_fixperms ++ dh_installdeb -Ndash-udeb ++ dh_shlibdeps ++ dh_gencontrol ++ dh_md5sums ++ dh_builddeb ++ ++# Build architecture-independent files here. ++binary-indep: install ++ $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common ++ ++# Build architecture-dependent files here. ++binary-arch: install ++ $(MAKE) -f debian/rules DH_OPTIONS=-a binary-common ++ ++ for i in ../dash-udeb_*.deb; do mv $$i $${i%deb}udeb; done ++ sed '/^[^ ]*\.udeb/d; s/^\(dash-udeb_[^ ]*\.\)deb/\1udeb/' \ ++ debian/files > debian/files.new ++ mv debian/files.new debian/files ++ ++binary: binary-indep binary-arch ++.PHONY: build clean binary-indep binary-arch binary binary-common install setup +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/error.c bin_NetBSD-1.6release/src/bin/sh/error.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/error.c 2002-05-16 11:41:19.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/error.c 2003-02-08 14:35:42.000000000 +0000 +@@ -1,4 +1,4 @@ +-/* $NetBSD: error.c,v 1.24 2002/05/15 16:33:35 christos Exp $ */ ++/* $NetBSD: error.c,v 1.25 2002/05/25 23:09:06 wiz Exp $ */ + + /*- + * Copyright (c) 1991, 1993 +@@ -41,7 +41,7 @@ + #if 0 + static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95"; + #else +-__RCSID("$NetBSD: error.c,v 1.24 2002/05/15 16:33:35 christos Exp $"); ++__RCSID("$NetBSD: error.c,v 1.25 2002/05/25 23:09:06 wiz Exp $"); + #endif + #endif /* not lint */ + +@@ -51,6 +51,7 @@ + + #include <signal.h> + #include <stdlib.h> ++#include <string.h> + #include <unistd.h> + #include <errno.h> + +@@ -60,6 +61,8 @@ + #include "output.h" + #include "error.h" + #include "show.h" ++#include "eval.h" ++#include "parser.h" + + + /* +@@ -68,13 +71,12 @@ + + struct jmploc *handler; + int exception; +-volatile int suppressint; +-volatile int intpending; +-char *commandname; ++int suppressint; ++volatile sig_atomic_t intpending; + + +-static void exverror __P((int, const char *, va_list)) +- __attribute__((__noreturn__)); ++static void exverror(int, const char *, va_list) __attribute__((__noreturn__)); ++static void vwarn(const char *, va_list); + + /* + * Called to raise an exception. Since C doesn't include exceptions, we +@@ -86,8 +88,12 @@ + exraise(e) + int e; + { ++#ifdef DEBUG + if (handler == NULL) + abort(); ++#endif ++ INTOFF; ++ + exception = e; + longjmp(handler->loc, 1); + } +@@ -97,29 +103,18 @@ + * 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.) ++ * are held using the INTOFF macro. (The test for iflag is just ++ * defensive programming.) + */ + + void + onint() { +- sigset_t sigset; +- +- if (suppressint) { +- intpending++; +- return; +- } + intpending = 0; +- sigemptyset(&sigset); +- sigprocmask(SIG_SETMASK, &sigset, NULL); +- if (rootshell && iflag) +- exraise(EXINT); +- else { ++ if (!(rootshell && iflag)) { + signal(SIGINT, SIG_DFL); + raise(SIGINT); + } ++ exraise(EXINT); + /* NOTREACHED */ + } + +@@ -135,73 +130,37 @@ + const char *msg; + va_list ap; + { +- CLEAR_PENDING_INT; +- INTOFF; +- + #ifdef 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'); +- } ++ vwarn(msg, ap); + flushall(); + exraise(cond); + /* NOTREACHED */ + } + + +-#ifdef __STDC__ + void + error(const char *msg, ...) +-#else +-void +-error(va_alist) +- va_dcl +-#endif + { +-#ifndef __STDC__ +- const char *msg; +-#endif + va_list ap; +-#ifdef __STDC__ ++ + va_start(ap, msg); +-#else +- va_start(ap); +- msg = va_arg(ap, const char *); +-#endif + exverror(EXERROR, msg, ap); + /* NOTREACHED */ + va_end(ap); + } + + +-#ifdef __STDC__ + void + exerror(int cond, const char *msg, ...) +-#else +-void +-exerror(va_alist) +- va_dcl +-#endif + { +-#ifndef __STDC__ +- int cond; +- const char *msg; +-#endif + va_list ap; +-#ifdef __STDC__ ++ + va_start(ap, msg); +-#else +- va_start(ap); +- cond = va_arg(ap, int); +- msg = va_arg(ap, const char *); +-#endif + exverror(cond, msg, ap); + /* NOTREACHED */ + va_end(ap); +@@ -223,56 +182,14 @@ + #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_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_OPEN, "No such file" }, ++ { ENOTDIR, E_CREAT,"Directory nonexistent" }, + { ENOTDIR, E_EXEC, "not found" }, +- { EISDIR, ALL, "is a directory" }, +-#ifdef notdef +- { 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 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" }, ++ { EAGAIN, E_EXEC, "Not enough memory" }, + #endif + { 0, 0, NULL }, + }; +@@ -290,12 +207,55 @@ + 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; ++ return strerror(e); ++} ++ ++ ++#ifdef REALLY_SMALL ++void ++__inton() { ++ if (--suppressint == 0 && intpending) { ++ onint(); ++ } ++} ++#endif ++ ++ ++ ++/* ++ * Print an error message for the current command. ++ */ ++static void vwarn(const char *const msg, va_list ap) { ++ struct output *errs; ++ const char *name; ++ const char *fmt; ++ ++ errs = out2; ++ name = arg0; ++ fmt = "%s: "; ++ if (commandname) { ++ name = commandname; ++ fmt = "%s: %d: "; ++ } ++ outfmt(errs, fmt, name, startlinno); ++ doformat(errs, msg, ap); ++#if FLUSHERR ++ outc('\n', errs); ++#else ++ outcslow('\n', errs); ++#endif ++} ++ ++ ++void warnx(const char *msg, ...) { ++ va_list ap; ++ ++ va_start(ap, msg); ++ vwarn(msg, ap); ++ va_end(ap); + } +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/error.h bin_NetBSD-1.6release/src/bin/sh/error.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/error.h 2001-02-05 11:15:29.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/error.h 2003-02-08 14:35:42.000000000 +0000 +@@ -38,6 +38,9 @@ + * @(#)error.h 8.2 (Berkeley) 5/4/95 + */ + ++#include <setjmp.h> ++#include <signal.h> ++ + /* + * Types of operations (passed to the errmsg routine). + */ +@@ -57,8 +60,6 @@ + * inner scope, and restore handler on exit from the scope. + */ + +-#include <setjmp.h> +- + struct jmploc { + jmp_buf loc; + }; +@@ -71,6 +72,7 @@ + #define EXERROR 1 /* a generic error */ + #define EXSHELLPROC 2 /* execute a shell procedure */ + #define EXEXEC 3 /* command execution failed */ ++#define EXEXIT 4 /* exit the shell */ + + + /* +@@ -80,20 +82,53 @@ + * more fun than worrying about efficiency and portability. :-)) + */ + +-extern volatile int suppressint; +-extern volatile int intpending; ++extern int suppressint; ++extern volatile sig_atomic_t intpending; + +-#define INTOFF suppressint++ +-#define INTON { if (--suppressint == 0 && intpending) onint(); } +-#define FORCEINTON {suppressint = 0; if (intpending) onint();} ++#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); }) ++#define INTOFF \ ++ ({ \ ++ suppressint++; \ ++ barrier(); \ ++ 0; \ ++ }) ++#ifdef REALLY_SMALL ++void __inton __P((void)); ++#define INTON __inton() ++#else ++#define INTON \ ++ ({ \ ++ barrier(); \ ++ if (--suppressint == 0 && intpending) onint(); \ ++ 0; \ ++ }) ++#endif ++#define FORCEINTON \ ++ ({ \ ++ barrier(); \ ++ suppressint = 0; \ ++ if (intpending) onint(); \ ++ 0; \ ++ }) ++#define SAVEINT(v) ((v) = suppressint) ++#define RESTOREINT(v) \ ++ ({ \ ++ barrier(); \ ++ if ((suppressint = (v)) == 0 && intpending) onint(); \ ++ }) + #define CLEAR_PENDING_INT intpending = 0 + #define int_pending() intpending + + void exraise __P((int)) __attribute__((__noreturn__)); ++#ifdef USE_NORETURN ++void onint __P((void)) __attribute__((__noreturn__)); ++#else + void onint __P((void)); ++#endif + void error __P((const char *, ...)) __attribute__((__noreturn__)); + void exerror __P((int, const char *, ...)) __attribute__((__noreturn__)); + const char *errmsg __P((int, int)); ++void warnx __P((const char *, ...)); + + + /* +@@ -101,7 +136,7 @@ + * so we use _setjmp instead. + */ + +-#if defined(BSD) && !defined(__SVR4) ++#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__) + #define setjmp(jmploc) _setjmp(jmploc) + #define longjmp(jmploc, val) _longjmp(jmploc, val) + #endif +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/eval.c bin_NetBSD-1.6release/src/bin/sh/eval.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/eval.c 2002-05-16 11:41:20.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/eval.c 2003-02-08 14:35:42.000000000 +0000 +@@ -45,8 +45,11 @@ + #endif + #endif /* not lint */ + ++#include <sys/types.h> + #include <signal.h> ++#include <malloc.h> + #include <unistd.h> ++#include <errno.h> + + /* + * Evaluate a command. +@@ -98,9 +101,18 @@ + STATIC void evalcase __P((union node *, int)); + STATIC void evalsubshell __P((union node *, int)); + STATIC void expredir __P((union node *)); +-STATIC void evalpipe __P((union node *)); ++STATIC void evalpipe __P((union node *, int)); ++#ifdef notyet + STATIC void evalcommand __P((union node *, int, struct backcmd *)); ++#else ++STATIC void evalcommand __P((union node *, int)); ++#endif + STATIC void prehash __P((union node *)); ++STATIC void eprintlist __P((struct strlist *)); ++#if !defined(__alpha__) || !defined(GCC_BROKEN_NG) ++STATIC ++#endif ++void evaltreenr __P((union node *, int)) __attribute__ ((noreturn)); + + + /* +@@ -115,10 +127,6 @@ + loopnest = 0; + funcnest = 0; + } +- +-SHELLPROC { +- exitstatus = 0; +-} + #endif + + +@@ -142,8 +150,7 @@ + STARTSTACKSTR(concat); + ap = argv + 2; + for (;;) { +- while (*p) +- STPUTC(*p++, concat); ++ concat = stputs(p, concat); + if ((p = *ap++) == NULL) + break; + STPUTC(' ', concat); +@@ -170,10 +177,12 @@ + struct stackmark smark; + + setstackmark(&smark); +- setinputstring(s, 1); ++ setinputstring(s); + while ((n = parsecmd(0)) != NEOF) { + evaltree(n, flag); + popstackmark(&smark); ++ if (evalskip) ++ break; + } + popfile(); + popstackmark(&smark); +@@ -191,9 +200,12 @@ + union node *n; + int flags; + { ++ int checkexit = 0; ++ void (*evalfn)(union node *, int); ++ unsigned isor; ++ int status; + if (n == NULL) { + TRACE(("evaltree(NULL) called\n")); +- exitstatus = 0; + goto out; + } + #ifndef SMALL +@@ -201,89 +213,122 @@ + #endif + TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type)); + switch (n->type) { +- case NSEMI: +- 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) { +- /* don't bomb out on "set -e; false && true" */ +- flags |= EV_TESTED; +- goto out; +- } +- evaltree(n->nbinary.ch2, flags | EV_TESTED); +- break; +- case NOR: +- evaltree(n->nbinary.ch1, EV_TESTED); +- if (evalskip || exitstatus == 0) +- goto out; +- evaltree(n->nbinary.ch2, flags | EV_TESTED); ++ default: ++#ifdef DEBUG ++ out1fmt("Node type = %d\n", n->type); ++#ifndef USE_GLIBC_STDIO ++ flushout(out1); ++#endif + break; ++#endif ++ case NNOT: ++ evaltree(n->nnot.com, EV_TESTED); ++ status = !exitstatus; ++ goto setstatus; + case NREDIR: + expredir(n->nredir.redirect); +- redirect(n->nredir.redirect, REDIR_PUSH); +- evaltree(n->nredir.n, flags); +- popredir(); ++ status = redirectsafe(n->nredir.redirect, REDIR_PUSH); ++ if (!status) { ++ evaltree(n->nredir.n, flags & EV_TESTED); ++ status = exitstatus; ++ } ++ popredir(0); ++ goto setstatus; ++ case NCMD: ++#ifdef notyet ++ if (eflag && !(flags & EV_TESTED)) ++ checkexit = ~0; ++ evalcommand(n, flags, (struct backcmd *)NULL); + break; ++#else ++ evalfn = evalcommand; ++checkexit: ++ if (eflag && !(flags & EV_TESTED)) ++ checkexit = ~0; ++ goto calleval; ++#endif ++ case NFOR: ++ evalfn = evalfor; ++ goto calleval; ++ case NWHILE: ++ case NUNTIL: ++ evalfn = evalloop; ++ goto calleval; + case NSUBSHELL: +- evalsubshell(n, flags); +- break; + case NBACKGND: +- evalsubshell(n, flags); ++ evalfn = evalsubshell; ++ goto calleval; ++ case NPIPE: ++ evalfn = evalpipe; ++#ifdef notyet ++ if (eflag && !(flags & EV_TESTED)) ++ checkexit = ~0; ++ goto calleval; ++#else ++ goto checkexit; ++#endif ++ case NCASE: ++ evalfn = evalcase; ++ goto calleval; ++ case NAND: ++ case NOR: ++ case NSEMI: ++#if NAND + 1 != NOR ++#error NAND + 1 != NOR ++#endif ++#if NOR + 1 != NSEMI ++#error NOR + 1 != NSEMI ++#endif ++ isor = n->type - NAND; ++ evaltree( ++ n->nbinary.ch1, ++ (flags | ((isor >> 1) - 1)) & EV_TESTED ++ ); ++ if (!exitstatus == isor) + break; +- case NIF: { +- evaltree(n->nif.test, EV_TESTED); +- if (evalskip) +- goto out; +- if (exitstatus == 0) +- evaltree(n->nif.ifpart, flags); +- else if (n->nif.elsepart) +- evaltree(n->nif.elsepart, flags); +- else +- exitstatus = 0; ++ if (!evalskip) { ++ n = n->nbinary.ch2; ++evaln: ++ evalfn = evaltree; ++calleval: ++ evalfn(n, flags); + break; + } +- case NWHILE: +- case NUNTIL: +- evalloop(n, flags); + break; +- case NFOR: +- evalfor(n, flags); +- break; +- case NCASE: +- evalcase(n, flags); ++ case NIF: ++ evaltree(n->nif.test, EV_TESTED); ++ if (evalskip) + break; ++ if (exitstatus == 0) { ++ n = n->nif.ifpart; ++ goto evaln; ++ } else if (n->nif.elsepart) { ++ n = n->nif.elsepart; ++ goto evaln; ++ } ++ goto success; + case NDEFUN: + defun(n->narg.text, n->narg.next); +- exitstatus = 0; +- break; +- case NNOT: +- evaltree(n->nnot.com, EV_TESTED); +- exitstatus = !exitstatus; +- break; +- +- case NPIPE: +- evalpipe(n); +- break; +- case NCMD: +- evalcommand(n, flags, (struct backcmd *)NULL); +- break; +- default: +- out1fmt("Node type = %d\n", n->type); +- flushout(&output); ++success: ++ status = 0; ++setstatus: ++ exitstatus = status; + break; + } + out: + if (pendingsigs) + dotrap(); +- if ((flags & EV_EXIT) != 0) +- exitshell(exitstatus); ++ if (flags & EV_EXIT || checkexit & exitstatus) ++ exraise(EXEXIT); + } + + ++#if !defined(__alpha__) || !defined(GCC_BROKEN_NG) ++STATIC ++#endif ++void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"))); ++ ++ + STATIC void + evalloop(n, flags) + union node *n; +@@ -293,6 +338,7 @@ + + loopnest++; + status = 0; ++ flags &= EV_TESTED; + for (;;) { + evaltree(n->nbinary.ch1, EV_TESTED); + if (evalskip) { +@@ -311,7 +357,7 @@ + if (exitstatus == 0) + break; + } +- evaltree(n->nbinary.ch2, flags & EV_TESTED); ++ evaltree(n->nbinary.ch2, flags); + status = exitstatus; + if (evalskip) + goto skipping; +@@ -344,9 +390,10 @@ + + exitstatus = 0; + loopnest++; ++ flags &= EV_TESTED; + for (sp = arglist.list ; sp ; sp = sp->next) { + setvar(n->nfor.var, sp->text, 0); +- evaltree(n->nfor.body, flags & EV_TESTED); ++ evaltree(n->nfor.body, flags); + if (evalskip) { + if (evalskip == SKIPCONT && --skipcount <= 0) { + evalskip = 0; +@@ -377,6 +424,7 @@ + setstackmark(&smark); + arglist.lastp = &arglist.list; + oexitstatus = exitstatus; ++ exitstatus = 0; + 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) { +@@ -405,20 +453,28 @@ + { + struct job *jp; + int backgnd = (n->type == NBACKGND); ++ int status; + + expredir(n->nredir.redirect); ++ if (!backgnd && flags & EV_EXIT && !trap[0]) ++ goto nofork; ++ INTOFF; + jp = makejob(n, 1); + if (forkshell(jp, n, backgnd) == 0) { ++ INTON; ++ flags |= EV_EXIT; + if (backgnd) + flags &=~ EV_TESTED; ++nofork: + redirect(n->nredir.redirect, 0); +- evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ ++ evaltreenr(n->nredir.n, flags); ++ /* never returns */ + } +- if (! backgnd) { +- INTOFF; +- exitstatus = waitforjob(jp); ++ status = 0; ++ if (!backgnd) ++ status = waitforjob(jp); ++ exitstatus = status; + INTON; +- } + } + + +@@ -467,8 +523,9 @@ + */ + + STATIC void +-evalpipe(n) ++evalpipe(n, flags) + union node *n; ++ int flags; + { + struct job *jp; + struct nodelist *lp; +@@ -480,6 +537,7 @@ + pipelen = 0; + for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) + pipelen++; ++ flags |= EV_EXIT; + INTOFF; + jp = makejob(n, pipelen); + prevfd = -1; +@@ -494,33 +552,29 @@ + } + if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { + INTON; ++ if (pip[1] >= 0) { ++ close(pip[0]); ++ } + if (prevfd > 0) { +- close(0); +- copyfd(prevfd, 0); ++ dup2(prevfd, 0); + close(prevfd); + } +- if (pip[1] >= 0) { +- close(pip[0]); +- if (pip[1] != 1) { +- close(1); +- copyfd(pip[1], 1); ++ if (pip[1] > 1) { ++ dup2(pip[1], 1); + close(pip[1]); + } +- } +- evaltree(lp->n, EV_EXIT); ++ evaltree(lp->n, flags); + } + if (prevfd >= 0) + close(prevfd); + prevfd = pip[0]; + close(pip[1]); + } +- INTON; + if (n->npipe.backgnd == 0) { +- INTOFF; + exitstatus = waitforjob(jp); + TRACE(("evalpipe: job done exit status %d\n", exitstatus)); +- INTON; + } ++ INTON; + } + + +@@ -595,10 +649,16 @@ + */ + + STATIC void ++#ifdef notyet + evalcommand(cmd, flags, backcmd) + union node *cmd; + int flags; + struct backcmd *backcmd; ++#else ++evalcommand(cmd, flags) ++ union node *cmd; ++ int flags; ++#endif + { + struct stackmark smark; + union node *argp; +@@ -607,25 +667,30 @@ + char **argv; + int argc; + char **envp; +- int varflag; + struct strlist *sp; + int mode; ++#ifdef notyet + int pip[2]; ++#endif + struct cmdentry cmdentry; + struct job *jp; +- struct jmploc jmploc; +- struct jmploc *volatile savehandler; + char *volatile savecmdname; + volatile struct shparam saveparam; + struct localvar *volatile savelocalvars; +- volatile int e; + char *lastarg; ++ const char *path; ++ int spclbltin; ++ int redir; ++ struct jmploc *volatile savehandler; ++ struct jmploc jmploc; + #if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &argv; + (void) &argc; + (void) &lastarg; + (void) &flags; ++ (void) &spclbltin; ++ (void) &redir; + #endif + + /* First expand the arguments. */ +@@ -633,22 +698,15 @@ + setstackmark(&smark); + arglist.lastp = &arglist.list; + varlist.lastp = &varlist.list; +- varflag = 1; ++ arglist.list = 0; + oexitstatus = exitstatus; + exitstatus = 0; +- 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 == '=') { ++ path = pathval(); ++ for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { + expandarg(argp, &varlist, EXP_VARTILDE); +- continue; +- } + } ++ for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); +- varflag = 0; + } + *arglist.lastp = NULL; + *varlist.lastp = NULL; +@@ -670,77 +728,140 @@ + + /* Print the command if xflag is set. */ + if (xflag) { ++#ifdef FLUSHERR + outc('+', &errout); +- for (sp = varlist.list ; sp ; sp = sp->next) { +- outc(' ', &errout); +- out2str(sp->text); +- } +- for (sp = arglist.list ; sp ; sp = sp->next) { +- outc(' ', &errout); +- out2str(sp->text); +- } ++#else ++ outcslow('+', &errout); ++#endif ++ eprintlist(varlist.list); ++ eprintlist(arglist.list); ++#ifdef FLUSHERR + outc('\n', &errout); + flushout(&errout); ++#else ++ outcslow('\n', &errout); ++#endif + } + ++ redir = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH); ++ + /* Now locate the command. */ + if (argc == 0) { + cmdentry.cmdtype = CMDBUILTIN; +- cmdentry.u.index = BLTINCMD; ++ cmdentry.u.cmd = BLTINCMD; ++ spclbltin = 1; + } else { +- static const char PATH[] = "PATH="; +- const char *path = pathval(); ++ const char *oldpath; ++ int findflag = DO_ERR; ++ int oldfindflag; + + /* + * 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) +- path = sp->text + sizeof(PATH) - 1; +- +- find_command(argv[0], &cmdentry, DO_ERR, path); ++ if (varequal(sp->text, defpathvar)) { ++ path = sp->text + 5; ++ findflag |= DO_BRUTE; ++ } ++ oldpath = path; ++ oldfindflag = findflag; ++ spclbltin = -1; ++ for(;;) { ++ find_command(argv[0], &cmdentry, findflag, path); + if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ +- exitstatus = 127; +- flushout(&errout); +- return; ++ goto notfound; + } +- /* implement the bltin builtin here */ +- if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { +- for (;;) { ++ /* implement bltin and command here */ ++ if (cmdentry.cmdtype != CMDBUILTIN) { ++ break; ++ } ++ if (spclbltin < 0) { ++ spclbltin = ++ !!( ++ cmdentry.u.cmd->flags & ++ BUILTIN_SPECIAL ++ ) * 2 ++ ; ++ } ++ if (cmdentry.u.cmd == BLTINCMD) { ++ for(;;) { ++ struct builtincmd *bcmd; ++ + argv++; + if (--argc == 0) +- break; +- if ((cmdentry.u.index = find_builtin(*argv)) < 0) { ++ goto found; ++ if (!(bcmd = find_builtin(*argv))) { + outfmt(&errout, "%s: not found\n", *argv); ++notfound: + exitstatus = 127; ++#ifdef FLUSHERR + flushout(&errout); +- return; ++#endif ++ goto out; + } +- if (cmdentry.u.index != BLTINCMD) ++ cmdentry.u.cmd = bcmd; ++ if (bcmd != BLTINCMD) + break; + } + } ++ if (cmdentry.u.cmd == COMMANDCMD) { ++ argv++; ++ if (--argc == 0) { ++ goto found; ++ } ++ if (*argv[0] == '-') { ++ if (!equal(argv[0], "-p")) { ++ argv--; ++ argc++; ++ break; ++ } ++ argv++; ++ if (--argc == 0) { ++ goto found; ++ } ++ path = defpath; ++ findflag |= DO_BRUTE; ++ } else { ++ path = oldpath; ++ findflag = oldfindflag; ++ } ++ findflag |= DO_NOFUN; ++ continue; ++ } ++found: ++ break; ++ } + } + + /* Fork off a child process if necessary. */ +- if (cmd->ncmd.backgnd +- || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) ++ if ( ++ ( ++ cmdentry.cmdtype == CMDNORMAL && ++ (!(flags & EV_EXIT) || trap[0]) ++ ) ++#ifdef notyet + || ((flags & EV_BACKCMD) != 0 + && (cmdentry.cmdtype != CMDBUILTIN +- || cmdentry.u.index == DOTCMD +- || cmdentry.u.index == EVALCMD))) { ++ || cmdentry.u.bcmd == DOTCMD ++ || cmdentry.u.bcmd == EVALCMD)) ++#endif ++ ) { ++ INTOFF; + jp = makejob(cmd, 1); +- mode = cmd->ncmd.backgnd; ++ mode = FORK_FG; ++#ifdef notyet + if (flags & EV_BACKCMD) { + mode = FORK_NOJOB; + if (pipe(pip) < 0) + error("Pipe call failed"); + } ++#endif + if (forkshell(jp, cmd, mode) != 0) + goto parent; /* at end of routine */ +- if (flags & EV_BACKCMD) { + FORCEINTON; ++#ifdef notyet ++ if (flags & EV_BACKCMD) { + close(pip[0]); + if (pip[1] != 1) { + close(1); +@@ -748,148 +869,168 @@ + close(pip[1]); + } + } ++#endif + flags |= EV_EXIT; ++ } else { ++ flags &= ~EV_EXIT; + } + + /* This is the child process if a fork occurred. */ + /* Execute the command. */ +- if (cmdentry.cmdtype == CMDFUNCTION) { ++ if (redir) { ++ /* We have a redirection error. */ ++ exitstatus = redir; ++ if (spclbltin == 2) ++ exraise(EXERROR); ++ } else if (cmdentry.cmdtype == CMDFUNCTION) { + #ifdef DEBUG + trputs("Shell function: "); trargs(argv); + #endif +- redirect(cmd->ncmd.redirect, REDIR_PUSH); ++ exitstatus = oexitstatus; + saveparam = shellparam; +- shellparam.malloc = 0; +- shellparam.reset = 1; +- shellparam.nparam = argc - 1; +- shellparam.p = argv + 1; +- shellparam.optnext = NULL; +- INTOFF; + savelocalvars = localvars; +- localvars = NULL; +- INTON; ++ exception = -1; + if (setjmp(jmploc.loc)) { +- if (exception == EXSHELLPROC) { +- freeparam((volatile struct shparam *) +- &saveparam); +- } else { +- freeparam(&shellparam); +- shellparam = saveparam; +- } +- poplocalvars(); +- localvars = savelocalvars; +- handler = savehandler; +- longjmp(handler->loc, 1); ++ goto funcdone; + } ++ INTOFF; + savehandler = handler; + handler = &jmploc; +- for (sp = varlist.list ; sp ; sp = sp->next) +- mklocal(sp->text); ++ localvars = NULL; ++ shellparam.malloc = 0; ++ cmdentry.u.func->count++; ++ INTON; ++ shellparam.nparam = argc - 1; ++ shellparam.p = argv + 1; ++ shellparam.optind = 1; ++ shellparam.optoff = -1; ++ listsetvar(varlist.list, 0); + funcnest++; +- evaltree(cmdentry.u.func, flags & EV_TESTED); ++ evaltree(&cmdentry.u.func->n, flags & EV_TESTED); + funcnest--; ++funcdone: + INTOFF; ++ freefunc(cmdentry.u.func); + poplocalvars(); + localvars = savelocalvars; + freeparam(&shellparam); + shellparam = saveparam; + handler = savehandler; +- popredir(); + INTON; ++ if (exception >= 0) { ++ longjmp(handler->loc, 1); ++ } + if (evalskip == SKIPFUNC) { + evalskip = 0; + skipcount = 0; + } +- if (flags & EV_EXIT) +- exitshell(exitstatus); + } else if (cmdentry.cmdtype == CMDBUILTIN) { + #ifdef DEBUG + trputs("builtin command: "); trargs(argv); + #endif +- mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; +- if (flags == EV_BACKCMD) { +- memout.nleft = 0; +- memout.nextc = memout.buf; +- memout.bufsize = 64; +- mode |= REDIR_BACKQ; ++ if (spclbltin) { ++ int f = 0; ++ if (cmdentry.u.cmd == EXECCMD) { ++ redir++; ++ if (argc > 1) ++ f = VEXPORT; ++ } ++ listsetvar(varlist.list, f); + } +- redirect(cmd->ncmd.redirect, mode); + savecmdname = commandname; + cmdenviron = varlist.list; +- e = -1; ++ exception = -1; + if (setjmp(jmploc.loc)) { +- e = exception; +- exitstatus = (e == EXINT)? SIGINT+128 : 2; + goto cmddone; + } + savehandler = handler; + handler = &jmploc; ++#ifdef notyet ++ if (flags == EV_BACKCMD) { ++#ifdef USE_GLIBC_STDIO ++ openmemout(); ++#else ++ memout.nleft = 0; ++ memout.nextc = memout.buf; ++ memout.bufsize = 64; ++#endif ++ } ++#endif + commandname = argv[0]; + argptr = argv + 1; + optptr = NULL; /* initialize nextopt */ +- exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); ++ exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv); + flushall(); + cmddone: ++ exitstatus |= outerr(out1); ++#ifdef notyet + out1 = &output; + out2 = &errout; ++#endif + freestdout(); + cmdenviron = NULL; +- if (e != EXSHELLPROC) { + commandname = savecmdname; +- 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 SMALL +- || cmdentry.u.index == HISTCMD +-#endif +- || cmdentry.u.index == EXECCMD) +- exraise(e); ++ if (exception >= 0) { ++ int f = exception; ++ if (f != EXEXIT) { ++ int status = (f == EXINT) ? SIGINT + 128 : 2; ++ exitstatus = status; ++ } ++ if (f == EXINT || spclbltin & 2) { ++ exraise(f); ++ } + FORCEINTON; + } +- if (cmdentry.u.index != EXECCMD) +- popredir(); ++#ifdef notyet + if (flags == EV_BACKCMD) { ++#ifdef USE_GLIBC_STDIO ++ if (__closememout()) { ++ error( ++ "__closememout() failed: %s", ++ strerror(errno) ++ ); ++ } ++#endif + backcmd->buf = memout.buf; ++#ifdef USE_GLIBC_STDIO ++ backcmd->nleft = memout.bufsize; ++#else + backcmd->nleft = memout.nextc - memout.buf; ++#endif + memout.buf = NULL; + } ++#endif + } else { + #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); + envp = environment(); +- shellexec(argv, envp, pathval(), cmdentry.u.index); ++ shellexec(argv, envp, path, cmdentry.u.index); + } ++ if (flags & EV_EXIT) ++ exraise(EXEXIT); + goto out; + + parent: /* parent process gets here (if we forked) */ +- if (mode == 0) { /* argument to fork */ +- INTOFF; ++ if (mode == FORK_FG) { /* argument to fork */ + exitstatus = waitforjob(jp); +- INTON; +- } else if (mode == 2) { ++#ifdef notyet ++ } else if (mode == FORK_NOJOB) { + backcmd->fd = pip[0]; + close(pip[1]); + backcmd->jp = jp; ++#endif + } ++ INTON; + + out: ++ popredir(redir); + if (lastarg) + setvar("_", lastarg, 0); + popstackmark(&smark); +- +- if (eflag && exitstatus && !(flags & EV_TESTED)) +- exitshell(exitstatus); + } + + +@@ -897,8 +1038,7 @@ + /* + * 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 +- * the child. The check for "goodname" is an overly conservative +- * check that the name will not be subject to expansion. ++ * the child. + */ + + STATIC void +@@ -908,9 +1048,7 @@ + struct cmdentry entry; + + if (n->type == NCMD && n->ncmd.args) +- if (goodname(n->ncmd.args->narg.text)) +- find_command(n->ncmd.args->narg.text, &entry, 0, +- pathval()); ++ find_command(n->ncmd.args->narg.text, &entry, 0, pathval()); + } + + +@@ -930,7 +1068,6 @@ + int argc; + char **argv; + { +- listsetvar(cmdenviron); + /* + * Preserve exitstatus of a previous possible redirection + * as POSIX mandates +@@ -957,6 +1094,8 @@ + { + int n = argc > 1 ? number(argv[1]) : 1; + ++ if (n <= 0) ++ error(illnum, argv[1]); + if (n > loopnest) + n = loopnest; + if (n > 0) { +@@ -1016,14 +1155,18 @@ + char **argv; + { + if (argc > 1) { +- struct strlist *sp; +- + iflag = 0; /* exit on error */ + mflag = 0; + optschanged(); +- for (sp = cmdenviron; sp ; sp = sp->next) +- setvareq(sp->text, VEXPORT|VSTACK); + shellexec(argv + 1, environment(), pathval(), 0); + } + return 0; + } ++ ++STATIC void ++eprintlist(struct strlist *sp) ++{ ++ for (; sp; sp = sp->next) { ++ outfmt(&errout, " %s",sp->text); ++ } ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/exec.c bin_NetBSD-1.6release/src/bin/sh/exec.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/exec.c 2001-02-05 11:15:30.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/exec.c 2003-02-08 14:35:42.000000000 +0000 +@@ -51,6 +51,9 @@ + #include <fcntl.h> + #include <errno.h> + #include <stdlib.h> ++#include <sysexits.h> ++#include <stdbool.h> ++#include <paths.h> + + /* + * When commands are first encountered, they are entered in a hash table. +@@ -99,19 +102,21 @@ + + STATIC struct tblentry *cmdtable[CMDTABLESIZE]; + STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */ +-int exerrno = 0; /* Last exec error */ ++int exerrno; /* Last exec error */ + + + STATIC void tryexec __P((char *, char **, char **)); ++#if !defined(BSD) && !defined(linux) + STATIC void execinterp __P((char **, char **)); ++#endif + STATIC void printentry __P((struct tblentry *, int)); + STATIC void clearcmdentry __P((int)); + STATIC struct tblentry *cmdlookup __P((char *, int)); + STATIC void delete_cmd_entry __P((void)); ++STATIC int describe_command __P((struct output *, char *, int)); ++STATIC int path_change __P((const char *, int *)); + + +-extern char *const parsekwd[]; +- + /* + * Exec a program. Never returns. If you change this routine, you may + * have to change the find_command routine as well. +@@ -126,6 +131,7 @@ + char *cmdname; + int e; + ++ clearredir(1); + if (strchr(argv[0], '/') != NULL) { + tryexec(argv[0], argv, envp); + e = errno; +@@ -164,11 +170,12 @@ + char **argv; + char **envp; + { +- int e; +-#ifndef BSD ++ int repeated = 0; ++#if !defined(BSD) && !defined(linux) + char *p; + #endif + ++repeat: + #ifdef SYSV + do { + execve(cmd, argv, envp); +@@ -176,103 +183,22 @@ + #else + execve(cmd, argv, envp); + #endif +- e = errno; +- if (e == ENOEXEC) { +- 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); +- } +- 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(argv, envp) +- char **argv, **envp; +- { +- int n; +- char *inp; +- char *outp; +- char c; +- char *p; ++ if (repeated++) { ++ ckfree(argv); ++ } else if (errno == ENOEXEC) { + 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:; ++ for (ap = argv; *ap; ap++) ++ ; ++ ap = new = ckmalloc((ap - argv + 2) * sizeof(char *)); ++ *ap++ = cmd = _PATH_BSHELL; ++ while ((*ap++ = *argv++)) ++ ; ++ argv = new; ++ goto repeat; + } +- 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 + + + +@@ -296,7 +222,7 @@ + const char *p; + char *q; + const char *start; +- int len; ++ size_t len; + + if (*path == NULL) + return NULL; +@@ -345,6 +271,7 @@ + while ((c = nextopt("rv")) != '\0') { + if (c == 'r') { + clearcmdentry(0); ++ return 0; + } else if (c == 'v') { + verbose++; + } +@@ -352,27 +279,29 @@ + if (*argptr == NULL) { + for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { + for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { ++ if (cmdp->cmdtype != CMDBUILTIN) { + printentry(cmdp, verbose); + } + } ++ } + return 0; + } ++ c = 0; + while ((name = *argptr) != NULL) { + if ((cmdp = cmdlookup(name, 0)) != NULL + && (cmdp->cmdtype == CMDNORMAL + || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) + delete_cmd_entry(); + find_command(name, &entry, DO_ERR, pathval()); +- if (verbose) { +- if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */ ++ if (entry.cmdtype == CMDUNKNOWN) c = 1; ++ else if (verbose) { + cmdp = cmdlookup(name, 0); +- printentry(cmdp, verbose); +- } ++ if (cmdp) printentry(cmdp, verbose); + flushall(); + } + argptr++; + } +- return 0; ++ return c; + } + + +@@ -399,9 +328,8 @@ + out1fmt("function %s", cmdp->cmdname); + if (verbose) { + INTOFF; +- name = commandtext(cmdp->param.func); +- out1c(' '); +- out1str(name); ++ name = commandtext(&cmdp->param.func->n); ++ out1fmt(" %s", name); + ckfree(name); + INTON; + } +@@ -410,9 +338,7 @@ + error("internal error: cmdtype %d", cmdp->cmdtype); + #endif + } +- if (cmdp->rehash) +- out1c('*'); +- out1c('\n'); ++ out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr); + } + + +@@ -433,14 +359,18 @@ + int idx; + int prev; + char *fullname; +- struct stat statb; ++ struct stat64 statb; + int e; +- int i; ++ int bltin; ++ int firstchange; ++ int updatetbl; ++ bool regular; ++ struct builtincmd *bcmd; + + /* If name contains a slash, don't use the hash table */ + if (strchr(name, '/') != NULL) { + if (act & DO_ABS) { +- while (stat(name, &statb) < 0) { ++ while (stat64(name, &statb) < 0) { + #ifdef SYSV + if (errno == EINTR) + continue; +@@ -460,23 +390,69 @@ + return; + } + ++ updatetbl = 1; ++ if (act & DO_BRUTE) { ++ firstchange = path_change(path, &bltin); ++ } else { ++ bltin = builtinloc; ++ firstchange = 9999; ++ } ++ + /* If name is in the table, and not invalidated by cd, we're done */ +- if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) ++ if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) { ++ if (cmdp->cmdtype == CMDFUNCTION) { ++ if (act & DO_NOFUN) { ++ updatetbl = 0; ++ } else { ++ goto success; ++ } ++ } else if (act & DO_BRUTE) { ++ if ((cmdp->cmdtype == CMDNORMAL && ++ cmdp->param.index >= firstchange) || ++ (cmdp->cmdtype == CMDBUILTIN && ++ ((builtinloc < 0 && bltin >= 0) ? ++ bltin : builtinloc) >= firstchange)) { ++ /* need to recompute the entry */ ++ } else { ++ goto success; ++ } ++ } else { ++ goto success; ++ } ++ } ++ ++ bcmd = find_builtin(name); ++ regular = bcmd && bcmd->flags & BUILTIN_REGULAR; ++ ++ if (regular) { ++ if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) { + goto success; ++ } ++ } else if (act & DO_BRUTE) { ++ if (firstchange == 0) { ++ updatetbl = 0; ++ } ++ } + + /* If %builtin not in path, check for builtin next */ +- if (builtinloc < 0 && (i = find_builtin(name)) >= 0) { ++ if (regular || (bltin < 0 && bcmd)) { ++builtin: ++ if (!updatetbl) { ++ entry->cmdtype = CMDBUILTIN; ++ entry->u.cmd = bcmd; ++ return; ++ } + INTOFF; + cmdp = cmdlookup(name, 1); + cmdp->cmdtype = CMDBUILTIN; +- cmdp->param.index = i; ++ cmdp->param.cmd = bcmd; + INTON; + goto success; + } + + /* We have to search path. */ + prev = -1; /* where to start */ +- if (cmdp) { /* doing a rehash */ ++ if (cmdp && cmdp->rehash) { /* doing a rehash */ + if (cmdp->cmdtype == CMDBUILTIN) + prev = builtinloc; + else +@@ -489,30 +465,31 @@ + while ((fullname = padvance(&path, name)) != NULL) { + stunalloc(fullname); + idx++; ++ if (idx >= firstchange) { ++ updatetbl = 0; ++ } + if (pathopt) { + if (prefix("builtin", pathopt)) { +- if ((i = find_builtin(name)) < 0) +- goto loop; +- INTOFF; +- cmdp = cmdlookup(name, 1); +- cmdp->cmdtype = CMDBUILTIN; +- cmdp->param.index = i; +- INTON; +- goto success; +- } else if (prefix("func", pathopt)) { ++ if ((bcmd = find_builtin(name))) { ++ goto builtin; ++ } ++ continue; ++ } else if (!(act & DO_NOFUN) && ++ prefix("func", pathopt)) { + /* handled below */ + } else { +- goto loop; /* ignore unimplemented options */ ++ continue; /* ignore unimplemented options */ + } + } + /* if rehash, don't redo absolute path names */ +- if (fullname[0] == '/' && idx <= prev) { ++ if (fullname[0] == '/' && idx <= prev && ++ idx < firstchange) { + if (idx < prev) +- goto loop; ++ continue; + TRACE(("searchexec \"%s\": no change\n", name)); + goto success; + } +- while (stat(fullname, &statb) < 0) { ++ while (stat64(fullname, &statb) < 0) { + #ifdef SYSV + if (errno == EINTR) + continue; +@@ -523,7 +500,7 @@ + } + e = EACCES; /* if we fail, this will be the error */ + if (!S_ISREG(statb.st_mode)) +- goto loop; ++ continue; + if (pathopt) { /* this is a %func directory */ + stalloc(strlen(fullname) + 1); + readcmdfile(fullname); +@@ -545,6 +522,13 @@ + } + #endif + TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); ++ /* If we aren't called with DO_BRUTE and cmdp is set, it must ++ be a function and we're being called with DO_NOFUN */ ++ if (!updatetbl) { ++ entry->cmdtype = CMDNORMAL; ++ entry->u.index = idx; ++ return; ++ } + INTOFF; + cmdp = cmdlookup(name, 1); + cmdp->cmdtype = CMDNORMAL; +@@ -554,10 +538,10 @@ + } + + /* We failed. If there was an entry for this command, delete it */ +- if (cmdp) ++ if (cmdp && updatetbl) + delete_cmd_entry(); + if (act & DO_ERR) +- outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC)); ++ warnx("%s: %s", name, errmsg(e, E_EXEC)); + entry->cmdtype = CMDUNKNOWN; + return; + +@@ -573,17 +557,16 @@ + * Search the table of builtin commands. + */ + +-int +-find_builtin(name) +- char *name; ++struct builtincmd * ++find_builtin(const char *name) + { +- const struct builtincmd *bp; ++ struct builtincmd *bp; + +- for (bp = builtincmd ; bp->name ; bp++) { +- if (*bp->name == *name && equal(bp->name, name)) +- return bp->code; +- } +- return -1; ++ bp = bsearch( ++ &name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd), ++ pstrcmp ++ ); ++ return bp; + } + + +@@ -619,37 +602,12 @@ + changepath(newval) + const char *newval; + { +- const char *old, *new; +- int idx; + int firstchange; + int bltin; + +- old = pathval(); +- new = newval; +- firstchange = 9999; /* assume no change */ +- idx = 0; +- bltin = -1; +- for (;;) { +- if (*old != *new) { +- firstchange = idx; +- if ((*old == '\0' && *new == ':') +- || (*old == ':' && *new == '\0')) +- firstchange++; +- old = new; /* ignore subsequent differences */ +- } +- if (*new == '\0') +- break; +- if (*new == '%' && bltin < 0 && prefix("builtin", new + 1)) +- bltin = idx; +- if (*new == ':') { +- idx++; +- } +- new++, old++; +- } ++ firstchange = path_change(newval, &bltin); + if (builtinloc < 0 && bltin >= 0) + builtinloc = bltin; /* zap builtins */ +- if (builtinloc >= 0 && bltin < 0) +- firstchange = 0; + clearcmdentry(firstchange); + builtinloc = bltin; + } +@@ -687,41 +645,6 @@ + } + + +-/* +- * Delete all functions. +- */ +- +-#ifdef mkinit +-MKINIT void deletefuncs __P((void)); +- +-SHELLPROC { +- deletefuncs(); +-} +-#endif +- +-void +-deletefuncs() { +- struct tblentry **tblp; +- struct tblentry **pp; +- struct tblentry *cmdp; +- +- INTOFF; +- for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { +- pp = tblp; +- while ((cmdp = *pp) != NULL) { +- if (cmdp->cmdtype == CMDFUNCTION) { +- *pp = cmdp->next; +- freefunc(cmdp->param.func); +- ckfree(cmdp); +- } else { +- pp = &cmdp->next; +- } +- } +- } +- INTON; +-} +- +- + + /* + * Locate a command in the command hash table. If "add" is nonzero, +@@ -780,6 +703,8 @@ + INTOFF; + cmdp = *lastcmdentry; + *lastcmdentry = cmdp->next; ++ if (cmdp->cmdtype == CMDFUNCTION) ++ freefunc(cmdp->param.func); + ckfree(cmdp); + INTON; + } +@@ -851,18 +776,14 @@ + * Delete a function if it exists. + */ + +-int ++void + unsetfunc(name) + char *name; + { + struct tblentry *cmdp; + +- if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) { +- freefunc(cmdp->param.func); ++ if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) + delete_cmd_entry(); +- return (0); +- } +- return (1); + } + + /* +@@ -874,74 +795,187 @@ + int argc; + char **argv; + { +- struct cmdentry entry; +- struct tblentry *cmdp; +- char * const *pp; +- struct alias *ap; + int i; + int err = 0; + + for (i = 1; i < argc; i++) { +- out1str(argv[i]); +- /* First look at the keywords */ +- for (pp = parsekwd; *pp; pp++) +- if (**pp == *argv[i] && equal(*pp, argv[i])) +- break; ++ err |= describe_command(out1, argv[i], 1); ++ } ++ return err; ++} + +- if (*pp) { +- out1str(" is a shell keyword\n"); +- continue; ++STATIC int ++describe_command(out, command, verbose) ++ struct output *out; ++ char *command; ++ int verbose; ++{ ++ struct cmdentry entry; ++ struct tblentry *cmdp; ++ const struct alias *ap; ++ const char *path = pathval(); ++ ++ if (verbose) { ++ outstr(command, out); ++ } ++ ++ /* First look at the keywords */ ++ if (findkwd(command)) { ++ outstr(verbose ? " is a shell keyword" : command, out); ++ goto out; + } + + /* Then look at the aliases */ +- if ((ap = lookupalias(argv[i], 1)) != NULL) { +- out1fmt(" is an alias for %s\n", ap->val); +- continue; ++ if ((ap = lookupalias(command, 0)) != NULL) { ++ if (verbose) { ++ outfmt(out, " is an alias for %s", ap->val); ++ } else { ++ outstr("alias ", out); ++ printalias(ap); ++ return 0; ++ } ++ goto out; + } + + /* Then check if it is a tracked alias */ +- if ((cmdp = cmdlookup(argv[i], 0)) != NULL) { ++ if ((cmdp = cmdlookup(command, 0)) != NULL) { + entry.cmdtype = cmdp->cmdtype; + entry.u = cmdp->param; +- } +- else { ++ } else { + /* Finally use brute force */ +- find_command(argv[i], &entry, DO_ABS, pathval()); ++ find_command(command, &entry, DO_ABS, path); + } + + switch (entry.cmdtype) { + case CMDNORMAL: { +- if (strchr(argv[i], '/') == NULL) { +- const char *path = pathval(); +- char *name; + int j = entry.u.index; ++ char *p; ++ if (j == -1) { ++ p = command; ++ } else { + do { +- name = padvance(&path, argv[i]); +- stunalloc(name); ++ p = padvance(&path, command); ++ stunalloc(p); + } while (--j >= 0); +- out1fmt(" is%s %s\n", +- cmdp ? " a tracked alias for" : "", name); ++ } ++ if (verbose) { ++ outfmt( ++ out, " is%s %s", ++ cmdp ? " a tracked alias for" : nullstr, p ++ ); + } else { +- if (access(argv[i], X_OK) == 0) +- out1fmt(" is %s\n", argv[i]); +- else +- out1fmt(": %s\n", strerror(errno)); ++ outstr(p, out); + } + break; + } ++ + case CMDFUNCTION: +- out1str(" is a shell function\n"); ++ if (verbose) { ++ outstr(" is a shell function", out); ++ } else { ++ outstr(command, out); ++ } + break; + + case CMDBUILTIN: +- out1str(" is a shell builtin\n"); ++ if (verbose) { ++ outfmt( ++ out, " is a %sshell builtin", ++ entry.u.cmd->flags & BUILTIN_SPECIAL ? ++ "special " : nullstr ++ ); ++ } else { ++ outstr(command, out); ++ } + break; + + default: +- out1str(": not found\n"); +- err |= 127; ++ if (verbose) { ++ outstr(": not found\n", out); ++ } ++ return 127; ++ } ++ ++out: ++ outc('\n', out); ++ return 0; ++} ++ ++int ++commandcmd(argc, argv) ++ int argc; ++ char **argv; ++{ ++ int c; ++ int default_path = 0; ++ int verify_only = 0; ++ int verbose_verify_only = 0; ++ ++ while ((c = nextopt("pvV")) != '\0') ++ switch (c) { ++ case 'p': ++ default_path = 1; + break; ++ case 'v': ++ verify_only = 1; ++ break; ++ case 'V': ++ verbose_verify_only = 1; ++ break; ++ default: ++ outfmt(out2, ++"command: nextopt returned character code 0%o\n", c); ++ return EX_SOFTWARE; + } ++ ++ if (default_path + verify_only + verbose_verify_only > 1 || ++ !*argptr) { ++ outfmt(out2, ++"command [-p] command [arg ...]\n"); ++ outfmt(out2, ++"command {-v|-V} command\n"); ++ return EX_USAGE; + } +- return err; ++ ++ if (verify_only || verbose_verify_only) { ++ return describe_command(out1, *argptr, verbose_verify_only); ++ } ++ ++ return 0; ++} ++ ++STATIC int ++path_change(newval, bltin) ++ const char *newval; ++ int *bltin; ++{ ++ const char *old, *new; ++ int idx; ++ int firstchange; ++ ++ old = pathval(); ++ new = newval; ++ firstchange = 9999; /* assume no change */ ++ idx = 0; ++ *bltin = -1; ++ for (;;) { ++ if (*old != *new) { ++ firstchange = idx; ++ if ((*old == '\0' && *new == ':') ++ || (*old == ':' && *new == '\0')) ++ firstchange++; ++ old = new; /* ignore subsequent differences */ ++ } ++ if (*new == '\0') ++ break; ++ if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1)) ++ *bltin = idx; ++ if (*new == ':') { ++ idx++; ++ } ++ new++, old++; ++ } ++ if (builtinloc >= 0 && *bltin < 0) ++ firstchange = 0; ++ return firstchange; + } +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/exec.h bin_NetBSD-1.6release/src/bin/sh/exec.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/exec.h 2000-05-23 11:03:19.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/exec.h 2003-02-08 14:35:42.000000000 +0000 +@@ -49,13 +49,16 @@ + int cmdtype; + union param { + int index; +- union node *func; ++ struct funcnode *func; ++ const struct builtincmd *cmd; + } u; + }; + + + #define DO_ERR 1 /* find_command prints errors */ + #define DO_ABS 2 /* find_command checks absolute paths */ ++#define DO_NOFUN 4 /* find_command ignores functions */ ++#define DO_BRUTE 8 /* find_command ignores hash table */ + + extern const char *pathopt; /* set by padvance */ + extern int exerrno; /* last exec error */ +@@ -65,12 +68,12 @@ + char *padvance __P((const char **, const char *)); + int hashcmd __P((int, char **)); + void find_command __P((char *, struct cmdentry *, int, const char *)); +-int find_builtin __P((char *)); ++struct builtincmd *find_builtin __P((const char *)); + void hashcd __P((void)); + void changepath __P((const char *)); +-void deletefuncs __P((void)); + void getcmdentry __P((char *, struct cmdentry *)); + void addcmdentry __P((char *, struct cmdentry *)); + void defun __P((char *, union node *)); +-int unsetfunc __P((char *)); ++void unsetfunc __P((char *)); + int typecmd __P((int, char **)); ++int commandcmd __P((int, char **)); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/expand.c bin_NetBSD-1.6release/src/bin/sh/expand.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/expand.c 2002-05-16 11:41:20.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/expand.c 2003-02-08 14:35:42.000000000 +0000 +@@ -54,6 +54,15 @@ + #include <pwd.h> + #include <stdlib.h> + #include <stdio.h> ++#include <limits.h> ++#if defined(__GLIBC__) ++#if !defined(FNMATCH_BROKEN) ++#include <fnmatch.h> ++#if !defined(GLOB_BROKEN) ++#include <glob.h> ++#endif ++#endif ++#endif + + /* + * Routines to expand arguments to commands. We have to deal with +@@ -78,6 +87,15 @@ + #include "show.h" + + /* ++ * _rmescape() flags ++ */ ++#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ ++#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ ++#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ ++#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ ++#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ ++ ++/* + * Structure specifying which parts of the string should be searched + * for IFS characters. + */ +@@ -89,34 +107,84 @@ + int nulonly; /* search for nul bytes only */ + }; + +- +-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 */ ++/* output of current string */ ++static char *expdest; ++/* list of back quote expressions */ ++static struct nodelist *argbackq; ++/* first struct in list of ifs regions */ ++static struct ifsregion ifsfirst; ++/* last struct in list */ ++static struct ifsregion *ifslastp; ++/* holds expanded arg list */ ++static struct arglist exparg; + + STATIC void argstr __P((char *, int)); + STATIC char *exptilde __P((char *, int)); + STATIC void expbackq __P((union node *, int, int)); +-STATIC int subevalvar __P((char *, char *, int, int, int, int)); ++STATIC const char *subevalvar __P((char *, char *, int, int, int, int, int)); + STATIC char *evalvar __P((char *, int)); + STATIC int varisset __P((char *, int)); ++STATIC void strtodest __P((const char *, const char *, int)); ++STATIC void memtodest __P((const char *, size_t, const char *, int)); + STATIC void varvalue __P((char *, int, int)); + STATIC void recordregion __P((int, int, int)); + STATIC void removerecordregions __P((int)); + STATIC void ifsbreakup __P((char *, struct arglist *)); + STATIC void ifsfree __P((void)); + STATIC void expandmeta __P((struct strlist *, int)); ++#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) ++STATIC void addglob __P((const glob_t *)); ++#else + STATIC void expmeta __P((char *, char *)); ++#endif + STATIC void addfname __P((char *)); ++#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) + STATIC struct strlist *expsort __P((struct strlist *)); + STATIC struct strlist *msort __P((struct strlist *, int)); +-STATIC int pmatch __P((char *, char *, int)); +-STATIC char *cvtnum __P((int, char *)); ++#endif ++STATIC int patmatch __P((char *, const char *)); ++#if !defined(__GLIBC__) || defined(FNMATCH_BROKEN) ++STATIC int pmatch __P((const char *, const char *)); ++#else ++#define pmatch(a, b) !fnmatch((a), (b), 0) ++#endif ++STATIC int cvtnum __P((long)); ++STATIC size_t esclen __P((const char *, const char *)); ++STATIC char *scanleft __P((char *, char *, char *, char *, int, int)); ++STATIC char *scanright __P((char *, char *, char *, char *, int, int)); ++static void varunset(const char *, const char *, const char *, int) ++ __attribute__((__noreturn__)); + + extern int oexitstatus; + ++ ++/* ++ * Prepare a pattern for a glob(3) call. ++ * ++ * Returns an stalloced string. ++ */ ++ ++STATIC inline char * ++preglob(const char *pattern, int quoted, int flag) { ++ flag |= RMESCAPE_GLOB; ++ if (quoted) { ++ flag |= RMESCAPE_QUOTED; ++ } ++ return _rmescapes((char *)pattern, flag); ++} ++ ++ ++STATIC size_t ++esclen(const char *start, const char *p) { ++ size_t esc = 0; ++ ++ while (p > start && *--p == CTLESC) { ++ esc++; ++ } ++ return esc; ++} ++ ++ + /* + * Expand shell variables and backquotes inside a here document. + */ +@@ -196,64 +264,126 @@ + char *p; + int flag; + { +- char c; ++ static const char spclchars[] = { ++ '=', ++ ':', ++ CTLQUOTEMARK, ++ CTLENDVAR, ++ CTLESC, ++ CTLVAR, ++ CTLBACKQ, ++ CTLBACKQ | CTLQUOTE, ++ CTLENDARI, ++ 0 ++ }; ++ const char *reject = spclchars; ++ int c; + int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ +- int firsteq = 1; ++ int breakall = flag & EXP_WORD; ++ int inquotes; ++ size_t length; ++ int startloc; + +- if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) ++ if (!(flag & EXP_VARTILDE)) { ++ reject += 2; ++ } else if (flag & EXP_VARTILDE2) { ++ reject++; ++ } ++ inquotes = 0; ++ length = 0; ++ if (flag & EXP_TILDE) { ++ flag &= ~EXP_TILDE; ++tilde: + p = exptilde(p, flag); ++ } ++start: ++ startloc = expdest - stackblock(); + for (;;) { +- switch (c = *p++) { ++ length += strcspn(p + length, reject); ++ c = p[length]; ++ if ((c && !(c & 0x80)) || c == CTLENDARI) { ++ /* c == '=' || c == ':' || c == CTLENDARI */ ++ length++; ++ } ++ if (length > 0) { ++ int newloc; ++ expdest = stnputs(p, length, expdest); ++ newloc = expdest - stackblock(); ++ if (breakall && !inquotes && newloc > startloc) { ++ recordregion(startloc, newloc, 0); ++ } ++ startloc = newloc; ++ } ++ p += length + 1; ++ length = 0; ++ ++ switch (c) { + case '\0': ++ goto breakloop; ++ case '=': ++ if (flag & EXP_VARTILDE2) { ++ p--; ++ continue; ++ } ++ flag |= EXP_VARTILDE2; ++ reject++; ++ /* fall through */ ++ case ':': ++ /* ++ * sort of a hack - expand tildes in variable ++ * assignments (after the first '=' and after ':'s). ++ */ ++ if (*--p == '~') { ++ goto tilde; ++ } ++ continue; ++ } ++ ++ switch (c) { + case CTLENDVAR: /* ??? */ + goto breakloop; + case CTLQUOTEMARK: + /* "$@" syntax adherence hack */ +- if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=') +- break; +- if ((flag & EXP_FULL) != 0) +- STPUTC(c, expdest); ++ if ( ++ !inquotes && ++ !memcmp(p, dolatstr, DOLATSTRLEN) && ++ (p[4] == CTLQUOTEMARK || ( ++ p[4] == CTLENDVAR && ++ p[5] == CTLQUOTEMARK ++ )) ++ ) { ++ p = evalvar(p + 1, flag) + 1; ++ goto start; ++ } ++ inquotes = !inquotes; ++addquote: ++ if (quotes) { ++ p--; ++ length++; ++ startloc++; ++ } + break; + case CTLESC: +- if (quotes) +- STPUTC(c, expdest); +- c = *p++; +- STPUTC(c, expdest); +- break; ++ startloc++; ++ length++; ++ goto addquote; + case CTLVAR: + p = evalvar(p, flag); +- break; ++ goto start; + case CTLBACKQ: ++ c = 0; + case CTLBACKQ|CTLQUOTE: +- expbackq(argbackq->n, c & CTLQUOTE, flag); ++ expbackq(argbackq->n, c, quotes); + argbackq = argbackq->next; +- break; ++ goto start; + case CTLENDARI: +- expari(flag); +- break; +- case ':': +- case '=': +- /* +- * sort of a hack - expand tildes in variable +- * assignments (after the first '=' and after ':'s). +- */ +- STPUTC(c, expdest); +- if (flag & EXP_VARTILDE && *p == '~') { +- if (c == '=') { +- if (firsteq) +- firsteq = 0; +- else +- break; +- } +- p = exptilde(p, flag); +- } +- break; +- default: +- STPUTC(c, expdest); ++ p--; ++ expari(quotes); ++ goto start; + } + } +-breakloop:; +- return; ++breakloop: ++ ; + } + + STATIC char * +@@ -262,11 +392,21 @@ + int flag; + { + char c, *startp = p; ++ char *name; + struct passwd *pw; + const char *home; + int quotes = flag & (EXP_FULL | EXP_CASE); ++ int startloc; + +- while ((c = *p) != '\0') { ++ if (*p == CTLESC && (flag & EXP_QWORD)) { ++ p++; ++ } ++ if (*p != '~') { ++ return startp; ++ } ++ name = p + 1; ++ ++ while ((c = *++p) != '\0') { + switch(c) { + case CTLESC: + return (startp); +@@ -277,28 +417,26 @@ + goto done; + break; + case '/': ++ case CTLENDVAR: + goto done; + } +- p++; + } + done: + *p = '\0'; +- if (*(startp+1) == '\0') { +- if ((home = lookupvar("HOME")) == NULL) ++ if (*name == '\0') { ++ if ((home = lookupvar(homestr)) == NULL) + goto lose; + } else { +- if ((pw = getpwnam(startp+1)) == NULL) ++ if ((pw = getpwnam(name)) == NULL) + goto lose; + home = pw->pw_dir; + } + if (*home == '\0') + goto lose; + *p = c; +- while ((c = *home++) != '\0') { +- if (quotes && SQSYNTAX[(int)c] == CCTL) +- STPUTC(CTLESC, expdest); +- STPUTC(c, expdest); +- } ++ startloc = expdest - stackblock(); ++ strtodest(home, SQSYNTAX, quotes); ++ recordregion(startloc, expdest - stackblock(), 0); + return (p); + lose: + *p = c; +@@ -352,61 +490,60 @@ + * evaluate, place result in (backed up) result, adjust string position. + */ + void +-expari(flag) +- int flag; ++expari(quotes) ++ int quotes; + { + char *p, *start; +- int result; + int begoff; +- int quotes = flag & (EXP_FULL | EXP_CASE); +- int quoted; ++ int flag; ++ int len; + + /* 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 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. ++ * efficiency. Next we scan backwards looking for the ++ * start of arithmetic. + */ +-#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10 +-#error "integers with more than 10 digits are not supported" +-#endif +- CHECKSTRSPACE(12 - 2, expdest); +- USTPUTC('\0', expdest); + start = stackblock(); + p = expdest - 1; +- while (*p != CTLARI && p >= start) +- --p; +- if (*p != CTLARI) ++ *p = '\0'; ++ p--; ++ do { ++ int esc; ++ ++ while (*p != CTLARI) { ++ p--; ++#ifdef DEBUG ++ if (p < start) { + error("missing CTLARI (shouldn't happen)"); +- if (p > start && *(p-1) == CTLESC) +- for (p = start; *p != CTLARI; p++) +- if (*p == CTLESC) +- p++; ++ } ++#endif ++ } ++ ++ esc = esclen(start, p); ++ if (!(esc % 2)) { ++ break; ++ } ++ ++ p -= esc + 1; ++ } while (1); + +- if (p[1] == '"') +- quoted=1; +- else +- quoted=0; + begoff = p - start; ++ + removerecordregions(begoff); ++ ++ flag = p[1]; ++ ++ expdest = p; ++ + if (quotes) +- rmescapes(p+2); +- result = arith(p+2); +- fmtstr(p, 12, "%d", result); ++ rmescapes(p + 2); + +- while (*p++) +- ; ++ len = cvtnum(arith(p + 2)); + +- if (quoted == 0) +- recordregion(begoff, p - 1 - start, 0); +- result = expdest - p + 1; +- STADJUST(-result, expdest); ++ if (flag != '"') ++ recordregion(begoff, begoff + len, 0); + } + + +@@ -415,42 +552,47 @@ + */ + + STATIC void +-expbackq(cmd, quoted, flag) ++expbackq(cmd, quoted, quotes) + union node *cmd; + int quoted; +- int flag; ++ int quotes; + { + struct backcmd in; + int i; + char buf[128]; + char *p; + char *dest = expdest; +- struct ifsregion saveifs, *savelastp; ++ struct ifsregion saveifs; ++ struct ifsregion *savelastp; + struct nodelist *saveargbackq; +- char lastc; + int startloc = dest - stackblock(); + char const *syntax = quoted? DQSYNTAX : BASESYNTAX; + int saveherefd; +- int quotes = flag & (EXP_FULL | EXP_CASE); + +- INTOFF; ++ in.fd = -1; ++ in.buf = 0; ++ in.jp = 0; ++ + saveifs = ifsfirst; + savelastp = ifslastp; + saveargbackq = argbackq; + saveherefd = herefd; + herefd = -1; +- p = grabstackstr(dest); +- evalbackcmd(cmd, &in); +- ungrabstackstr(p, dest); ++ ++ INTOFF; ++ evalbackcmd(cmd, (struct backcmd *) &in); + ifsfirst = saveifs; + ifslastp = savelastp; + argbackq = saveargbackq; + herefd = saveherefd; + + p = in.buf; +- lastc = '\0'; ++ i = in.nleft; ++ if (i == 0) ++ goto read; + for (;;) { +- if (--in.nleft < 0) { ++ memtodest(p, i, syntax, quotes); ++read: + if (in.fd < 0) + break; + while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR); +@@ -458,18 +600,12 @@ + if (i <= 0) + break; + p = buf; +- in.nleft = i - 1; +- } +- lastc = *p++; +- if (lastc != '\0') { +- if (quotes && syntax[(int)lastc] == CCTL) +- STPUTC(CTLESC, dest); +- STPUTC(lastc, dest); +- } + } + ++ dest = expdest; ++ + /* Eat all trailing newlines */ +- for (p--; lastc == '\n'; lastc = *--p) ++ for (; dest > stackblock() && dest[-1] == '\n';) + STUNPUTC(dest); + + if (in.fd >= 0) +@@ -478,6 +614,7 @@ + ckfree(in.buf); + if (in.jp) + exitstatus = waitforjob(in.jp); ++ INTON; + if (quoted == 0) + recordregion(startloc, dest - stackblock(), 0); + TRACE(("evalbackq: size=%d: \"%.*s\"\n", +@@ -485,131 +622,149 @@ + (dest - stackblock()) - startloc, + stackblock() + startloc)); + expdest = dest; +- INTON; + } + + ++STATIC char * ++scanleft( ++ char *startp, char *rmesc, char *rmescend, char *str, int quotes, ++ int zero ++) { ++ char *loc; ++ char *loc2; ++ char c; ++ ++ loc = startp; ++ loc2 = rmesc; ++ do { ++ int match; ++ const char *s = loc2; ++ c = *loc2; ++ if (zero) { ++ *loc2 = '\0'; ++ s = rmesc; ++ } ++ match = pmatch(str, s); ++ *loc2 = c; ++ if (match) ++ return loc; ++ if (quotes && *loc == CTLESC) ++ loc++; ++ loc++; ++ loc2++; ++ } while (c); ++ return 0; ++} ++ ++ ++STATIC char * ++scanright( ++ char *startp, char *rmesc, char *rmescend, char *str, int quotes, ++ int zero ++) { ++ int esc = 0; ++ char *loc; ++ char *loc2; + +-STATIC int +-subevalvar(p, str, strloc, subtype, startloc, varflags) ++ for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) { ++ int match; ++ char c = *loc2; ++ const char *s = loc2; ++ if (zero) { ++ *loc2 = '\0'; ++ s = rmesc; ++ } ++ match = pmatch(str, s); ++ *loc2 = c; ++ if (match) ++ return loc; ++ loc--; ++ if (quotes) { ++ if (--esc < 0) { ++ esc = esclen(startp, loc); ++ } ++ if (esc % 2) { ++ esc--; ++ loc--; ++ } ++ } ++ } ++ return 0; ++} ++ ++STATIC const char * ++subevalvar(p, str, strloc, subtype, startloc, varflags, quotes) + char *p; + char *str; + int strloc; + int subtype; + int startloc; + int varflags; ++ int quotes; + { + char *startp; +- char *loc = NULL; +- char *q; +- int c = 0; ++ char *loc; + int saveherefd = herefd; + struct nodelist *saveargbackq = argbackq; + int amount; ++ char *rmesc, *rmescend; ++ int zero; ++ char *(*scan)(char *, char *, char *, char *, int , int); + + herefd = -1; +- argstr(p, 0); +- STACKSTRNUL(expdest); ++ argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); ++ STPUTC('\0', expdest); + herefd = saveherefd; + argbackq = saveargbackq; + startp = stackblock() + startloc; +- if (str == NULL) +- str = stackblock() + strloc; + + switch (subtype) { + case VSASSIGN: + setvar(str, startp, 0); + amount = startp - expdest; + STADJUST(amount, expdest); +- varflags &= ~VSNUL; +- if (c != 0) +- *loc = c; +- return 1; ++ return startp; + + case VSQUESTION: +- if (*p != CTLENDVAR) { +- outfmt(&errout, "%s\n", startp); +- error((char *)NULL); +- } +- error("%.*s: parameter %snot set", p - str - 1, +- str, (varflags & VSNUL) ? "null or " +- : nullstr); ++ varunset(p, str, startp, varflags); + /* NOTREACHED */ +- +- case VSTRIMLEFT: +- for (loc = startp; loc < str; loc++) { +- c = *loc; +- *loc = '\0'; +- if (patmatch(str, startp, varflags & VSQUOTE)) +- goto recordleft; +- *loc = c; +- if ((varflags & VSQUOTE) && *loc == CTLESC) +- loc++; + } +- return 0; + +- case VSTRIMLEFTMAX: +- for (loc = str - 1; loc >= startp;) { +- c = *loc; +- *loc = '\0'; +- if (patmatch(str, startp, varflags & VSQUOTE)) +- goto recordleft; +- *loc = c; +- loc--; +- if ((varflags & VSQUOTE) && loc > startp && +- *(loc - 1) == CTLESC) { +- for (q = startp; q < loc; q++) +- if (*q == CTLESC) +- q++; +- if (q > loc) +- loc--; +- } +- } +- return 0; ++ subtype -= VSTRIMRIGHT; ++#ifdef DEBUG ++ if (subtype < 0 || subtype > 3) ++ abort(); ++#endif + +- case VSTRIMRIGHT: +- for (loc = str - 1; loc >= startp;) { +- if (patmatch(str, loc, varflags & VSQUOTE)) +- goto recordright; +- loc--; +- if ((varflags & VSQUOTE) && loc > startp && +- *(loc - 1) == CTLESC) { +- for (q = startp; q < loc; q++) +- if (*q == CTLESC) +- q++; +- if (q > loc) +- loc--; ++ rmesc = startp; ++ rmescend = stackblock() + strloc; ++ if (quotes) { ++ rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); ++ if (rmesc != startp) { ++ rmescend = expdest; ++ startp = stackblock() + startloc; + } + } +- return 0; ++ rmescend--; ++ str = stackblock() + strloc; ++ preglob(str, varflags & VSQUOTE, 0); + +- case VSTRIMRIGHTMAX: +- for (loc = startp; loc < str - 1; loc++) { +- if (patmatch(str, loc, varflags & VSQUOTE)) +- goto recordright; +- if ((varflags & VSQUOTE) && *loc == CTLESC) +- loc++; +- } +- return 0; ++ /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ ++ zero = subtype >> 1; ++ /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ ++ scan = (subtype & 1) ^ zero ? scanleft : scanright; + +- default: +- abort(); ++ loc = scan(startp, rmesc, rmescend, str, quotes, zero); ++ if (loc) { ++ if (zero) { ++ memmove(startp, loc, str - loc); ++ loc = startp + (str - loc) - 1; + } +- +-recordleft: +- *loc = c; +- amount = ((str - 1) - (loc - startp)) - expdest; +- STADJUST(amount, expdest); +- while (loc != str - 1) +- *startp++ = *loc++; +- return 1; +- +-recordright: ++ *loc = '\0'; + amount = loc - expdest; + STADJUST(amount, expdest); +- STPUTC('\0', expdest); +- STADJUST(-1, expdest); +- return 1; ++ } ++ return loc; + } + + +@@ -617,120 +772,129 @@ + * Expand a variable, and return a pointer to the next character in the + * input string. + */ +- + STATIC char * + evalvar(p, flag) + char *p; +- int flag; ++ const int flag; + { + int subtype; + int varflags; + char *var; +- char *val; + int patloc; + int c; + int set; +- int special; + int startloc; +- int varlen; ++ size_t varlen; + int easy; +- int quotes = flag & (EXP_FULL | EXP_CASE); ++ int quotes; ++ int quoted; + ++ quotes = flag & (EXP_FULL | EXP_CASE); + varflags = *p++; + subtype = varflags & VSTYPE; ++ quoted = varflags & VSQUOTE; + var = p; +- special = 0; +- if (! is_name(*p)) +- special = 1; +- p = strchr(p, '=') + 1; +-again: /* jump here after setting a variable with ${var=text} */ +- if (special) { +- set = varisset(var, varflags & VSNUL); +- val = NULL; +- } else { +- val = lookupvar(var); +- if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { +- val = NULL; +- set = 0; +- } else +- set = 1; +- } ++ easy = (!quoted || (*var == '@' && shellparam.nparam)); + varlen = 0; + startloc = expdest - stackblock(); +- if (!set && uflag) +- switch (subtype) { +- case VSNORMAL: +- case VSTRIMLEFT: +- case VSTRIMLEFTMAX: +- case VSTRIMRIGHT: +- case VSTRIMRIGHTMAX: +- case VSLENGTH: +- error("%.*s: parameter not set", p - var - 1, var); +- /* NOTREACHED */ +- } +- if (set && subtype != VSPLUS) { +- /* insert the value of the variable */ +- if (special) { +- varvalue(var, varflags & VSQUOTE, flag & EXP_FULL); ++ p = strchr(p, '=') + 1; ++ ++ if (!is_name(*var)) { ++ set = varisset(var, varflags & VSNUL); ++ set--; ++ if (subtype == VSPLUS) ++ goto vsplus; ++ if (++set) { ++ varvalue(var, quoted, flag); + if (subtype == VSLENGTH) { + varlen = expdest - stackblock() - startloc; + STADJUST(-varlen, expdest); ++ goto vslen; ++ } + } + } else { +- char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX +- : BASESYNTAX; ++ const char *val; ++again: ++ /* jump here after setting a variable with ${var=text} */ ++ val = lookupvar(var); ++ set = !val || ((varflags & VSNUL) && !*val); ++ if (subtype == VSPLUS) ++ goto vsplus; ++ if (--set) { ++ varlen = strlen(val); ++ if (subtype == VSLENGTH) ++ goto vslen; ++ memtodest( ++ val, varlen, quoted ? DQSYNTAX : BASESYNTAX, ++ quotes ++ ); ++ } ++ } + +- if (subtype == VSLENGTH) { +- for (;*val; val++) +- varlen++; ++ ++ if (subtype == VSMINUS) { ++vsplus: ++ if (!set) { ++ argstr( ++ p, flag | EXP_TILDE | ++ (quoted ? EXP_QWORD : EXP_WORD) ++ ); ++ goto end; + } +- else { +- while (*val) { +- if (quotes && syntax[(int)*val] == CCTL) +- STPUTC(CTLESC, expdest); +- STPUTC(*val++, expdest); ++ if (easy) ++ goto record; ++ goto end; + } + ++ if (subtype == VSASSIGN || subtype == VSQUESTION) { ++ if (!set) { ++ if (subevalvar(p, var, 0, subtype, startloc, ++ varflags, 0)) { ++ varflags &= ~VSNUL; ++ /* ++ * Remove any recorded regions beyond ++ * start of variable ++ */ ++ removerecordregions(startloc); ++ goto again; + } ++ goto end; + } ++ if (easy) ++ goto record; ++ goto end; + } + +- if (subtype == VSPLUS) +- set = ! set; +- +- easy = ((varflags & VSQUOTE) == 0 || +- (*var == '@' && shellparam.nparam != 1)); +- ++ if (!set && uflag) ++ varunset(p, var, 0, 0); + +- switch (subtype) { +- case VSLENGTH: +- expdest = cvtnum(varlen, expdest); ++ if (subtype == VSLENGTH) { ++vslen: ++ cvtnum(varlen); + goto record; ++ } + +- case VSNORMAL: ++ if (subtype == VSNORMAL) { + if (!easy) +- break; ++ goto end; + record: +- recordregion(startloc, expdest - stackblock(), +- varflags & VSQUOTE); +- break; +- +- case VSPLUS: +- case VSMINUS: +- if (!set) { +- argstr(p, flag); +- break; ++ recordregion(startloc, expdest - stackblock(), quoted); ++ goto end; + } +- if (easy) +- goto record; +- break; + ++#ifdef DEBUG ++ switch (subtype) { + case VSTRIMLEFT: + case VSTRIMLEFTMAX: + case VSTRIMRIGHT: + case VSTRIMRIGHTMAX: +- if (!set) + break; ++ default: ++ abort(); ++ } ++#endif ++ ++ if (set) { + /* + * Terminate the string and start recording the pattern + * right after it +@@ -738,37 +902,16 @@ + STPUTC('\0', expdest); + patloc = expdest - stackblock(); + if (subevalvar(p, NULL, patloc, subtype, +- startloc, varflags) == 0) { +- int amount = (expdest - stackblock() - patloc) + 1; ++ startloc, varflags, quotes) == 0) { ++ int amount = expdest - (stackblock() + patloc - 1); + STADJUST(-amount, expdest); + } + /* Remove any recorded regions beyond start of variable */ + removerecordregions(startloc); + goto record; +- +- 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; +- } +- break; +- } +- if (easy) +- goto record; +- break; +- +- default: +- abort(); + } + ++end: + if (subtype != VSNORMAL) { /* skip to end of alternative */ + int nesting = 1; + for (;;) { +@@ -801,7 +944,7 @@ + int nulok; + { + if (*name == '!') +- return backgndpid != -1; ++ return backgndpid != 0; + else if (*name == '@' || *name == '*') { + if (*shellparam.p == NULL) + return 0; +@@ -835,37 +978,60 @@ + + + /* ++ * Put a string on the stack. ++ */ ++ ++STATIC void ++memtodest(const char *p, size_t len, const char *syntax, int quotes) { ++ char *q = expdest; ++ ++ q = makestrspace(len * 2, q); ++ ++ while (len--) { ++ int c = *p++; ++ if (!c) ++ continue; ++ if (quotes && (syntax[c] == CCTL || syntax[c] == CBACK)) ++ USTPUTC(CTLESC, q); ++ USTPUTC(c, q); ++ } ++ ++ expdest = q; ++} ++ ++ ++STATIC void ++strtodest(p, syntax, quotes) ++ const char *p; ++ const char *syntax; ++ int quotes; ++{ ++ memtodest(p, strlen(p), syntax, quotes); ++} ++ ++ ++ ++/* + * Add the value of a specialized variable to the stack string. + */ + + STATIC void +-varvalue(name, quoted, allow_split) ++varvalue(name, quoted, flags) + char *name; + int quoted; +- int allow_split; ++ int flags; + { + int num; + char *p; + int i; +- char sep; ++ int sep; ++ int sepq = 0; + char **ap; + char const *syntax; ++ int allow_split = flags & EXP_FULL; ++ int quotes = flags & (EXP_FULL | EXP_CASE); + +-#define STRTODEST(p) \ +- do {\ +- if (allow_split) { \ +- syntax = quoted? DQSYNTAX : BASESYNTAX; \ +- while (*p) { \ +- if (syntax[(int)*p] == CCTL) \ +- STPUTC(CTLESC, expdest); \ +- STPUTC(*p++, expdest); \ +- } \ +- } else \ +- while (*p) \ +- STPUTC(*p++, expdest); \ +- } while (0) +- +- ++ syntax = quoted ? DQSYNTAX : BASESYNTAX; + switch (*name) { + case '$': + num = rootpid; +@@ -879,46 +1045,44 @@ + case '!': + num = backgndpid; + numvar: +- expdest = cvtnum(num, expdest); ++ cvtnum(num); + break; + case '-': + for (i = 0 ; i < NOPTS ; i++) { +- if (optlist[i].val) +- STPUTC(optlist[i].letter, expdest); ++ if (optlist[i]) ++ STPUTC(optletters[i], expdest); + } + break; + case '@': + if (allow_split && quoted) { +- for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { +- STRTODEST(p); +- if (*ap) +- STPUTC('\0', expdest); +- } +- break; ++ sep = 1 << CHAR_BIT; ++ goto param; + } + /* fall through */ + case '*': +- if (ifsset() != 0) +- sep = ifsval()[0]; +- else +- sep = ' '; ++ sep = ifsset() ? ifsval()[0] : ' '; ++ if (quotes) { ++ sepq = (syntax[sep] == CCTL) || (syntax[sep] == CBACK); ++ } ++param: + for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { +- STRTODEST(p); +- if (*ap && sep) +- STPUTC(sep, expdest); ++ strtodest(p, syntax, quotes); ++ if (*ap && sep) { ++ p = expdest; ++ if (sepq) ++ STPUTC(CTLESC, p); ++ STPUTC(sep, p); ++ expdest = p; ++ } + } + break; + case '0': +- p = arg0; +- STRTODEST(p); ++ strtodest(arg0, syntax, quotes); + break; + default: +- if (is_digit(*name)) { + num = atoi(name); + if (num > 0 && num <= shellparam.nparam) { +- p = shellparam.p[num - 1]; +- STRTODEST(p); +- } ++ strtodest(shellparam.p[num - 1], syntax, quotes); + } + break; + } +@@ -942,11 +1106,13 @@ + if (ifslastp == NULL) { + ifsp = &ifsfirst; + } else { ++ INTOFF; + ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); ++ ifsp->next = NULL; + ifslastp->next = ifsp; ++ INTON; + } + ifslastp = ifsp; +- ifslastp->next = NULL; + ifslastp->begoff = start; + ifslastp->endoff = end; + ifslastp->nulonly = nulonly; +@@ -969,7 +1135,7 @@ + char *start; + char *p; + char *q; +- const char *ifs; ++ const char *ifs, *realifs; + int ifsspc; + int nulonly; + +@@ -977,13 +1143,13 @@ + start = string; + ifsspc = 0; + nulonly = 0; ++ realifs = ifsset() ? ifsval() : defifs; + if (ifslastp != NULL) { + ifsp = &ifsfirst; + do { + p = string + ifsp->begoff; + nulonly = ifsp->nulonly; +- ifs = nulonly ? nullstr : +- ( ifsset() ? ifsval() : " \t\n" ); ++ ifs = nulonly ? nullstr : realifs; + ifsspc = 0; + while (p < string + ifsp->endoff) { + q = p; +@@ -991,7 +1157,7 @@ + p++; + if (strchr(ifs, *p)) { + if (!nulonly) +- ifsspc = (strchr(" \t\n", *p) != NULL); ++ ifsspc = (strchr(defifs, *p) != NULL); + /* Ignore IFS whitespace at start */ + if (q == start && ifsspc) { + p++; +@@ -1015,7 +1181,7 @@ + if (strchr(ifs, *p) == NULL ) { + p = q; + break; +- } else if (strchr(" \t\n",*p) == NULL) { ++ } else if (strchr(defifs, *p) == NULL) { + if (ifsspc) { + p++; + ifsspc = 0; +@@ -1032,19 +1198,18 @@ + p++; + } + } while ((ifsp = ifsp->next) != NULL); +- if (*start || (!ifsspc && start > string && +- (nulonly || 1))) { +- sp = (struct strlist *)stalloc(sizeof *sp); +- sp->text = start; +- *arglist->lastp = sp; +- arglist->lastp = &sp->next; ++ if (nulonly) ++ goto add; + } +- } else { ++ ++ if (!*start) ++ return; ++ ++add: + sp = (struct strlist *)stalloc(sizeof *sp); + sp->text = start; + *arglist->lastp = sp; + arglist->lastp = &sp->next; +- } + } + + STATIC void +@@ -1069,7 +1234,69 @@ + * should be escapes. The results are stored in the list exparg. + */ + +-char *expdir; ++#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) ++STATIC void ++expandmeta(str, flag) ++ struct strlist *str; ++ int flag; ++{ ++ /* TODO - EXP_REDIR */ ++ ++ while (str) { ++ const char *p; ++ glob_t pglob; ++ int i; ++ ++ if (fflag) ++ goto nometa; ++ INTOFF; ++ p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); ++ i = glob(p, GLOB_NOMAGIC, 0, &pglob); ++ if (p != str->text) ++ ckfree(p); ++ switch (i) { ++ case 0: ++ if (!(pglob.gl_flags & GLOB_MAGCHAR)) ++ goto nometa2; ++ addglob(&pglob); ++ globfree(&pglob); ++ INTON; ++ break; ++ case GLOB_NOMATCH: ++nometa2: ++ globfree(&pglob); ++ INTON; ++nometa: ++ *exparg.lastp = str; ++ rmescapes(str->text); ++ exparg.lastp = &str->next; ++ break; ++ default: /* GLOB_NOSPACE */ ++ error("Out of space"); ++ } ++ str = str->next; ++ } ++} ++ ++ ++/* ++ * Add the result of glob(3) to the list. ++ */ ++ ++STATIC void ++addglob(pglob) ++ const glob_t *pglob; ++{ ++ char **p = pglob->gl_pathv; ++ ++ do { ++ addfname(*p); ++ } while (*++p); ++} ++ ++ ++#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ ++STATIC char *expdir; + + + STATIC void +@@ -1077,32 +1304,33 @@ + struct strlist *str; + int flag; + { +- char *p; +- struct strlist **savelastp; +- struct strlist *sp; +- char c; ++ static const char metachars[] = { ++ '*', '?', '[', 0 ++ }; + /* TODO - EXP_REDIR */ + + while (str) { ++ struct strlist **savelastp; ++ struct strlist *sp; ++ char *p; ++ + if (fflag) + goto nometa; +- p = str->text; +- for (;;) { /* fast check for meta chars */ +- if ((c = *p++) == '\0') ++ if (!strpbrk(str->text, metachars)) + goto nometa; +- if (c == '*' || c == '?' || c == '[' || c == '!') +- break; +- } + savelastp = exparg.lastp; ++ + INTOFF; +- if (expdir == NULL) { ++ p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); ++ { + int i = strlen(str->text); + expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ + } + +- expmeta(expdir, str->text); ++ expmeta(expdir, p); + ckfree(expdir); +- expdir = NULL; ++ if (p != str->text) ++ ckfree(p); + INTON; + if (exparg.lastp == savelastp) { + /* +@@ -1135,11 +1363,10 @@ + { + char *p; + const char *cp; +- char *q; + char *start; + char *endname; + int metaflag; +- struct stat statb; ++ struct stat64 statb; + DIR *dirp; + struct dirent *dp; + int atend; +@@ -1147,17 +1374,15 @@ + + metaflag = 0; + start = name; +- for (p = name ; ; p++) { ++ for (p = name; *p; p++) { + if (*p == '*' || *p == '?') + metaflag = 1; + else if (*p == '[') { +- q = p + 1; ++ char *q = p + 1; + if (*q == '!') + q++; + for (;;) { +- while (*q == CTLQUOTEMARK) +- q++; +- if (*q == CTLESC) ++ if (*q == '\\') + q++; + if (*q == '/' || *q == '\0') + break; +@@ -1166,46 +1391,36 @@ + break; + } + } +- } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { +- metaflag = 1; +- } else if (*p == '\0') +- break; +- else if (*p == CTLQUOTEMARK) +- continue; +- else if (*p == CTLESC) ++ } else if (*p == '\\') + p++; +- if (*p == '/') { ++ else if (*p == '/') { + if (metaflag) +- break; ++ goto out; + start = p + 1; + } + } ++out: + if (metaflag == 0) { /* we've reached the end of the file name */ + if (enddir != expdir) + metaflag++; +- for (p = name ; ; p++) { +- if (*p == CTLQUOTEMARK) +- continue; +- if (*p == CTLESC) ++ p = name; ++ do { ++ if (*p == '\\') + p++; + *enddir++ = *p; +- if (*p == '\0') +- break; +- } +- if (metaflag == 0 || lstat(expdir, &statb) >= 0) ++ } while (*p++); ++ if (metaflag == 0 || lstat64(expdir, &statb) >= 0) + addfname(expdir); + return; + } + endname = p; +- if (start != name) { ++ if (name < start) { + p = name; +- while (p < start) { +- while (*p == CTLQUOTEMARK) +- p++; +- if (*p == CTLESC) ++ do { ++ if (*p == '\\') + p++; + *enddir++ = *p++; +- } ++ } while (p < start); + } + if (enddir == expdir) { + cp = "."; +@@ -1227,16 +1442,14 @@ + } + matchdot = 0; + p = start; +- while (*p == CTLQUOTEMARK) +- p++; +- if (*p == CTLESC) ++ if (*p == '\\') + p++; + if (*p == '.') + matchdot++; + while (! int_pending() && (dp = readdir(dirp)) != NULL) { + if (dp->d_name[0] == '.' && ! matchdot) + continue; +- if (patmatch(start, dp->d_name, 0)) { ++ if (pmatch(start, dp->d_name)) { + if (atend) { + scopy(dp->d_name, enddir); + addfname(expdir); +@@ -1253,6 +1466,7 @@ + if (! atend) + endname[-1] = '/'; + } ++#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ + + + /* +@@ -1263,18 +1477,16 @@ + addfname(name) + char *name; + { +- char *p; + struct strlist *sp; + +- p = stalloc(strlen(name) + 1); +- scopy(name, p); + sp = (struct strlist *)stalloc(sizeof *sp); +- sp->text = p; ++ sp->text = sstrdup(name); + *exparg.lastp = sp; + exparg.lastp = &sp->next; + } + + ++#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) + /* + * Sort the results of file name expansion. It calculates the number of + * strings to sort and then calls msort (short for merge sort) to do the +@@ -1336,35 +1548,29 @@ + } + return list; + } +- ++#endif + + + /* + * Returns true if the pattern matches the string. + */ + +-int +-patmatch(pattern, string, squoted) ++STATIC inline int ++patmatch(pattern, string) + char *pattern; +- char *string; +- int squoted; /* string might have quote chars */ ++ const char *string; + { +-#ifdef notdef +- if (pattern[0] == '!' && pattern[1] == '!') +- return 1 - pmatch(pattern + 2, string); +- else +-#endif +- return pmatch(pattern, string, squoted); ++ return pmatch(preglob(pattern, 0, 0), string); + } + + ++#if !defined(__GLIBC__) || defined(FNMATCH_BROKEN) + STATIC int +-pmatch(pattern, string, squoted) +- char *pattern; +- char *string; +- int squoted; ++pmatch(pattern, string) ++ const char *pattern; ++ const char *string; + { +- char *p, *q; ++ const char *p, *q; + char c; + + p = pattern; +@@ -1373,46 +1579,33 @@ + switch (c = *p++) { + case '\0': + goto breakloop; +- case CTLESC: +- if (squoted && *q == CTLESC) +- q++; +- if (*q++ != *p++) +- return 0; +- break; +- case CTLQUOTEMARK: +- continue; ++ case '\\': ++ if (*p) { ++ c = *p++; ++ } ++ goto dft; + case '?': +- if (squoted && *q == CTLESC) +- q++; + if (*q++ == '\0') + return 0; + break; + case '*': + c = *p; +- while (c == CTLQUOTEMARK || c == '*') ++ while (c == '*') + c = *++p; +- if (c != CTLESC && c != CTLQUOTEMARK && +- c != '?' && c != '*' && c != '[') { ++ if (c != '\\' && c != '?' && c != '*' && c != '[') { + while (*q != c) { +- if (squoted && *q == CTLESC && +- q[1] == c) +- break; + if (*q == '\0') + return 0; +- if (squoted && *q == CTLESC) +- q++; + q++; + } + } + do { +- if (pmatch(p, q, squoted)) ++ if (pmatch(p, q)) + return 1; +- if (squoted && *q == CTLESC) +- q++; + } while (*q++ != '\0'); + return 0; + case '[': { +- char *endp; ++ const char *endp; + int invert, found; + char chr; + +@@ -1420,11 +1613,9 @@ + if (*endp == '!') + endp++; + for (;;) { +- while (*endp == CTLQUOTEMARK) +- endp++; + if (*endp == '\0') + goto dft; /* no matching ] */ +- if (*endp == CTLESC) ++ if (*endp == '\\') + endp++; + if (*++endp == ']') + break; +@@ -1436,21 +1627,15 @@ + } + found = 0; + chr = *q++; +- if (squoted && chr == CTLESC) +- chr = *q++; + if (chr == '\0') + return 0; + c = *p++; + do { +- if (c == CTLQUOTEMARK) +- continue; +- if (c == CTLESC) ++ if (c == '\\') + c = *p++; + if (*p == '-' && p[1] != ']') { + p++; +- while (*p == CTLQUOTEMARK) +- p++; +- if (*p == CTLESC) ++ if (*p == '\\') + p++; + if (chr >= c && chr <= *p) + found = 1; +@@ -1465,8 +1650,6 @@ + break; + } + dft: default: +- if (squoted && *q == CTLESC) +- q++; + if (*q++ != c) + return 0; + break; +@@ -1477,6 +1660,7 @@ + return 0; + return 1; + } ++#endif + + + +@@ -1484,28 +1668,75 @@ + * Remove any CTLESC characters from a string. + */ + +-void +-rmescapes(str) ++char * ++_rmescapes(str, flag) + char *str; ++ int flag; + { +- char *p, *q; ++ char *p, *q, *r; ++ static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 }; ++ unsigned inquotes; ++ int notescaped; ++ int globbing; + +- p = str; +- while (*p != CTLESC && *p != CTLQUOTEMARK) { +- if (*p++ == '\0') +- return; ++ p = strpbrk(str, qchars); ++ if (!p) { ++ return str; + } + q = p; ++ r = str; ++ if (flag & RMESCAPE_ALLOC) { ++ size_t len = p - str; ++ size_t fulllen = len + strlen(p) + 1; ++ ++ if (flag & RMESCAPE_GROW) { ++ r = makestrspace(fulllen, expdest); ++ } else if (flag & RMESCAPE_HEAP) { ++ r = ckmalloc(fulllen); ++ } else { ++ r = stalloc(fulllen); ++ } ++ q = r; ++ if (len > 0) { ++#ifdef _GNU_SOURCE ++ q = mempcpy(q, str, len); ++#else ++ memcpy(q, str, len); ++ q += len; ++#endif ++ } ++ } ++ inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; ++ globbing = flag & RMESCAPE_GLOB; ++ notescaped = globbing; + while (*p) { + if (*p == CTLQUOTEMARK) { ++ inquotes = ~inquotes; + p++; ++ notescaped = globbing; + continue; + } +- if (*p == CTLESC) ++ if (*p == '\\') { ++ /* naked back slash */ ++ notescaped = 0; ++ goto copy; ++ } ++ if (*p == CTLESC) { + p++; ++ if (notescaped && inquotes && *p != '/') { ++ *q++ = '\\'; ++ } ++ } ++ notescaped = globbing; ++copy: + *q++ = *p++; + } + *q = '\0'; ++ if (flag & RMESCAPE_GROW) { ++ expdest = r; ++ STADJUST(q - r + 1, expdest); ++ } ++ return r; + } + + +@@ -1521,16 +1752,14 @@ + { + struct stackmark smark; + int result; +- char *p; + + setstackmark(&smark); + argbackq = pattern->narg.backquote; + STARTSTACKSTR(expdest); + ifslastp = NULL; + argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); +- STPUTC('\0', expdest); +- p = grabstackstr(expdest); +- result = patmatch(p, val, 0); ++ STACKSTRNUL(expdest); ++ result = patmatch(stackblock(), val); + popstackmark(&smark); + return result; + } +@@ -1539,25 +1768,30 @@ + * Our own itoa(). + */ + +-STATIC char * +-cvtnum(num, buf) +- int num; +- char *buf; +- { +- char temp[32]; +- int neg = num < 0; +- char *p = temp + 31; +- +- temp[31] = '\0'; ++STATIC int ++cvtnum(long num) { ++ int len; + +- do { +- *--p = num % 10 + '0'; +- } while ((num /= 10) != 0); ++ expdest = makestrspace(32, expdest); ++ len = fmtstr(expdest, 32, "%ld", num); ++ STADJUST(len, expdest); ++ return len; ++} + +- if (neg) +- *--p = '-'; ++static void ++varunset(const char *end, const char *var, const char *umsg, int varflags) ++{ ++ const char *msg; ++ const char *tail; + +- while (*p) +- STPUTC(*p++, buf); +- return buf; ++ tail = nullstr; ++ msg = "parameter not set"; ++ if (umsg) { ++ if (*end == CTLENDVAR) { ++ if (varflags & VSNUL) ++ tail = " or null"; ++ } else ++ msg = umsg; ++ } ++ error("%.*s: %s%s", end - var - 1, var, msg, tail); + } +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/expand.h bin_NetBSD-1.6release/src/bin/sh/expand.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/expand.h 1999-07-09 12:02:06.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/expand.h 2003-02-08 14:35:42.000000000 +0000 +@@ -58,18 +58,25 @@ + #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ + #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ + #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ ++#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ ++#define EXP_WORD 0x80 /* expand word in parameter expansion */ ++#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ + + + union node; + void expandhere __P((union node *, int)); + void expandarg __P((union node *, struct arglist *, int)); + void expari __P((int)); +-int patmatch __P((char *, char *, int)); +-void rmescapes __P((char *)); ++#define rmescapes(p) _rmescapes((p), 0) ++char *_rmescapes __P((char *, int)); + int casematch __P((union node *, char *)); + + /* From arith.y */ + int arith __P((const char *)); + int expcmd __P((int , char **)); ++#ifdef USE_LEX + void arith_lex_reset __P((void)); ++#else ++#define arith_lex_reset() ++#endif + int yylex __P((void)); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/hetio.c bin_NetBSD-1.6release/src/bin/sh/hetio.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/hetio.c 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/hetio.c 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,397 @@ ++/* ++ * Termios command line History and Editting for NetBSD sh (ash) ++ * Copyright (c) 1999 ++ * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu> ++ * Etc: Dave Cinege <dcinege@psychosis.com> ++ * ++ * You may use this code as you wish, so long as the original author(s) ++ * are attributed in any redistributions of the source code. ++ * This code is 'as is' with no warranty. ++ * This code may safely be consumed by a BSD or GPL license. ++ * ++ * v 0.5 19990328 Initial release ++ * ++ * Future plans: Simple file and path name completion. (like BASH) ++ * ++ */ ++ ++/* ++Usage and Known bugs: ++ Terminal key codes are not extensive, and more will probably ++ need to be added. This version was created on Debian GNU/Linux 2.x. ++ Delete, Backspace, Home, End, and the arrow keys were tested ++ to work in an Xterm and console. Ctrl-A also works as Home. ++ Ctrl-E also works as End. Ctrl-D and Ctrl-U perform their respective ++ functions. The binary size increase is <3K. ++ ++ Editting will not display correctly for lines greater then the ++ terminal width. (more then one line.) However, history will. ++*/ ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <stdlib.h> ++#include <string.h> ++#include <termios.h> ++#include <ctype.h> ++#include <sys/ioctl.h> ++ ++#include "input.h" ++#include "output.h" ++ ++#include "hetio.h" ++ ++ ++#define MAX_HISTORY 15 /* Maximum length of the linked list for the command line history */ ++ ++#define ESC 27 ++#define DEL 127 ++ ++static struct history *his_front = NULL; /* First element in command line list */ ++static struct history *his_end = NULL; /* Last element in command line list */ ++static struct termios old_term, new_term; /* Current termio and the previous termio before starting ash */ ++ ++static int history_counter = 0; /* Number of commands in history list */ ++static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ ++static int hetio_inter = 0; ++ ++struct history ++{ ++ char *s; ++ struct history *p; ++ struct history *n; ++}; ++ ++ ++void input_delete (int); ++void input_home (int *); ++void input_end (int *, int); ++void input_backspace (int *, int *); ++ ++ ++ ++void hetio_init(void) ++{ ++ hetio_inter = 1; ++} ++ ++ ++void hetio_reset_term(void) ++{ ++ if (reset_term) ++ tcsetattr(1, TCSANOW, &old_term); ++} ++ ++ ++void setIO(struct termios *new, struct termios *old) /* Set terminal IO to canonical mode, and save old term settings. */ ++{ ++ tcgetattr(0, old); ++ memcpy(new, old, sizeof(*new)); ++ new->c_cc[VMIN] = 1; ++ new->c_cc[VTIME] = 0; ++ new->c_lflag &= ~ICANON; /* unbuffered input */ ++ new->c_lflag &= ~ECHO; ++ tcsetattr(0, TCSANOW, new); ++} ++ ++void input_home(int *cursor) /* Command line input routines */ ++{ ++ while (*cursor > 0) { ++ out1c('\b'); ++ --*cursor; ++ } ++ flushout(out1); ++} ++ ++ ++void input_delete(int cursor) ++{ ++ int j = 0; ++ ++ memmove(parsenextc + cursor, parsenextc + cursor + 1, ++ BUFSIZ - cursor - 1); ++ for (j = cursor; j < (BUFSIZ - 1); j++) { ++ if (!*(parsenextc + j)) ++ break; ++ else ++ out1c(*(parsenextc + j)); ++ } ++ ++ out1str(" \b"); ++ ++ while (j-- > cursor) ++ out1c('\b'); ++ flushout(out1); ++} ++ ++ ++void input_end(int *cursor, int len) ++{ ++ while (*cursor < len) { ++ out1str("\033[C"); ++ ++*cursor; ++ } ++ flushout(out1); ++} ++ ++ ++void ++input_backspace(int *cursor, int *len) ++{ ++ int j = 0; ++ ++ if (*cursor > 0) { ++ out1str("\b \b"); ++ --*cursor; ++ memmove(parsenextc + *cursor, parsenextc + *cursor + 1, ++ BUFSIZ - *cursor + 1); ++ ++ for (j = *cursor; j < (BUFSIZ - 1); j++) { ++ if (!*(parsenextc + j)) ++ break; ++ else ++ out1c(*(parsenextc + j)); ++ } ++ ++ out1str(" \b"); ++ ++ while (j-- > *cursor) ++ out1c('\b'); ++ ++ --*len; ++ flushout(out1); ++ } ++} ++ ++int hetio_read_input(int fd) ++{ ++ int nr = 0; ++ ++ /* Are we an interactive shell? */ ++ if (!hetio_inter || fd) { ++ return -255; ++ } else { ++ int len = 0; ++ int j = 0; ++ int cursor = 0; ++ int break_out = 0; ++ int ret = 0; ++ char c = 0; ++ struct history *hp = his_end; ++ ++ if (!reset_term) { ++ setIO(&new_term, &old_term); ++ reset_term = 1; ++ } else { ++ tcsetattr(0, TCSANOW, &new_term); ++ } ++ ++ memset(parsenextc, 0, BUFSIZ); ++ ++ while (1) { ++ if ((ret = read(fd, &c, 1)) < 1) ++ return ret; ++ ++ switch (c) { ++ case 1: /* Control-A Beginning of line */ ++ input_home(&cursor); ++ break; ++ case 5: /* Control-E EOL */ ++ input_end(&cursor, len); ++ break; ++ case 4: /* Control-D */ ++ if (!len) ++ exitshell(0); ++ break; ++ case 21: /* Control-U */ ++ /* Return to begining of line. */ ++ for (; cursor > 0; cursor--) ++ out1c('\b'); ++ /* Erase old command. */ ++ for (j = 0; j < len; j++) { ++ /* ++ * Clear buffer while we're at ++ * it. ++ */ ++ parsenextc[j] = 0; ++ out1c(' '); ++ } ++ /* return to begining of line */ ++ for (; len > 0; len--) ++ out1c('\b'); ++ flushout(out1); ++ break; ++ case '\b': /* Backspace */ ++ case DEL: ++ input_backspace(&cursor, &len); ++ break; ++ case '\n': /* Enter */ ++ *(parsenextc + len++ + 1) = c; ++ out1c(c); ++ flushout(out1); ++ break_out = 1; ++ break; ++ case ESC: /* escape sequence follows */ ++ if ((ret = read(fd, &c, 1)) < 1) ++ return ret; ++ ++ if (c == '[' ) { /* 91 */ ++ if ((ret = read(fd, &c, 1)) < 1) ++ return ret; ++ ++ switch (c) { ++ case 'A': ++ if (hp && hp->p) { /* Up */ ++ hp = hp->p; ++ goto hop; ++ } ++ break; ++ case 'B': ++ if (hp && hp->n && hp->n->s) { /* Down */ ++ hp = hp->n; ++ goto hop; ++ } ++ break; ++ ++hop: /* hop */ ++ len = strlen(parsenextc); ++ ++ for (; cursor > 0; cursor--) /* return to begining of line */ ++ out1c('\b'); ++ ++ for (j = 0; j < len; j++) /* erase old command */ ++ out1c(' '); ++ ++ for (; j > 0; j--) /* return to begining of line */ ++ out1c('\b'); ++ ++ strcpy (parsenextc, hp->s); /* write new command */ ++ len = strlen (hp->s); ++ out1str(parsenextc); ++ flushout(out1); ++ cursor = len; ++ break; ++ case 'C': /* Right */ ++ if (cursor < len) { ++ out1str("\033[C"); ++ cursor++; ++ flushout(out1); ++ } ++ break; ++ case 'D': /* Left */ ++ if (cursor > 0) { ++ out1str("\033[D"); ++ cursor--; ++ flushout(out1); ++ } ++ break; ++ case '3': /* Delete */ ++ if (cursor != len) { ++ input_delete(cursor); ++ len--; ++ } ++ break; ++ case '1': /* Home (Ctrl-A) */ ++ input_home(&cursor); ++ break; ++ case '4': /* End (Ctrl-E) */ ++ input_end(&cursor, len); ++ break; ++ } ++ if (c == '1' || c == '3' || c == '4') ++ if ((ret = read(fd, &c, 1)) < 1) ++ return ret; /* read 126 (~) */ ++ } ++ ++ if (c == 'O') { /* 79 */ ++ if ((ret = read(fd, &c, 1)) < 1) ++ return ret; ++ switch (c) { ++ case 'H': /* Home (xterm) */ ++ input_home(&cursor); ++ break; ++ case 'F': /* End (xterm_ */ ++ input_end(&cursor, len); ++ break; ++ } ++ } ++ ++ c = 0; ++ break; ++ ++ default: /* If it's regular input, do the normal thing */ ++ if (!isprint(c)) /* Skip non-printable characters */ ++ break; ++ ++ if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ ++ break; ++ ++ len++; ++ ++ if (cursor == (len - 1)) { /* Append if at the end of the line */ ++ *(parsenextc + cursor) = c; ++ } else { /* Insert otherwise */ ++ memmove(parsenextc + cursor + 1, parsenextc + cursor, ++ len - cursor - 1); ++ ++ *(parsenextc + cursor) = c; ++ ++ for (j = cursor; j < len; j++) ++ out1c(*(parsenextc + j)); ++ for (; j > cursor; j--) ++ out1str("\033[D"); ++ } ++ ++ cursor++; ++ out1c(c); ++ flushout(out1); ++ break; ++ } ++ ++ if (break_out) /* Enter is the command terminator, no more input. */ ++ break; ++ } ++ ++ nr = len + 1; ++ tcsetattr(0, TCSANOW, &old_term); ++ ++ if (*(parsenextc)) { /* Handle command history log */ ++ struct history *h = his_end; ++ ++ if (!h) { /* No previous history */ ++ h = his_front = malloc(sizeof (struct history)); ++ h->n = malloc(sizeof (struct history)); ++ h->p = NULL; ++ h->s = strdup(parsenextc); ++ ++ h->n->p = h; ++ h->n->n = NULL; ++ h->n->s = NULL; ++ his_end = h->n; ++ history_counter++; ++ } else { /* Add a new history command */ ++ ++ h->n = malloc(sizeof (struct history)); ++ ++ h->n->p = h; ++ h->n->n = NULL; ++ h->n->s = NULL; ++ h->s = strdup(parsenextc); ++ his_end = h->n; ++ ++ if (history_counter >= MAX_HISTORY) { /* After max history, remove the last known command */ ++ struct history *p = his_front->n; ++ ++ p->p = NULL; ++ free(his_front->s); ++ free(his_front); ++ his_front = p; ++ } else { ++ history_counter++; ++ } ++ } ++ } ++ } ++ ++ return nr; ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/hetio.h bin_NetBSD-1.6release/src/bin/sh/hetio.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/hetio.h 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/hetio.h 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,22 @@ ++/* ++ * Termios command line History and Editting for NetBSD sh (ash) ++ * Copyright (c) 1999 ++ * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu> ++ * Etc: Dave Cinege <dcinege@psychosis.com> ++ * ++ * You may use this code as you wish, so long as the original author(s) ++ * are attributed in any redistributions of the source code. ++ * This code is 'as is' with no warranty. ++ * This code may safely be consumed by a BSD or GPL license. ++ * ++ * v 0.5 19990328 Initial release ++ * ++ * Future plans: Simple file and path name completion. (like BASH) ++ * ++ */ ++ ++void hetio_init(void); ++int hetio_read_input(int fd); ++void hetio_reset_term(void); ++ ++extern int hetio_inter; +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/histedit.c bin_NetBSD-1.6release/src/bin/sh/histedit.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/histedit.c 2002-03-12 11:22:09.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/histedit.c 2003-02-08 14:35:42.000000000 +0000 +@@ -60,9 +60,9 @@ + #include "main.h" + #include "output.h" + #include "mystring.h" +-#include "myhistedit.h" + #include "error.h" + #ifndef SMALL ++#include "myhistedit.h" + #include "eval.h" + #include "memalloc.h" + +@@ -219,7 +219,11 @@ + if (argc == 1) + error("missing history argument"); + ++#ifdef __GLIBC__ ++ optind = 0; ++#else + optreset = 1; optind = 1; /* initialize getopt */ ++#endif + while (not_fcnumber(argv[optind]) && + (ch = getopt(argc, argv, ":e:lnrs")) != -1) + switch ((char)ch) { +@@ -277,8 +281,8 @@ + */ + if (sflg == 0) { + if (editor == NULL && +- (editor = bltinlookup("FCEDIT", 1)) == NULL && +- (editor = bltinlookup("EDITOR", 1)) == NULL) ++ (editor = bltinlookup("FCEDIT")) == NULL && ++ (editor = bltinlookup("EDITOR")) == NULL) + editor = DEFEDITOR; + if (editor[0] == '-' && editor[1] == '\0') { + sflg = 1; /* no edit */ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/input.c bin_NetBSD-1.6release/src/bin/sh/input.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/input.c 2001-02-05 11:15:30.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/input.c 2003-02-08 14:35:42.000000000 +0000 +@@ -66,17 +66,24 @@ + #include "error.h" + #include "alias.h" + #include "parser.h" ++#ifndef SMALL + #include "myhistedit.h" ++#endif ++ ++#ifdef HETIO ++#include "hetio.h" ++#endif + + #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ ++#define IBUFSIZ (BUFSIZ + 1) + + MKINIT + struct strpush { + struct strpush *prev; /* preceding string on stack */ + char *prevstring; + int prevnleft; +- int prevlleft; + struct alias *ap; /* if push was associated with an alias */ ++ char *string; /* remember the string since it may change */ + }; + + /* +@@ -103,12 +110,13 @@ + MKINIT int parselleft; /* copy of parsefile->lleft */ + char *parsenextc; /* copy of parsefile->nextc */ + MKINIT struct parsefile basepf; /* top level input file */ +-MKINIT char basebuf[BUFSIZ]; /* buffer for top level input file */ ++MKINIT char basebuf[IBUFSIZ]; /* buffer for top level input file */ + struct parsefile *parsefile = &basepf; /* current input file */ +-int init_editline = 0; /* editline library initialized? */ + int whichprompt; /* 1 == PS1, 2 == PS2 */ + ++#ifndef SMALL + EditLine *el; /* cookie for editline package */ ++#endif + + STATIC void pushfile __P((void)); + static int preadfd __P((void)); +@@ -123,14 +131,9 @@ + } + + RESET { +- if (exception != EXSHELLPROC) + parselleft = parsenleft = 0; /* clear input buffer */ + popallfiles(); + } +- +-SHELLPROC { +- popallfiles(); +-} + #endif + + +@@ -148,7 +151,7 @@ + int c; + + while (--nleft > 0) { +- c = pgetc_macro(); ++ c = pgetc2(); + if (c == PEOF) { + if (p == line) + return NULL; +@@ -163,7 +166,6 @@ + } + + +- + /* + * Read a character from the script, returning PEOF on end of file. + * Nul characters in the input are silently discarded. +@@ -176,6 +178,21 @@ + } + + ++/* ++ * Same as pgetc(), but ignores PEOA. ++ */ ++ ++int ++pgetc2() ++{ ++ int c; ++ do { ++ c = pgetc_macro(); ++ } while (c == PEOA); ++ return c; ++} ++ ++ + static int + preadfd() + { +@@ -197,10 +214,14 @@ + } + } else + #endif +- nr = read(parsefile->fd, buf, BUFSIZ - 1); ++ ++#ifdef HETIO ++ nr = hetio_read_input(parsefile->fd); ++ if (nr == -255) ++#endif ++ nr = read(parsefile->fd, buf, IBUFSIZ - 1); + + +- if (nr <= 0) { + if (nr < 0) { + if (errno == EINTR) + goto retry; +@@ -215,8 +236,6 @@ + } + } + } +- nr = -1; +- } + return nr; + } + +@@ -235,10 +254,18 @@ + { + char *p, *q; + int more; ++#ifndef SMALL + int something; ++#endif + char savec; + +- if (parsefile->strpush) { ++ while (parsefile->strpush) { ++ if ( ++ parsenleft == -1 && parsefile->strpush->ap && ++ parsenextc[-1] != ' ' && parsenextc[-1] != '\t' ++ ) { ++ return PEOA; ++ } + popstring(); + if (--parsenleft >= 0) + return (*parsenextc++); +@@ -246,11 +273,13 @@ + if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) + return PEOF; + flushout(&output); ++#ifdef FLUSHERR + flushout(&errout); ++#endif + + again: + if (parselleft <= 0) { +- if ((parselleft = preadfd()) == -1) { ++ if ((parselleft = preadfd()) <= 0) { + parselleft = parsenleft = EOF_NLEFT; + return PEOF; + } +@@ -259,34 +288,39 @@ + q = p = parsenextc; + + /* delete nul characters */ ++#ifndef SMALL + something = 0; ++#endif + for (more = 1; more;) { + switch (*p) { + case '\0': + p++; /* Skip nul */ + goto check; + ++#ifndef SMALL + case '\t': + case ' ': + break; ++#endif + + case '\n': + parsenleft = q - parsenextc; + more = 0; /* Stop processing here */ + break; + ++#ifndef SMALL + default: + something = 1; + break; ++#endif + } + + *q++ = *p++; + check: +- if (--parselleft <= 0) { ++ if (--parselleft <= 0 && more) { + parsenleft = q - parsenextc - 1; + if (parsenleft < 0) + goto again; +- *q = '\0'; + more = 0; + } + } +@@ -306,7 +340,9 @@ + + if (vflag) { + out2str(parsenextc); ++#ifdef FLUSHERR + flushout(out2); ++#endif + } + + *q = savec; +@@ -330,13 +366,14 @@ + * We handle aliases this way. + */ + void +-pushstring(s, len, ap) ++pushstring(s, ap) + char *s; +- int len; + void *ap; + { + struct strpush *sp; ++ size_t len; + ++ len = strlen(s); + INTOFF; + /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ + if (parsefile->strpush) { +@@ -347,10 +384,11 @@ + sp = parsefile->strpush = &(parsefile->basestrpush); + sp->prevstring = parsenextc; + sp->prevnleft = parsenleft; +- sp->prevlleft = parselleft; + sp->ap = (struct alias *)ap; +- if (ap) ++ if (ap) { + ((struct alias *)ap)->flag |= ALIASINUSE; ++ sp->string = s; ++ } + parsenextc = s; + parsenleft = len; + INTON; +@@ -362,12 +400,21 @@ + struct strpush *sp = parsefile->strpush; + + INTOFF; ++ if (sp->ap) { ++ if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { ++ checkkwd |= CHKALIAS; ++ } ++ if (sp->string != sp->ap->val) { ++ ckfree(sp->string); ++ } ++ sp->ap->flag &= ~ALIASINUSE; ++ if (sp->ap->flag & ALIASDEAD) { ++ unalias(sp->ap->name); ++ } ++ } + parsenextc = sp->prevstring; + parsenleft = sp->prevnleft; +- parselleft = sp->prevlleft; + /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ +- if (sp->ap) +- sp->ap->flag &= ~ALIASINUSE; + parsefile->strpush = sp->prev; + if (sp != &(parsefile->basestrpush)) + ckfree(sp); +@@ -414,13 +461,15 @@ + (void) fcntl(fd, F_SETFD, FD_CLOEXEC); + if (push) { + pushfile(); +- parsefile->buf = ckmalloc(BUFSIZ); ++ parsefile->buf = 0; ++ } else { ++ closescript(); ++ while (parsefile->strpush) ++ popstring(); + } +- if (parsefile->fd > 0) +- close(parsefile->fd); + parsefile->fd = fd; + if (parsefile->buf == NULL) +- parsefile->buf = ckmalloc(BUFSIZ); ++ parsefile->buf = ckmalloc(IBUFSIZ); + parselleft = parsenleft = 0; + plinno = 1; + } +@@ -431,15 +480,13 @@ + */ + + void +-setinputstring(string, push) ++setinputstring(string) + char *string; +- int push; + { + INTOFF; +- if (push) + pushfile(); + parsenextc = string; +- parselleft = parsenleft = strlen(string); ++ parsenleft = strlen(string); + parsefile->buf = NULL; + plinno = 1; + INTON; +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/input.h bin_NetBSD-1.6release/src/bin/sh/input.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/input.h 2000-05-23 11:03:19.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/input.h 2003-02-08 14:35:42.000000000 +0000 +@@ -48,17 +48,17 @@ + extern int plinno; + extern int parsenleft; /* number of characters left in input buffer */ + extern char *parsenextc; /* next character in input buffer */ +-extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */ + + char *pfgets __P((char *, int)); + int pgetc __P((void)); ++int pgetc2 __P((void)); + int preadbuffer __P((void)); + void pungetc __P((void)); +-void pushstring __P((char *, int, void *)); ++void pushstring __P((char *, void *)); + void popstring __P((void)); + void setinputfile __P((const char *, int)); + void setinputfd __P((int, int)); +-void setinputstring __P((char *, int)); ++void setinputstring __P((char *)); + void popfile __P((void)); + void popallfiles __P((void)); + void closescript __P((void)); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/jobs.c bin_NetBSD-1.6release/src/bin/sh/jobs.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/jobs.c 2002-05-16 11:41:20.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/jobs.c 2003-02-08 14:35:42.000000000 +0000 +@@ -85,21 +85,30 @@ + #include "mystring.h" + + +-struct job *jobtab; /* array of jobs */ +-int njobs; /* size of array */ +-MKINIT short backgndpid = -1; /* pid of last background process */ ++/* array of jobs */ ++STATIC struct job *jobtab; ++/* size of array */ ++STATIC int njobs; ++/* pid of last background process */ ++MKINIT pid_t backgndpid; + #if JOBS +-int initialpgrp; /* pgrp of shell on invocation */ +-short curjob; /* current job */ ++/* pgrp of shell on invocation */ ++STATIC int initialpgrp; ++/* current job */ ++STATIC struct job *curjob; + #endif +-static int ttyfd = -1; ++STATIC int ttyfd = -1; ++/* number of presumed living untracked jobs */ ++STATIC int jobless; + + STATIC void restartjob __P((struct job *)); + STATIC void freejob __P((struct job *)); + STATIC struct job *getjob __P((char *)); + STATIC int dowait __P((int, struct job *)); ++#ifdef SYSV + STATIC int onsigchild __P((void)); +-STATIC int waitproc __P((int, struct job *, int *)); ++#endif ++STATIC int waitproc __P((int, int *)); + STATIC void cmdtxt __P((union node *)); + STATIC void cmdputs __P((const char *)); + +@@ -127,12 +136,15 @@ + } + #endif + ++#if JOBS + /* + * 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. ++ * ++ * Called with interrupts off. + */ + + MKINIT int jobctl; +@@ -144,93 +156,185 @@ + #ifdef OLD_TTY_DRIVER + int ldisc; + #endif ++ int fd; ++ int pgrp; + + if (on == jobctl || rootshell == 0) + return; + if (on) { + #if defined(FIOCLEX) || defined(FD_CLOEXEC) +- int err; +- if (ttyfd != -1) +- close(ttyfd); +- if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) { +- int i; +- for (i = 0; i < 3; i++) { +- if (isatty(i) && (ttyfd = dup(i)) != -1) +- break; ++ int ofd; ++ ofd = fd = open(_PATH_TTY, O_RDWR); ++ if (fd < 0) { ++ fd += 3; ++ while (!isatty(fd) && --fd >= 0) ++ ; + } +- if (i == 3) ++ fd = fcntl(fd, F_DUPFD, 10); ++ close(ofd); ++ if (fd < 0) + goto out; +- } +-#ifdef FIOCLEX +- err = ioctl(ttyfd, FIOCLEX, 0); +-#elif FD_CLOEXEC +- err = fcntl(ttyfd, FD_CLOEXEC, 1); ++#ifdef linux ++ fcntl(fd, F_SETFD, FD_CLOEXEC); ++#elif defined(FIOCLEX) ++ ioctl(fd, FIOCLEX, 0); ++#elif defined(FD_CLOEXEC) ++ fcntl(fd, FD_CLOEXEC, 1); + #endif +- if (err == -1) { +- close(ttyfd); +- ttyfd = -1; +- goto out; +- } + #else +- out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control"); +- goto out; ++ warnx("Need FIOCLEX or FD_CLOEXEC to support job control"); ++ mflag = 0; ++ return; + #endif + do { /* while we are in the background */ +- if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) { ++ if ((pgrp = tcgetpgrp(fd)) < 0) { + out: +- out2str("sh: can't access tty; job control turned off\n"); +- mflag = 0; +- return; ++ warnx("can't access tty; job control turned off"); ++ mflag = on = 0; ++ goto close; + } +- if (initialpgrp == -1) +- initialpgrp = getpgrp(); +- else if (initialpgrp != getpgrp()) { ++ if (pgrp == getpgrp()) ++ break; + killpg(0, SIGTTIN); +- continue; +- } +- } while (0); ++ } while (1); ++ initialpgrp = pgrp; + + #ifdef OLD_TTY_DRIVER +- if (ioctl(ttyfd, TIOCGETD, (char *)&ldisc) < 0 ++ if (ioctl(fd, TIOCGETD, (char *)&ldisc) < 0 + || ldisc != NTTYDISC) { +- out2str("sh: need new tty driver to run job control; job control turned off\n"); +- mflag = 0; +- return; ++ warnx("need new tty driver to run job control; job control turned off"); ++ mflag = on = 0; ++ goto close; + } + #endif + 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; ++ pgrp = rootpid; ++ setpgid(0, pgrp); ++ tcsetpgrp(fd, pgrp); ++ } else { ++ /* turning job control off */ ++ fd = ttyfd; ++ pgrp = initialpgrp; ++ tcsetpgrp(fd, pgrp); ++ setpgid(0, pgrp); + setsignal(SIGTSTP); + setsignal(SIGTTOU); + setsignal(SIGTTIN); ++close: ++ close(fd); ++ fd = -1; + } ++ ttyfd = fd; + jobctl = on; + } ++#endif + + +-#ifdef mkinit +-INCLUDE <stdlib.h> + +-SHELLPROC { +- backgndpid = -1; + #if JOBS +- jobctl = 0; +-#endif +-} ++int ++killcmd(argc, argv) ++ int argc; ++ char **argv; ++{ ++ extern char *signal_names[]; ++ int signo = -1; ++ int list = 0; ++ int i; ++ pid_t pid; ++ struct job *jp; ++ ++ if (argc <= 1) { ++usage: ++ error( ++"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n" ++"kill -l [exitstatus]" ++ ); ++ } ++ ++ if (*argv[1] == '-') { ++ signo = decode_signal(argv[1] + 1, 1); ++ if (signo < 0) { ++ int c; + ++ while ((c = nextopt("ls:")) != '\0') ++ switch (c) { ++ case 'l': ++ list = 1; ++ break; ++ case 's': ++ signo = decode_signal(optionarg, 1); ++ if (signo < 0) { ++ error( ++ "invalid signal number or name: %s", ++ optionarg ++ ); ++ } ++ break; ++#ifdef DEBUG ++ default: ++ error( ++ "nextopt returned character code 0%o", c); + #endif ++ } ++ } else ++ argptr++; ++ } + ++ if (!list && signo < 0) ++ signo = SIGTERM; + ++ if ((signo < 0 || !*argptr) ^ list) { ++ goto usage; ++ } ++ ++ if (list) { ++ if (!*argptr) { ++ out1str("0\n"); ++ for (i = 1; i < NSIG; i++) { ++ out1fmt(snlfmt, signal_names[i]); ++ } ++ return 0; ++ } ++ signo = atoi(*argptr); ++ if (signo > 128) ++ signo -= 128; ++ if (0 < signo && signo < NSIG) ++ out1fmt(snlfmt, signal_names[signo]); ++ else ++ error("invalid signal number or exit status: %s", ++ *argptr); ++ return 0; ++ } ++ ++ i = 0; ++ do { ++ if (**argptr == '%') { ++ jp = getjob(*argptr); ++ if (jp->jobctl == 0) { ++ outfmt( ++ out2, ++ "job %s not created " ++ "under job control\n", ++ *argptr ++ ); ++ i = 1; ++ continue; ++ } ++ pid = -jp->ps[0].pid; ++ } else ++ pid = atoi(*argptr); ++ if (kill(pid, signo) != 0) { ++ outfmt(out2, "%s: %s\n", *argptr, strerror(errno)); ++ i = 1; ++ } ++ } while (*++argptr); ++ ++ return i; ++} + +-#if JOBS + int + fgcmd(argc, argv) + int argc; +@@ -246,9 +350,7 @@ + pgrp = jp->ps[0].pid; + tcsetpgrp(ttyfd, pgrp); + restartjob(jp); +- INTOFF; + status = waitforjob(jp); +- INTON; + return status; + } + +@@ -366,12 +468,10 @@ + } + out1str(s); + col += strlen(s); +- do { +- out1c(' '); +- col++; +- } while (col < 30); +- out1str(ps->cmd); +- out1c('\n'); ++ out1fmt( ++ "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ', ++ ps->cmd ++ ); + if (--procno <= 0) + break; + } +@@ -399,14 +499,11 @@ + if (ps->cmd != nullstr) + ckfree(ps->cmd); + } +- if (jp->ps != &jp->ps0) { ++ if (jp->ps != &jp->ps0) + ckfree(jp->ps); +- jp->ps = &jp->ps0; +- } +- jp->nprocs = 0; + jp->used = 0; + #if JOBS +- if (curjob == jp - jobtab + 1) ++ if (curjob == jp) + curjob = 0; + #endif + INTON; +@@ -423,8 +520,9 @@ + int status, retval; + struct job *jp; + +- if (argc > 1) { +- job = getjob(argv[1]); ++ if (--argc > 0) { ++start: ++ job = getjob(*++argv); + } else { + job = NULL; + } +@@ -432,6 +530,11 @@ + if (job != NULL) { + if (job->state) { + status = job->ps[job->nprocs - 1].status; ++ if (! iflag) ++ freejob(job); ++ if (--argc) { ++ goto start; ++ } + if (WIFEXITED(status)) + retval = WEXITSTATUS(status); + #if JOBS +@@ -442,26 +545,28 @@ + /* XXX: limits number of signals */ + retval = WTERMSIG(status) + 128; + } +- if (! iflag) +- freejob(job); + return retval; + } + } else { ++ struct job *end = jobtab + njobs; + for (jp = jobtab ; ; jp++) { +- if (jp >= jobtab + njobs) { /* no running procs */ ++ if (jp >= end) { ++ /* no running procs */ + return 0; + } + if (jp->used && jp->state == 0) + break; + } + } +- if (dowait(1, (struct job *)NULL) == -1) +- return 128 + SIGINT; ++ dowait(2, 0); ++ if (pendingsigs) ++ return 128 + pendingsigs; + } + } + + + ++#if 0 + int + jobidcmd(argc, argv) + int argc; +@@ -472,11 +577,14 @@ + + jp = getjob(argv[1]); + for (i = 0 ; i < jp->nprocs ; ) { +- out1fmt("%ld", (long)jp->ps[i].pid); +- out1c(++i < jp->nprocs? ' ' : '\n'); ++ out1fmt( ++ "%ld%c", (long)jp->ps[i].pid, ++ ++i < jp->nprocs? ' ' : '\n' ++ ); + } + return 0; + } ++#endif + + + +@@ -496,9 +604,9 @@ + if (name == NULL) { + #if JOBS + currentjob: +- if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0) ++ if (!curjob || !curjob->used) + error("No current job"); +- return &jobtab[jobno - 1]; ++ return curjob; + #else + error("No current job"); + #endif +@@ -575,13 +683,13 @@ + break; + } + INTOFF; +- jp->state = 0; +- jp->used = 1; +- jp->changed = 0; + jp->nprocs = 0; ++ jp->state = 0; + #if JOBS + jp->jobctl = jobctl; + #endif ++ jp->changed = 0; ++ jp->used = 1; + if (nprocs > 1) { + jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); + } else { +@@ -636,23 +744,17 @@ + TRACE(("Child shell %d\n", getpid())); + wasroot = rootshell; + rootshell = 0; +- for (i = njobs, p = jobtab ; --i >= 0 ; p++) { +- if (p == jp) +- continue; /* don't free current job */ +- if (p->used) +- freejob(p); +- } + closescript(); + INTON; + clear_traps(); + #if JOBS +- jobctl = 0; /* do job control only in root shell */ ++ jobctl = pid; /* 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; +- setpgid(0, pgrp); ++ setpgid(pid, pgrp); + if (mode == FORK_FG) { + /*** this causes superfluous TIOCSPGRPS ***/ + if (tcsetpgrp(ttyfd, pgrp) < 0) +@@ -661,32 +763,26 @@ + 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(devnull, O_RDONLY) != 0) +- error(nullerr, devnull); +- } +- } + #else + if (mode == FORK_BG) { ++#endif + ignoresig(SIGINT); + ignoresig(SIGQUIT); +- if ((jp == NULL || jp->nprocs == 0) && +- ! fd0_redirected_p ()) { +- close(0); ++ if ((jp == NULL || jp->nprocs == 0)) { ++ close(pid); + if (open(devnull, O_RDONLY) != 0) + error(nullerr, devnull); + } + } +-#endif ++ for (i = njobs, p = jobtab ; --i >= 0 ; p++) ++ if (p->used) ++ freejob(p); + if (wasroot && iflag) { + setsignal(SIGINT); + setsignal(SIGQUIT); + setsignal(SIGTERM); + } ++ jobless = pid; + return pid; + } + if (rootshell && mode != FORK_NOJOB && mflag) { +@@ -705,6 +801,9 @@ + ps->cmd = nullstr; + if (iflag && rootshell && n) + ps->cmd = commandtext(n); ++ } else { ++ while (jobless && dowait(0, 0) > 0); ++ jobless++; + } + INTON; + TRACE(("In parent shell: child = %d\n", pid)); +@@ -753,7 +852,7 @@ + error("tcsetpgrp failed, errno=%d\n", errno); + } + if (jp->state == JOBSTOPPED) +- curjob = jp - jobtab + 1; ++ curjob = jp; + #endif + status = jp->ps[jp->nprocs - 1].status; + /* convert to 8 bits */ +@@ -798,29 +897,31 @@ + { + int pid; + int status; +- struct procstat *sp; + struct job *jp; ++ struct job *end; + struct job *thisjob; +- int done; +- int stopped; + int core; + int sig; +- extern volatile char gotsig[]; ++ int state; + + TRACE(("dowait(%d) called\n", block)); + do { +- pid = waitproc(block, job, &status); ++ pid = waitproc(block, &status); + TRACE(("wait returns %d, status=%d\n", pid, status)); +- } while (pid == -1 && errno == EINTR && gotsig[SIGINT - 1] == 0); ++ } while (!(block & 2) && pid == -1 && errno == EINTR); + 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++) { ++ end = jobtab + njobs; ++ for (jp = jobtab; jp < end; jp++) { ++ struct procstat *sp; ++ struct procstat *spend; ++ if (!jp->used) ++ continue; ++ state = JOBDONE; ++ spend = jp->ps + jp->nprocs; ++ for (sp = jp->ps; sp < spend; sp++) { + if (sp->pid == -1) + continue; + if (sp->pid == pid) { +@@ -829,23 +930,30 @@ + thisjob = jp; + } + if (sp->status == -1) +- stopped = 0; ++ state = 0; + else if (WIFSTOPPED(sp->status)) +- done = 0; ++ state = JOBSTOPPED; + } +- 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 (!thisjob) ++ continue; ++ if (state) { ++ /* stopped or done */ ++ if (thisjob->state != state) { ++ TRACE(("Job %d: changing state from %d to %d\n", thisjob - jobtab + 1, thisjob->state, state)); ++ thisjob->state = state; + #if JOBS +- if (done && curjob == jp - jobtab + 1) +- curjob = 0; /* no current job */ +-#endif ++ if (state == JOBDONE && curjob == thisjob) { ++ /* no current job */ ++ curjob = 0; + } ++#endif + } + } ++ goto gotjob; + } ++ if (!WIFSTOPPED(status)) ++ jobless--; ++gotjob: + INTON; + if (! rootshell || ! iflag || (job && thisjob == job)) { + core = WCOREDUMP(status); +@@ -871,7 +979,9 @@ + if (core) + out2str(" - core dumped"); + out2c('\n'); ++#ifdef FLUSHERR + flushout(&errout); ++#endif + } else { + TRACE(("Not printing status: status=%d, sig=%d\n", + status, sig)); +@@ -925,16 +1035,15 @@ + + + STATIC int +-waitproc(block, jp, status) ++waitproc(block, status) + int block; +- struct job *jp; + int *status; + { + #ifdef BSD + int flags = 0; + + #if JOBS +- if (jp != NULL && jp->jobctl) ++ if (jobctl) + flags |= WUNTRACED; + #endif + if (block == 0) +@@ -963,7 +1072,7 @@ + /* + * return 1 if there are stopped jobs, otherwise 0 + */ +-int job_warning = 0; ++int job_warning; + int + stoppedjobs() + { +@@ -1088,10 +1197,10 @@ + for (np = n->ncmd.args ; np ; np = np->narg.next) { + cmdtxt(np); + if (np->narg.next) +- cmdputs(" "); ++ cmdputs(spcstr); + } + for (np = n->ncmd.redirect ; np ; np = np->nfile.next) { +- cmdputs(" "); ++ cmdputs(spcstr); + cmdtxt(np); + } + break; +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/jobs.h bin_NetBSD-1.6release/src/bin/sh/jobs.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/jobs.h 2000-05-23 11:03:19.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/jobs.h 2003-02-08 14:35:42.000000000 +0000 +@@ -38,6 +38,9 @@ + * @(#)jobs.h 8.2 (Berkeley) 5/4/95 + */ + ++#include <stdint.h> ++#include <sys/types.h> ++ + /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ + #define FORK_FG 0 + #define FORK_BG 1 +@@ -66,20 +69,22 @@ + struct job { + struct procstat ps0; /* status of process */ + struct procstat *ps; /* status or processes when more than one */ +- short nprocs; /* number of processes */ +- short 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 */ ++ pid_t pgrp; /* process group of this job */ ++ uint32_t ++ nprocs: 16, /* number of processes */ ++ state: 8, /* true if job is finished */ + #if JOBS +- char jobctl; /* job running under job control */ ++ jobctl: 1, /* job running under job control */ + #endif ++ used: 1, /* true if this entry is in used */ ++ changed: 1; /* true if status has changed */ + }; + +-extern short backgndpid; /* pid of last background process */ ++extern pid_t backgndpid; /* pid of last background process */ + extern int job_warning; /* user was warned about stopped jobs */ + + void setjobctl __P((int)); ++int killcmd __P((int, char **)); + int fgcmd __P((int, char **)); + int bgcmd __P((int, char **)); + int jobscmd __P((int, char **)); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/mail.c bin_NetBSD-1.6release/src/bin/sh/mail.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/mail.c 2001-01-12 16:50:36.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/mail.c 2003-02-08 14:35:42.000000000 +0000 +@@ -53,73 +53,73 @@ + #include <stdlib.h> + + #include "shell.h" ++#include "nodes.h" + #include "exec.h" /* defines padvance() */ + #include "var.h" + #include "output.h" + #include "memalloc.h" + #include "error.h" + #include "mail.h" ++#include "mystring.h" + + + #define MAXMBOXES 10 + +- +-STATIC int nmboxes; /* number of mailboxes */ +-STATIC time_t mailtime[MAXMBOXES]; /* times of mailboxes */ ++/* times of mailboxes */ ++static time_t mailtime[MAXMBOXES]; ++/* Set if MAIL or MAILPATH is changed. */ ++static int changed; + + + + /* +- * Print appropriate message(s) if mail has arrived. If the argument is +- * nozero, then the value of MAIL has changed, so we just update the +- * values. ++ * Print appropriate message(s) if mail has arrived. If changed is set, ++ * then the value of MAIL has changed, so we just update the values. + */ + + void +-chkmail(silent) +- int silent; ++chkmail() + { +- int i; + const char *mpath; + char *p; + char *q; ++ time_t *mtp; + struct stackmark smark; +- struct stat statb; ++ struct stat64 statb; + +- if (silent) +- nmboxes = 10; +- if (nmboxes == 0) +- return; + setstackmark(&smark); + mpath = mpathset()? mpathval() : mailval(); +- for (i = 0 ; i < nmboxes ; i++) { ++ for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) { + p = padvance(&mpath, nullstr); + if (p == NULL) + break; + if (*p == '\0') + continue; + for (q = p ; *q ; q++); ++#ifdef DEBUG + if (q[-1] != '/') + abort(); ++#endif + q[-1] = '\0'; /* delete trailing '/' */ +-#ifdef notdef /* this is what the System V shell claims to do (it lies) */ +- if (stat(p, &statb) < 0) +- statb.st_mtime = 0; +- if (statb.st_mtime > mailtime[i] && ! silent) { +- out2str(pathopt? pathopt : "you have mail"); +- out2c('\n'); ++ if (stat64(p, &statb) < 0) { ++ *mtp = 0; ++ continue; + } +- mailtime[i] = statb.st_mtime; +-#else /* this is what it should do */ +- if (stat(p, &statb) < 0) +- statb.st_size = 0; +- if (statb.st_size > mailtime[i] && ! silent) { +- out2str(pathopt? pathopt : "you have mail"); +- out2c('\n'); ++ if (!changed && statb.st_mtime != *mtp) { ++ outfmt( ++ &errout, snlfmt, ++ pathopt? pathopt : "you have mail" ++ ); + } +- mailtime[i] = statb.st_size; +-#endif ++ *mtp = statb.st_mtime; + } +- nmboxes = i; ++ changed = 0; + popstackmark(&smark); + } ++ ++ ++void ++changemail(const char *val) ++{ ++ changed++; ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/mail.h bin_NetBSD-1.6release/src/bin/sh/mail.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/mail.h 1995-10-14 00:44:08.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/mail.h 2003-02-08 14:35:42.000000000 +0000 +@@ -38,4 +38,5 @@ + * @(#)mail.h 8.2 (Berkeley) 5/4/95 + */ + +-void chkmail __P((int)); ++void chkmail __P((void)); ++void changemail __P((const char *)); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/main.c bin_NetBSD-1.6release/src/bin/sh/main.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/main.c 2001-06-13 11:08:37.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/main.c 2003-02-08 14:35:42.000000000 +0000 +@@ -79,12 +79,14 @@ + #include "exec.h" + #include "cd.h" + ++#ifdef HETIO ++#include "hetio.h" ++#endif ++ + #define PROFILE 0 + + int rootpid; + int rootshell; +-STATIC union node *curcmd; +-STATIC union node *prevcmd; + #if PROFILE + short profile_buf[16384]; + extern int etext(); +@@ -108,53 +110,49 @@ + int argc; + char **argv; + { ++ char *shinit; ++ volatile int state; + struct jmploc jmploc; + struct stackmark smark; +- volatile int state; +- char *shinit; + + #if PROFILE + monitor(4, etext, profile_buf, sizeof profile_buf, 50); + #endif + state = 0; + if (setjmp(jmploc.loc)) { +- /* +- * When a shell procedure is executed, we raise the +- * exception EXSHELLPROC to clean up before executing +- * the shell procedure. +- */ +- switch (exception) { +- case EXSHELLPROC: +- rootpid = getpid(); +- rootshell = 1; +- minusc = NULL; +- state = 3; +- break; ++ int status; ++ int e; + ++ reset(); ++ ++ e = exception; ++ switch (exception) { + case EXEXEC: +- exitstatus = exerrno; ++ status = exerrno; + break; + + case EXERROR: +- exitstatus = 2; ++ status = 2; + break; + + default: ++ status = exitstatus; + break; + } ++ exitstatus = status; + +- if (exception != EXSHELLPROC) { +- if (state == 0 || iflag == 0 || ! rootshell) +- exitshell(exitstatus); +- } +- reset(); +- if (exception == EXINT ++ if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell) ++ exitshell(); ++ ++ if (e == EXINT + #if ATTY + && (! attyset() || equal(termval(), "emacs")) + #endif + ) { + out2c('\n'); +- flushout(&errout); ++#ifdef FLUSHERR ++ flushout(out2); ++#endif + } + popstackmark(&smark); + FORCEINTON; /* enable interrupts */ +@@ -186,29 +184,18 @@ + } + state2: + state = 3; +- if (getuid() == geteuid() && getgid() == getegid()) { ++ if ( ++#ifndef linux ++ getuid() == geteuid() && getgid() == getegid() && ++#endif ++ iflag ++ ) { + if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { +- state = 3; + read_profile(shinit); + } + } + state3: + state = 4; +- if (sflag == 0 || minusc) { +- static int sigs[] = { +- SIGINT, SIGQUIT, SIGHUP, +-#ifdef SIGTSTP +- SIGTSTP, +-#endif +- SIGPIPE +- }; +-#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) +- int i; +- +- for (i = 0; i < SIGSSIZE; i++) +- setsignal(sigs[i]); +- } +- + if (minusc) + evalstring(minusc, 0); + +@@ -219,7 +206,7 @@ + #if PROFILE + monitor(0); + #endif +- exitshell(exitstatus); ++ exitshell(); + /* NOTREACHED */ + } + +@@ -240,6 +227,10 @@ + + TRACE(("cmdloop(%d) called\n", top)); + setstackmark(&smark); ++#ifdef HETIO ++ if(iflag && top) ++ hetio_init(); ++#endif + for (;;) { + if (pendingsigs) + dotrap(); +@@ -247,7 +238,7 @@ + if (iflag && top) { + inter++; + showjobs(1); +- chkmail(0); ++ chkmail(); + flushout(&output); + } + n = parsecmd(inter); +@@ -376,12 +367,8 @@ + 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; + struct stackmark smark; +@@ -403,12 +390,14 @@ + int argc; + char **argv; + { ++ int status; ++ + if (stoppedjobs()) + return 0; ++ status = oexitstatus; + if (argc > 1) +- exitstatus = number(argv[1]); +- else +- exitstatus = oexitstatus; +- exitshell(exitstatus); ++ status = number(argv[1]); ++ exitstatus = status; ++ exraise(EXEXIT); + /* NOTREACHED */ + } +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/Makefile bin_NetBSD-1.6release/src/bin/sh/Makefile +--- bin_NetBSD-1.6release.orig/src/bin/sh/Makefile 2002-12-07 08:17:35.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/Makefile 2003-02-08 14:39:28.000000000 +0000 +@@ -1,40 +1,35 @@ +-# $NetBSD: Makefile,v 1.57.2.2 2002/12/06 23:29:26 he Exp $ ++# $NetBSD: Makefile,v 1.59 2002/09/15 00:19:22 thorpej 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 \ ++SHSRCS= alias.c arith_yylex.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 +-GENSRCS=arith.c arith.h arith_lex.c builtins.c builtins.h init.c nodes.c \ +- nodes.h syntax.c syntax.h token.h ++ mystring.c options.c parser.c printf.c redir.c show.c trap.c output.c \ ++ var.c test.c setmode.c times.c hetio.c ++GENSRCS=arith.c arith.h builtins.c builtins.h init.c nodes.c \ ++ nodes.h signames.c syntax.c syntax.h token.h + SRCS= ${SHSRCS} ${GENSRCS} + +-LDADD+= -ll -ledit -ltermcap +-DPADD+= ${LIBL} ${LIBEDIT} ${LIBTERMCAP} +- +-LFLAGS= -8 # 8-bit lex scanner for arithmetic + YFLAGS= -d + + CPPFLAGS+=-DSHELL -I. -I${.CURDIR} ++CPPFLAGS+=-DSMALL -DHETIO + +-.ifdef SMALLPROG +-CPPFLAGS+=-DSMALL +-.endif +- +-.PATH: ${.CURDIR}/bltin ${.CURDIR}/../test ++.PATH: ${.CURDIR}/bltin ${NETBSDSRCDIR}/bin/test + + CLEANFILES+= mkinit mknodes mksyntax + CLEANFILES+= ${GENSRCS} y.tab.h + ++BLTINDEFS=specialbltins.def regularbltins.def assignbltins.def ++ + token.h: mktokens + sh ${.ALLSRC} + +-builtins.c builtins.h: mkbuiltins shell.h builtins.def +- sh ${.ALLSRC} ${.OBJDIR} ++builtins.c builtins.h: mkbuiltins shell.h builtins.def ${BLTINDEFS} ++ sh ${.ALLSRC} ${.OBJDIR} '${CFLAGS}' + + init.c: mkinit ${SHSRCS} + ./${.ALLSRC} +@@ -45,22 +40,18 @@ + syntax.c syntax.h: mksyntax + ./${.ALLSRC} + ++signames.c: mksignames ++ ./${.ALLSRC} ++ + mkinit: mkinit.c + ${HOST_LINK.c} -o mkinit ${.IMPSRC} + + mknodes: mknodes.c + ${HOST_LINK.c} -o mknodes ${.IMPSRC} + +-.if (${MACHINE_ARCH} == "powerpc") || \ +- (${MACHINE_CPU} == "arm") +-TARGET_CHARFLAG= -DTARGET_CHAR="unsigned char" +-.else +-TARGET_CHARFLAG= -DTARGET_CHAR="signed char" +-.endif +- + mksyntax: mksyntax.c + ${HOST_LINK.c} ${TARGET_CHARFLAG} -o mksyntax ${.IMPSRC} + + .include <bsd.prog.mk> + +-${OBJS}: builtins.h nodes.h syntax.h token.h ++${OBJS}: arith.h builtins.h nodes.h syntax.h token.h +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/memalloc.c bin_NetBSD-1.6release/src/bin/sh/memalloc.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/memalloc.c 2001-01-12 16:50:36.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/memalloc.c 2003-02-08 14:35:42.000000000 +0000 +@@ -60,15 +60,11 @@ + */ + + pointer +-ckmalloc(nbytes) +- int nbytes; ++ckmalloc(size_t nbytes) + { + pointer p; + +- INTOFF; +- p = malloc(nbytes); +- INTON; +- if (p == NULL) ++ if ((p = malloc(nbytes)) == NULL) + error("Out of space"); + return p; + } +@@ -79,9 +75,7 @@ + */ + + pointer +-ckrealloc(p, nbytes) +- pointer p; +- int nbytes; ++ckrealloc(pointer p, size_t nbytes) + { + + if ((p = realloc(p, nbytes)) == NULL) +@@ -96,12 +90,11 @@ + + char * + savestr(s) +- char *s; ++ const char *s; + { +- char *p; +- +- p = ckmalloc(strlen(s) + 1); +- scopy(s, p); ++ char *p = strdup(s); ++ if (!p) ++ error("Out of space"); + return p; + } + +@@ -115,7 +108,7 @@ + * well. + */ + +-#define MINSIZE 504 /* minimum size of a block */ ++#define MINSIZE ALIGN(504) /* minimum size of a block */ + + + struct stack_block { +@@ -127,37 +120,42 @@ + struct stack_block *stackp = &stackbase; + struct stackmark *markp; + char *stacknxt = stackbase.space; +-int stacknleft = MINSIZE; +-int sstrnleft; ++size_t stacknleft = MINSIZE; ++char *sstrend = stackbase.space + MINSIZE; + int herefd = -1; + + + + pointer +-stalloc(nbytes) +- int nbytes; ++stalloc(size_t nbytes) + { + char *p; ++ size_t aligned; + +- nbytes = ALIGN(nbytes); ++ aligned = ALIGN(nbytes); + if (nbytes > stacknleft) { +- int blocksize; ++ size_t len; ++ size_t blocksize; + struct stack_block *sp; + +- blocksize = nbytes; ++ blocksize = aligned; + if (blocksize < MINSIZE) + blocksize = MINSIZE; ++ len = sizeof(struct stack_block) - MINSIZE + blocksize; ++ if (len < blocksize) ++ error("Out of space"); + INTOFF; +- sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize); ++ sp = ckmalloc(len); + sp->prev = stackp; + stacknxt = sp->space; + stacknleft = blocksize; ++ sstrend = stacknxt + blocksize; + stackp = sp; + INTON; + } + p = stacknxt; +- stacknxt += nbytes; +- stacknleft -= nbytes; ++ stacknxt += aligned; ++ stacknleft -= aligned; + return p; + } + +@@ -166,10 +164,12 @@ + stunalloc(p) + pointer p; + { +- if (p == NULL) { /*DEBUG */ ++#ifdef DEBUG ++ if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { + write(2, "stunalloc\n", 10); + abort(); + } ++#endif + stacknleft += stacknxt - (char *)p; + stacknxt = p; + } +@@ -203,6 +203,7 @@ + } + stacknxt = mark->stacknxt; + stacknleft = mark->stacknleft; ++ sstrend = mark->stacknxt + mark->stacknleft; + INTON; + } + +@@ -220,22 +221,31 @@ + void + growstackblock() { + char *p; +- int newlen = ALIGN(stacknleft * 2 + 100); ++ size_t newlen, grosslen; + char *oldspace = stacknxt; +- int oldlen = stacknleft; ++ size_t oldlen = stacknleft; + struct stack_block *sp; + struct stack_block *oldstackp; ++ struct stack_block *prevstackp; ++ ++ grosslen = stacknleft * 2; ++ if (grosslen < stacknleft) ++ error("Out of space"); ++ if (grosslen < 128) ++ grosslen += 128 + sizeof(struct stack_block) - MINSIZE; ++ newlen = grosslen - (sizeof(struct stack_block) - MINSIZE); + + if (stacknxt == stackp->space && stackp != &stackbase) { + INTOFF; + oldstackp = stackp; + sp = stackp; +- stackp = sp->prev; +- sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen); +- sp->prev = stackp; ++ prevstackp = sp->prev; ++ sp = ckrealloc((pointer)sp, grosslen); ++ sp->prev = prevstackp; + stackp = sp; + stacknxt = sp->space; + stacknleft = newlen; ++ sstrend = sp->space + newlen; + { + /* Stack marks pointing to the start of the old block + * must be relocated to point to the new block +@@ -252,17 +262,16 @@ + INTON; + } else { + p = stalloc(newlen); +- memcpy(p, oldspace, oldlen); +- stacknxt = p; /* free the space */ +- stacknleft += newlen; /* we just allocated */ ++ /* free the space we just allocated */ ++ stacknxt = memcpy(p, oldspace, oldlen); ++ stacknleft += newlen; + } + } + + + + void +-grabstackblock(len) +- int len; ++grabstackblock(size_t len) + { + len = ALIGN(len); + stacknxt += len; +@@ -290,16 +299,14 @@ + */ + + +-char * ++void * + growstackstr() { +- int len = stackblocksize(); ++ size_t len = stackblocksize(); + if (herefd >= 0 && len >= 1024) { + xwrite(herefd, stackblock(), len); +- sstrnleft = len - 1; + return stackblock(); + } + growstackblock(); +- sstrnleft = stackblocksize() - len - 1; + return stackblock() + len; + } + +@@ -309,21 +316,33 @@ + */ + + char * +-makestrspace() { +- int len = stackblocksize() - sstrnleft; ++makestrspace(size_t newlen, char *p) { ++ size_t len = p - stackblock(); ++ size_t size = stackblocksize(); ++ ++ for (;;) { ++ size_t nleft; ++ ++ size = stackblocksize(); ++ nleft = size - len; ++ if (nleft >= newlen) ++ break; + growstackblock(); +- sstrnleft = stackblocksize() - len; ++ } + return stackblock() + len; + } + + + +-void +-ungrabstackstr(s, p) +- char *s; +- char *p; +- { +- stacknleft += stacknxt - s; +- stacknxt = s; +- sstrnleft = stacknleft - (p - s); ++char * ++stnputs(const char *s, size_t n, char *p) { ++ p = makestrspace(n, p); ++ p = mempcpy(p, s, n); ++ return p; ++} ++ ++ ++char * ++stputs(const char *s, char *p) { ++ return stnputs(s, strlen(s), p); + } +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/memalloc.h bin_NetBSD-1.6release/src/bin/sh/memalloc.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/memalloc.h 2001-01-12 16:50:37.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/memalloc.h 2003-02-08 14:35:42.000000000 +0000 +@@ -38,44 +38,62 @@ + * @(#)memalloc.h 8.2 (Berkeley) 5/4/95 + */ + ++#include <stddef.h> ++ + struct stackmark { + struct stack_block *stackp; + char *stacknxt; +- int stacknleft; ++ size_t stacknleft; + struct stackmark *marknext; + }; + + + extern char *stacknxt; +-extern int stacknleft; +-extern int sstrnleft; ++extern size_t stacknleft; ++extern char *sstrend; + extern int herefd; + +-pointer ckmalloc __P((int)); +-pointer ckrealloc __P((pointer, int)); +-char *savestr __P((char *)); +-pointer stalloc __P((int)); ++pointer ckmalloc __P((size_t)); ++pointer ckrealloc __P((pointer, size_t)); ++char *savestr __P((const char *)); ++pointer stalloc __P((size_t)); + void stunalloc __P((pointer)); + void setstackmark __P((struct stackmark *)); + void popstackmark __P((struct stackmark *)); + void growstackblock __P((void)); +-void grabstackblock __P((int)); +-char *growstackstr __P((void)); +-char *makestrspace __P((void)); +-void ungrabstackstr __P((char *, char *)); ++void grabstackblock __P((size_t)); ++void *growstackstr __P((void)); ++char *makestrspace __P((size_t, char *)); ++char *stnputs __P((const char *, size_t, char *)); ++char *stputs __P((const char *, char *)); + + ++static inline char *_STPUTC(char c, char *p) { ++ if (p == sstrend) ++ p = growstackstr(); ++ *p++ = c; ++ return p; ++} + + #define stackblock() stacknxt + #define stackblocksize() stacknleft +-#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize() +-#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c))) +-#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(); } +-#define USTPUTC(c, p) (--sstrnleft, *p++ = (c)) +-#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0')) +-#define STUNPUTC(p) (++sstrnleft, --p) ++#define STARTSTACKSTR(p) (p) = ((void *) stackblock()) ++#define STPUTC(c, p) (p) = _STPUTC(c, p) ++#define CHECKSTRSPACE(n, p) \ ++ ({ \ ++ char *q = (p); \ ++ size_t l = (n); \ ++ size_t m = sstrend - q; \ ++ if (l > m) \ ++ (p) = makestrspace(l, q); \ ++ 0; \ ++ }) ++#define USTPUTC(c, p) (*p++ = (c)) ++#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0')) ++#define STUNPUTC(p) (--p) + #define STTOPC(p) p[-1] +-#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount)) +-#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft) ++#define STADJUST(amount, p) (p += (amount)) ++#define grabstackstr(p) stalloc(((char *) (p)) - stackblock()) ++#define ungrabstackstr(s, p) stunalloc((s)) + + #define ckfree(p) free((pointer)(p)) +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/miscbltin.c bin_NetBSD-1.6release/src/bin/sh/miscbltin.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/miscbltin.c 2001-02-05 11:15:31.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/miscbltin.c 2003-02-08 14:35:42.000000000 +0000 +@@ -70,6 +70,15 @@ + + #undef rflag + ++#ifdef __GLIBC__ ++mode_t getmode(const void *, mode_t); ++void *setmode(const char *); ++ ++#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 ++typedef enum __rlimit_resource rlim_t; ++#endif ++#endif ++ + + + /* +@@ -89,7 +98,7 @@ + char c; + int rflag; + char *prompt; +- char *ifs; ++ const char *ifs; + char *p; + int startword; + int status; +@@ -105,12 +114,14 @@ + } + if (prompt && isatty(0)) { + out2str(prompt); ++#ifdef FLUSHERR + flushall(); ++#endif + } + if (*(ap = argptr) == NULL) + error("arg count"); +- if ((ifs = bltinlookup("IFS", 1)) == NULL) +- ifs = nullstr; ++ if ((ifs = bltinlookup("IFS")) == NULL) ++ ifs = defifs; + status = 0; + startword = 1; + backslash = 0; +@@ -125,7 +136,7 @@ + if (backslash) { + backslash = 0; + if (c != '\n') +- STPUTC(c, p); ++ goto put; + continue; + } + if (!rflag && c == '\\') { +@@ -138,19 +149,14 @@ + continue; + } + startword = 0; +- if (backslash && c == '\\') { +- if (read(0, &c, 1) != 1) { +- status = 1; +- break; +- } +- STPUTC(c, p); +- } else if (ap[1] != NULL && strchr(ifs, c) != NULL) { ++ if (ap[1] != NULL && strchr(ifs, c) != NULL) { + STACKSTRNUL(p); + setvar(*ap, stackblock(), 0); + ap++; + startword = 1; + STARTSTACKSTR(p); + } else { ++put: + STPUTC(c, p); + } + } +@@ -225,7 +231,7 @@ + mask = 0; + do { + if (*ap >= '8' || *ap < '0') +- error("Illegal number: %s", argv[1]); ++ error(illnum, argv[1]); + mask = (mask << 3) + (*ap - '0'); + } while (*++ap != '\0'); + umask(mask); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/mkbuiltins bin_NetBSD-1.6release/src/bin/sh/mkbuiltins +--- bin_NetBSD-1.6release.orig/src/bin/sh/mkbuiltins 1999-07-09 12:02:07.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/mkbuiltins 2003-02-08 14:35:42.000000000 +0000 +@@ -37,21 +37,25 @@ + # + # @(#)mkbuiltins 8.2 (Berkeley) 5/4/95 + +-temp=/tmp/ka$$ ++trap 'rm -f $temp $temp2' EXIT ++temp=$(tempfile) ++temp2=$(tempfile) ++ ++shell=$1 ++builtins=$2 ++specialbltins=$3 ++regularbltins=$4 ++assignbltins=$5 ++objdir=$6 + + havehist=1 +-if [ "X$1" = "X-h" ]; then ++if [ -z "${7##*-DSMALL*}" ]; then + havehist=0 +- shift + fi +-shell=$1 +-builtins=$2 +-objdir=$3 + +-havejobs=0 +-if grep '^#define JOBS[ ]*1' ${shell} > /dev/null +-then +- havejobs=1 ++havejobs=1 ++if [ -z "${7##*-DJOBS=0*}" ]; then ++ havejobs=0 + fi + + exec > ${objdir}/builtins.c +@@ -65,19 +69,19 @@ + + ! + awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \ +- print $0}' ${builtins} | sed 's/-j//' > $temp ++ print $0}' ${builtins} | sed 's/-[hj]//' > $temp + awk '{ printf "int %s __P((int, char **));\n", $1}' $temp + echo ' +-int (*const builtinfunc[]) __P((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 } +-};' ++ print $i "\t" $1 ++ }}' $temp | sort -k 1,1 | tee $temp2 | ++ join -a 1 -e 0 -o 1.1,1.2,2.1 - $specialbltins | ++ join -a 1 -e 0 -o 1.1,1.2,1.3,2.1 - $regularbltins | ++ join -a 1 -e 0 -o 1.1,1.2,1.3,1.4,2.1 - $assignbltins | ++ awk '{ printf "\t{ \"%s\", %s, %d },\n", $1, $2, ++ !!$3 + (!!$4 * 2) + (!!$5 * 4)}' ++echo '};' + + exec > ${objdir}/builtins.h + cat <<\! +@@ -87,14 +91,19 @@ + + #include <sys/cdefs.h> + ! +-tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ < $temp | +- awk '{ printf "#define %s %d\n", $1, NR-1}' ++nl -v 0 $temp2 | sort -u -k 3,3 | ++tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ | ++ awk '{ printf "#define %s (builtincmd + %d)\n", $3, $1}' ++printf '\n#define NUMBUILTINS %d\n' $(wc -l < $temp2) + echo ' ++#define BUILTIN_SPECIAL 0x1 ++#define BUILTIN_REGULAR 0x2 ++#define BUILTIN_ASSIGN 0x4 ++ + struct builtincmd { + const char *name; +- int code; ++ int (*const builtinfunc) __P((int, char **)); ++ unsigned flags; + }; + +-extern int (*const builtinfunc[]) __P((int, char **)); + extern const struct builtincmd builtincmd[];' +-rm -f $temp +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/mkinit.c bin_NetBSD-1.6release/src/bin/sh/mkinit.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/mkinit.c 2001-01-12 16:50:37.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/mkinit.c 2003-02-08 14:35:42.000000000 +0000 +@@ -131,16 +131,10 @@ + * 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} + }; + +@@ -218,8 +212,6 @@ + doinclude(line); + if (line[0] == 'M' && match("MKINIT", line)) + dodecl(line, fp); +- if (line[0] == '#' && gooddefine(line)) +- addstr(line, &defines); + if (line[0] == '#' && gooddefine(line)) { + char *cp; + char line2[1024]; +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/mknodes.c bin_NetBSD-1.6release/src/bin/sh/mknodes.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/mknodes.c 2001-01-12 16:50:38.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/mknodes.c 2003-02-08 14:35:42.000000000 +0000 +@@ -1,4 +1,4 @@ +-/* $NetBSD: mknodes.c,v 1.18 2000/07/27 04:06:49 cgd Exp $ */ ++/* $NetBSD: mknodes.c,v 1.19 2002/05/25 23:09:06 wiz Exp $ */ + + /*- + * Copyright (c) 1991, 1993 +@@ -47,7 +47,7 @@ + static char sccsid[] = "@(#)mknodes.c 8.2 (Berkeley) 5/4/95"; + #else + static const char rcsid[] = +- "$NetBSD: mknodes.c,v 1.18 2000/07/27 04:06:49 cgd Exp $"; ++ "$NetBSD: mknodes.c,v 1.19 2002/05/25 23:09:06 wiz Exp $"; + #endif + #endif /* not lint */ + +@@ -59,12 +59,7 @@ + #include <stdio.h> + #include <stdlib.h> + #include <string.h> +-#ifdef __STDC__ + #include <stdarg.h> +-#else +-#include <varargs.h> +-#endif +- + + #define MAXTYPES 50 /* max number of node types */ + #define MAXFIELDS 20 /* max fields in a structure */ +@@ -270,13 +265,12 @@ + fputs("\tstruct nodelist *next;\n", hfile); + fputs("\tunion node *n;\n", hfile); + fputs("};\n\n\n", hfile); +- fputs("#ifdef __STDC__\n", hfile); +- fputs("union node *copyfunc(union node *);\n", hfile); +- fputs("void freefunc(union node *);\n", hfile); +- fputs("#else\n", hfile); +- fputs("union node *copyfunc();\n", hfile); +- fputs("void freefunc();\n", hfile); +- fputs("#endif\n", hfile); ++ fputs("struct funcnode {\n", hfile); ++ fputs("\tint count;\n", hfile); ++ fputs("\tunion node n;\n", hfile); ++ fputs("};\n\n\n", hfile); ++ fputs("struct funcnode *copyfunc(union node *);\n", hfile); ++ fputs("void freefunc(struct funcnode *);\n", hfile); + + fputs(writer, cfile); + while (fgets(line, sizeof line, patfile) != NULL) { +@@ -451,21 +445,11 @@ + + + static void +-#ifdef __STDC__ + error(const char *msg, ...) +-#else +-error(va_alist) +- va_dcl +-#endif + { + va_list va; +-#ifdef __STDC__ ++ + va_start(va, msg); +-#else +- char *msg; +- va_start(va); +- msg = va_arg(va, char *); +-#endif + + (void) fprintf(stderr, "line %d: ", linno); + (void) vfprintf(stderr, msg, va); +Files bin_NetBSD-1.6release.orig/src/bin/sh/mksignames and bin_NetBSD-1.6release/src/bin/sh/mksignames differ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/mksignames.c bin_NetBSD-1.6release/src/bin/sh/mksignames.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/mksignames.c 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/mksignames.c 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,419 @@ ++/* signames.c -- Create and write `signames.c', which contains an array of ++ signal names. */ ++ ++/* Copyright (C) 1992 Free Software Foundation, Inc. ++ ++ This file is part of GNU Bash, the Bourne Again SHell. ++ ++ Bash is free software; you can redistribute it and/or modify it under ++ the terms of the GNU General Public License as published by the Free ++ Software Foundation; either version 2, or (at your option) any later ++ version. ++ ++ Bash is distributed in the hope that it will be useful, but WITHOUT ANY ++ WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ for more details. ++ ++ You should have received a copy of the GNU General Public License along ++ with Bash; see the file COPYING. If not, write to the Free Software ++ Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ ++ ++#include <stdio.h> ++#include <sys/types.h> ++#include <signal.h> ++#include <stdlib.h> ++ ++#if !defined (NSIG) ++# define NSIG 64 ++#endif ++ ++/* ++ * Special traps: ++ * EXIT == 0 ++ */ ++#define LASTSIG NSIG-1 ++ ++char *signal_names[2 * NSIG + 3]; ++ ++#define signal_names_size (sizeof(signal_names)/sizeof(signal_names[0])) ++ ++char *progname; ++ ++/* AIX 4.3 defines SIGRTMIN and SIGRTMAX as 888 and 999 respectively. ++ I don't want to allocate so much unused space for the intervening signal ++ numbers, so we just punt if SIGRTMAX is past the bounds of the ++ signal_names array (handled in configure). */ ++#if defined (SIGRTMAX) && defined (UNUSABLE_RT_SIGNALS) ++# undef SIGRTMAX ++# undef SIGRTMIN ++#endif ++ ++#if defined (SIGRTMAX) || defined (SIGRTMIN) ++# define RTLEN 14 ++# define RTLIM 256 ++#endif ++ ++void ++initialize_signames () ++{ ++ register int i; ++#if defined (SIGRTMAX) || defined (SIGRTMIN) ++ int rtmin, rtmax, rtcnt; ++#endif ++ ++ for (i = 1; i < signal_names_size; i++) ++ signal_names[i] = (char *)NULL; ++ ++ /* `signal' 0 is what we do on exit. */ ++ signal_names[0] = "EXIT"; ++ ++ /* Place signal names which can be aliases for more common signal ++ names first. This allows (for example) SIGABRT to overwrite SIGLOST. */ ++ ++ /* POSIX 1003.1b-1993 real time signals, but take care of incomplete ++ implementations. Acoording to the standard, both, SIGRTMIN and ++ SIGRTMAX must be defined, SIGRTMIN must be stricly less than ++ SIGRTMAX, and the difference must be at least 7, that is, there ++ must be at least eight distinct real time signals. */ ++ ++ /* The generated signal names are SIGRTMIN, SIGRTMIN+1, ..., ++ SIGRTMIN+x, SIGRTMAX-x, ..., SIGRTMAX-1, SIGRTMAX. If the number ++ of RT signals is odd, there is an extra SIGRTMIN+(x+1). ++ These names are the ones used by ksh and /usr/xpg4/bin/sh on SunOS5. */ ++ ++#if defined (SIGRTMIN) ++ rtmin = SIGRTMIN; ++ signal_names[rtmin] = "RTMIN"; ++#endif ++ ++#if defined (SIGRTMAX) ++ rtmax = SIGRTMAX; ++ signal_names[rtmax] = "RTMAX"; ++#endif ++ ++#if defined (SIGRTMAX) && defined (SIGRTMIN) ++ if (rtmax > rtmin) ++ { ++ rtcnt = (rtmax - rtmin - 1) / 2; ++ /* croak if there are too many RT signals */ ++ if (rtcnt >= RTLIM/2) ++ { ++ rtcnt = RTLIM/2-1; ++ fprintf(stderr, "%s: error: more than %i real time signals, fix `%s'\n", ++ progname, RTLIM, progname); ++ } ++ ++ for (i = 1; i <= rtcnt; i++) ++ { ++ signal_names[rtmin+i] = (char *)malloc(RTLEN); ++ if (signal_names[rtmin+i]) ++ sprintf (signal_names[rtmin+i], "RTMIN+%d", i); ++ signal_names[rtmax-i] = (char *)malloc(RTLEN); ++ if (signal_names[rtmax-i]) ++ sprintf (signal_names[rtmax-i], "RTMAX-%d", i); ++ } ++ ++ if (rtcnt < RTLIM/2-1 && rtcnt != (rtmax-rtmin)/2) ++ { ++ /* Need an extra RTMIN signal */ ++ signal_names[rtmin+rtcnt+1] = (char *)malloc(RTLEN); ++ if (signal_names[rtmin+rtcnt+1]) ++ sprintf (signal_names[rtmin+rtcnt+1], "RTMIN+%d", rtcnt+1); ++ } ++ } ++#endif /* SIGRTMIN && SIGRTMAX */ ++ ++/* AIX */ ++#if defined (SIGLOST) /* resource lost (eg, record-lock lost) */ ++ signal_names[SIGLOST] = "LOST"; ++#endif ++ ++#if defined (SIGMSG) /* HFT input data pending */ ++ signal_names[SIGMSG] = "MSG"; ++#endif ++ ++#if defined (SIGDANGER) /* system crash imminent */ ++ signal_names[SIGDANGER] = "DANGER"; ++#endif ++ ++#if defined (SIGMIGRATE) /* migrate process to another CPU */ ++ signal_names[SIGMIGRATE] = "MIGRATE"; ++#endif ++ ++#if defined (SIGPRE) /* programming error */ ++ signal_names[SIGPRE] = "PRE"; ++#endif ++ ++#if defined (SIGVIRT) /* AIX virtual time alarm */ ++ signal_names[SIGVIRT] = "VIRT"; ++#endif ++ ++#if defined (SIGALRM1) /* m:n condition variables */ ++ signal_names[SIGALRM1] = "ALRM1"; ++#endif ++ ++#if defined (SIGWAITING) /* m:n scheduling */ ++ signal_names[SIGWAITING] = "WAITING"; ++#endif ++ ++#if defined (SIGGRANT) /* HFT monitor mode granted */ ++ signal_names[SIGGRANT] = "GRANT"; ++#endif ++ ++#if defined (SIGKAP) /* keep alive poll from native keyboard */ ++ signal_names[SIGKAP] = "KAP"; ++#endif ++ ++#if defined (SIGRETRACT) /* HFT monitor mode retracted */ ++ signal_names[SIGRETRACT] = "RETRACT"; ++#endif ++ ++#if defined (SIGSOUND) /* HFT sound sequence has completed */ ++ signal_names[SIGSOUND] = "SOUND"; ++#endif ++ ++#if defined (SIGSAK) /* Secure Attention Key */ ++ signal_names[SIGSAK] = "SAK"; ++#endif ++ ++/* SunOS5 */ ++#if defined (SIGLWP) /* special signal used by thread library */ ++ signal_names[SIGLWP] = "LWP"; ++#endif ++ ++#if defined (SIGFREEZE) /* special signal used by CPR */ ++ signal_names[SIGFREEZE] = "FREEZE"; ++#endif ++ ++#if defined (SIGTHAW) /* special signal used by CPR */ ++ signal_names[SIGTHAW] = "THAW"; ++#endif ++ ++#if defined (SIGCANCEL) /* thread cancellation signal used by libthread */ ++ signal_names[SIGCANCEL] = "CANCEL"; ++#endif ++ ++/* HP-UX */ ++#if defined (SIGDIL) /* DIL signal (?) */ ++ signal_names[SIGDIL] = "DIL"; ++#endif ++ ++/* System V */ ++#if defined (SIGCLD) /* Like SIGCHLD. */ ++ signal_names[SIGCLD] = "CLD"; ++#endif ++ ++#if defined (SIGPWR) /* power state indication */ ++ signal_names[SIGPWR] = "PWR"; ++#endif ++ ++#if defined (SIGPOLL) /* Pollable event (for streams) */ ++ signal_names[SIGPOLL] = "POLL"; ++#endif ++ ++/* Unknown */ ++#if defined (SIGWINDOW) ++ signal_names[SIGWINDOW] = "WINDOW"; ++#endif ++ ++/* Common */ ++#if defined (SIGHUP) /* hangup */ ++ signal_names[SIGHUP] = "HUP"; ++#endif ++ ++#if defined (SIGINT) /* interrupt */ ++ signal_names[SIGINT] = "INT"; ++#endif ++ ++#if defined (SIGQUIT) /* quit */ ++ signal_names[SIGQUIT] = "QUIT"; ++#endif ++ ++#if defined (SIGILL) /* illegal instruction (not reset when caught) */ ++ signal_names[SIGILL] = "ILL"; ++#endif ++ ++#if defined (SIGTRAP) /* trace trap (not reset when caught) */ ++ signal_names[SIGTRAP] = "TRAP"; ++#endif ++ ++#if defined (SIGIOT) /* IOT instruction */ ++ signal_names[SIGIOT] = "IOT"; ++#endif ++ ++#if defined (SIGABRT) /* Cause current process to dump core. */ ++ signal_names[SIGABRT] = "ABRT"; ++#endif ++ ++#if defined (SIGEMT) /* EMT instruction */ ++ signal_names[SIGEMT] = "EMT"; ++#endif ++ ++#if defined (SIGFPE) /* floating point exception */ ++ signal_names[SIGFPE] = "FPE"; ++#endif ++ ++#if defined (SIGKILL) /* kill (cannot be caught or ignored) */ ++ signal_names[SIGKILL] = "KILL"; ++#endif ++ ++#if defined (SIGBUS) /* bus error */ ++ signal_names[SIGBUS] = "BUS"; ++#endif ++ ++#if defined (SIGSEGV) /* segmentation violation */ ++ signal_names[SIGSEGV] = "SEGV"; ++#endif ++ ++#if defined (SIGSYS) /* bad argument to system call */ ++ signal_names[SIGSYS] = "SYS"; ++#endif ++ ++#if defined (SIGPIPE) /* write on a pipe with no one to read it */ ++ signal_names[SIGPIPE] = "PIPE"; ++#endif ++ ++#if defined (SIGALRM) /* alarm clock */ ++ signal_names[SIGALRM] = "ALRM"; ++#endif ++ ++#if defined (SIGTERM) /* software termination signal from kill */ ++ signal_names[SIGTERM] = "TERM"; ++#endif ++ ++#if defined (SIGURG) /* urgent condition on IO channel */ ++ signal_names[SIGURG] = "URG"; ++#endif ++ ++#if defined (SIGSTOP) /* sendable stop signal not from tty */ ++ signal_names[SIGSTOP] = "STOP"; ++#endif ++ ++#if defined (SIGTSTP) /* stop signal from tty */ ++ signal_names[SIGTSTP] = "TSTP"; ++#endif ++ ++#if defined (SIGCONT) /* continue a stopped process */ ++ signal_names[SIGCONT] = "CONT"; ++#endif ++ ++#if defined (SIGCHLD) /* to parent on child stop or exit */ ++ signal_names[SIGCHLD] = "CHLD"; ++#endif ++ ++#if defined (SIGTTIN) /* to readers pgrp upon background tty read */ ++ signal_names[SIGTTIN] = "TTIN"; ++#endif ++ ++#if defined (SIGTTOU) /* like TTIN for output if (tp->t_local<OSTOP) */ ++ signal_names[SIGTTOU] = "TTOU"; ++#endif ++ ++#if defined (SIGIO) /* input/output possible signal */ ++ signal_names[SIGIO] = "IO"; ++#endif ++ ++#if defined (SIGXCPU) /* exceeded CPU time limit */ ++ signal_names[SIGXCPU] = "XCPU"; ++#endif ++ ++#if defined (SIGXFSZ) /* exceeded file size limit */ ++ signal_names[SIGXFSZ] = "XFSZ"; ++#endif ++ ++#if defined (SIGVTALRM) /* virtual time alarm */ ++ signal_names[SIGVTALRM] = "VTALRM"; ++#endif ++ ++#if defined (SIGPROF) /* profiling time alarm */ ++ signal_names[SIGPROF] = "PROF"; ++#endif ++ ++#if defined (SIGWINCH) /* window changed */ ++ signal_names[SIGWINCH] = "WINCH"; ++#endif ++ ++/* 4.4 BSD */ ++#if defined (SIGINFO) && !defined (_SEQUENT_) /* information request */ ++ signal_names[SIGINFO] = "INFO"; ++#endif ++ ++#if defined (SIGUSR1) /* user defined signal 1 */ ++ signal_names[SIGUSR1] = "USR1"; ++#endif ++ ++#if defined (SIGUSR2) /* user defined signal 2 */ ++ signal_names[SIGUSR2] = "USR2"; ++#endif ++ ++#if defined (SIGKILLTHR) /* BeOS: Kill Thread */ ++ signal_names[SIGKILLTHR] = "KILLTHR"; ++#endif ++ ++ for (i = 0; i < NSIG; i++) ++ if (signal_names[i] == (char *)NULL) ++ { ++ signal_names[i] = (char *)malloc (18); ++ if (signal_names[i]) ++ sprintf (signal_names[i], "%d", i); ++ } ++} ++ ++void ++write_signames (stream) ++ FILE *stream; ++{ ++ register int i; ++ ++ fprintf (stream, "/* This file was automatically created by %s.\n", ++ progname); ++ fprintf (stream, " Do not edit. Edit support/mksignames.c instead. */\n\n"); ++ fprintf (stream, "#include <signal.h>\n\n"); ++ fprintf (stream, ++ "/* A translation list so we can be polite to our users. */\n"); ++ fprintf (stream, "const char *const signal_names[NSIG + 1] = {\n"); ++ ++ for (i = 0; i <= LASTSIG; i++) ++ fprintf (stream, " \"%s\",\n", signal_names[i]); ++ ++ fprintf (stream, " (char *)0x0\n"); ++ fprintf (stream, "};\n"); ++} ++ ++int ++main (argc, argv) ++ int argc; ++ char **argv; ++{ ++ char *stream_name; ++ FILE *stream; ++ ++ progname = argv[0]; ++ ++ if (argc == 1) ++ { ++ stream_name = "signames.c"; ++ } ++ else if (argc == 2) ++ { ++ stream_name = argv[1]; ++ } ++ else ++ { ++ fprintf (stderr, "Usage: %s [output-file]\n", progname); ++ exit (1); ++ } ++ ++ stream = fopen (stream_name, "w"); ++ if (!stream) ++ { ++ fprintf (stderr, "%s: %s: cannot open for writing\n", ++ progname, stream_name); ++ exit (2); ++ } ++ ++ initialize_signames (); ++ write_signames (stream); ++ exit (0); ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/mksyntax.c bin_NetBSD-1.6release/src/bin/sh/mksyntax.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/mksyntax.c 2002-06-02 02:11:43.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/mksyntax.c 2003-02-08 14:35:42.000000000 +0000 +@@ -1,4 +1,4 @@ +-/* $NetBSD: mksyntax.c,v 1.24.4.1 2002/05/31 16:42:05 tv Exp $ */ ++/* $NetBSD: mksyntax.c,v 1.25 2002/05/31 16:18:48 christos Exp $ */ + + /*- + * Copyright (c) 1991, 1993 +@@ -47,7 +47,7 @@ + static char sccsid[] = "@(#)mksyntax.c 8.2 (Berkeley) 5/4/95"; + #else + static const char rcsid[] = +- "$NetBSD: mksyntax.c,v 1.24.4.1 2002/05/31 16:42:05 tv Exp $"; ++ "$NetBSD: mksyntax.c,v 1.25 2002/05/31 16:18:48 christos Exp $"; + #endif + #endif /* not lint */ + +@@ -73,6 +73,7 @@ + { "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" }, +@@ -81,6 +82,7 @@ + { "CEOF", "end of file" }, + { "CCTL", "like CWORD, except it must be escaped" }, + { "CSPCL", "these terminate a word" }, ++ { "CIGN", "character should be ignored" }, + { NULL, NULL } + }; + +@@ -168,7 +170,7 @@ + exit(2); + } + size = (1 << nbits) + 1; +- base = 1; ++ base = 2; + if (sign) + base += 1 << (nbits - 1); + digit_contig = 1; +@@ -179,6 +181,11 @@ + + fputs("#include <sys/cdefs.h>\n", hfile); + fputs("#include <ctype.h>\n", hfile); ++ fputs("\n", hfile); ++ fputs("#ifdef CEOF\n", hfile); ++ fputs("#undef CEOF\n", hfile); ++ fputs("#endif\n", hfile); ++ fputs("\n", hfile); + + /* Generate the #define statements in the header file */ + fputs("/* Syntax classes */\n", hfile); +@@ -201,10 +208,7 @@ + putc('\n', hfile); + fprintf(hfile, "#define SYNBASE %d\n", base); + fprintf(hfile, "#define PEOF %d\n\n", -base); +- if (sign) +- fprintf(hfile, "#define UPEOF ((char)%d)\n\n", -base); +- else +- fprintf(hfile, "#define UPEOF ((unsigned char)%d)\n\n", -base); ++ fprintf(hfile, "#define PEOA %d\n\n", -base + 1); + putc('\n', hfile); + fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile); + fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile); +@@ -227,32 +231,31 @@ + add("$", "CVAR"); + add("}", "CENDVAR"); + add("<>();&| \t", "CSPCL"); ++ syntax[1] = "CSPCL"; + print("basesyntax"); + init(); + fputs("\n/* syntax table used when in double quotes */\n", cfile); + add("\n", "CNL"); + add("\\", "CBACK"); +- add("\"", "CDQUOTE"); ++ add("\"", "CENDQUOTE"); + add("`", "CBQUOTE"); + add("$", "CVAR"); + add("}", "CENDVAR"); + /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ +- add("!*?[=~:/-", "CCTL"); ++ add("!*?[=~:/-]", "CCTL"); + print("dqsyntax"); + init(); + fputs("\n/* syntax table used when in single quotes */\n", cfile); + add("\n", "CNL"); +- add("'", "CSQUOTE"); ++ add("'", "CENDQUOTE"); + /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ +- add("!*?[=~:/-", "CCTL"); ++ 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"); +@@ -298,6 +301,7 @@ + { + filltable("CWORD"); + syntax[0] = "CEOF"; ++ syntax[1] = "CIGN"; + #ifdef TARGET_CHAR + syntax[base + (TARGET_CHAR)CTLESC] = "CCTL"; + syntax[base + (TARGET_CHAR)CTLVAR] = "CCTL"; +@@ -374,9 +378,9 @@ + + static char *macro[] = { + "#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)", +- "#define is_alpha(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))", +- "#define is_name(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))", +- "#define is_in_name(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))", ++ "#define is_alpha(c)\t(((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))", ++ "#define is_name(c)\t(((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))", ++ "#define is_in_name(c)\t(((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))", + "#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))", + NULL + }; +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/mktokens bin_NetBSD-1.6release/src/bin/sh/mktokens +--- bin_NetBSD-1.6release.orig/src/bin/sh/mktokens 1999-07-09 12:02:07.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/mktokens 2003-02-08 14:35:42.000000000 +0000 +@@ -55,21 +55,22 @@ + TENDBQUOTE 1 "`" + TREDIR 0 redirection + TWORD 0 word +-TIF 0 "if" +-TTHEN 1 "then" +-TELSE 1 "else" ++TNOT 0 "!" ++TCASE 0 "case" ++TDO 1 "do" ++TDONE 1 "done" + TELIF 1 "elif" ++TELSE 1 "else" ++TESAC 1 "esac" + TFI 1 "fi" +-TWHILE 0 "while" +-TUNTIL 0 "until" + TFOR 0 "for" +-TDO 1 "do" +-TDONE 1 "done" ++TIF 0 "if" ++TIN 0 "in" ++TTHEN 1 "then" ++TUNTIL 0 "until" ++TWHILE 0 "while" + TBEGIN 0 "{" + TEND 1 "}" +-TCASE 0 "case" +-TESAC 1 "esac" +-TNOT 0 "!" + ! + nl=`wc -l /tmp/ka$$` + exec > token.h +@@ -87,10 +88,9 @@ + echo '}; + ' + sed 's/"//g' /tmp/ka$$ | awk ' +-/TIF/{print "#define KWDOFFSET " NR-1; print ""; +- print "const char *const parsekwd[] = {"} +-/TIF/,/neverfound/{print " \"" $3 "\","}' +-echo ' 0 +-};' ++/TNOT/{print "#define KWDOFFSET " NR-1; print ""; ++ print "STATIC const char *const parsekwd[] = {"} ++/TNOT/,/neverfound/{if (last) print " \"" last "\","; last = $3} ++END{print " \"" last "\"\n};"}' + + rm /tmp/ka$$ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/mystring.c bin_NetBSD-1.6release/src/bin/sh/mystring.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/mystring.c 1999-07-09 12:02:07.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/mystring.c 2003-02-08 14:35:42.000000000 +0000 +@@ -60,9 +60,16 @@ + #include "syntax.h" + #include "error.h" + #include "mystring.h" ++#include "memalloc.h" ++#include "parser.h" + + + char nullstr[1]; /* zero length string */ ++const char spcstr[] = " "; ++const char snlfmt[] = "%s\n"; ++const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' }; ++const char illnum[] = "Illegal number: %s"; ++const char homestr[] = "HOME"; + + /* + * equal - #defined in mystring.h +@@ -73,6 +80,7 @@ + */ + + ++#if 0 + /* + * scopyn - copy a string from "from" to "to", truncating the string + * if necessary. "To" is always nul terminated, even if +@@ -92,6 +100,7 @@ + } + *to = '\0'; + } ++#endif + + + /* +@@ -122,7 +131,7 @@ + { + + if (! is_number(s)) +- error("Illegal number: %s", s); ++ error(illnum, s); + return atoi(s); + } + +@@ -142,3 +151,78 @@ + } while (*++p != '\0'); + return 1; + } ++ ++ ++/* ++ * Produce a possibly single quoted string suitable as input to the shell. ++ * The return string is allocated on the stack. ++ */ ++ ++char * ++single_quote(const char *s) { ++ char *p; ++ ++ STARTSTACKSTR(p); ++ ++ do { ++ char *q; ++ size_t len; ++ ++ len = strchrnul(s, '\'') - s; ++ ++ q = p = makestrspace(len + 3, p); ++ ++ *q++ = '\''; ++ q = mempcpy(q, s, len); ++ *q++ = '\''; ++ s += len; ++ ++ STADJUST(q - p, p); ++ ++ len = strspn(s, "'"); ++ if (!len) ++ break; ++ ++ q = p = makestrspace(len + 3, p); ++ ++ *q++ = '"'; ++ q = mempcpy(q, s, len); ++ *q++ = '"'; ++ s += len; ++ ++ STADJUST(q - p, p); ++ } while (*s); ++ ++ USTPUTC(0, p); ++ ++ return stackblock(); ++} ++ ++/* ++ * Like strdup but works with the ash stack. ++ */ ++ ++char * ++sstrdup(const char *p) ++{ ++ size_t len = strlen(p) + 1; ++ return memcpy(stalloc(len), p, len); ++} ++ ++/* ++ * Wrapper around strcmp for qsort/bsearch/... ++ */ ++int ++pstrcmp(const void *a, const void *b) ++{ ++ return strcmp(*(const char *const *) a, *(const char *const *) b); ++} ++ ++/* ++ * Find a string is in a sorted array. ++ */ ++const char *const * ++findstring(const char *s, const char *const *array, size_t nmemb) ++{ ++ return bsearch(&s, array, nmemb, sizeof(const char *), pstrcmp); ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/mystring.h bin_NetBSD-1.6release/src/bin/sh/mystring.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/mystring.h 1995-10-14 00:44:16.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/mystring.h 2003-02-08 14:35:42.000000000 +0000 +@@ -40,10 +40,23 @@ + + #include <string.h> + ++extern const char snlfmt[]; ++extern const char spcstr[]; ++extern const char dolatstr[]; ++#define DOLATSTRLEN 4 ++extern const char illnum[]; ++extern const char homestr[]; ++ ++#if 0 + void scopyn __P((const char *, char *, int)); ++#endif + int prefix __P((const char *, const char *)); + int number __P((const char *)); + int is_number __P((const char *)); ++char *single_quote __P((const char *)); ++char *sstrdup __P((const char *)); ++int pstrcmp __P((const void *, const void *)); ++const char *const *findstring __P((const char *, const char *const *, size_t)); + + #define equal(s1, s2) (strcmp(s1, s2) == 0) + #define scopy(s1, s2) ((void)strcpy(s2, s1)) +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/nodes.c.pat bin_NetBSD-1.6release/src/bin/sh/nodes.c.pat +--- bin_NetBSD-1.6release.orig/src/bin/sh/nodes.c.pat 1997-04-12 12:18:24.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/nodes.c.pat 2003-02-08 14:35:42.000000000 +0000 +@@ -70,18 +70,22 @@ + * Make a copy of a parse tree. + */ + +-union node * +-copyfunc(n) +- union node *n; ++struct funcnode * ++copyfunc(union node *n) + { +- if (n == NULL) +- return NULL; +- funcblocksize = 0; ++ struct funcnode *f; ++ size_t blocksize; ++ ++ funcblocksize = offsetof(struct funcnode, n); + funcstringsize = 0; + calcsize(n); +- funcblock = ckmalloc(funcblocksize + funcstringsize); +- funcstring = (char *) funcblock + funcblocksize; +- return copynode(n); ++ blocksize = funcblocksize; ++ f = ckmalloc(blocksize + funcstringsize); ++ funcblock = (char *) f + offsetof(struct funcnode, n); ++ funcstring = (char *) f + blocksize; ++ copynode(n); ++ f->count = 0; ++ return f; + } + + +@@ -144,6 +148,12 @@ + nodesavestr(s) + char *s; + { ++#ifdef _GNU_SOURCE ++ char *rtn = funcstring; ++ ++ funcstring = stpcpy(funcstring, s) + 1; ++ return rtn; ++#else + register char *p = s; + register char *q = funcstring; + char *rtn = funcstring; +@@ -152,6 +162,7 @@ + continue; + funcstring = q; + return rtn; ++#endif + } + + +@@ -161,9 +172,8 @@ + */ + + void +-freefunc(n) +- union node *n; ++freefunc(struct funcnode *f) + { +- if (n) +- ckfree(n); ++ if (f && --f->count < 0) ++ ckfree(f); + } +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/nodetypes bin_NetBSD-1.6release/src/bin/sh/nodetypes +--- bin_NetBSD-1.6release.orig/src/bin/sh/nodetypes 2002-05-16 11:41:21.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/nodetypes 2003-02-08 14:35:42.000000000 +0000 +@@ -52,14 +52,9 @@ + # The last two types should be followed by the text of a C declaration for + # the field. + +-NSEMI nbinary # two commands separated by a semicolon +- type int +- ch1 nodeptr # the first child +- ch2 nodeptr # the second child +- + NCMD ncmd # a simple command + type int +- backgnd int # set to run command in background ++ assign nodeptr # variable assignments + args nodeptr # the arguments + redirect nodeptr # list of file redirections + +@@ -79,6 +74,11 @@ + NAND nbinary # the && operator + NOR nbinary # the || operator + ++NSEMI nbinary # two commands separated by a semicolon ++ type int ++ ch1 nodeptr # the first child ++ ch2 nodeptr # the second child ++ + NIF nif # the if statement. Elif clauses are handled + type int # using multiple if nodes. + test nodeptr # if test +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/options.c bin_NetBSD-1.6release/src/bin/sh/options.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/options.c 2001-02-27 11:04:47.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/options.c 2003-02-08 14:35:42.000000000 +0000 +@@ -75,11 +75,51 @@ + + char *minusc; /* argument to -c option */ + ++static const char *const optnames[NOPTS] = { ++ "errexit", ++ "noglob", ++ "ignoreeof", ++ "interactive", ++ "monitor", ++ "noexec", ++ "stdin", ++ "xtrace", ++ "verbose", ++ "vi", ++ "emacs", ++ "noclobber", ++ "allexport", ++ "notify", ++ "nounset", ++ "quietprofile", ++}; ++ ++const char optletters[NOPTS] = { ++ 'e', ++ 'f', ++ 'I', ++ 'i', ++ 'm', ++ 'n', ++ 's', ++ 'x', ++ 'v', ++ 'V', ++ 'E', ++ 'C', ++ 'a', ++ 'b', ++ 'u', ++ 'q', ++}; ++ ++char optlist[NOPTS]; ++ + + STATIC void options __P((int)); + STATIC void minus_o __P((char *, int)); + STATIC void setoption __P((int, int)); +-STATIC int getopts __P((char *, char *, char **, char ***, char **)); ++STATIC int getopts __P((char *, char *, char **, int *, int *)); + + + /* +@@ -97,7 +137,7 @@ + if (argc > 0) + argptr++; + for (i = 0; i < NOPTS; i++) +- optlist[i].val = 2; ++ optlist[i] = 2; + options(1); + if (*argptr == NULL && minusc == NULL) + sflag = 1; +@@ -106,21 +146,22 @@ + if (mflag == 2) + mflag = iflag; + for (i = 0; i < NOPTS; i++) +- if (optlist[i].val == 2) +- optlist[i].val = 0; ++ if (optlist[i] == 2) ++ optlist[i] = 0; + arg0 = argv[0]; +- if (sflag == 0 && minusc == NULL) { +- 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 (*argptr) { ++ char *p = *argptr++; ++ if (!minusc) ++ setinputfile(p, 0); ++ arg0 = p; ++ } ++ if (!sflag) ++ commandname = arg0; + + shellparam.p = argptr; +- shellparam.reset = 1; ++ shellparam.optind = 1; ++ shellparam.optoff = -1; + /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ + while (*argptr) { + shellparam.nparam++; +@@ -210,12 +251,12 @@ + if (name == NULL) { + out1str("Current option settings\n"); + for (i = 0; i < NOPTS; i++) +- out1fmt("%-16s%s\n", optlist[i].name, +- optlist[i].val ? "on" : "off"); ++ out1fmt("%-16s%s\n", optnames[i], ++ optlist[i] ? "on" : "off"); + } else { + for (i = 0; i < NOPTS; i++) +- if (equal(name, optlist[i].name)) { +- setoption(optlist[i].letter, val); ++ if (equal(name, optnames[i])) { ++ setoption(optletters[i], val); + return; + } + error("Illegal option -o %s", name); +@@ -231,8 +272,8 @@ + int i; + + for (i = 0; i < NOPTS; i++) +- if (optlist[i].letter == flag) { +- optlist[i].val = val; ++ if (optletters[i] == flag) { ++ optlist[i] = val; + if (val) { + /* #%$ hack for ksh semantics */ + if (flag == 'V') +@@ -248,20 +289,6 @@ + + + +-#ifdef mkinit +-INCLUDE "options.h" +- +-SHELLPROC { +- int i; +- +- for (i = 0; i < NOPTS; i++) +- optlist[i].val = 0; +- optschanged(); +- +-} +-#endif +- +- + /* + * Set the shell parameters. + */ +@@ -284,7 +311,8 @@ + shellparam.malloc = 1; + shellparam.nparam = nparam; + shellparam.p = newparam; +- shellparam.optnext = NULL; ++ shellparam.optind = 1; ++ shellparam.optoff = -1; + } + + +@@ -332,7 +360,8 @@ + } + ap2 = shellparam.p; + while ((*ap2++ = *ap1++) != NULL); +- shellparam.optnext = NULL; ++ shellparam.optind = 1; ++ shellparam.optoff = -1; + INTON; + return 0; + } +@@ -365,10 +394,8 @@ + getoptsreset(value) + const char *value; + { +- if (number(value) == 1) { +- shellparam.optnext = NULL; +- shellparam.reset = 1; +- } ++ shellparam.optind = number(value); ++ shellparam.optoff = -1; + } + + /* +@@ -387,50 +414,58 @@ + + if (argc < 3) + error("Usage: getopts optstring var [arg]"); +- else if (argc == 3) ++ else if (argc == 3) { + optbase = shellparam.p; +- else ++ if (shellparam.optind > shellparam.nparam + 1) { ++ shellparam.optind = 1; ++ shellparam.optoff = -1; ++ } ++ } ++ else { + optbase = &argv[3]; +- +- if (shellparam.reset == 1) { +- shellparam.optnext = optbase; +- shellparam.optptr = NULL; +- shellparam.reset = 0; ++ if (shellparam.optind > argc - 2) { ++ shellparam.optind = 1; ++ shellparam.optoff = -1; ++ } + } + +- return getopts(argv[1], argv[2], optbase, &shellparam.optnext, +- &shellparam.optptr); ++ return getopts(argv[1], argv[2], optbase, &shellparam.optind, ++ &shellparam.optoff); + } + + STATIC int +-getopts(optstr, optvar, optfirst, optnext, optpptr) ++getopts(optstr, optvar, optfirst, optind, optoff) + char *optstr; + char *optvar; + char **optfirst; +- char ***optnext; +- char **optpptr; ++ int *optind; ++ int *optoff; + { + char *p, *q; + char c = '?'; + int done = 0; +- int ind = 0; + int err = 0; + char s[10]; ++ char **optnext = optfirst + *optind - 1; + +- if ((p = *optpptr) == NULL || *p == '\0') { ++ if (*optind <= 1 || *optoff < 0 || !(*(optnext - 1)) || ++ strlen(*(optnext - 1)) < *optoff) ++ p = NULL; ++ else ++ p = *(optnext - 1) + *optoff; ++ if (p == NULL || *p == '\0') { + /* Current word is done, advance */ +- if (*optnext == NULL) ++ if (optnext == NULL) + return 1; +- p = **optnext; ++ p = *optnext; + if (p == NULL || *p != '-' || *++p == '\0') { + atend: +- ind = *optnext - optfirst + 1; +- *optnext = NULL; ++ *optind = optnext - optfirst + 1; + p = NULL; + done = 1; + goto out; + } +- (*optnext)++; ++ optnext++; + if (p[0] == '-' && p[1] == '\0') /* check for "--" */ + goto atend; + } +@@ -455,7 +490,7 @@ + } + + if (*++q == ':') { +- if (*p == '\0' && (p = **optnext) == NULL) { ++ if (*p == '\0' && (p = *optnext) == NULL) { + if (optstr[0] == ':') { + s[0] = c; + s[1] = '\0'; +@@ -470,30 +505,29 @@ + goto bad; + } + +- if (p == **optnext) +- (*optnext)++; ++ if (p == *optnext) ++ optnext++; + setvarsafe("OPTARG", p, 0); + p = NULL; + } + else +- setvarsafe("OPTARG", "", 0); +- ind = *optnext - optfirst + 1; ++ setvarsafe("OPTARG", nullstr, 0); ++ *optind = optnext - optfirst + 1; + goto out; + + bad: +- ind = 1; +- *optnext = NULL; ++ *optind = 1; + p = NULL; + out: +- *optpptr = p; +- fmtstr(s, sizeof(s), "%d", ind); ++ *optoff = p ? p - *(optnext - 1) : -1; ++ fmtstr(s, sizeof(s), "%d", *optind); + err |= setvarsafe("OPTIND", s, VNOFUNC); + s[0] = c; + s[1] = '\0'; + err |= setvarsafe(optvar, s, 0); + if (err) { +- *optnext = NULL; +- *optpptr = NULL; ++ *optind = 1; ++ *optoff = -1; + flushall(); + exraise(EXERROR); + } +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/options.h bin_NetBSD-1.6release/src/bin/sh/options.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/options.h 2001-02-05 11:15:31.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/options.h 2003-02-08 14:35:42.000000000 +0000 +@@ -41,61 +41,34 @@ + struct shparam { + int nparam; /* # of positional parameters (without $0) */ + unsigned char malloc; /* if parameter list dynamically allocated */ +- unsigned char reset; /* if getopts has been reset */ + char **p; /* parameter list */ +- char **optnext; /* next parameter to be processed by getopts */ +- char *optptr; /* used by getopts */ ++ int optind; /* next parameter to be processed by getopts */ ++ int optoff; /* used by getopts */ + }; + + + +-#define eflag optlist[0].val +-#define fflag optlist[1].val +-#define Iflag optlist[2].val +-#define iflag optlist[3].val +-#define mflag optlist[4].val +-#define nflag optlist[5].val +-#define sflag optlist[6].val +-#define xflag optlist[7].val +-#define vflag optlist[8].val +-#define Vflag optlist[9].val +-#define Eflag optlist[10].val +-#define Cflag optlist[11].val +-#define aflag optlist[12].val +-#define bflag optlist[13].val +-#define uflag optlist[14].val +-#define qflag optlist[15].val ++#define eflag optlist[0] ++#define fflag optlist[1] ++#define Iflag optlist[2] ++#define iflag optlist[3] ++#define mflag optlist[4] ++#define nflag optlist[5] ++#define sflag optlist[6] ++#define xflag optlist[7] ++#define vflag optlist[8] ++#define Vflag optlist[9] ++#define Eflag optlist[10] ++#define Cflag optlist[11] ++#define aflag optlist[12] ++#define bflag optlist[13] ++#define uflag optlist[14] ++#define qflag optlist[15] + + #define NOPTS 16 + +-struct optent { +- const char *name; +- const char letter; +- char val; +-}; +- +-#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 }, +- { "quietprofile", 'q', 0 }, +-}; +-#else +-extern struct optent optlist[NOPTS]; +-#endif ++extern const char optletters[NOPTS]; ++extern char optlist[NOPTS]; + + + extern char *minusc; /* argument to -c option */ +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/output.c bin_NetBSD-1.6release/src/bin/sh/output.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/output.c 2002-04-09 11:25:14.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/output.c 2003-02-08 14:35:42.000000000 +0000 +@@ -1,4 +1,4 @@ +-/* $NetBSD: output.c,v 1.25 2002/04/09 00:52:05 thorpej Exp $ */ ++/* $NetBSD: output.c,v 1.26 2002/05/25 23:09:06 wiz Exp $ */ + + /*- + * Copyright (c) 1991, 1993 +@@ -41,7 +41,7 @@ + #if 0 + static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; + #else +-__RCSID("$NetBSD: output.c,v 1.25 2002/04/09 00:52:05 thorpej Exp $"); ++__RCSID("$NetBSD: output.c,v 1.26 2002/05/25 23:09:06 wiz Exp $"); + #endif + #endif /* not lint */ + +@@ -65,6 +65,10 @@ + #include <errno.h> + #include <unistd.h> + #include <stdlib.h> ++#ifdef USE_GLIBC_STDIO ++#include <fcntl.h> ++#endif ++#include <limits.h> + + #include "shell.h" + #include "syntax.h" +@@ -74,69 +78,126 @@ + + + #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}; +-struct output errout = {NULL, 0, NULL, 100, 2, 0}; +-struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; ++#ifdef USE_GLIBC_STDIO ++struct output output = { ++ stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 1, flags: 0 ++}; ++struct output errout = { ++ stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 2, flags: 0 ++} ++#ifdef notyet ++struct output memout = { ++ stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: MEM_OUT, flags: 0 ++}; ++#endif ++#else ++struct output output = { ++ nextc: 0, end: 0, buf: 0, bufsize: OUTBUFSIZ, fd: 1, flags: 0 ++}; ++struct output errout = { ++ nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 2, flags: 0 ++}; ++#ifdef notyet ++struct output memout = { ++ nextc: 0, end: 0, buf: 0, bufsize: 0, fd: MEM_OUT, flags: 0 ++}; ++#endif ++#endif + struct output *out1 = &output; + struct output *out2 = &errout; + + ++#ifndef USE_GLIBC_STDIO ++static void __outstr(const char *, size_t, struct output *); ++#endif ++static int xvsnprintf(char *, size_t, const char *, va_list); ++ + + #ifdef mkinit + + INCLUDE "output.h" + INCLUDE "memalloc.h" + ++INIT { ++#ifdef USE_GLIBC_STDIO ++ initstreams(); ++#endif ++} ++ + RESET { ++#ifdef notyet + out1 = &output; + out2 = &errout; ++#ifdef USE_GLIBC_STDIO ++ if (memout.stream != NULL) ++ __closememout(); ++#endif + if (memout.buf != NULL) { + ckfree(memout.buf); + memout.buf = NULL; + } ++#endif + } + + #endif + + +-#ifdef notdef /* no longer used */ +-/* +- * Set up an output file to write to memory rather than a file. +- */ +- +-void +-open_mem(block, length, file) +- char *block; +- int length; +- struct output *file; +- { +- file->nextc = block; +- file->nleft = --length; +- file->fd = BLOCK_OUT; +- file->flags = 0; +-} +-#endif ++#ifndef USE_GLIBC_STDIO ++static void ++__outstr(const char *p, size_t len, struct output *dest) { ++ size_t bufsize; ++ size_t offset; ++ size_t nleft; + ++ nleft = dest->end - dest->nextc; ++ if (nleft >= len) { ++buffered: ++ dest->nextc = mempcpy(dest->nextc, p, len); ++ return; ++ } + +-void +-out1str(p) +- const char *p; +- { +- outstr(p, out1); +-} ++ bufsize = dest->bufsize; ++ if (!bufsize) { ++ ; ++ } else if (dest->buf == NULL) { ++ if (dest->fd == MEM_OUT && len > bufsize) { ++ bufsize = len; ++ } ++ offset = 0; ++ goto alloc; ++ } else if (dest->fd == MEM_OUT) { ++ offset = bufsize; ++ if (bufsize >= len) { ++ bufsize <<= 1; ++ } else { ++ bufsize += len; ++ } ++ if (bufsize < offset) ++ goto err; ++alloc: ++ INTOFF; ++ dest->buf = ckrealloc(dest->buf, bufsize); ++ dest->bufsize = bufsize; ++ dest->end = dest->buf + bufsize; ++ dest->nextc = dest->buf + offset; ++ INTON; ++ } else { ++ flushout(dest); ++ } + ++ nleft = dest->end - dest->nextc; ++ if (nleft > len) ++ goto buffered; + +-void +-out2str(p) +- const char *p; +- { +- outstr(p, out2); ++ if ((xwrite(dest->fd, p, len))) { ++err: ++ dest->flags |= OUTPUT_ERR; ++ } + } ++#endif + + + void +@@ -144,51 +205,36 @@ + const char *p; + struct output *file; + { +- while (*p) +- outc(*p++, file); +- if (file == out2) +- flushout(file); ++#ifdef USE_GLIBC_STDIO ++ INTOFF; ++ fputs(p, file->stream); ++ INTON; ++#else ++ size_t len; ++ ++ len = strlen(p); ++ __outstr(p, len, file); ++#endif + } + + +-char out_junk[16]; ++#ifndef USE_GLIBC_STDIO + + + void +-emptyoutbuf(dest) +- struct output *dest; +- { +- int offset; +- +- if (dest->fd == BLOCK_OUT) { +- dest->nextc = out_junk; +- dest->nleft = sizeof out_junk; +- dest->flags |= OUTPUT_ERR; +- } else if (dest->buf == NULL) { +- INTOFF; +- dest->buf = ckmalloc(dest->bufsize); +- dest->nextc = dest->buf; +- dest->nleft = dest->bufsize; +- INTON; +- } else if (dest->fd == MEM_OUT) { +- offset = dest->bufsize; +- INTOFF; +- dest->bufsize <<= 1; +- dest->buf = ckrealloc(dest->buf, dest->bufsize); +- dest->nleft = dest->bufsize - offset; +- dest->nextc = dest->buf + offset; +- INTON; +- } else { +- flushout(dest); +- } +- dest->nleft--; ++outcslow(char c, struct output *dest) ++{ ++ __outstr(&c, 1, dest); + } ++#endif + + + void + flushall() { + flushout(&output); ++#ifdef FLUSHERR + flushout(&errout); ++#endif + } + + +@@ -196,343 +242,93 @@ + flushout(dest) + struct output *dest; + { ++#ifdef USE_GLIBC_STDIO ++ INTOFF; ++ fflush(dest->stream); ++ INTON; ++#else ++ size_t len; + +- if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) ++ len = dest->nextc - dest->buf; ++ if (dest->buf == NULL || !len || dest->fd < 0) + return; +- if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) +- dest->flags |= OUTPUT_ERR; + dest->nextc = dest->buf; +- dest->nleft = dest->bufsize; +-} +- +- +-void +-freestdout() { +- INTOFF; +- if (output.buf) { +- ckfree(output.buf); +- output.buf = NULL; +- output.nleft = 0; +- } +- INTON; ++ if ((xwrite(dest->fd, dest->buf, len))) ++ dest->flags |= OUTPUT_ERR; ++#endif + } + + + void +-#ifdef __STDC__ + outfmt(struct output *file, const char *fmt, ...) +-#else +-void +-outfmt(va_alist) +- va_dcl +-#endif + { + va_list ap; +-#ifndef __STDC__ +- struct output *file; +- const char *fmt; + +- va_start(ap); +- file = va_arg(ap, struct output *); +- fmt = va_arg(ap, const char *); +-#else + va_start(ap, fmt); +-#endif + doformat(file, fmt, ap); + va_end(ap); + } + + + void +-#ifdef __STDC__ + out1fmt(const char *fmt, ...) +-#else +-out1fmt(va_alist) +- va_dcl +-#endif + { + va_list ap; +-#ifndef __STDC__ +- const char *fmt; + +- va_start(ap); +- fmt = va_arg(ap, const char *); +-#else + va_start(ap, fmt); +-#endif + doformat(out1, fmt, ap); + va_end(ap); + } + +-void +-#ifdef __STDC__ +-dprintf(const char *fmt, ...) +-#else +-dprintf(va_alist) +- va_dcl +-#endif +-{ +- va_list ap; +-#ifndef __STDC__ +- const char *fmt; +- +- va_start(ap); +- fmt = va_arg(ap, const char *); +-#else +- va_start(ap, fmt); +-#endif +- doformat(out2, fmt, ap); +- va_end(ap); +- flushout(out2); +-} + +-void +-#ifdef __STDC__ ++int + fmtstr(char *outbuf, size_t length, const char *fmt, ...) +-#else +-fmtstr(va_alist) +- va_dcl +-#endif + { + va_list ap; +- struct output strout; +-#ifndef __STDC__ +- char *outbuf; +- size_t length; +- const char *fmt; ++ int ret; + +- va_start(ap); +- outbuf = va_arg(ap, char *); +- length = va_arg(ap, size_t); +- fmt = va_arg(ap, const char *); +-#else + va_start(ap, fmt); +-#endif +- 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'; ++ ret = xvsnprintf(outbuf, length, fmt, ap); + va_end(ap); ++ return ret; + } + +-/* +- * Formatted output. This routine handles a subset of the printf formats: +- * - Formats supported: d, u, o, p, X, s, and c. +- * - The x format is also accepted but is treated like X. +- * - 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. +- * - The obsolete practice of preceding the width with a zero to get +- * zero padding is not supported; use the precision field. +- * - A % may be printed by writing %% in the format string. +- */ +- +-#define TEMPSIZE 24 +- +-#ifdef BSD4_4 +-#define HAVE_VASPRINTF 1 +-#endif + ++#ifndef USE_GLIBC_STDIO + void + doformat(dest, f, ap) + struct output *dest; + const char *f; /* format string */ + va_list ap; + { +-#if HAVE_VASPRINTF ++ struct stackmark smark; + char *s; ++ int len, ret; ++ size_t size; ++ va_list ap2; + +- vasprintf(&s, f, ap); +- 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; +- u_long num; +-#endif +- unsigned base; +- int len; +- int size; +- int pad; +- +- while ((c = *f++) != '\0') { +- if (c != '%') { +- outc(c, dest); +- continue; +- } +- flushleft = 0; +- sharp = 0; +- width = 0; +- prec = -1; +- islong = 0; +- isquad = 0; +- for (;;) { +- if (*f == '-') +- flushleft++; +- else if (*f == '#') +- sharp++; +- else +- break; +- f++; +- } +- if (*f == '*') { +- width = va_arg(ap, int); +- f++; +- } else { +- while (is_digit(*f)) { +- width = 10 * width + digit_val(*f++); +- } +- } +- if (*f == '.') { +- if (*++f == '*') { +- prec = va_arg(ap, int); +- f++; +- } else { +- prec = 0; +- while (is_digit(*f)) { +- prec = 10 * prec + digit_val(*f++); +- } +- } +- } +- if (*f == 'l') { +- f++; +- if (*f == 'l') { +- isquad++; +- f++; +- } else +- islong++; +- } else if (*f == 'q') { +- isquad++; +- f++; ++ va_copy(ap2, ap); ++ size = dest->end - dest->nextc; ++ len = xvsnprintf(dest->nextc, size, f, ap2); ++ va_end(ap2); ++ if (len < 0) { ++ dest->flags |= OUTPUT_ERR; ++ return; + } +- 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 +- l = va_arg(ap, int); +- sign = 0; +- num = l; +- if (l < 0) { +- num = -l; +- sign = 1; ++ if (len < size) { ++ dest->nextc += len; ++ return; + } +- base = 10; +- goto number; +- case 'u': +- base = 10; +- goto uns_number; +- 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); ++ setstackmark(&smark); ++ s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1); ++ ret = xvsnprintf(s, len + 1, f, ap); ++ if (ret == len) ++ __outstr(s, len, dest); + else +- num = va_arg(ap, unsigned int); +-number: /* process a number */ +- p = temp + TEMPSIZE - 1; +- *p = '\0'; +- while (num) { +- *--p = digit[num % base]; +- num /= base; +- } +- len = (temp + TEMPSIZE - 1) - p; +- if (prec < 0) +- prec = 1; +- if (sharp && *f == 'o' && prec <= len) +- prec = len + 1; +- pad = 0; +- if (width) { +- size = len; +- if (size < prec) +- size = prec; +- size += sign; +- pad = width - size; +- if (flushleft == 0) { +- while (--pad >= 0) +- outc(' ', dest); +- } +- } +- if (sign) +- outc('-', dest); +- prec -= len; +- while (--prec >= 0) +- outc('0', dest); +- while (*p) +- outc(*p++, dest); +- while (--pad >= 0) +- outc(' ', dest); +- break; +- case 's': +- p = va_arg(ap, char *); +- pad = 0; +- if (width) { +- len = strlen(p); +- if (prec >= 0 && len > prec) +- len = prec; +- pad = width - len; +- if (flushleft == 0) { +- while (--pad >= 0) +- outc(' ', dest); +- } +- } +- prec++; +- while (--prec != 0 && *p) +- outc(*p++, dest); +- while (--pad >= 0) +- outc(' ', dest); +- break; +- case 'c': +- c = va_arg(ap, int); +- outc(c, dest); +- break; +- default: +- outc(*f, dest); +- break; +- } +- f++; +- } +-#endif /* !HAVE_VASPRINTF */ ++ dest->flags |= OUTPUT_ERR; ++ popstackmark(&smark); + } ++#endif + + + +@@ -541,47 +337,63 @@ + */ + + int +-xwrite(fd, buf, nbytes) +- int fd; +- char *buf; +- int nbytes; +- { +- int ntry; +- int i; +- int n; ++xwrite(int fd, const void *p, size_t n) ++{ ++ const char *buf = p; + +- n = nbytes; +- ntry = 0; +- for (;;) { +- i = write(fd, buf, n); +- if (i > 0) { +- if ((n -= i) <= 0) +- return nbytes; +- buf += i; +- ntry = 0; +- } else if (i == 0) { +- if (++ntry > 10) +- return nbytes - n; +- } else if (errno != EINTR) { ++ while (n) { ++ ssize_t i; ++ size_t m; ++ ++ m = n; ++ if (m > SSIZE_MAX) ++ m = SSIZE_MAX; ++ do { ++ i = write(fd, buf, m); ++ } while (i < 0 && errno == EINTR); ++ if (i < 0) + return -1; ++ buf += i; ++ n -= i; + } +- } ++ return 0; + } + + +-/* +- * Version of ioctl that retries after a signal is caught. +- * XXX unused function +- */ ++#ifdef notyet ++#ifdef USE_GLIBC_STDIO ++void initstreams() { ++ output.stream = stdout; ++ errout.stream = stderr; ++} ++ ++ ++void ++openmemout() { ++ INTOFF; ++ memout.stream = open_memstream(&memout.buf, &memout.bufsize); ++ INTON; ++} ++ + + int +-xioctl(fd, request, arg) +- int fd; +- unsigned long request; +- char * arg; ++__closememout() { ++ int error; ++ error = fclose(memout.stream); ++ memout.stream = NULL; ++ return error; ++} ++#endif ++#endif ++ ++ ++static int ++xvsnprintf(char *outbuf, size_t length, const char *fmt, va_list ap) + { +- int i; ++ int ret; + +- while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); +- return i; ++ INTOFF; ++ ret = vsnprintf(outbuf, length, fmt, ap); ++ INTON; ++ return ret; + } +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/output.h bin_NetBSD-1.6release/src/bin/sh/output.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/output.h 1998-01-31 18:28:11.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/output.h 2003-02-08 14:35:42.000000000 +0000 +@@ -1,4 +1,4 @@ +-/* $NetBSD: output.h,v 1.14 1998/01/31 12:37:55 christos Exp $ */ ++/* $NetBSD: output.h,v 1.15 2002/05/25 23:13:26 wiz Exp $ */ + + /*- + * Copyright (c) 1991, 1993 +@@ -40,50 +40,76 @@ + + #ifndef OUTPUT_INCL + +-#ifdef __STDC__ + #include <stdarg.h> +-#else +-#include <varargs.h> ++#ifdef USE_GLIBC_STDIO ++#include <stdio.h> + #endif ++#include <sys/types.h> + + struct output { ++#ifdef USE_GLIBC_STDIO ++ FILE *stream; ++#endif + char *nextc; +- int nleft; ++ char *end; + char *buf; +- int bufsize; +- short fd; +- short flags; ++ size_t bufsize; ++ int fd; ++ int flags; + }; + + extern struct output output; + extern struct output errout; ++#ifdef notyet + extern struct output memout; ++#endif + extern struct output *out1; + extern struct output *out2; + +-void open_mem __P((char *, int, struct output *)); +-void out1str __P((const char *)); +-void out2str __P((const char *)); + void outstr __P((const char *, struct output *)); +-void emptyoutbuf __P((struct output *)); ++#ifndef USE_GLIBC_STDIO ++void outcslow __P((char, struct output *)); ++#endif + void flushall __P((void)); + void flushout __P((struct output *)); +-void freestdout __P((void)); + void outfmt __P((struct output *, const char *, ...)) + __attribute__((__format__(__printf__,2,3))); + void out1fmt __P((const char *, ...)) + __attribute__((__format__(__printf__,1,2))); +-void dprintf __P((const char *, ...)) +- __attribute__((__format__(__printf__,1,2))); +-void fmtstr __P((char *, size_t, const char *, ...)) ++int fmtstr __P((char *, size_t, const char *, ...)) + __attribute__((__format__(__printf__,3,4))); ++#ifndef USE_GLIBC_STDIO + void doformat __P((struct output *, const char *, va_list)); +-int xwrite __P((int, char *, int)); +-int xioctl __P((int, unsigned long, char *)); ++#endif ++int xwrite __P((int, const void *, size_t)); ++#ifdef notyet ++#ifdef USE_GLIBC_STDIO ++void initstreams __P((void)); ++void openmemout __P((void)); ++int __closememout __P((void)); ++#endif ++#endif + +-#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); ++static inline void ++freestdout() ++{ ++ output.nextc = output.buf; ++ output.flags = 0; ++} ++ ++#define OUTPUT_ERR 01 /* error occurred on output */ ++ ++#ifdef USE_GLIBC_STDIO ++#define outc(c, o) putc((c), (o)->stream) ++#define doformat(d, f, a) vfprintf((d)->stream, (f), (a)) ++#else ++#define outc(c, file) ((file)->nextc == (file)->end ? outcslow((c), (file)) : (*(file)->nextc = (c), (file)->nextc++)) ++#endif ++#define out1c(c) outc((c), out1) ++#define out2c(c) outc((c), out2) ++#define out1str(s) outstr((s), out1) ++#define out2str(s) outstr((s), out2) ++#define outerr(f) ((f)->flags & OUTPUT_ERR) + + #define OUTPUT_INCL + #endif +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/parser.c bin_NetBSD-1.6release/src/bin/sh/parser.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/parser.c 2002-05-16 11:41:21.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/parser.c 2003-02-08 14:35:42.000000000 +0000 +@@ -53,6 +53,7 @@ + #include "expand.h" /* defines rmescapes() */ + #include "eval.h" /* defines commandname */ + #include "redir.h" /* defines copyfd() */ ++#include "exec.h" /* defines find_builtin() */ + #include "syntax.h" + #include "options.h" + #include "input.h" +@@ -63,6 +64,7 @@ + #include "mystring.h" + #include "alias.h" + #include "show.h" ++#include "builtins.h" + #ifndef SMALL + #include "myhistedit.h" + #endif +@@ -76,8 +78,6 @@ + /* values returned by readtoken */ + #include "token.h" + +-#define OPENBRACE '{' +-#define CLOSEBRACE '}' + + + struct heredoc { +@@ -89,7 +89,6 @@ + + + +-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 */ +@@ -97,7 +96,7 @@ + int lasttoken; /* last token read */ + MKINIT int tokpushback; /* last token pushed back */ + char *wordtext; /* text of last word returned by readtoken */ +-MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ ++int checkkwd; + struct nodelist *backquotelist; + union node *redirnode; + struct heredoc *heredoc; +@@ -109,7 +108,7 @@ + STATIC union node *andor __P((void)); + STATIC union node *pipeline __P((void)); + STATIC union node *command __P((void)); +-STATIC union node *simplecmd __P((union node **, union node *)); ++STATIC union node *simplecmd __P((void)); + STATIC union node *makename __P((void)); + STATIC void parsefname __P((void)); + STATIC void parseheredoc __P((void)); +@@ -123,6 +122,22 @@ + STATIC void setprompt __P((int)); + + ++static inline int ++goodname(const char *p) ++{ ++ return !*endofname(p); ++} ++ ++static inline int ++isassignment(const char *p) ++{ ++ const char *q = endofname(p); ++ if (p == q) ++ return 0; ++ return *q == '='; ++} ++ ++ + /* + * Read and parse a command. Returns NEOF on end of file. (NULL is a + * valid parse tree indicating a blank line.) +@@ -136,9 +151,7 @@ + tokpushback = 0; + doprompt = interact; + if (doprompt) +- setprompt(1); +- else +- setprompt(0); ++ setprompt(doprompt); + needprompt = 0; + t = readtoken(); + if (t == TEOF) +@@ -157,25 +170,25 @@ + union node *n1, *n2, *n3; + int tok; + +- checkkwd = 2; +- if (nlflag == 0 && tokendlist[peektoken()]) ++ checkkwd = CHKNL | CHKKWD | CHKALIAS; ++ if (nlflag == 2 && tokendlist[peektoken()]) + return NULL; + n1 = NULL; + for (;;) { + n2 = andor(); + tok = readtoken(); + if (tok == TBACKGND) { +- if (n2->type == NCMD || n2->type == NPIPE) { +- n2->ncmd.backgnd = 1; +- } else if (n2->type == NREDIR) { +- n2->type = NBACKGND; ++ if (n2->type == NPIPE) { ++ n2->npipe.backgnd = 1; + } else { +- n3 = (union node *)stalloc(sizeof (struct nredir)); +- n3->type = NBACKGND; ++ if (n2->type != NREDIR) { ++ n3 = stalloc(sizeof(struct nredir)); + n3->nredir.n = n2; + n3->nredir.redirect = NULL; + n2 = n3; + } ++ n2->type = NBACKGND; ++ } + } + if (n1 == NULL) { + n1 = n2; +@@ -195,12 +208,12 @@ + case TNL: + if (tok == TNL) { + parseheredoc(); +- if (nlflag) ++ if (nlflag == 1) + return n1; + } else { + tokpushback++; + } +- checkkwd = 2; ++ checkkwd = CHKNL | CHKKWD | CHKALIAS; + if (tokendlist[peektoken()]) + return n1; + break; +@@ -211,7 +224,7 @@ + pungetc(); /* push back EOF on input */ + return n1; + default: +- if (nlflag) ++ if (nlflag == 1) + synexpect(-1); + tokpushback++; + return n1; +@@ -236,6 +249,7 @@ + tokpushback++; + return n1; + } ++ checkkwd = CHKNL | CHKKWD | CHKALIAS; + n2 = pipeline(); + n3 = (union node *)stalloc(sizeof (struct nbinary)); + n3->type = t; +@@ -255,8 +269,10 @@ + + negate = 0; + TRACE(("pipeline: entered\n")); +- while (readtoken() == TNOT) ++ if (readtoken() == TNOT) { + negate = !negate; ++ checkkwd = CHKKWD | CHKALIAS; ++ } else + tokpushback++; + n1 = command(); + if (readtoken() == TPIPE) { +@@ -269,6 +285,7 @@ + do { + prev = lp; + lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); ++ checkkwd = CHKNL | CHKKWD | CHKALIAS; + lp->n = command(); + prev->next = lp; + } while (readtoken() == TPIPE); +@@ -293,28 +310,16 @@ + union node *ap, **app; + union node *cp, **cpp; + union node *redir, **rpp; +- int t, negate = 0; ++ union node **rpp2; ++ int t; + +- checkkwd = 2; + redir = NULL; +- n1 = NULL; +- rpp = &redir; +- +- /* Check for redirection which may precede command */ +- while (readtoken() == TREDIR) { +- *rpp = n2 = redirnode; +- rpp = &n2->nfile.next; +- parsefname(); +- } +- tokpushback++; +- +- while (readtoken() == TNOT) { +- TRACE(("command: TNOT recognized\n")); +- negate = !negate; +- } +- tokpushback++; ++ rpp2 = &redir; + + switch (readtoken()) { ++ default: ++ synexpect(-1); ++ /* NOTREACHED */ + case TIF: + n1 = (union node *)stalloc(sizeof (struct nif)); + n1->type = NIF; +@@ -338,9 +343,7 @@ + n2->nif.elsepart = NULL; + tokpushback++; + } +- if (readtoken() != TFI) +- synexpect(TFI); +- checkkwd = 1; ++ t = TFI; + break; + case TWHILE: + case TUNTIL: { +@@ -353,9 +356,7 @@ + synexpect(TDO); + } + n1->nbinary.ch2 = list(0); +- if (readtoken() != TDONE) +- synexpect(TDONE); +- checkkwd = 1; ++ t = TDONE; + break; + } + case TFOR: +@@ -364,7 +365,8 @@ + n1 = (union node *)stalloc(sizeof (struct nfor)); + n1->type = NFOR; + n1->nfor.var = wordtext; +- if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { ++ checkkwd = CHKKWD | CHKALIAS; ++ if (readtoken() == TIN) { + app = ≈ + while (readtoken() == TWORD) { + n2 = (union node *)stalloc(sizeof (struct narg)); +@@ -379,11 +381,9 @@ + if (lasttoken != TNL && lasttoken != TSEMI) + synexpect(-1); + } else { +- static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, +- '@', '=', '\0'}; + n2 = (union node *)stalloc(sizeof (struct narg)); + n2->type = NARG; +- n2->narg.text = argvars; ++ n2->narg.text = (char *)dolatstr; + n2->narg.backquote = NULL; + n2->narg.next = NULL; + n1->nfor.args = n2; +@@ -394,17 +394,11 @@ + if (lasttoken != TNL && lasttoken != TSEMI) + tokpushback++; + } +- checkkwd = 2; +- if ((t = readtoken()) == TDO) +- t = TDONE; +- else if (t == TBEGIN) +- t = TEND; +- else +- synexpect(-1); ++ checkkwd = CHKNL | CHKKWD | CHKALIAS; ++ if (readtoken() != TDO) ++ synexpect(TDO); + n1->nfor.body = list(0); +- if (readtoken() != t) +- synexpect(t); +- checkkwd = 1; ++ t = TDONE; + break; + case TCASE: + n1 = (union node *)stalloc(sizeof (struct ncase)); +@@ -416,13 +410,18 @@ + n2->narg.text = wordtext; + n2->narg.backquote = backquotelist; + n2->narg.next = NULL; +- while (readtoken() == TNL); +- if (lasttoken != TWORD || ! equal(wordtext, "in")) +- synerror("expecting \"in\""); +- cpp = &n1->ncase.cases; +- noalias = 1; +- checkkwd = 2, readtoken(); + do { ++ checkkwd = CHKKWD | CHKALIAS; ++ } while (readtoken() == TNL); ++ if (lasttoken != TIN) ++ synexpect(TIN); ++ cpp = &n1->ncase.cases; ++next_case: ++ checkkwd = CHKNL | CHKKWD; ++ t = readtoken(); ++ while(t != TESAC) { ++ if (lasttoken == TLP) ++ readtoken(); + *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); + cp->type = NCLIST; + app = &cp->nclist.pattern; +@@ -431,73 +430,52 @@ + ap->type = NARG; + ap->narg.text = wordtext; + ap->narg.backquote = backquotelist; +- if (checkkwd = 2, readtoken() != TPIPE) ++ if (readtoken() != TPIPE) + break; + app = &ap->narg.next; + readtoken(); + } + ap->narg.next = NULL; +- noalias = 0; +- if (lasttoken != TRP) { ++ if (lasttoken != TRP) + synexpect(TRP); +- } +- cp->nclist.body = list(0); ++ cp->nclist.body = list(2); + +- checkkwd = 2; ++ cpp = &cp->nclist.next; ++ ++ checkkwd = CHKNL | CHKKWD; + if ((t = readtoken()) != TESAC) { +- if (t != TENDCASE) { +- noalias = 0; ++ if (t != TENDCASE) + synexpect(TENDCASE); +- } else { +- noalias = 1; +- checkkwd = 2; +- readtoken(); ++ else ++ goto next_case; + } + } +- cpp = &cp->nclist.next; +- } while(lasttoken != TESAC); +- noalias = 0; + *cpp = NULL; +- checkkwd = 1; +- break; ++ goto redir; + case TLP: + n1 = (union node *)stalloc(sizeof (struct nredir)); + n1->type = NSUBSHELL; + n1->nredir.n = list(0); + n1->nredir.redirect = NULL; +- if (readtoken() != TRP) +- synexpect(TRP); +- checkkwd = 1; ++ t = TRP; + break; + case TBEGIN: + n1 = list(0); +- if (readtoken() != TEND) +- synexpect(TEND); +- checkkwd = 1; ++ t = TEND; + break; +- /* Handle an empty command like other simple commands. */ +- case TSEMI: +- /* +- * 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: +- case TRP: ++ case TREDIR: + tokpushback++; +- n1 = simplecmd(rpp, redir); +- goto checkneg; +- default: +- synexpect(-1); +- /* NOTREACHED */ ++ return simplecmd(); + } + ++ if (readtoken() != t) ++ synexpect(t); ++ ++redir: + /* Now check for redirection which may follow command */ ++ checkkwd = CHKKWD | CHKALIAS; ++ rpp = rpp2; + while (readtoken() == TREDIR) { + *rpp = n2 = redirnode; + rpp = &n2->nfile.next; +@@ -515,92 +493,87 @@ + n1->nredir.redirect = redir; + } + +-checkneg: +- if (negate) { +- n2 = (union node *)stalloc(sizeof (struct nnot)); +- n2->type = NNOT; +- n2->nnot.com = n1; +- return n2; +- } +- else + return n1; + } + + + STATIC union node * +-simplecmd(rpp, redir) +- union node **rpp, *redir; +- { ++simplecmd() { + union node *args, **app; +- union node **orig_rpp = rpp; +- union node *n = NULL, *n2; +- int negate = 0; +- +- /* If we don't have any redirections already, then we must reset */ +- /* rpp to be the address of the local redir variable. */ +- if (redir == 0) +- rpp = &redir; ++ union node *n = NULL; ++ union node *vars, **vpp; ++ union node **rpp, *redir; ++ int savecheckkwd; + + args = NULL; + app = &args; +- /* +- * We save the incoming value, because we need this for shell +- * functions. There can not be a redirect or an argument between +- * the function name and the open parenthesis. +- */ +- orig_rpp = rpp; +- +- while (readtoken() == TNOT) { +- TRACE(("command: TNOT recognized\n")); +- negate = !negate; +- } +- tokpushback++; ++ vars = NULL; ++ vpp = &vars; ++ redir = NULL; ++ rpp = &redir; + ++ savecheckkwd = CHKALIAS; + for (;;) { +- if (readtoken() == TWORD) { ++ checkkwd = savecheckkwd; ++ switch (readtoken()) { ++ case TWORD: + n = (union node *)stalloc(sizeof (struct narg)); + n->type = NARG; + n->narg.text = wordtext; + n->narg.backquote = backquotelist; ++ if (savecheckkwd && isassignment(wordtext)) { ++ *vpp = n; ++ vpp = &n->narg.next; ++ } else { + *app = n; + app = &n->narg.next; +- } else if (lasttoken == TREDIR) { ++ savecheckkwd = 0; ++ } ++ break; ++ case TREDIR: + *rpp = n = redirnode; + rpp = &n->nfile.next; + parsefname(); /* read name of redirection file */ +- } else if (lasttoken == TLP && app == &args->narg.next +- && rpp == orig_rpp) { ++ break; ++ case TLP: ++ if ( ++ args && app == &args->narg.next && ++ !vars && !redir ++ ) { ++ struct builtincmd *bcmd; ++ const char *name; ++ + /* We have a function */ + if (readtoken() != TRP) + synexpect(TRP); +-#ifdef notdef +- if (! goodname(n->narg.text)) ++ name = n->narg.text; ++ if ( ++ !goodname(name) || ( ++ (bcmd = find_builtin(name)) && ++ bcmd->flags & BUILTIN_SPECIAL ++ ) ++ ) + synerror("Bad function name"); +-#endif + n->type = NDEFUN; ++ checkkwd = CHKNL | CHKKWD | CHKALIAS; + n->narg.next = command(); +- goto checkneg; +- } else { ++ return n; ++ } ++ /* fall through */ ++ default: + tokpushback++; +- break; ++ goto out; + } + } ++out: + *app = NULL; ++ *vpp = NULL; + *rpp = NULL; + n = (union node *)stalloc(sizeof (struct ncmd)); + n->type = NCMD; +- n->ncmd.backgnd = 0; + n->ncmd.args = args; ++ n->ncmd.assign = vars; + n->ncmd.redirect = redir; +- +-checkneg: +- if (negate) { +- n2 = (union node *)stalloc(sizeof (struct nnot)); +- n2->type = NNOT; +- n2->nnot.com = n; +- return n2; +- } +- else + return n; + } + +@@ -682,9 +655,10 @@ + struct heredoc *here; + union node *n; + +- while (heredoclist) { + here = heredoclist; +- heredoclist = here->next; ++ heredoclist = 0; ++ ++ while (here) { + if (needprompt) { + setprompt(2); + needprompt = 0; +@@ -697,6 +671,7 @@ + n->narg.text = wordtext; + n->narg.backquote = backquotelist; + here->here->nhere.doc = n; ++ here = here->next; + } + } + +@@ -712,53 +687,51 @@ + STATIC int + readtoken() { + int t; +- int savecheckkwd = checkkwd; + #ifdef DEBUG + int alreadyseen = tokpushback; + #endif +- struct alias *ap; + +- top: ++top: + t = xxreadtoken(); + +- if (checkkwd) { + /* + * eat newlines + */ +- if (checkkwd == 2) { +- checkkwd = 0; ++ if (checkkwd & CHKNL) { + while (t == TNL) { + parseheredoc(); + t = xxreadtoken(); + } +- } else +- checkkwd = 0; ++ } ++ ++ if (t != TWORD || quoteflag) { ++ goto out; ++ } ++ + /* +- * check for keywords and aliases ++ * check for keywords + */ +- if (t == TWORD && !quoteflag) +- { ++ if (checkkwd & CHKKWD) { + const char *const *pp; + +- for (pp = parsekwd; *pp; pp++) { +- if (**pp == *wordtext && equal(*pp, wordtext)) +- { +- lasttoken = t = pp - +- parsekwd + KWDOFFSET; ++ if ((pp = findkwd(wordtext))) { ++ lasttoken = t = pp - parsekwd + KWDOFFSET; + TRACE(("keyword %s recognized\n", tokname[t])); + goto out; + } + } +- if(!noalias && +- (ap = lookupalias(wordtext, 1)) != NULL) { +- pushstring(ap->val, strlen(ap->val), ap); +- checkkwd = savecheckkwd; ++ ++ if (checkkwd & CHKALIAS) { ++ struct alias *ap; ++ if ((ap = lookupalias(wordtext, 1)) != NULL) { ++ if (*ap->val) { ++ pushstring(ap->val, ap); ++ } + goto top; + } + } + out: +- checkkwd = (t == TNOT) ? savecheckkwd : 0; +- } ++ checkkwd = 0; + #ifdef DEBUG + if (!alreadyseen) + TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); +@@ -804,10 +777,9 @@ + 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': ++ case PEOA: + continue; + case '#': + while ((c = pgetc()) != '\n' && c != PEOF); +@@ -818,8 +790,6 @@ + startlinno = ++plinno; + if (doprompt) + setprompt(2); +- else +- setprompt(0); + continue; + } + pungetc(); +@@ -879,28 +849,6 @@ + #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(firstc, syntax, eofmark, striptabs) + int firstc; +@@ -914,24 +862,22 @@ + char line[EOFMARKLEN + 1]; + struct nodelist *bqlist; + int quotef; +- int *dblquotep = NULL; +- size_t maxnest = 32; + int dblquote; + int varnest; /* levels of variables expansion */ + int arinest; /* levels of arithmetic expansion */ + int parenlevel; /* levels of parens in arithmetic */ ++ int dqvarnest; /* levels of variables expansion within double quotes */ + int oldstyle; + char const *prevsyntax; /* syntax before arithmetic */ + #if __GNUC__ + /* Avoid longjmp clobbering */ +- (void) &maxnest; +- (void) &dblquotep; + (void) &out; + (void) "ef; + (void) &dblquote; + (void) &varnest; + (void) &arinest; + (void) &parenlevel; ++ (void) &dqvarnest; + (void) &oldstyle; + (void) &prevsyntax; + (void) &syntax; +@@ -939,14 +885,14 @@ + + startlinno = plinno; + dblquote = 0; +- varnest = 0; +- if (syntax == DQSYNTAX) { +- SETDBLQUOTE(); +- } ++ if (syntax == DQSYNTAX) ++ dblquote = 1; + quotef = 0; + bqlist = NULL; ++ varnest = 0; + arinest = 0; + parenlevel = 0; ++ dqvarnest = 0; + + STARTSTACKSTR(out); + loop: { /* for each line, until end of word */ +@@ -962,7 +908,7 @@ + #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 */ ++ CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ + switch(syntax[c]) { + case CNL: /* '\n' */ + if (syntax == BASESYNTAX) +@@ -971,82 +917,76 @@ + plinno++; + if (doprompt) + setprompt(2); +- else +- setprompt(0); + c = pgetc(); + goto loop; /* continue outer loop */ + case CWORD: + USTPUTC(c, out); + break; + case CCTL: +- if (eofmark == NULL || ISDBLQUOTE()) ++ if (eofmark == NULL || dblquote) + USTPUTC(CTLESC, out); + USTPUTC(c, out); + break; + case CBACK: /* backslash */ +- c = pgetc(); ++ c = pgetc2(); + if (c == PEOF) { ++ USTPUTC(CTLESC, out); + USTPUTC('\\', out); + pungetc(); + } else if (c == '\n') { + if (doprompt) + setprompt(2); +- else +- setprompt(0); + } else { +- if (ISDBLQUOTE() && c != '\\' && +- c != '`' && c != '$' && +- (c != '"' || eofmark != NULL)) ++ if ( ++ dblquote && ++ c != '\\' && c != '`' && ++ c != '$' && ( ++ c != '"' || ++ eofmark != NULL ++ ) ++ ) { ++ USTPUTC(CTLESC, out); + USTPUTC('\\', out); ++ } + if (SQSYNTAX[c] == CCTL) + USTPUTC(CTLESC, out); +- else if (eofmark == NULL) +- USTPUTC(CTLQUOTEMARK, out); + USTPUTC(c, out); + quotef++; + } + break; + case CSQUOTE: +- if (syntax != SQSYNTAX) { +- if (eofmark == NULL) +- USTPUTC(CTLQUOTEMARK, out); + syntax = SQSYNTAX; +- break; ++quotemark: ++ if (eofmark == NULL) { ++ USTPUTC(CTLQUOTEMARK, out); + } +- /* FALLTHROUGH */ ++ break; + case CDQUOTE: ++ syntax = DQSYNTAX; ++ dblquote = 1; ++ goto quotemark; ++ case CENDQUOTE: + if (eofmark != NULL && arinest == 0 && + varnest == 0) { + USTPUTC(c, out); + } else { +- if (arinest) { +- if (c != '"' || ISDBLQUOTE()) { +- syntax = ARISYNTAX; +- CLRDBLQUOTE(); +- } else { +- syntax = DQSYNTAX; +- SETDBLQUOTE(); +- USTPUTC(CTLQUOTEMARK, out); +- } +- } else if (eofmark == NULL) { +- if (c != '"' || ISDBLQUOTE()) { ++ if (dqvarnest == 0) { + syntax = BASESYNTAX; +- CLRDBLQUOTE(); +- } else { +- syntax = DQSYNTAX; +- SETDBLQUOTE(); +- USTPUTC(CTLQUOTEMARK, out); +- } ++ dblquote = 0; + } + quotef++; ++ goto quotemark; + } + break; + case CVAR: /* '$' */ + PARSESUB(); /* parse substitution */ + break; +- case CENDVAR: /* CLOSEBRACE */ +- if (varnest > 0 && !ISDBLQUOTE()) { ++ case CENDVAR: /* '}' */ ++ if (varnest > 0) { + varnest--; ++ if (dqvarnest > 0) { ++ dqvarnest--; ++ } + USTPUTC(CTLENDVAR, out); + } else { + USTPUTC(c, out); +@@ -1066,9 +1006,9 @@ + USTPUTC(CTLENDARI, out); + syntax = prevsyntax; + if (syntax == DQSYNTAX) +- SETDBLQUOTE(); ++ dblquote = 1; + else +- CLRDBLQUOTE(); ++ dblquote = 0; + } else + USTPUTC(')', out); + } else { +@@ -1086,11 +1026,15 @@ + break; + case CEOF: + goto endword; /* exit outer loop */ ++ case CIGN: ++ break; + default: + if (varnest == 0) + goto endword; /* exit outer loop */ ++ if (c != PEOA) { + USTPUTC(c, out); + } ++ } + c = pgetc_macro(); + } + } +@@ -1122,8 +1066,6 @@ + backquotelist = bqlist; + grabstackblock(len); + wordtext = out; +- if (dblquotep != NULL) +- ckfree(dblquotep); + return lasttoken = TWORD; + /* end of readtoken routine */ + +@@ -1137,9 +1079,13 @@ + + checkend: { + if (eofmark) { ++ if (c == PEOA) { ++ c = pgetc2(); ++ } + if (striptabs) { +- while (c == '\t') +- c = pgetc(); ++ while (c == '\t') { ++ c = pgetc2(); ++ } + } + if (c == *eofmark) { + if (pfgets(line, sizeof line) != NULL) { +@@ -1152,7 +1098,7 @@ + plinno++; + needprompt = doprompt; + } else { +- pushstring(line, strlen(line), NULL); ++ pushstring(line, NULL); + } + } + } +@@ -1238,7 +1184,10 @@ + static const char types[] = "}-+?="; + + c = pgetc(); +- if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) { ++ if ( ++ c <= PEOA || ++ (c != '(' && c != '{' && !is_name(c) && !is_special(c)) ++ ) { + USTPUTC('$', out); + pungetc(); + } else if (c == '(') { /* $(command) or $((arith)) */ +@@ -1253,10 +1202,10 @@ + typeloc = out - stackblock(); + USTPUTC(VSNORMAL, out); + subtype = VSNORMAL; +- if (c == OPENBRACE) { ++ if (c == '{') { + c = pgetc(); + if (c == '#') { +- if ((c = pgetc()) == CLOSEBRACE) ++ if ((c = pgetc()) == '}') + c = '#'; + else + subtype = VSLENGTH; +@@ -1264,11 +1213,11 @@ + else + subtype = 0; + } +- if (is_name(c)) { ++ if (c > PEOA && is_name(c)) { + do { + STPUTC(c, out); + c = pgetc(); +- } while (is_in_name(c)); ++ } while (c > PEOA && is_in_name(c)); + } else if (is_digit(c)) { + do { + USTPUTC(c, out); +@@ -1313,15 +1262,13 @@ + } else { + pungetc(); + } +- if (ISDBLQUOTE() || arinest) ++ if (dblquote || arinest) + flags |= VSQUOTE; + *(stackblock() + typeloc) = subtype | flags; + if (subtype != VSNORMAL) { + varnest++; +- if (varnest >= maxnest) { +- dblquotep = ckrealloc(dblquotep, maxnest / 8); +- dblquotep[(maxnest / 32) - 1] = 0; +- maxnest += 32; ++ if (dblquote || arinest) { ++ dqvarnest++; + } + } + } +@@ -1343,7 +1290,7 @@ + char *volatile str; + struct jmploc jmploc; + struct jmploc *volatile savehandler; +- int savelen; ++ size_t savelen; + int saveprompt; + #ifdef __GNUC__ + (void) &saveprompt; +@@ -1373,7 +1320,7 @@ + reread it as input, interpreting it normally. */ + char *pout; + int pc; +- int psavelen; ++ size_t psavelen; + char *pstr; + + +@@ -1392,8 +1339,6 @@ + plinno++; + if (doprompt) + setprompt(2); +- else +- setprompt(0); + /* + * If eating a newline, avoid putting + * the newline into the new character +@@ -1403,18 +1348,21 @@ + continue; + } + if (pc != '\\' && pc != '`' && pc != '$' +- && (!ISDBLQUOTE() || pc != '"')) ++ && (!dblquote || pc != '"')) + STPUTC('\\', pout); ++ if (pc > PEOA) { + break; +- +- case '\n': +- plinno++; +- needprompt = doprompt; +- break; ++ } ++ /* fall through */ + + case PEOF: ++ case PEOA: + startlinno = plinno; + synerror("EOF in backquote substitution"); ++ ++ case '\n': ++ plinno++; ++ needprompt = doprompt; + break; + + default: +@@ -1427,7 +1375,7 @@ + psavelen = pout - stackblock(); + if (psavelen > 0) { + pstr = grabstackstr(pout); +- setinputstring(pstr, 1); ++ setinputstring(pstr); + } + } + nlpp = &bqlist; +@@ -1442,7 +1390,7 @@ + doprompt = 0; + } + +- n = list(0); ++ n = list(2); + + if (oldstyle) + doprompt = saveprompt; +@@ -1473,7 +1421,7 @@ + } + parsebackquote = savepbq; + handler = savehandler; +- if (arinest || ISDBLQUOTE()) ++ if (arinest || dblquote) + USTPUTC(CTLBACKQ | CTLQUOTE, out); + else + USTPUTC(CTLBACKQ, out); +@@ -1492,7 +1440,7 @@ + prevsyntax = syntax; + syntax = ARISYNTAX; + USTPUTC(CTLARI, out); +- if (ISDBLQUOTE()) ++ if (dblquote) + USTPUTC('"',out); + else + USTPUTC(' ',out); +@@ -1511,6 +1459,7 @@ + + + #ifdef mkinit ++INCLUDE "parser.h" + RESET { + tokpushback = 0; + checkkwd = 0; +@@ -1543,23 +1492,23 @@ + + + /* +- * Return true if the argument is a legal variable name (a letter or +- * underscore followed by zero or more letters, underscores, and digits). ++ * Return of a legal variable name (a letter or underscore followed by zero or ++ * more letters, underscores, and digits). + */ + +-int +-goodname(char *name) ++char * ++endofname(const char *name) + { + char *p; + +- p = name; ++ p = (char *) name; + if (! is_name(*p)) +- return 0; ++ return p; + while (*++p) { + if (! is_in_name(*p)) +- return 0; ++ break; + } +- return 1; ++ return p; + } + + +@@ -1587,13 +1536,9 @@ + + + STATIC void +-synerror(msg) +- const char *msg; +- { +- if (commandname) +- outfmt(&errout, "%s: %d: ", commandname, startlinno); +- outfmt(&errout, "Syntax error: %s\n", msg); +- error((char *)NULL); ++synerror(const char *msg) ++{ ++ error("Syntax error: %s", msg); + /* NOTREACHED */ + } + +@@ -1618,7 +1563,7 @@ + { + switch (whichprompt) { + case 0: +- return ""; ++ return nullstr; + case 1: + return ps1val(); + case 2: +@@ -1627,3 +1572,10 @@ + return "<internal prompt error>"; + } + } ++ ++const char *const * ++findkwd(const char *s) { ++ return findstring( ++ s, parsekwd, sizeof(parsekwd) / sizeof(const char *) ++ ); ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/parser.h bin_NetBSD-1.6release/src/bin/sh/parser.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/parser.h 2001-01-12 16:50:39.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/parser.h 2003-02-08 14:35:42.000000000 +0000 +@@ -60,12 +60,17 @@ + #define VSPLUS 0x3 /* ${var+text} */ + #define VSQUESTION 0x4 /* ${var?message} */ + #define VSASSIGN 0x5 /* ${var=text} */ +-#define VSTRIMLEFT 0x6 /* ${var#pattern} */ +-#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */ +-#define VSTRIMRIGHT 0x8 /* ${var%pattern} */ +-#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */ ++#define VSTRIMRIGHT 0x6 /* ${var%pattern} */ ++#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */ ++#define VSTRIMLEFT 0x8 /* ${var#pattern} */ ++#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ + #define VSLENGTH 0xa /* ${#var} */ + ++/* values of checkkwd variable */ ++#define CHKALIAS 0x1 ++#define CHKKWD 0x2 ++#define CHKNL 0x4 ++ + + /* + * NEOF is returned by parsecmd when it encounters an end of file. It +@@ -75,9 +80,12 @@ + extern int tokpushback; + #define NEOF ((union node *)&tokpushback) + extern int whichprompt; /* 1 == PS1, 2 == PS2 */ ++extern int checkkwd; ++extern int startlinno; /* line # where last token started */ + + + union node *parsecmd(int); + void fixredir(union node *, const char *, int); +-int goodname(char *); + const char *getprompt(void *); ++const char *const *findkwd(const char *); ++char *endofname(const char *); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/redir.c bin_NetBSD-1.6release/src/bin/sh/redir.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/redir.c 2002-05-16 11:41:22.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/redir.c 2003-02-08 14:35:42.000000000 +0000 +@@ -45,6 +45,7 @@ + #endif + #endif /* not lint */ + ++#include <sys/stat.h> + #include <sys/types.h> + #include <sys/param.h> /* PIPE_BUF */ + #include <signal.h> +@@ -80,21 +81,22 @@ + MKINIT + struct redirtab { + struct redirtab *next; +- short renamed[10]; ++ int renamed[10]; ++ int nullredirs; + }; + + + MKINIT struct redirtab *redirlist; ++MKINIT int nullredirs; + +-/* +- * We keep track of whether or not fd0 has been redirected. This is for +- * background commands, where we want to redirect fd0 to /dev/null only +- * if it hasn't already been redirected. +-*/ +-int fd0_redirected = 0; +- +-STATIC void openredirect __P((union node *, char[10 ])); ++STATIC int openredirect __P((union node *)); ++#ifdef notyet ++STATIC void dupredirect __P((union node *, int, char[10 ])); ++#else ++STATIC void dupredirect __P((union node *, int)); ++#endif + STATIC int openhere __P((union node *)); ++STATIC int noclobberopen __P((const char *)); + + + /* +@@ -111,137 +113,173 @@ + int flags; + { + union node *n; +- struct redirtab *sv = NULL; ++ struct redirtab *sv; + int i; + int fd; +- int try; ++ int newfd; ++ int *p; ++#if notyet + char memory[10]; /* file descriptors to write to memory */ + + for (i = 10 ; --i >= 0 ; ) + memory[i] = 0; + memory[1] = flags & REDIR_BACKQ; ++#endif ++ if (!redir) { ++ if (flags & REDIR_PUSH) ++ nullredirs++; ++ return; ++ } ++ sv = NULL; ++ INTOFF; + if (flags & REDIR_PUSH) { +- sv = ckmalloc(sizeof (struct redirtab)); ++ struct redirtab *q; ++ q = ckmalloc(sizeof (struct redirtab)); ++ q->next = redirlist; ++ redirlist = q; ++ q->nullredirs = nullredirs; + for (i = 0 ; i < 10 ; i++) +- sv->renamed[i] = EMPTY; +- sv->next = redirlist; +- redirlist = sv; ++ q->renamed[i] = EMPTY; ++ nullredirs = 0; ++ sv = q; + } +- for (n = redir ; n ; n = n->nfile.next) { ++ n = redir; ++ do { + 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*/ +- default: +- INTON; +- error("%d: %s", fd, strerror(errno)); ++ newfd = openredirect(n); ++ if (fd == newfd) ++ continue; ++ if (sv && *(p = &sv->renamed[fd]) == EMPTY) { ++ int i = fcntl(fd, F_DUPFD, 10); ++ if (i == -1) { ++ i = errno; ++ if (i != EBADF) { ++ const char *m = strerror(i); ++ close(newfd); ++ error("%d: %s", fd, m); + /* NOTREACHED */ + } +- } +- if (!try) { +- sv->renamed[fd] = i; ++ } else { ++ *p = i; + close(fd); + } +- INTON; + } else { + close(fd); + } +- if (fd == 0) +- fd0_redirected++; +- if (!try) +- openredirect(n, memory); +- } ++#ifdef notyet ++ dupredirect(n, newfd, memory); ++#else ++ dupredirect(n, newfd); ++#endif ++ } while ((n = n->nfile.next)); ++ INTON; ++#ifdef notyet + if (memory[1]) + out1 = &memout; + if (memory[2]) + out2 = &memout; ++#endif + } + + +-STATIC void +-openredirect(redir, memory) ++STATIC int ++openredirect(redir) + union node *redir; +- char memory[10]; + { +- int fd = redir->nfile.fd; + char *fname; + int f; +- int flags = O_WRONLY|O_CREAT|O_TRUNC; + +- /* +- * We suppress interrupts so that we won't leave open file +- * descriptors around. This may not be such a good idea because +- * an open of a device or a fifo can block indefinitely. +- */ +- INTOFF; +- memory[fd] = 0; + switch (redir->nfile.type) { + case NFROM: + fname = redir->nfile.expfname; +- if ((f = open(fname, O_RDONLY)) < 0) ++ if ((f = open64(fname, O_RDONLY)) < 0) + goto eopen; + break; + case NFROMTO: + fname = redir->nfile.expfname; +- if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) ++ if ((f = open64(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) + goto ecreate; + break; + case NTO: +- if (Cflag) +- flags |= O_EXCL; ++ /* Take care of noclobber mode. */ ++ if (Cflag) { ++ fname = redir->nfile.expfname; ++ if ((f = noclobberopen(fname)) < 0) ++ goto ecreate; ++ break; ++ } + /* FALLTHROUGH */ + case NCLOBBER: + fname = redir->nfile.expfname; +- if ((f = open(fname, flags, 0666)) < 0) ++ if ((f = open64(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) + goto ecreate; + break; + case NAPPEND: + fname = redir->nfile.expfname; +- if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) ++ if ((f = open64(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) + goto ecreate; + break; ++ default: ++#ifdef DEBUG ++ abort(); ++#endif ++ /* Fall through to eliminate warning. */ + case NTOFD: + case NFROMFD: ++ f = -1; ++ break; ++ case NHERE: ++ case NXHERE: ++ f = openhere(redir); ++ break; ++ } ++ ++ return f; ++ecreate: ++ error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); ++eopen: ++ error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); ++} ++ ++ ++STATIC void ++#ifdef notyet ++dupredirect(redir, f, memory) ++#else ++dupredirect(redir, f) ++#endif ++ union node *redir; ++ int f; ++#ifdef notyet ++ char memory[10]; ++#endif ++ { ++ int fd = redir->nfile.fd; ++ ++#ifdef notyet ++ memory[fd] = 0; ++#endif ++ if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { + if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ ++#ifdef notyet + if (memory[redir->ndup.dupfd]) + memory[fd] = 1; + else ++#endif + copyfd(redir->ndup.dupfd, fd); + } +- INTON; + return; +- case NHERE: +- case NXHERE: +- f = openhere(redir); +- break; +- default: +- abort(); + } + + if (f != fd) { + copyfd(f, fd); + close(f); + } +- INTON; + return; +-ecreate: +- error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); +-eopen: +- error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); + } + + +@@ -256,7 +294,7 @@ + union node *redir; + { + int pip[2]; +- int len = 0; ++ size_t len = 0; + + if (pipe(pip) < 0) + error("Pipe call failed"); +@@ -294,24 +332,26 @@ + */ + + void +-popredir() { ++popredir(int drop) { + struct redirtab *rp = redirlist; + int i; + ++ INTOFF; ++ if (--nullredirs >= 0) ++ goto out; + for (i = 0 ; i < 10 ; i++) { + if (rp->renamed[i] != EMPTY) { +- if (i == 0) +- fd0_redirected--; ++ if (!drop) { + close(i); +- if (rp->renamed[i] >= 0) { + copyfd(rp->renamed[i], i); +- close(rp->renamed[i]); + } ++ close(rp->renamed[i]); + } + } +- INTOFF; + redirlist = rp->next; ++ nullredirs = rp->nullredirs; + ckfree(rp); ++out: + INTON; + } + +@@ -324,38 +364,22 @@ + INCLUDE "redir.h" + + RESET { +- while (redirlist) +- popredir(); +-} +- +-SHELLPROC { +- clearredir(); ++ clearredir(0); + } + + #endif + +-/* Return true if fd 0 has already been redirected at least once. */ +-int +-fd0_redirected_p () { +- return fd0_redirected != 0; +-} +- + /* + * Discard all saved file descriptors. + */ + + void +-clearredir() { +- struct redirtab *rp; +- int i; +- +- for (rp = redirlist ; rp ; rp = rp->next) { +- for (i = 0 ; i < 10 ; i++) { +- if (rp->renamed[i] >= 0) { +- close(rp->renamed[i]); +- } +- rp->renamed[i] = EMPTY; +- } ++clearredir(int drop) { ++ for (;;) { ++ nullredirs = 0; ++ if (!redirlist) ++ break; ++ popredir(drop); + } + } + +@@ -368,18 +392,104 @@ + */ + + int +-copyfd(from, to) +- int from; +- int to; ++copyfd(int from, int to) + { + int newfd; + + newfd = fcntl(from, F_DUPFD, to); + if (newfd < 0) { +- if (errno == EMFILE) ++ int errno2 = errno; ++ if (errno2 == EMFILE) + return EMPTY; + else +- error("%d: %s", from, strerror(errno)); ++ error("%d: %s", from, strerror(errno2)); + } + return newfd; + } ++ ++ ++/* ++ * Open a file in noclobber mode. ++ * The code was copied from bash. ++ */ ++int ++noclobberopen(fname) ++ const char *fname; ++{ ++ int r, fd; ++ struct stat64 finfo, finfo2; ++ ++ /* ++ * If the file exists and is a regular file, return an error ++ * immediately. ++ */ ++ r = stat64(fname, &finfo); ++ if (r == 0 && S_ISREG(finfo.st_mode)) { ++ errno = EEXIST; ++ return -1; ++ } ++ ++ /* ++ * If the file was not present (r != 0), make sure we open it ++ * exclusively so that if it is created before we open it, our open ++ * will fail. Make sure that we do not truncate an existing file. ++ * Note that we don't turn on O_EXCL unless the stat failed -- if the ++ * file was not a regular file, we leave O_EXCL off. ++ */ ++ if (r != 0) ++ return open64(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); ++ fd = open64(fname, O_WRONLY|O_CREAT, 0666); ++ ++ /* If the open failed, return the file descriptor right away. */ ++ if (fd < 0) ++ return fd; ++ ++ /* ++ * OK, the open succeeded, but the file may have been changed from a ++ * non-regular file to a regular file between the stat and the open. ++ * We are assuming that the O_EXCL open handles the case where FILENAME ++ * did not exist and is symlinked to an existing file between the stat ++ * and open. ++ */ ++ ++ /* ++ * If we can open it and fstat the file descriptor, and neither check ++ * revealed that it was a regular file, and the file has not been ++ * replaced, return the file descriptor. ++ */ ++ if (fstat64(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) && ++ finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) ++ return fd; ++ ++ /* The file has been replaced. badness. */ ++ close(fd); ++ errno = EEXIST; ++ return -1; ++} ++ ++ ++int ++redirectsafe(union node *redir, int flags) ++{ ++ int err; ++ int e; ++ volatile int saveint; ++ struct jmploc *volatile savehandler = handler; ++ struct jmploc jmploc; ++ ++ SAVEINT(saveint); ++ exception = -1; ++ if (setjmp(jmploc.loc)) ++ err = 2; ++ else { ++ handler = &jmploc; ++ redirect(redir, flags); ++ err = 0; ++ } ++ handler = savehandler; ++ e = exception; ++ if (e >= 0 && e != EXERROR) ++ longjmp(handler->loc, 1); ++ RESTOREINT(saveint); ++ return err; ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/redir.h bin_NetBSD-1.6release/src/bin/sh/redir.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/redir.h 2000-05-23 11:03:19.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/redir.h 2003-02-08 14:35:42.000000000 +0000 +@@ -40,12 +40,14 @@ + + /* flags passed to redirect */ + #define REDIR_PUSH 01 /* save previous values of file descriptors */ ++#ifdef notyet + #define REDIR_BACKQ 02 /* save the command output in memory */ ++#endif + + union node; + void redirect __P((union node *, int)); +-void popredir __P((void)); +-int fd0_redirected_p __P((void)); +-void clearredir __P((void)); ++void popredir __P((int)); ++void clearredir __P((int)); + int copyfd __P((int, int)); ++int redirectsafe __P((union node *, int)); + +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/regularbltins.def bin_NetBSD-1.6release/src/bin/sh/regularbltins.def +--- bin_NetBSD-1.6release.orig/src/bin/sh/regularbltins.def 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/regularbltins.def 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,16 @@ ++alias ++bg ++cd ++command ++false ++fc ++fg ++getopts ++jobs ++kill ++newgrp ++read ++true ++umask ++unalias ++wait +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/setmode.c bin_NetBSD-1.6release/src/bin/sh/setmode.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/setmode.c 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/setmode.c 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,486 @@ ++/* $NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $ */ ++ ++/* ++ * 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. ++ */ ++ ++#include <sys/cdefs.h> ++#if defined(LIBC_SCCS) && !defined(lint) ++#if 0 ++static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94"; ++#else ++__RCSID("$NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $"); ++#endif ++#endif /* LIBC_SCCS and not lint */ ++ ++#include <sys/types.h> ++#include <sys/stat.h> ++ ++#include <assert.h> ++#include <ctype.h> ++#include <errno.h> ++#include <signal.h> ++#include <stdlib.h> ++#include <unistd.h> ++ ++#ifdef SETMODE_DEBUG ++#include <stdio.h> ++#endif ++ ++#ifdef __weak_alias ++__weak_alias(getmode,_getmode) ++__weak_alias(setmode,_setmode) ++#endif ++ ++#ifdef __GLIBC__ ++#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 __P((BITCMD *, int, int, int, u_int)); ++static void compress_mode __P((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) ++ const void *bbox; ++ mode_t omode; ++{ ++ const BITCMD *set; ++ mode_t clrval, newmode, value; ++ ++ _DIAGASSERT(bbox != NULL); ++ ++ set = (const 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) do { \ ++ if (set >= endset) { \ ++ BITCMD *newset; \ ++ setlen += SET_LEN_INCR; \ ++ newset = realloc(saveset, sizeof(BITCMD) * setlen); \ ++ if (newset == NULL) { \ ++ free(saveset); \ ++ return (NULL); \ ++ } \ ++ set = newset + (set - saveset); \ ++ saveset = newset; \ ++ endset = newset + (setlen - 2); \ ++ } \ ++ set = addcmd(set, (a), (b), (c), (d)); \ ++} while (/*CONSTCOND*/0) ++ ++#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) ++ ++void * ++setmode(p) ++ const char *p; ++{ ++ int perm, who; ++ char op, *ep; ++ BITCMD *set, *saveset, *endset; ++ sigset_t sigset, sigoset; ++ mode_t mask; ++ int equalopdone = 0; /* pacify gcc */ ++ int 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((u_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((unsigned char)*p)) { ++ perm = (mode_t)strtol(p, &ep, 8); ++ if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) { ++ free(saveset); ++ return (NULL); ++ } ++ ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); ++ set->cmd = 0; ++ 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 specific bits where requested and ++ * only "other" bits ignore set-id. ++ */ ++ if (who == 0 || (who & ~S_IRWXO)) ++ perm |= S_ISUID|S_ISGID; ++ break; ++ case 't': ++ /* ++ * If specific bits where requested and ++ * only "other" bits ignore set-id. ++ */ ++ if (who == 0 || (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; ++ int oparg, who; ++ int op; ++ u_int mask; ++{ ++ ++ _DIAGASSERT(set != NULL); ++ ++ 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 = (mode_t)~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) ++ BITCMD *set; ++{ ++ ++ _DIAGASSERT(set != NULL); ++ ++ 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) ++ BITCMD *set; ++{ ++ BITCMD *nset; ++ int setbits, clrbits, Xbits, op; ++ ++ _DIAGASSERT(set != NULL); ++ ++ 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++; ++ } ++ } ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/sh.1 bin_NetBSD-1.6release/src/bin/sh/sh.1 +--- bin_NetBSD-1.6release.orig/src/bin/sh/sh.1 2002-05-16 11:41:22.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/sh.1 2003-02-08 14:35:42.000000000 +0000 +@@ -188,7 +188,7 @@ + or + .Ic until ; + or if the command is the left hand operand of an +-.Dq \*[Am]\*[Am] ++.Dq && + or + .Dq || + operator. +@@ -256,9 +256,9 @@ + 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] ++.Dl & && \&( \&) \&; ;; | || \*[Lt]newline\*[Gt] + .It "Redirection operators:" +-.Dl \*[Lt] \*[Gt] \*[Gt]| \*[Lt]\*[Lt] \*[Gt]\*[Gt] \*[Lt]\*[Am] \*[Gt]\*[Am] \*[Lt]\*[Lt]- \*[Lt]\*[Gt] ++.Dl \*[Lt] \*[Gt] \*[Gt]| \*[Lt]\*[Lt] \*[Gt]\*[Gt] \*[Lt]& \*[Gt]& \*[Lt]\*[Lt]- \*[Lt]\*[Gt] + .El + .Ss Quoting + Quoting is used to remove the special meaning of certain characters or +@@ -381,13 +381,13 @@ + 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 ++.It [n1] Ns \*[Lt]& Ns n2 + Duplicate standard input (or n1) from file descriptor n2. +-.It [n] Ns \*[Lt]\*[Am]- ++.It [n] Ns \*[Lt]&- + Close standard input (or n). +-.It [n1] Ns \*[Gt]\*[Am] Ns n2 ++.It [n1] Ns \*[Gt]& Ns n2 + Duplicate standard output (or n1) from n2. +-.It [n] Ns \*[Gt]\*[Am]- ++.It [n] Ns \*[Gt]&- + Close standard output (or n). + .It [n] Ns \*[Lt]\*[Gt] file + Open file for reading and writing on standard input (or n). +@@ -525,27 +525,27 @@ + takes place before redirection, it can be modified by redirection. For + example: + .Pp +-.Dl $ command1 2\*[Gt]\*[Am]1 | command2 ++.Dl $ command1 2\*[Gt]&1 | command2 + .Pp + sends both the standard output and standard error of command1 + to the standard input of command2. + .Pp + A ; or \*[Lt]newline\*[Gt] terminator causes the preceding AND-OR-list (described +-next) to be executed sequentially; a \*[Am] causes asynchronous execution of ++next) to be executed sequentially; a & 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 builtin, 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 ++.Ss Background Commands -- & ++If a command is terminated by the control operator ampersand (&), 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] ...] ++.Dl command1 & [command2 & ...] + .Pp + If the shell is not interactive, the standard input of an asynchronous + command is set to +@@ -558,17 +558,17 @@ + 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] ++.Dq && + and + .Dq || + are AND-OR list operators. +-.Dq \*[Am]\*[Am] ++.Dq && + executes the first command, and then executes the second command iff the + exit status of the first command is zero. + .Dq || + is similar, but executes the second command iff the exit status of the first + command is nonzero. +-.Dq \*[Am]\*[Am] ++.Dq && + and + .Dq || + both have the same priority. +@@ -646,7 +646,7 @@ + they were one program: + .Pp + .Bd -literal -offset indent +-{ echo -n \*q hello \*q ; echo \*q world" ; } \*[Gt] greeting ++{ printf \*q hello \*q ; printf \*q world\\n" ; } \*[Gt] greeting + .Ed + .Pp + Note that +@@ -961,11 +961,11 @@ + .Ss Shell Patterns + A pattern consists of normal characters, which match themselves, + and meta-characters. The meta-characters are +-.Dq ! , ++.Dq \&! , + .Dq * , +-.Dq ? , ++.Dq \&? , + and +-.Dq [ . ++.Dq \&[ . + These characters lose their 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 +@@ -999,14 +999,10 @@ + .Ss Builtins + This 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 that may +-be builtin for efficiency (e.g. +-.Xr printf 1 , +-.Xr echo 1 , +-.Xr test 1 , +-etc). ++process. + .Bl -tag -width 5n + .It : ++.It true + 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. +@@ -1032,9 +1028,12 @@ + .It command Ar command Ar arg ... + Execute the specified builtin command. (This is useful when you + have a shell function with the same name as a builtin command.) +-.It cd Op Ar directory ++.It cd Ar - ++.It Xo cd Op Fl LP ++.Op Ar directory ++.Xc + Switch to the specified directory (default +-.Ev $HOME ) . ++.Ev HOME ) . + If an entry for + .Ev CDPATH + appears in the environment of the +@@ -1048,13 +1047,61 @@ + .Ev CDPATH + is the same as that of + .Ev PATH . +-In an interactive shell, the ++If a single dash is specified as the argument, it will be replaced by the ++value of ++.Ev OLDPWD . ++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. ++mechanism was used or because the argument is a single dash. ++The ++.Fl P ++option causes the physical directory structure to be used, that is, all ++symbolic links are resolved to their repective values. The ++.Fl L ++option turns off the effect of any preceding ++.Fl P ++options. ++.It Xo echo Op Fl n ++.Ar args... ++.Xc ++Print the arguments on the standard output, separated by spaces. ++Unless the ++.Fl n ++option is present, a newline is output following the arguments. ++.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 ++.Ic echo ++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 octal digits. ++If there are zero digits, a nul character is output. ++.It Li \e\e ++Output a backslash. ++.El ++.Pp ++All other backslash sequences elicit undefined behaviour. + .It eval Ar string ... + Concatenate all the arguments with spaces. Then re-parse and execute + the command. +@@ -1217,7 +1264,7 @@ + will set the variable + .Va var + to a +-.Dq ? ; ++.Dq \&? ; + .Ic getopts + will then unset + .Ev OPTARG +@@ -1236,7 +1283,7 @@ + otherwise, it will set + .Va var + to +-.Dq ? . ++.Dq \&? . + .Pp + The following code fragment shows how one might process the arguments + for a command that can take the options +@@ -1295,7 +1342,7 @@ + .It jobs + This command lists out all the background processes + which are children of the current shell process. +-.It pwd ++.It pwd Op Fl LP + 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 +@@ -1304,6 +1351,14 @@ + renamed, the builtin version of + .Ic pwd + will continue to print the old name for the directory. ++The ++.Fl P ++option causes the phyical value of the current working directory to be shown, ++that is, all symbolic links are resolved to their repective values. The ++.Fl L ++option turns off the effect of any preceding ++.Fl P ++options. + .It Xo read Op Fl p Ar prompt + .Op Fl r + .Ar variable +@@ -1314,7 +1369,9 @@ + 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 ++above, and the pieces are assigned to the variables in order. ++At least one variable must be specified. ++If there are + more pieces than variables, the remaining pieces (along with the + characters in + .Ev IFS +@@ -1346,6 +1403,225 @@ + .Fl p + option specified the output will be formatted suitably for non-interactive use. + .Pp ++.It Xo printf Ar format ++.Op Ar arguments ... ++.Xc ++.Ic printf ++formats and prints its arguments, after the first, under control ++of the ++.Ar format . ++The ++.Ar format ++is a character string which contains three types of objects: plain characters, ++which are simply copied to standard output, character escape sequences which ++are converted and copied to the standard output, and format specifications, ++each of which causes printing of the next successive ++.Ar argument . ++.Pp ++The ++.Ar arguments ++after the first are treated as strings if the corresponding format is ++either ++.Cm b , ++.Cm c ++or ++.Cm s ; ++otherwise it is evaluated as a C constant, with the following extensions: ++.Pp ++.Bl -bullet -offset indent -compact ++.It ++A leading plus or minus sign is allowed. ++.It ++If the leading character is a single or double quote, the value is the ++.Tn ASCII ++code of the next character. ++.El ++.Pp ++The format string is reused as often as necessary to satisfy the ++.Ar arguments . ++Any extra format specifications are evaluated with zero or the null ++string. ++.Pp ++Character escape sequences are in backslash notation as defined in ++.St -ansiC . ++The characters and their meanings ++are as follows: ++.Bl -tag -width Ds -offset indent ++.It Cm \ee ++Write an \*[Lt]escape\*[Gt] character. ++.It Cm \ea ++Write a \*[Lt]bell\*[Gt] character. ++.It Cm \eb ++Write a \*[Lt]backspace\*[Gt] character. ++.It Cm \ef ++Write a \*[Lt]form-feed\*[Gt] character. ++.It Cm \en ++Write a \*[Lt]new-line\*[Gt] character. ++.It Cm \er ++Write a \*[Lt]carriage return\*[Gt] character. ++.It Cm \et ++Write a \*[Lt]tab\*[Gt] character. ++.It Cm \ev ++Write a \*[Lt]vertical tab\*[Gt] character. ++.It Cm \e\' ++Write a \*[Lt]single quote\*[Gt] character. ++.It Cm \e\e ++Write a backslash character. ++.It Cm \e Ns Ar num ++Write an 8-bit character whose ++.Tn ASCII ++value is the 1-, 2-, or 3-digit ++octal number ++.Ar num . ++.El ++.Pp ++Each format specification is introduced by the percent character ++(``%''). ++The remainder of the format specification includes, ++in the following order: ++.Bl -tag -width Ds ++.It "Zero or more of the following flags:" ++.Bl -tag -width Ds ++.It Cm # ++A `#' character ++specifying that the value should be printed in an ``alternative form''. ++For ++.Cm c , ++.Cm d , ++and ++.Cm s , ++formats, this option has no effect. For the ++.Cm o ++formats the precision of the number is increased to force the first ++character of the output string to a zero. For the ++.Cm x ++.Pq Cm X ++format, a non-zero result has the string ++.Li 0x ++.Pq Li 0X ++prepended to it. For ++.Cm e , ++.Cm E , ++.Cm f , ++.Cm g , ++and ++.Cm G , ++formats, the result will always contain a decimal point, even if no ++digits follow the point (normally, a decimal point only appears in the ++results of those formats if a digit follows the decimal point). For ++.Cm g ++and ++.Cm G ++formats, trailing zeros are not removed from the result as they ++would otherwise be; ++.It Cm \&\- ++A minus sign `\-' which specifies ++.Em left adjustment ++of the output in the indicated field; ++.It Cm \&+ ++A `+' character specifying that there should always be ++a sign placed before the number when using signed formats. ++.It Sq \&\ \& ++A space specifying that a blank should be left before a positive number ++for a signed format. A `+' overrides a space if both are used; ++.It Cm \&0 ++A zero `0' character indicating that zero-padding should be used ++rather than blank-padding. A `\-' overrides a `0' if both are used; ++.El ++.It "Field Width:" ++An optional digit string specifying a ++.Em field width ; ++if the output string has fewer characters than the field width it will ++be blank-padded on the left (or right, if the left-adjustment indicator ++has been given) to make up the field width (note that a leading zero ++is a flag, but an embedded zero is part of a field width); ++.It Precision : ++An optional period, ++.Sq Cm \&.\& , ++followed by an optional digit string giving a ++.Em precision ++which specifies the number of digits to appear after the decimal point, ++for ++.Cm e ++and ++.Cm f ++formats, or the maximum number of characters to be printed ++from a string; if the digit string is missing, the precision is treated ++as zero; ++.It Format : ++A character which indicates the type of format to use (one of ++.Cm diouxXfwEgGbcs ) . ++.El ++.Pp ++A field width or precision may be ++.Sq Cm \&* ++instead of a digit string. ++In this case an ++.Ar argument ++supplies the field width or precision. ++.Pp ++The format characters and their meanings are: ++.Bl -tag -width Fl ++.It Cm diouXx ++The ++.Ar argument ++is printed as a signed decimal (d or i), unsigned octal, unsigned decimal, ++or unsigned hexadecimal (X or x), respectively. ++.It Cm f ++The ++.Ar argument ++is printed in the style ++.Sm off ++.Pf [\-]ddd Cm \&. No ddd ++.Sm on ++where the number of d's ++after the decimal point is equal to the precision specification for ++the argument. ++If the precision is missing, 6 digits are given; if the precision ++is explicitly 0, no digits and no decimal point are printed. ++.It Cm eE ++The ++.Ar argument ++is printed in the style ++.Sm off ++.Pf [\-]d Cm \&. No ddd Cm e No \\*(Pmdd ++.Sm on ++where there ++is one digit before the decimal point and the number after is equal to ++the precision specification for the argument; when the precision is ++missing, 6 digits are produced. ++An upper-case E is used for an `E' format. ++.It Cm gG ++The ++.Ar argument ++is printed in style ++.Cm f ++or in style ++.Cm e ++.Pq Cm E ++whichever gives full precision in minimum space. ++.It Cm b ++Characters from the string ++.Ar argument ++are printed with backslash-escape sequences expanded as in ++.Ic echo . ++.It Cm c ++The first character of ++.Ar argument ++is printed. ++.It Cm s ++Characters from the string ++.Ar argument ++are printed until the end is reached or until the number of characters ++indicated by the precision specification is reached; however if the ++precision is 0 or missing, all characters in the string are printed. ++.It Cm \&% ++Print a `%'; no argument is used. ++.El ++.Pp ++In no case does a non-existent or small field width cause truncation of ++a field; padding takes place only if the specified field width exceeds ++the actual width. + .It Xo set + .Oo { + .Fl options | Cm +options | Cm -- } +@@ -1392,15 +1668,248 @@ + and so on, decreasing + the value of + .Va $# +-by one. If there are zero positional parameters, ++by one. If n is greater than the number of positional parameters, + .Ic shift +-does nothing. +-.It Xo trap +-.Op Fl l +-.Xc ++will issue an error message, and exit with return status 2. ++.It test Ar expression ++.It \&[ Ar expression Cm ] ++The ++.Ic test ++utility evaluates the expression and, if it evaluates ++to true, returns a zero (true) exit status; otherwise ++it returns 1 (false). ++If there is no expression, test also ++returns 1 (false). ++.Pp ++All operators and flags are separate arguments to the ++.Ic test ++utility. ++.Pp ++The following primaries are used to construct expression: ++.Bl -tag -width Ar ++.It Fl b Ar file ++True if ++.Ar file ++exists and is a block special ++file. ++.It Fl c Ar file ++True if ++.Ar file ++exists and is a character ++special file. ++.It Fl d Ar file ++True if ++.Ar file ++exists and is a directory. ++.It Fl e Ar file ++True if ++.Ar file ++exists (regardless of type). ++.It Fl f Ar file ++True if ++.Ar file ++exists and is a regular file. ++.It Fl g Ar file ++True if ++.Ar file ++exists and its set group ID flag ++is set. ++.It Fl h Ar file ++True if ++.Ar file ++exists and is a symbolic link. ++.It Fl k Ar file ++True if ++.Ar file ++exists and its sticky bit is set. ++.It Fl n Ar string ++True if the length of ++.Ar string ++is nonzero. ++.It Fl p Ar file ++True if ++.Ar file ++is a named pipe ++.Po Tn FIFO Pc . ++.It Fl r Ar file ++True if ++.Ar file ++exists and is readable. ++.It Fl s Ar file ++True if ++.Ar file ++exists and has a size greater ++than zero. ++.It Fl t Ar file_descriptor ++True if the file whose file descriptor number ++is ++.Ar file_descriptor ++is open and is associated with a terminal. ++.It Fl u Ar file ++True if ++.Ar file ++exists and its set user ID flag ++is set. ++.It Fl w Ar file ++True if ++.Ar file ++exists and is writable. ++True ++indicates only that the write flag is on. ++The file is not writable on a read-only file ++system even if this test indicates true. ++.It Fl x Ar file ++True if ++.Ar file ++exists and is executable. ++True ++indicates only that the execute flag is on. ++If ++.Ar file ++is a directory, true indicates that ++.Ar file ++can be searched. ++.It Fl z Ar string ++True if the length of ++.Ar string ++is zero. ++.It Fl L Ar file ++True if ++.Ar file ++exists and is a symbolic link. ++This operator is retained for compatibility with previous versions of ++this program. Do not rely on its existence; use ++.Fl h ++instead. ++.It Fl O Ar file ++True if ++.Ar file ++exists and its owner matches the effective user id of this process. ++.It Fl G Ar file ++True if ++.Ar file ++exists and its group matches the effective group id of this process. ++.It Fl S Ar file ++True if ++.Ar file ++exists and is a socket. ++.It Ar file1 Fl nt Ar file2 ++True if ++.Ar file1 ++exists and is newer than ++.Ar file2 . ++.It Ar file1 Fl ot Ar file2 ++True if ++.Ar file1 ++exists and is older than ++.Ar file2 . ++.It Ar file1 Fl ef Ar file2 ++True if ++.Ar file1 ++and ++.Ar file2 ++exist and refer to the same file. ++.It Ar string ++True if ++.Ar string ++is not the null ++string. ++.It Ar \&s\&1 Cm \&= Ar \&s\&2 ++True if the strings ++.Ar \&s\&1 ++and ++.Ar \&s\&2 ++are identical. ++.It Ar \&s\&1 Cm \&!= Ar \&s\&2 ++True if the strings ++.Ar \&s\&1 ++and ++.Ar \&s\&2 ++are not identical. ++.It Ar \&s\&1 Cm \&\*[Lt] Ar \&s\&2 ++True if string ++.Ar \&s\&1 ++comes before ++.Ar \&s\&2 ++based on the ASCII value of their characters. ++.It Ar \&s\&1 Cm \&\*[Gt] Ar \&s\&2 ++True if string ++.Ar \&s\&1 ++comes after ++.Ar \&s\&2 ++based on the ASCII value of their characters. ++.It Ar \&n\&1 Fl \&eq Ar \&n\&2 ++True if the integers ++.Ar \&n\&1 ++and ++.Ar \&n\&2 ++are algebraically ++equal. ++.It Ar \&n\&1 Fl \&ne Ar \&n\&2 ++True if the integers ++.Ar \&n\&1 ++and ++.Ar \&n\&2 ++are not ++algebraically equal. ++.It Ar \&n\&1 Fl \> Ar \&n\&2 ++True if the integer ++.Ar \&n\&1 ++is algebraically ++greater than the integer ++.Ar \&n\&2 . ++.It Ar \&n\&1 Fl \&ge Ar \&n\&2 ++True if the integer ++.Ar \&n\&1 ++is algebraically ++greater than or equal to the integer ++.Ar \&n\&2 . ++.It Ar \&n\&1 Fl \< Ar \&n\&2 ++True if the integer ++.Ar \&n\&1 ++is algebraically less ++than the integer ++.Ar \&n\&2 . ++.It Ar \&n\&1 Fl \&le Ar \&n\&2 ++True if the integer ++.Ar \&n\&1 ++is algebraically less ++than or equal to the integer ++.Ar \&n\&2 . ++.El ++.Pp ++These primaries can be combined with the following operators: ++.Bl -tag -width Ar ++.It Cm \&! Ar expression ++True if ++.Ar expression ++is false. ++.It Ar expression1 Fl a Ar expression2 ++True if both ++.Ar expression1 ++and ++.Ar expression2 ++are true. ++.It Ar expression1 Fl o Ar expression2 ++True if either ++.Ar expression1 ++or ++.Ar expression2 ++are true. ++.It Cm \&( Ns Ar expression Ns Cm \&) ++True if expression is true. ++.El ++.Pp ++The ++.Fl a ++operator has higher precedence than the ++.Fl o ++operator. ++.It times ++Print the accumulated user and system times for the shell and for processes ++run from the shell. The return status is 0. + .It Xo trap +-.Op Ar action +-.Ar signal ... ++.Op Ar action Ar signal ... + .Xc + 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 +@@ -1420,11 +1929,6 @@ + .Ic trap + command has no effect on signals that were + ignored on entry to the shell. +-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 +@@ -1436,10 +1940,6 @@ + .Pp + List trapped signals and their corresponding action + .Pp +-.Dl trap -l +-.Pp +-Print a list of valid signals +-.Pp + .Dl trap '' SIGINT QUIT tstp 30 + .Pp + Ignore signals INT QUIT TSTP USR1 +@@ -1614,6 +2114,17 @@ + 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. ++.It Ev PWD ++The logical value of the current working directory. This is set by the ++.Ic cd ++command. ++.It Ev OLDPWD ++The previous logical value of the current working directory. This is set by ++the ++.Ic cd ++command. ++.It Ev PPID ++The process ID of the parent process of the shell. + .El + .Sh FILES + .Bl -item -width HOMEprofilexxxx +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/shell.h bin_NetBSD-1.6release/src/bin/sh/shell.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/shell.h 2000-05-23 11:03:19.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/shell.h 2003-02-08 14:35:42.000000000 +0000 +@@ -1,4 +1,4 @@ +-/* $NetBSD: shell.h,v 1.13 2000/05/22 10:18:47 elric Exp $ */ ++/* $NetBSD: shell.h,v 1.14 2002/05/25 23:09:06 wiz Exp $ */ + + /*- + * Copyright (c) 1991, 1993 +@@ -52,23 +52,18 @@ + */ + + ++#ifndef JOBS + #define JOBS 1 ++#endif + #ifndef BSD + #define BSD 1 + #endif + +-#ifdef __STDC__ + typedef void *pointer; + #ifndef NULL + #define NULL (void *)0 + #endif +-#else /* not __STDC__ */ +-typedef char *pointer; +-#ifndef NULL +-#define NULL 0 +-#endif +-#endif /* not __STDC__ */ +-#define STATIC /* empty */ ++#define STATIC static + #define MKINIT /* empty */ + + #include <sys/cdefs.h> +@@ -81,3 +76,7 @@ + #else + #define TRACE(param) + #endif ++ ++#if defined(__GNUC__) && __GNUC__ < 3 ++#define va_copy __va_copy ++#endif +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/show.c bin_NetBSD-1.6release/src/bin/sh/show.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/show.c 2002-05-16 11:41:22.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/show.c 2003-02-08 14:35:42.000000000 +0000 +@@ -1,4 +1,4 @@ +-/* $NetBSD: show.c,v 1.21 2002/05/15 16:33:35 christos Exp $ */ ++/* $NetBSD: show.c,v 1.22 2002/05/25 23:09:06 wiz Exp $ */ + + /*- + * Copyright (c) 1991, 1993 +@@ -41,16 +41,12 @@ + #if 0 + static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95"; + #else +-__RCSID("$NetBSD: show.c,v 1.21 2002/05/15 16:33:35 christos Exp $"); ++__RCSID("$NetBSD: show.c,v 1.22 2002/05/25 23:09:06 wiz Exp $"); + #endif + #endif /* not lint */ + + #include <stdio.h> +-#ifdef __STDC__ + #include <stdarg.h> +-#else +-#include <varargs.h> +-#endif + + #include "shell.h" + #include "parser.h" +@@ -276,7 +272,6 @@ + putc('\t', fp); + } + } +-#endif + + + +@@ -294,7 +289,6 @@ + #endif + + +-#ifdef DEBUG + void + trputc(c) + int c; +@@ -305,36 +299,22 @@ + if (c == '\n') + fflush(tracefile); + } +-#endif + + void +-#ifdef __STDC__ + trace(const char *fmt, ...) +-#else +-trace(va_alist) +- va_dcl +-#endif + { +-#ifdef DEBUG + va_list va; +-#ifdef __STDC__ ++ + va_start(va, fmt); +-#else +- char *fmt; +- va_start(va); +- fmt = va_arg(va, char *); +-#endif + if (tracefile != NULL) { + (void) vfprintf(tracefile, fmt, va); + if (strchr(fmt, '\n')) + (void) fflush(tracefile); + } + va_end(va); +-#endif + } + + +-#ifdef DEBUG + void + trputs(s) + const char *s; +@@ -386,14 +366,12 @@ + } + putc('"', tracefile); + } +-#endif + + + void + trargs(ap) + char **ap; + { +-#ifdef DEBUG + if (tracefile == NULL) + return; + while (*ap) { +@@ -404,11 +382,9 @@ + putc('\n', tracefile); + } + fflush(tracefile); +-#endif + } + + +-#ifdef DEBUG + void + opentrace() { + char s[100]; +@@ -421,7 +397,7 @@ + #ifdef not_this_way + { + char *p; +- if ((p = getenv("HOME")) == NULL) { ++ if ((p = getenv(homestr)) == NULL) { + if (geteuid() == 0) + p = "/"; + else +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/specialbltins.def bin_NetBSD-1.6release/src/bin/sh/specialbltins.def +--- bin_NetBSD-1.6release.orig/src/bin/sh/specialbltins.def 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/specialbltins.def 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,16 @@ ++. ++: ++break ++builtin ++continue ++eval ++exec ++exit ++export ++readonly ++return ++set ++shift ++times ++trap ++unset +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/trap.c bin_NetBSD-1.6release/src/bin/sh/trap.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/trap.c 2001-03-18 11:04:44.000000000 +0000 ++++ bin_NetBSD-1.6release/src/bin/sh/trap.c 2003-02-08 14:35:42.000000000 +0000 +@@ -48,6 +48,7 @@ + #include <signal.h> + #include <unistd.h> + #include <stdlib.h> ++#include <string.h> + + #include "shell.h" + #include "main.h" +@@ -63,6 +64,9 @@ + #include "trap.h" + #include "mystring.h" + ++#ifdef HETIO ++#include "hetio.h" ++#endif + + /* + * Sigmode records the current value of the signal handlers for the various +@@ -77,59 +81,24 @@ + #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 */ +-char gotsig[NSIG]; /* indicates specified signal received */ +-int pendingsigs; /* indicates some signal received */ +- +-static int getsigaction __P((int, sig_t *)); +-static int signame_to_signum __P((const char *)); +-void printsignals __P((void)); +- +-/* +- * 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(p) +- const char *p; +-{ +- int i; +- +- if (is_number(p)) +- return number(p); +- +- if (strcasecmp(p, "exit") == 0 ) +- return 0; ++/* trap handler commands */ ++char *trap[NSIG]; ++/* current value of signal */ ++STATIC char sigmode[NSIG - 1]; ++/* indicates specified signal received */ ++STATIC char gotsig[NSIG - 1]; ++/* last pending signal */ ++volatile sig_atomic_t pendingsigs; + +- if (strncasecmp(p, "sig", 3) == 0) +- p += 3; ++extern char *signal_names[]; + +- for (i = 0; i < NSIG; ++i) +- if (strcasecmp (p, sys_signame[i]) == 0) +- return i; +- return -1; ++#ifdef mkinit ++INCLUDE <signal.h> ++INIT { ++ signal(SIGCHLD, SIG_DFL); + } ++#endif + +-/* +- * Print a list of valid signal names +- */ +-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. +@@ -144,55 +113,37 @@ + char **ap; + int signo; + +- if (argc <= 1) { +- for (signo = 0 ; signo <= NSIG ; signo++) { +- if (trap[signo] != NULL) +- out1fmt("trap -- '%s' %s\n", trap[signo], +- (signo) ? sys_signame[signo] : "EXIT"); ++ nextopt(nullstr); ++ ap = argptr; ++ if (!*ap) { ++ for (signo = 0 ; signo < NSIG ; signo++) { ++ if (trap[signo] != NULL) { ++ out1fmt( ++ "trap -- %s %s\n", ++ single_quote(trap[signo]), ++ signal_names[signo] ++ ); + } +- 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] == NULL) +- ap++; +- else if ((*ap)[1] == 'l' && (*ap)[2] == NULL) { +- printsignals(); + return 0; + } +- else +- error("bad option %s\n", *ap); +- } ++ if (!ap[1]) ++ action = NULL; + else + action = *ap++; +- } +- + while (*ap) { +- if (is_number(*ap)) +- signo = number(*ap); +- else +- signo = signame_to_signum(*ap); +- +- if (signo < 0 || signo > NSIG) ++ if ((signo = decode_signal(*ap, 0)) < 0) + error("%s: bad trap", *ap); +- + INTOFF; +- if (action) ++ if (action) { ++ if (action[0] == '-' && action[1] == '\0') ++ action = NULL; ++ else + action = savestr(action); +- ++ } + if (trap[signo]) + ckfree(trap[signo]); +- + trap[signo] = action; +- + if (signo != 0) + setsignal(signo); + INTON; +@@ -211,7 +162,7 @@ + clear_traps() { + char **tp; + +- for (tp = trap ; tp <= &trap[NSIG] ; tp++) { ++ for (tp = trap ; tp < &trap[NSIG] ; tp++) { + if (*tp && **tp) { /* trap not NULL or SIG_IGN */ + INTOFF; + ckfree(*tp); +@@ -230,13 +181,13 @@ + * out what it should be set to. + */ + +-long ++void + setsignal(signo) + int signo; + { + int action; +- sig_t sigact = SIG_DFL; + char *t; ++ struct sigaction act; + + if ((t = trap[signo]) == NULL) + action = S_DFL; +@@ -279,15 +230,15 @@ + /* + * current setting unknown + */ +- if (!getsigaction(signo, &sigact)) { ++ if (sigaction(signo, 0, &act) == -1) { + /* + * 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; ++ return; + } +- if (sigact == SIG_IGN) { ++ if (act.sa_handler == SIG_IGN) { + if (mflag && (signo == SIGTSTP || + signo == SIGTTIN || signo == SIGTTOU)) { + *t = S_IGN; /* don't hard ignore these */ +@@ -298,31 +249,21 @@ + } + } + if (*t == S_HARD_IGN || *t == action) +- return 0; ++ return; + switch (action) { +- case S_DFL: sigact = SIG_DFL; break; +- case S_CATCH: sigact = onsig; break; +- case S_IGN: sigact = SIG_IGN; break; ++ case S_CATCH: ++ act.sa_handler = onsig; ++ break; ++ case S_IGN: ++ act.sa_handler = SIG_IGN; ++ break; ++ default: ++ act.sa_handler = SIG_DFL; + } + *t = action; +- siginterrupt(signo, 1); +- return (long)signal(signo, sigact); +-} +- +-/* +- * Return the current setting for sig w/o changing it. +- */ +-static int +-getsigaction(signo, sigact) +- 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; ++ act.sa_flags = 0; ++ sigfillset(&act.sa_mask); ++ sigaction(signo, &act, 0); + } + + /* +@@ -340,22 +281,6 @@ + } + + +-#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. +@@ -365,13 +290,15 @@ + onsig(signo) + int signo; + { +- signal(signo, onsig); + if (signo == SIGINT && trap[SIGINT] == NULL) { +- onint(); ++ if (suppressint) { ++ (*(sig_atomic_t *) &intpending)++; + return; + } ++ onint(); ++ } + gotsig[signo - 1] = 1; +- pendingsigs++; ++ pendingsigs = signo; + } + + +@@ -383,23 +310,15 @@ + + void + dotrap() { +- int i; ++ char *p; + int savestatus; + +- for (;;) { +- for (i = 1 ; ; i++) { +- if (gotsig[i - 1]) +- break; +- if (i >= NSIG) +- goto done; +- } +- gotsig[i - 1] = 0; ++ while (pendingsigs = 0, barrier(), (p = memchr(gotsig, 1, NSIG - 1))) { ++ *p = 0; + savestatus=exitstatus; +- evalstring(trap[i], 0); ++ evalstring(trap[p - gotsig + 1], 0); + exitstatus=savestatus; + } +-done: +- pendingsigs = 0; + } + + +@@ -415,12 +334,12 @@ + { + static int is_interactive; + +- if (on == is_interactive) ++ if (++on == is_interactive) + return; ++ is_interactive = on; + setsignal(SIGINT); + setsignal(SIGQUIT); + setsignal(SIGTERM); +- is_interactive = on; + } + + +@@ -430,29 +349,48 @@ + */ + + void +-exitshell(status) +- int status; ++exitshell(void) + { +- struct jmploc loc1, loc2; ++ struct jmploc loc; + char *p; ++ int status; + ++ status = exitstatus; + TRACE(("exitshell(%d) pid=%d\n", status, getpid())); +- if (setjmp(loc1.loc)) { +- goto l1; +- } +- if (setjmp(loc2.loc)) { +- goto l2; ++#ifdef HETIO ++ hetio_reset_term(); ++#endif ++ if (setjmp(loc.loc)) { ++ goto out; + } +- handler = &loc1; ++ handler = &loc; + 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); ++out: ++ _exit(status); + /* NOTREACHED */ + } ++ ++int decode_signal(const char *string, int minsig) ++{ ++ int signo; ++ ++ if (is_number(string)) { ++ signo = atoi(string); ++ if (signo >= NSIG) { ++ return -1; ++ } ++ return signo; ++ } ++ ++ for (signo = minsig; signo < NSIG; signo++) { ++ if (!strcasecmp(string, signal_names[signo])) { ++ return signo; ++ } ++ } ++ ++ return -1; ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/trap.h bin_NetBSD-1.6release/src/bin/sh/trap.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/trap.h 2000-05-23 11:03:19.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/trap.h 2003-02-08 14:35:42.000000000 +0000 +@@ -38,13 +38,17 @@ + * @(#)trap.h 8.3 (Berkeley) 6/5/95 + */ + +-extern int pendingsigs; ++#include <signal.h> ++ ++extern volatile sig_atomic_t pendingsigs; ++extern char *trap[]; + + int trapcmd __P((int, char **)); + void clear_traps __P((void)); +-long setsignal __P((int)); ++void setsignal __P((int)); + void ignoresig __P((int)); + void onsig __P((int)); + void dotrap __P((void)); + void setinteractive __P((int)); +-void exitshell __P((int)) __attribute__((noreturn)); ++void exitshell __P((void)) __attribute__((noreturn)); ++int decode_signal __P((const char *, int)); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/var.c bin_NetBSD-1.6release/src/bin/sh/var.c +--- bin_NetBSD-1.6release.orig/src/bin/sh/var.c 2002-05-16 11:41:23.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/var.c 2003-02-08 14:35:42.000000000 +0000 +@@ -67,6 +67,7 @@ + #include "error.h" + #include "mystring.h" + #include "parser.h" ++#include "mail.h" + #ifndef SMALL + #include "myhistedit.h" + #endif +@@ -75,76 +76,56 @@ + #define VTABSIZE 39 + + +-struct varinit { +- struct var *var; +- int flags; +- const char *text; +- void (*func) __P((const char *)); +-}; +- ++struct localvar *localvars; + +-#if ATTY +-struct var vatty; +-#endif +-#ifndef SMALL +-struct var vhistsize; +-struct var vterm; ++const char defpathvar[] = ++ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; ++#ifdef IFS_BROKEN ++const char defifsvar[] = "IFS= \t\n"; ++#else ++const char defifs[] = " \t\n"; + #endif +-struct var vifs; +-struct var vmail; +-struct var vmpath; +-struct var vpath; +-struct var vps1; +-struct var vps2; +-struct var vvers; +-struct var voptind; + +-const struct varinit varinit[] = { ++struct var varinit[] = { + #if ATTY +- { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=", +- NULL }, ++ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=", 0 }, + #endif +-#ifndef SMALL +- { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", +- sethistsize }, ++#ifdef IFS_BROKEN ++ { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 }, ++#else ++ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=", 0 }, + #endif +- { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n", +- NULL }, +- { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", +- NULL }, +- { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", +- NULL }, +- { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH, +- changepath }, +- /* +- * vps1 depends on uid +- */ +- { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", +- NULL }, ++ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", changemail }, ++ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", changemail }, ++ { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, ++ { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 }, ++ { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, ++ { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, + #ifndef SMALL +- { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=", +- setterm }, ++ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=", 0 }, ++ { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", sethistsize }, + #endif +- { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", +- getoptsreset }, +- { NULL, 0, NULL, +- NULL } + }; + +-struct var *vartab[VTABSIZE]; ++STATIC struct var *vartab[VTABSIZE]; + + STATIC struct var **hashvar __P((const char *)); +-STATIC int varequal __P((const char *, const char *)); ++STATIC void showvars __P((const char *, int, int)); ++STATIC struct var **findvar __P((struct var **, const char *)); + + /* + * Initialize the varable symbol tables and import the environment + */ + + #ifdef mkinit ++INCLUDE <unistd.h> ++INCLUDE "cd.h" ++INCLUDE "output.h" + INCLUDE "var.h" + MKINIT char **environ; + INIT { + char **envp; ++ static char ppid[32 + 5] = "PPID="; + + initvar(); + for (envp = environ ; *envp ; envp++) { +@@ -152,41 +133,37 @@ + setvareq(*envp, VEXPORT|VTEXTFIXED); + } + } ++ ++ fmtstr(ppid + 5, sizeof(ppid) - 5, "%ld", (long) getppid()); ++ setvareq(ppid, VTEXTFIXED); ++ setpwd(0, 0); + } + #endif + + + /* + * This routine initializes the builtin variables. It is called when the +- * shell is initialized and again when a shell procedure is spawned. ++ * shell is initialized. + */ + + void + initvar() { +- const struct varinit *ip; + struct var *vp; ++ struct var *end; + struct var **vpp; + +- for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { +- if ((vp->flags & VEXPORT) == 0) { +- vpp = hashvar(ip->text); ++ vp = varinit; ++ end = vp + sizeof(varinit) / sizeof(varinit[0]); ++ do { ++ vpp = hashvar(vp->text); + vp->next = *vpp; + *vpp = vp; +- vp->text = strdup(ip->text); +- vp->flags = ip->flags; +- vp->func = ip->func; +- } +- } ++ } while (++vp < end); + /* + * PS1 depends on uid + */ +- if ((vps1.flags & VEXPORT) == 0) { +- vpp = hashvar("PS1="); +- vps1.next = *vpp; +- *vpp = &vps1; +- vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# "); +- vps1.flags = VSTRFIXED|VTEXTFIXED; +- } ++ if (!geteuid()) ++ vps1.text = "PS1=# "; + } + + /* +@@ -198,20 +175,21 @@ + const char *name, *val; + int flags; + { +- struct jmploc jmploc; ++ int err; ++ volatile int saveint; + struct jmploc *volatile savehandler = handler; +- int err = 0; +-#ifdef __GNUC__ +- (void) &err; +-#endif ++ struct jmploc jmploc; + ++ SAVEINT(saveint); + if (setjmp(jmploc.loc)) + err = 1; + else { + handler = &jmploc; + setvar(name, val, flags); ++ err = 0; + } + handler = savehandler; ++ RESTOREINT(saveint); + return err; + } + +@@ -225,45 +203,31 @@ + const char *name, *val; + int flags; + { +- const char *p; +- const char *q; +- char *d; +- int len; +- int namelen; ++ char *p, *q; ++ size_t namelen; + char *nameeq; +- int isbad; ++ size_t vallen; + +- isbad = 0; +- p = name; +- if (! is_name(*p)) +- isbad = 1; +- p++; +- for (;;) { +- if (! is_in_name(*p)) { +- if (*p == '\0' || *p == '=') +- break; +- isbad = 1; +- } +- p++; +- } ++ q = endofname(name); ++ p = strchrnul(q, '='); + namelen = p - name; +- if (isbad) ++ if (!namelen || p != q) + error("%.*s: bad variable name", namelen, name); +- len = namelen + 2; /* 2 is space for '=' and '\0' */ ++ vallen = 0; + if (val == NULL) { + flags |= VUNSET; + } else { +- len += strlen(val); ++ vallen = strlen(val); + } +- d = nameeq = ckmalloc(len); +- q = name; +- while (--namelen >= 0) +- *d++ = *q++; +- *d++ = '='; +- *d = '\0'; +- if (val) +- scopy(val, d); ++ INTOFF; ++ p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen); ++ *p++ = '='; ++ if (vallen) { ++ p = mempcpy(p, val, vallen); ++ } ++ *p = '\0'; + setvareq(nameeq, flags); ++ INTON; + } + + +@@ -282,16 +246,15 @@ + { + struct var *vp, **vpp; + +- if (aflag) +- flags |= VEXPORT; + vpp = hashvar(s); +- for (vp = *vpp ; vp ; vp = vp->next) { +- if (varequal(s, vp->text)) { ++ flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); ++ vp = *findvar(vpp, s); ++ INTOFF; ++ if (vp) { + if (vp->flags & VREADONLY) { + size_t len = strchr(s, '=') - s; + error("%.*s: is read only", len, s); + } +- INTOFF; + + if (vp->func && (flags & VNOFUNC) == 0) + (*vp->func)(strchr(s, '=') + 1); +@@ -299,27 +262,17 @@ + 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); +- INTON; +- return; +- } +- } ++ flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VUNSET); ++ } else { + /* not found */ + vp = ckmalloc(sizeof (*vp)); +- vp->flags = flags; +- vp->text = s; + vp->next = *vpp; + vp->func = NULL; + *vpp = vp; ++ } ++ vp->text = s; ++ vp->flags = flags; ++ INTON; + } + + +@@ -329,14 +282,13 @@ + */ + + void +-listsetvar(list) +- 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; + } +@@ -353,45 +305,29 @@ + { + struct var *v; + +- for (v = *hashvar(name) ; v ; v = v->next) { +- if (varequal(v->text, name)) { +- if (v->flags & VUNSET) +- return NULL; ++ if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) { + return strchr(v->text, '=') + 1; + } +- } + return NULL; + } + + + + /* +- * Search the environment of a builtin command. If the second argument +- * is nonzero, return the value of a variable even if it hasn't been +- * exported. ++ * Search the environment of a builtin command. + */ + + char * +-bltinlookup(name, doall) ++bltinlookup(name) + const char *name; +- int doall; + { + struct strlist *sp; +- struct var *v; + + for (sp = cmdenviron ; sp ; sp = sp->next) { + if (varequal(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; ++ return lookupvar(name); + } + + +@@ -403,66 +339,28 @@ + + char ** + environment() { +- int nenv; + struct var **vpp; + struct var *vp; +- char **env; + char **ep; ++ void *epend; + +- nenv = 0; +- for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { +- for (vp = *vpp ; vp ; vp = vp->next) +- if (vp->flags & VEXPORT) +- nenv++; +- } +- ep = env = stalloc((nenv + 1) * sizeof *env); +- for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { ++ STARTSTACKSTR(ep); ++ epend = sstrend; ++ vpp = vartab; ++ do { + for (vp = *vpp ; vp ; vp = vp->next) +- if (vp->flags & VEXPORT) +- *ep++ = vp->text; +- } +- *ep = NULL; +- return env; +-} +- +- +-/* +- * Called when a shell procedure is invoked to clear out nonexported +- * variables. It is also necessary to reallocate variables of with +- * VSTACK set since these are currently allocated on the stack. +- */ +- +-#ifdef mkinit +-void shprocvar __P((void)); +- +-SHELLPROC { +- shprocvar(); +-} +-#endif +- +-void +-shprocvar() { +- struct var **vpp; +- struct var *vp, **prev; +- +- for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { +- for (prev = vpp ; (vp = *prev) != NULL ; ) { +- if ((vp->flags & VEXPORT) == 0) { +- *prev = vp->next; +- if ((vp->flags & VTEXTFIXED) == 0) +- ckfree(vp->text); +- if ((vp->flags & VSTRFIXED) == 0) +- ckfree(vp); +- } else { +- if (vp->flags & VSTACK) { +- vp->text = savestr(vp->text); +- vp->flags &=~ VSTACK; +- } +- prev = &vp->next; +- } ++ if (vp->flags & VEXPORT && !(vp->flags & VUNSET)) { ++ if (ep == epend) { ++ ep = growstackstr(); ++ epend = sstrend; + } ++ *ep++ = (char *) vp->text; + } +- initvar(); ++ } while (++vpp < vartab + VTABSIZE); ++ if (ep == epend) ++ ep = growstackstr(); ++ *ep++ = NULL; ++ return grabstackstr(ep); + } + + +@@ -478,15 +376,7 @@ + int argc; + char **argv; + { +- struct var **vpp; +- struct var *vp; +- +- for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { +- for (vp = *vpp ; vp ; vp = vp->next) { +- if ((vp->flags & VUNSET) == 0) +- out1fmt("%s\n", vp->text); +- } +- } ++ showvars(nullstr, VUNSET, VUNSET); + return 0; + } + +@@ -501,45 +391,28 @@ + int argc; + char **argv; + { +- struct var **vpp; + struct var *vp; + char *name; + const char *p; ++ char **aptr; + int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; +- int pflag; ++ int notp; + +- listsetvar(cmdenviron); +- pflag = (nextopt("p") == 'p'); +- if (argc > 1 && !pflag) { +- while ((name = *argptr++) != NULL) { ++ notp = nextopt("p") - 'p'; ++ if (notp && ((name = *(aptr = argptr)))) { ++ do { + if ((p = strchr(name, '=')) != NULL) { + p++; + } else { +- vpp = hashvar(name); +- for (vp = *vpp ; vp ; vp = vp->next) { +- if (varequal(vp->text, name)) { ++ if ((vp = *findvar(hashvar(name), name))) { + vp->flags |= flag; +- goto found; +- } ++ continue; + } + } + setvar(name, p, flag); +-found:; +- } +- } else { +- for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { +- for (vp = *vpp ; vp ; vp = vp->next) { +- if ((vp->flags & flag) == 0) +- continue; +- if (pflag) { +- out1fmt("%s %s\n", argv[0], vp->text); ++ } while ((name = *++aptr) != NULL); + } else { +- for (p = vp->text ; *p != '=' ; p++) +- out1c(*p); +- out1c('\n'); +- } +- } +- } ++ showvars(argv[0], flag, 0); + } + return 0; + } +@@ -589,7 +462,7 @@ + vp = NULL; + } else { + vpp = hashvar(name); +- for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next); ++ vp = *findvar(vpp, name); + if (vp == NULL) { + if (strchr(name, '=')) + setvareq(savestr(name), VSTRFIXED); +@@ -684,7 +557,7 @@ + + for (ap = argptr; *ap ; ap++) { + if (flg_func) +- ret |= unsetfunc(*ap); ++ unsetfunc(*ap); + if (flg_var) + ret |= unsetvar(*ap); + } +@@ -703,9 +576,9 @@ + struct var **vpp; + struct var *vp; + +- vpp = hashvar(s); +- for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { +- if (varequal(vp->text, s)) { ++ vpp = findvar(hashvar(s), s); ++ vp = *vpp; ++ if (vp) { + if (vp->flags & VREADONLY) + return (1); + INTOFF; +@@ -722,9 +595,8 @@ + INTON; + return (0); + } +- } + +- return (1); ++ return (0); + } + + +@@ -753,7 +625,7 @@ + * either '=' or '\0'. + */ + +-STATIC int ++int + varequal(p, q) + const char *p, *q; + { +@@ -765,3 +637,44 @@ + return 1; + return 0; + } ++ ++STATIC void ++showvars(const char *prefix, int mask, int xor) ++{ ++ struct var **vpp; ++ struct var *vp; ++ const char *sep = *prefix ? spcstr : prefix; ++ ++ vpp = vartab; ++ do { ++ for (vp = *vpp ; vp ; vp = vp->next) { ++ if ((vp->flags & mask) ^ xor) { ++ const char *p; ++ const char *q; ++ int len; ++ ++ p = strchr(vp->text, '='); ++ q = nullstr; ++ if (!(vp->flags & VUNSET)) ++ q = single_quote(++p); ++ len = p - vp->text; ++ ++ out1fmt( ++ "%s%s%.*s%s\n", prefix, sep, len, ++ vp->text, q ++ ); ++ } ++ } ++ } while (++vpp < vartab + VTABSIZE); ++} ++ ++STATIC struct var ** ++findvar(struct var **vpp, const char *name) ++{ ++ for (; *vpp; vpp = &(*vpp)->next) { ++ if (varequal((*vpp)->text, name)) { ++ break; ++ } ++ } ++ return vpp; ++} +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/var.h bin_NetBSD-1.6release/src/bin/sh/var.h +--- bin_NetBSD-1.6release.orig/src/bin/sh/var.h 2000-05-23 11:03:19.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/var.h 2003-02-08 14:35:42.000000000 +0000 +@@ -55,7 +55,7 @@ + struct var { + struct var *next; /* next entry in hash list */ + int flags; /* flags are defined above */ +- char *text; /* name=value */ ++ const char *text; /* name=value */ + void (*func) __P((const char *)); + /* function to be called when */ + /* the variable gets set/unset */ +@@ -66,26 +66,38 @@ + struct localvar *next; /* next local variable in list */ + struct var *vp; /* the variable that was made local */ + int flags; /* saved flags */ +- char *text; /* saved text */ ++ const char *text; /* saved text */ + }; + + +-struct localvar *localvars; ++extern struct localvar *localvars; ++extern struct var varinit[]; + + #if ATTY +-extern struct var vatty; ++#define vatty varinit[0] ++#define vifs varinit[1] ++#else ++#define vifs varinit[0] + #endif +-extern struct var vifs; +-extern struct var vmail; +-extern struct var vmpath; +-extern struct var vpath; +-extern struct var vps1; +-extern struct var vps2; ++#define vmail (&vifs)[1] ++#define vmpath (&vmail)[1] ++#define vpath (&vmpath)[1] ++#define vps1 (&vpath)[1] ++#define vps2 (&vps1)[1] ++#define voptind (&vps2)[1] + #ifndef SMALL +-extern struct var vterm; +-extern struct var vtermcap; +-extern struct var vhistsize; ++#define vterm (&voptind)[1] ++#define vhistsize (&vterm)[1] ++#endif ++ ++#ifdef IFS_BROKEN ++extern const char defifsvar[]; ++#define defifs (defifsvar + 4) ++#else ++extern const char defifs[]; + #endif ++extern const char defpathvar[]; ++#define defpath (defpathvar + 5) + + /* + * The following macros access the values of the above variables. +@@ -115,11 +127,10 @@ + void setvar __P((const char *, const char *, int)); + void setvareq __P((char *, int)); + struct strlist; +-void listsetvar __P((struct strlist *)); ++void listsetvar __P((struct strlist *, int)); + char *lookupvar __P((const char *)); +-char *bltinlookup __P((const char *, int)); ++char *bltinlookup __P((const char *)); + char **environment __P((void)); +-void shprocvar __P((void)); + int showvarscmd __P((int, char **)); + int exportcmd __P((int, char **)); + int localcmd __P((int, char **)); +@@ -129,3 +140,4 @@ + int unsetcmd __P((int, char **)); + int unsetvar __P((const char *)); + int setvarsafe __P((const char *, const char *, int)); ++int varequal __P((const char *, const char *)); +diff --minimal -ruPb bin_NetBSD-1.6release.orig/src/bin/sh/yaccfe.sh bin_NetBSD-1.6release/src/bin/sh/yaccfe.sh +--- bin_NetBSD-1.6release.orig/src/bin/sh/yaccfe.sh 1970-01-01 01:00:00.000000000 +0100 ++++ bin_NetBSD-1.6release/src/bin/sh/yaccfe.sh 2003-02-08 14:35:42.000000000 +0000 +@@ -0,0 +1,29 @@ ++#!/bin/sh ++# ++# Quick script to reformat yacc commands ++# so byacc isnt required. ++# ++# Expects: ++# yacc -d -o yourfile.c yourfile.y ++# Executes: ++# yacc -d -b yourfile yourfile.y ++# mv yourfile.tab.c yourfile.c ++# mv yourfile.tab.h yourfile.h ++# ++ ++yaccbin="/usr/bin/yacc" ++yaccflags="-d" ++ ++[ ! ${#} -gt 0 ] && exit 1 ++while getopts ":o:" opt ++do ++ case $opt in ++ o) output=${OPTARG%*.c} ;; ++ ?) ;; ++ esac ++done ++${yaccbin} ${yaccflags} -b ${output} ${output}.y || exit 1 ++for files in ${output}.tab.{c,h} ++do ++ mv ${files} $(sed 's/.tab//' <<< ${files}) || exit 1 ++done diff --git a/app-shells/ash/files/digest-ash-1.6 b/app-shells/ash/files/digest-ash-1.6 new file mode 100644 index 000000000000..5eb33abde8d6 --- /dev/null +++ b/app-shells/ash/files/digest-ash-1.6 @@ -0,0 +1 @@ +MD5 7e8fbb3654eeb6b57c1ec384c2d1b156 bin.tar.gz 850570 |