Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 8043 Details for
Bug 15319
new ebuild: NetBSD's ash shell
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
uncludes some enahancements from debian, and a quick script to avoid byacc requirement.
dash-ash-hetio-yacc.diff (text/plain), 406.52 KB, created by
Tavis Ormandy (RETIRED)
on 2003-02-08 13:38:00 UTC
(
hide
)
Description:
uncludes some enahancements from debian, and a quick script to avoid byacc requirement.
Filename:
MIME Type:
Creator:
Tavis Ormandy (RETIRED)
Created:
2003-02-08 13:38:00 UTC
Size:
406.52 KB
patch
obsolete
>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: arith_yylex.c,v 1.3 2002/10/26 11:37:45 herbert 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: times.c,v 1.6 2001/12/12 20:35:08 herbert 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: ash.postinst,v 1.9 2002/10/26 11:27:48 herbert 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: copyright,v 1.6 2003/01/01 01:51:50 herbert 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.config,v 1.1 2002/09/14 06:17:50 herbert 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.postinst,v 1.3 2002/10/26 11:26:55 herbert 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.prerm,v 1.1 2002/09/14 06:17:50 herbert 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: rules,v 1.38 2002/12/16 08:07:10 herbert 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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 15319
:
8042
| 8043