[Midnightbsd-cvs] src [10240] trunk/bin/sh: sync with freebsd 10 stable

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sat Jun 2 17:06:59 EDT 2018


Revision: 10240
          http://svnweb.midnightbsd.org/src/?rev=10240
Author:   laffer1
Date:     2018-06-02 17:06:59 -0400 (Sat, 02 Jun 2018)
Log Message:
-----------
 sync with freebsd 10 stable

Modified Paths:
--------------
    trunk/bin/sh/Makefile
    trunk/bin/sh/TOUR
    trunk/bin/sh/alias.c
    trunk/bin/sh/alias.h
    trunk/bin/sh/arith.h
    trunk/bin/sh/arith_yacc.c
    trunk/bin/sh/arith_yacc.h
    trunk/bin/sh/arith_yylex.c
    trunk/bin/sh/builtins.def
    trunk/bin/sh/cd.c
    trunk/bin/sh/cd.h
    trunk/bin/sh/error.c
    trunk/bin/sh/error.h
    trunk/bin/sh/eval.c
    trunk/bin/sh/eval.h
    trunk/bin/sh/exec.c
    trunk/bin/sh/exec.h
    trunk/bin/sh/expand.c
    trunk/bin/sh/expand.h
    trunk/bin/sh/funcs/cmv
    trunk/bin/sh/funcs/dirs
    trunk/bin/sh/funcs/login
    trunk/bin/sh/funcs/newgrp
    trunk/bin/sh/funcs/popd
    trunk/bin/sh/funcs/pushd
    trunk/bin/sh/funcs/suspend
    trunk/bin/sh/histedit.c
    trunk/bin/sh/input.c
    trunk/bin/sh/input.h
    trunk/bin/sh/jobs.c
    trunk/bin/sh/jobs.h
    trunk/bin/sh/mail.c
    trunk/bin/sh/mail.h
    trunk/bin/sh/main.c
    trunk/bin/sh/main.h
    trunk/bin/sh/memalloc.c
    trunk/bin/sh/memalloc.h
    trunk/bin/sh/miscbltin.c
    trunk/bin/sh/mkbuiltins
    trunk/bin/sh/mknodes.c
    trunk/bin/sh/mksyntax.c
    trunk/bin/sh/mktokens
    trunk/bin/sh/myhistedit.h
    trunk/bin/sh/mystring.c
    trunk/bin/sh/mystring.h
    trunk/bin/sh/nodes.c.pat
    trunk/bin/sh/nodetypes
    trunk/bin/sh/options.c
    trunk/bin/sh/options.h
    trunk/bin/sh/output.c
    trunk/bin/sh/output.h
    trunk/bin/sh/parser.c
    trunk/bin/sh/parser.h
    trunk/bin/sh/redir.c
    trunk/bin/sh/redir.h
    trunk/bin/sh/sh.1
    trunk/bin/sh/shell.h
    trunk/bin/sh/show.c
    trunk/bin/sh/show.h
    trunk/bin/sh/trap.c
    trunk/bin/sh/trap.h
    trunk/bin/sh/var.c
    trunk/bin/sh/var.h

Property Changed:
----------------
    trunk/bin/sh/TOUR
    trunk/bin/sh/builtins.def
    trunk/bin/sh/funcs/cmv
    trunk/bin/sh/funcs/dirs
    trunk/bin/sh/funcs/login
    trunk/bin/sh/funcs/newgrp
    trunk/bin/sh/funcs/popd
    trunk/bin/sh/funcs/pushd
    trunk/bin/sh/funcs/suspend
    trunk/bin/sh/mkbuiltins
    trunk/bin/sh/mktokens
    trunk/bin/sh/nodes.c.pat
    trunk/bin/sh/nodetypes
    trunk/bin/sh/sh.1

Modified: trunk/bin/sh/Makefile
===================================================================
--- trunk/bin/sh/Makefile	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/Makefile	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,6 +1,9 @@
+# $MidnightBSD$
 #	@(#)Makefile	8.4 (Berkeley) 5/5/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/Makefile 262951 2014-03-09 17:04:31Z jmmv $
 
+.include <bsd.own.mk>
+
 PROG=	sh
 INSTALLFLAGS= -S
 SHSRCS=	alias.c arith_yacc.c arith_yylex.c cd.c echo.c error.c eval.c \
@@ -8,7 +11,7 @@
 	histedit.c input.c jobs.c kill.c mail.c main.c memalloc.c miscbltin.c \
 	mystring.c options.c output.c parser.c printf.c redir.c show.c \
 	test.c trap.c var.c
-GENSRCS= builtins.c init.c nodes.c syntax.c
+GENSRCS= builtins.c nodes.c syntax.c
 GENHDRS= builtins.h nodes.h syntax.h token.h
 SRCS= ${SHSRCS} ${GENSRCS} ${GENHDRS}
 
@@ -30,26 +33,21 @@
 	${.CURDIR}/../test \
 	${.CURDIR}/../../usr.bin/printf
 
-CLEANFILES+= mkinit mkinit.o mknodes mknodes.o \
+CLEANFILES+= mknodes mknodes.o \
 	mksyntax mksyntax.o
 CLEANFILES+= ${GENSRCS} ${GENHDRS}
 
-build-tools: mkinit mknodes mksyntax
+build-tools: mknodes mksyntax
 
 .ORDER: builtins.c builtins.h
 builtins.c builtins.h: mkbuiltins builtins.def
-	cd ${.CURDIR}; sh mkbuiltins ${.OBJDIR}
+	sh ${.CURDIR}/mkbuiltins ${.CURDIR}
 
-init.c: mkinit alias.c eval.c exec.c input.c jobs.c options.c parser.c \
-	redir.c trap.c var.c
-	./mkinit ${.ALLSRC:S/^mkinit$//}
-
 # XXX this is just to stop the default .c rule being used, so that the
 # intermediate object has a fixed name.
 # XXX we have a default .c rule, but no default .o rule.
 .o:
 	${CC} ${CFLAGS} ${LDFLAGS} ${.IMPSRC} ${LDLIBS} -o ${.TARGET}
-mkinit: mkinit.o
 mknodes: mknodes.o
 mksyntax: mksyntax.o
 
@@ -64,7 +62,8 @@
 token.h: mktokens
 	sh ${.CURDIR}/mktokens
 
-regress:
-	cd ${.CURDIR}/../../tools/regression/bin/sh && ${MAKE} SH=${.OBJDIR}/sh
+.if ${MK_TESTS} != "no"
+SUBDIR+=    tests
+.endif
 
 .include <bsd.prog.mk>

Modified: trunk/bin/sh/TOUR
===================================================================
--- trunk/bin/sh/TOUR	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/TOUR	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,5 +1,5 @@
 #	@(#)TOUR	8.1 (Berkeley) 5/31/93
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/TOUR 253650 2013-07-25 15:08:41Z jilles $
 
 NOTE -- This is the original TOUR paper distributed with ash and
 does not represent the current state of the shell.  It is provided anyway
@@ -25,43 +25,12 @@
         program         input files         generates
         -------         -----------         ---------
         mkbuiltins      builtins            builtins.h builtins.c
-        mkinit          *.c                 init.c
         mknodes         nodetypes           nodes.h nodes.c
         mksyntax            -               syntax.h syntax.c
         mktokens            -               token.h
 
-There are undoubtedly too many of these.  Mkinit searches all the
-C source files for entries looking like:
+There are undoubtedly too many of these.
 
-        INIT {
-              x = 1;    /* executed during initialization */
-        }
-
-        RESET {
-              x = 2;    /* executed when the shell does a longjmp
-                           back to the main command loop */
-        }
-
-It pulls this code out into routines which are when particular
-events occur.  The intent is to improve modularity by isolating
-the information about which modules need to be explicitly
-initialized/reset within the modules themselves.
-
-Mkinit recognizes several constructs for placing declarations in
-the init.c file.
-        INCLUDE "file.h"
-includes a file.  The storage class MKINIT makes a declaration
-available in the init.c file, for example:
-        MKINIT int funcnest;    /* depth of function calls */
-MKINIT alone on a line introduces a structure or union declara-
-tion:
-        MKINIT
-        struct redirtab {
-              short renamed[10];
-        };
-Preprocessor #define statements are copied to init.c without any
-special action to request this.
-
 EXCEPTIONS:  Code for dealing with exceptions appears in
 exceptions.c.  The C language doesn't include exception handling,
 so I implement it using setjmp and longjmp.  The global variable


Property changes on: trunk/bin/sh/TOUR
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/alias.c
===================================================================
--- trunk/bin/sh/alias.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/alias.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/alias.c 286813 2015-08-15 19:58:00Z jilles $");
 
 #include <stdlib.h>
 #include "shell.h"
@@ -68,18 +69,7 @@
 		if (equal(name, ap->name)) {
 			INTOFF;
 			ckfree(ap->val);
-			/* See HACK below. */
-#ifdef notyet
 			ap->val	= savestr(val);
-#else
-			{
-			size_t len = strlen(val);
-			ap->val = ckmalloc(len + 2);
-			memcpy(ap->val, val, len);
-			ap->val[len] = ' ';
-			ap->val[len+1] = '\0';
-			}
-#endif
 			INTON;
 			return;
 		}
@@ -88,34 +78,7 @@
 	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 marks 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 */
-	{
-	size_t len = strlen(val);
-	ap->val = ckmalloc(len + 2);
-	memcpy(ap->val, val, len);
-	ap->val[len] = ' ';	/* fluff */
-	ap->val[len+1] = '\0';
-	}
-#endif
 	ap->flag = 0;
 	ap->next = *app;
 	*app = ap;
@@ -207,14 +170,8 @@
 static void
 printalias(const struct alias *a)
 {
-	char *p;
-
 	out1fmt("%s=", a->name);
-	/* Don't print the space added above. */
-	p = a->val + strlen(a->val) - 1;
-	*p = '\0';
 	out1qstr(a->val);
-	*p = ' ';
 	out1c('\n');
 }
 
@@ -224,6 +181,7 @@
 	int i, j;
 	struct alias **sorted, *ap;
 
+	INTOFF;
 	sorted = ckmalloc(aliases * sizeof(*sorted));
 	j = 0;
 	for (i = 0; i < ATABSIZE; i++)
@@ -231,23 +189,29 @@
 			if (*ap->name != '\0')
 				sorted[j++] = ap;
 	qsort(sorted, aliases, sizeof(*sorted), comparealiases);
-	for (i = 0; i < aliases; i++)
+	for (i = 0; i < aliases; i++) {
 		printalias(sorted[i]);
+		if (int_pending())
+			break;
+	}
 	ckfree(sorted);
+	INTON;
 }
 
 int
-aliascmd(int argc, char **argv)
+aliascmd(int argc __unused, char **argv __unused)
 {
 	char *n, *v;
 	int ret = 0;
 	struct alias *ap;
 
-	if (argc == 1) {
+	nextopt("");
+
+	if (*argptr == NULL) {
 		printaliases();
 		return (0);
 	}
-	while ((n = *++argv) != NULL) {
+	while ((n = *argptr++) != NULL) {
 		if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
 			if ((ap = lookupalias(n, 0)) == NULL) {
 				warning("%s: not found", n);
@@ -285,7 +249,7 @@
 {
 	unsigned int hashval;
 
-	hashval = *p << 4;
+	hashval = (unsigned char)*p << 4;
 	while (*p)
 		hashval+= *p++;
 	return &atab[hashval % ATABSIZE];

Modified: trunk/bin/sh/alias.h
===================================================================
--- trunk/bin/sh/alias.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/alias.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)alias.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/alias.h 223060 2011-06-13 21:03:27Z jilles $
  */
 
 #define ALIASINUSE	1

Modified: trunk/bin/sh/arith.h
===================================================================
--- trunk/bin/sh/arith.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/arith.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1995
  *      The Regents of the University of California.  All rights reserved.
@@ -27,7 +28,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)arith.h	1.1 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/arith.h 223060 2011-06-13 21:03:27Z jilles $
  */
 
 #include "shell.h"

Modified: trunk/bin/sh/arith_yacc.c
===================================================================
--- trunk/bin/sh/arith_yacc.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/arith_yacc.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -33,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/arith_yacc.c 230530 2012-01-25 08:42:19Z charnier $");
 
 #include <limits.h>
 #include <errno.h>
@@ -84,6 +85,8 @@
 
 #define ARITH_MAX_PREC 8
 
+int letcmd(int, char **);
+
 static __dead2 void yyerror(const char *s)
 {
 	error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
@@ -131,11 +134,11 @@
 			yyerror("divide error");
 		return op == ARITH_REM ? a % b : a / b;
 	case ARITH_MUL:
-		return a * b;
+		return (uintmax_t)a * (uintmax_t)b;
 	case ARITH_ADD:
-		return a + b;
+		return (uintmax_t)a + (uintmax_t)b;
 	case ARITH_SUB:
-		return a - b;
+		return (uintmax_t)a - (uintmax_t)b;
 	case ARITH_LSHIFT:
 		return a << b;
 	case ARITH_RSHIFT:
@@ -377,4 +380,3 @@
 	out1fmt(ARITH_FORMAT_STR "\n", i);
 	return !i;
 }
-

Modified: trunk/bin/sh/arith_yacc.h
===================================================================
--- trunk/bin/sh/arith_yacc.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/arith_yacc.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -31,7 +32,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/arith_yacc.h 218466 2011-02-08 23:18:06Z jilles $
  */
 
 #define ARITH_ASS 1

Modified: trunk/bin/sh/arith_yylex.c
===================================================================
--- trunk/bin/sh/arith_yylex.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/arith_yylex.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2002
  *	Herbert Xu.
@@ -33,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/arith_yylex.c 254806 2013-08-24 20:06:00Z jilles $");
 
 #include <inttypes.h>
 #include <stdlib.h>
@@ -53,7 +54,7 @@
 extern const char *arith_buf;
 
 int
-yylex()
+yylex(void)
 {
 	int value;
 	const char *buf = arith_buf;
@@ -218,9 +219,13 @@
 			value += ARITH_REM - '%';
 			goto checkeq;
 		case '+':
+			if (buf[1] == '+')
+				return ARITH_BAD;
 			value += ARITH_ADD - '+';
 			goto checkeq;
 		case '-':
+			if (buf[1] == '-')
+				return ARITH_BAD;
 			value += ARITH_SUB - '-';
 			goto checkeq;
 		case '~':

Modified: trunk/bin/sh/builtins.def
===================================================================
--- trunk/bin/sh/builtins.def	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/builtins.def	2018-06-02 21:06:59 UTC (rev 10240)
@@ -32,7 +32,7 @@
 # SUCH DAMAGE.
 #
 #	@(#)builtins.def	8.4 (Berkeley) 5/4/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/builtins.def 289938 2015-10-25 17:17:50Z jilles $
 
 #
 # This file lists all the builtin commands.  The first column is the name
@@ -65,6 +65,7 @@
 #exprcmd		expr
 falsecmd	false
 fgcmd -j	fg
+freebsd_wordexpcmd	freebsd_wordexp
 getoptscmd	getopts
 hashcmd		hash
 histcmd -h	fc


Property changes on: trunk/bin/sh/builtins.def
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/cd.c
===================================================================
--- trunk/bin/sh/cd.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/cd.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/cd.c 297749 2016-04-09 14:09:14Z jilles $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -79,7 +80,7 @@
 static char *cdcomppath;
 
 int
-cdcmd(int argc, char **argv)
+cdcmd(int argc __unused, char **argv __unused)
 {
 	const char *dest;
 	const char *path;
@@ -89,9 +90,8 @@
 	int rc;
 	int errno1 = ENOENT;
 
-	optreset = 1; optind = 1; opterr = 0; /* initialize getopt */
 	phys = Pflag;
-	while ((ch = getopt(argc, argv, "eLP")) != -1) {
+	while ((ch = nextopt("eLP")) != '\0') {
 		switch (ch) {
 		case 'e':
 			getcwderr = 1;
@@ -102,18 +102,13 @@
 		case 'P':
 			phys = 1;
 			break;
-		default:
-			error("unknown option: -%c", optopt);
-			break;
 		}
 	}
-	argc -= optind;
-	argv += optind;
 
-	if (argc > 1)
+	if (*argptr != NULL && argptr[1] != NULL)
 		error("too many arguments");
 
-	if ((dest = *argv) == NULL && (dest = bltinlookup("HOME", 1)) == NULL)
+	if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME", 1)) == NULL)
 		error("HOME not set");
 	if (*dest == '\0')
 		dest = ".";
@@ -195,8 +190,7 @@
 	 *  next time we get the value of the current directory.
 	 */
 	badstat = 0;
-	cdcomppath = stalloc(strlen(dest) + 1);
-	scopy(dest, cdcomppath);
+	cdcomppath = stsavestr(dest);
 	STARTSTACKSTR(p);
 	if (*dest == '/') {
 		STPUTC('/', p);
@@ -289,8 +283,7 @@
 	 */
 	if (dir == NULL || curdir == NULL)
 		return getpwd2();
-	cdcomppath = stalloc(strlen(dir) + 1);
-	scopy(dir, cdcomppath);
+	cdcomppath = stsavestr(dir);
 	STARTSTACKSTR(new);
 	if (*dir != '/') {
 		STPUTS(curdir, new);
@@ -330,14 +323,13 @@
 }
 
 int
-pwdcmd(int argc, char **argv)
+pwdcmd(int argc __unused, char **argv __unused)
 {
 	char *p;
 	int ch, phys;
 
-	optreset = 1; optind = 1; opterr = 0; /* initialize getopt */
 	phys = Pflag;
-	while ((ch = getopt(argc, argv, "LP")) != -1) {
+	while ((ch = nextopt("LP")) != '\0') {
 		switch (ch) {
 		case 'L':
 			phys = 0;
@@ -345,15 +337,10 @@
 		case 'P':
 			phys = 1;
 			break;
-		default:
-			error("unknown option: -%c", optopt);
-			break;
 		}
 	}
-	argc -= optind;
-	argv += optind;
 
-	if (argc != 0)
+	if (*argptr != NULL)
 		error("too many arguments");
 
 	if (!phys && getpwd()) {

Modified: trunk/bin/sh/cd.h
===================================================================
--- trunk/bin/sh/cd.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/cd.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1995
  *	The Regents of the University of California.  All rights reserved.
@@ -26,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/cd.h 223060 2011-06-13 21:03:27Z jilles $
  */
 
 void	 pwd_init(int);

Modified: trunk/bin/sh/error.c
===================================================================
--- trunk/bin/sh/error.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/error.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/error.c 216622 2010-12-21 20:47:06Z jilles $");
 
 /*
  * Errors and exceptions.

Modified: trunk/bin/sh/error.h
===================================================================
--- trunk/bin/sh/error.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/error.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)error.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/error.h 220978 2011-04-23 22:28:56Z jilles $
  */
 
 /*

Modified: trunk/bin/sh/eval.c
===================================================================
--- trunk/bin/sh/eval.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/eval.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/eval.c 287750 2015-09-13 13:43:08Z jilles $");
 
 #include <paths.h>
 #include <signal.h>
@@ -76,7 +77,7 @@
 
 int evalskip;			/* set if we are skipping commands */
 int skipcount;			/* number of levels to skip */
-MKINIT int loopnest;		/* current loop nesting level */
+static int loopnest;		/* current loop nesting level */
 int funcnest;			/* depth of function calls */
 static int builtin_flags;	/* evalcommand flags for builtins */
 
@@ -89,9 +90,10 @@
 
 static void evalloop(union node *, int);
 static void evalfor(union node *, int);
-static void evalcase(union node *, int);
+static union node *evalcase(union node *);
 static void evalsubshell(union node *, int);
 static void evalredir(union node *, int);
+static void exphere(union node *, struct arglist *);
 static void expredir(union node *);
 static void evalpipe(union node *);
 static int is_valid_fast_cmdsubst(union node *n);
@@ -103,18 +105,14 @@
  * Called to reset things after an exception.
  */
 
-#ifdef mkinit
-INCLUDE "eval.h"
-
-RESET {
+void
+reseteval(void)
+{
 	evalskip = 0;
 	loopnest = 0;
-	funcnest = 0;
 }
-#endif
 
 
-
 /*
  * The eval command.
  */
@@ -173,6 +171,7 @@
 			any = 1;
 		}
 		popstackmark(&smark);
+		setstackmark(&smark);
 	}
 	popfile();
 	popstackmark(&smark);
@@ -193,7 +192,9 @@
 {
 	int do_etest;
 	union node *next;
+	struct stackmark smark;
 
+	setstackmark(&smark);
 	do_etest = 0;
 	if (n == NULL) {
 		TRACE(("evaltree(NULL) called\n"));
@@ -256,8 +257,19 @@
 			evalfor(n, flags & ~EV_EXIT);
 			break;
 		case NCASE:
-			evalcase(n, flags);
+			next = evalcase(n);
 			break;
+		case NCLIST:
+			next = n->nclist.body;
+			break;
+		case NCLISTFALLTHRU:
+			if (n->nclist.body) {
+				evaltree(n->nclist.body, flags & ~EV_EXIT);
+				if (evalskip)
+					goto out;
+			}
+			next = n->nclist.next;
+			break;
 		case NDEFUN:
 			defun(n->narg.text, n->narg.next);
 			exitstatus = 0;
@@ -264,6 +276,8 @@
 			break;
 		case NNOT:
 			evaltree(n->nnot.com, EV_TESTED);
+			if (evalskip)
+				goto out;
 			exitstatus = !exitstatus;
 			break;
 
@@ -281,9 +295,12 @@
 			break;
 		}
 		n = next;
+		popstackmark(&smark);
+		setstackmark(&smark);
 	} while (n != NULL);
 out:
-	if (pendingsigs)
+	popstackmark(&smark);
+	if (pendingsig)
 		dotrap();
 	if (eflag && exitstatus != 0 && do_etest)
 		exitshell(exitstatus);
@@ -300,15 +317,16 @@
 	loopnest++;
 	status = 0;
 	for (;;) {
-		evaltree(n->nbinary.ch1, EV_TESTED);
+		if (!evalskip)
+			evaltree(n->nbinary.ch1, EV_TESTED);
 		if (evalskip) {
-skipping:	  if (evalskip == SKIPCONT && --skipcount <= 0) {
+			if (evalskip == SKIPCONT && --skipcount <= 0) {
 				evalskip = 0;
 				continue;
 			}
 			if (evalskip == SKIPBREAK && --skipcount <= 0)
 				evalskip = 0;
-			if (evalskip == SKIPFUNC || evalskip == SKIPFILE)
+			if (evalskip == SKIPRETURN)
 				status = exitstatus;
 			break;
 		}
@@ -321,8 +339,6 @@
 		}
 		evaltree(n->nbinary.ch2, flags);
 		status = exitstatus;
-		if (evalskip)
-			goto skipping;
 	}
 	loopnest--;
 	exitstatus = status;
@@ -336,23 +352,21 @@
 	struct arglist arglist;
 	union node *argp;
 	struct strlist *sp;
-	struct stackmark smark;
+	int status;
 
-	setstackmark(&smark);
 	arglist.lastp = &arglist.list;
 	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
 		oexitstatus = exitstatus;
 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
-		if (evalskip)
-			goto out;
 	}
 	*arglist.lastp = NULL;
 
-	exitstatus = 0;
 	loopnest++;
+	status = 0;
 	for (sp = arglist.list ; sp ; sp = sp->next) {
 		setvar(n->nfor.var, sp->text, 0);
 		evaltree(n->nfor.body, flags);
+		status = exitstatus;
 		if (evalskip) {
 			if (evalskip == SKIPCONT && --skipcount <= 0) {
 				evalskip = 0;
@@ -364,45 +378,44 @@
 		}
 	}
 	loopnest--;
-out:
-	popstackmark(&smark);
+	exitstatus = status;
 }
 
 
+/*
+ * Evaluate a case statement, returning the selected tree.
+ *
+ * The exit status needs care to get right.
+ */
 
-static void
-evalcase(union node *n, int flags)
+static union node *
+evalcase(union node *n)
 {
 	union node *cp;
 	union node *patp;
 	struct arglist arglist;
-	struct stackmark smark;
 
-	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 (cp = n->ncase.cases ; cp ; cp = cp->nclist.next) {
 		for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
 			if (casematch(patp, arglist.list->text)) {
 				while (cp->nclist.next &&
-				    cp->type == NCLISTFALLTHRU) {
-					if (evalskip != 0)
-						break;
-					evaltree(cp->nclist.body,
-					    flags & ~EV_EXIT);
+				    cp->type == NCLISTFALLTHRU &&
+				    cp->nclist.body == NULL)
 					cp = cp->nclist.next;
-				}
-				if (evalskip == 0) {
-					evaltree(cp->nclist.body, flags);
-				}
-				goto out;
+				if (cp->nclist.next &&
+				    cp->type == NCLISTFALLTHRU)
+					return (cp);
+				if (cp->nclist.body == NULL)
+					exitstatus = 0;
+				return (cp->nclist.body);
 			}
 		}
 	}
-out:
-	popstackmark(&smark);
+	exitstatus = 0;
+	return (NULL);
 }
 
 
@@ -476,6 +489,37 @@
 }
 
 
+static void
+exphere(union node *redir, struct arglist *fn)
+{
+	struct jmploc jmploc;
+	struct jmploc *savehandler;
+	struct localvar *savelocalvars;
+	int need_longjmp = 0;
+
+	redir->nhere.expdoc = nullstr;
+	savelocalvars = localvars;
+	localvars = NULL;
+	forcelocal++;
+	savehandler = handler;
+	if (setjmp(jmploc.loc))
+		need_longjmp = exception != EXERROR && exception != EXEXEC;
+	else {
+		handler = &jmploc;
+		expandarg(redir->nhere.doc, fn, 0);
+		redir->nhere.expdoc = fn->list->text;
+		INTOFF;
+	}
+	handler = savehandler;
+	forcelocal--;
+	poplocalvars();
+	localvars = savelocalvars;
+	if (need_longjmp)
+		longjmp(handler->loc, 1);
+	INTON;
+}
+
+
 /*
  * Compute the names of the files in a redirection list.
  */
@@ -494,16 +538,19 @@
 		case NFROMTO:
 		case NAPPEND:
 		case NCLOBBER:
-			expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
+			expandarg(redir->nfile.fname, &fn, EXP_TILDE);
 			redir->nfile.expfname = fn.list->text;
 			break;
 		case NFROMFD:
 		case NTOFD:
 			if (redir->ndup.vname) {
-				expandarg(redir->ndup.vname, &fn, EXP_TILDE | EXP_REDIR);
+				expandarg(redir->ndup.vname, &fn, EXP_TILDE);
 				fixredir(redir, fn.list->text, 1);
 			}
 			break;
+		case NXHERE:
+			exphere(redir, &fn);
+			break;
 		}
 	}
 }
@@ -538,7 +585,8 @@
 		pip[1] = -1;
 		if (lp->next) {
 			if (pipe(pip) < 0) {
-				close(prevfd);
+				if (prevfd >= 0)
+					close(prevfd);
 				error("Pipe call failed: %s", strerror(errno));
 			}
 		}
@@ -595,12 +643,11 @@
 {
 	int pip[2];
 	struct job *jp;
-	struct stackmark smark;		/* unnecessary */
+	struct stackmark smark;
 	struct jmploc jmploc;
 	struct jmploc *savehandler;
 	struct localvar *savelocalvars;
 
-	setstackmark(&smark);
 	result->fd = -1;
 	result->buf = NULL;
 	result->nleft = 0;
@@ -607,10 +654,11 @@
 	result->jp = NULL;
 	if (n == NULL) {
 		exitstatus = 0;
-		goto out;
+		return;
 	}
+	setstackmark(&smark);
+	exitstatus = oexitstatus;
 	if (is_valid_fast_cmdsubst(n)) {
-		exitstatus = oexitstatus;
 		savelocalvars = localvars;
 		localvars = NULL;
 		forcelocal++;
@@ -634,7 +682,6 @@
 		poplocalvars();
 		localvars = savelocalvars;
 	} else {
-		exitstatus = 0;
 		if (pipe(pip) < 0)
 			error("Pipe call failed: %s", strerror(errno));
 		jp = makejob(n, 1);
@@ -651,12 +698,96 @@
 		result->fd = pip[0];
 		result->jp = jp;
 	}
-out:
 	popstackmark(&smark);
 	TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
 		result->fd, result->buf, result->nleft, result->jp));
 }
 
+static int
+mustexpandto(const char *argtext, const char *mask)
+{
+	for (;;) {
+		if (*argtext == CTLQUOTEMARK || *argtext == CTLQUOTEEND) {
+			argtext++;
+			continue;
+		}
+		if (*argtext == CTLESC)
+			argtext++;
+		else if (BASESYNTAX[(int)*argtext] == CCTL)
+			return (0);
+		if (*argtext != *mask)
+			return (0);
+		if (*argtext == '\0')
+			return (1);
+		argtext++;
+		mask++;
+	}
+}
+
+static int
+isdeclarationcmd(struct narg *arg)
+{
+	int have_command = 0;
+
+	if (arg == NULL)
+		return (0);
+	while (mustexpandto(arg->text, "command")) {
+		have_command = 1;
+		arg = &arg->next->narg;
+		if (arg == NULL)
+			return (0);
+		/*
+		 * To also allow "command -p" and "command --" as part of
+		 * a declaration command, add code here.
+		 * We do not do this, as ksh does not do it either and it
+		 * is not required by POSIX.
+		 */
+	}
+	return (mustexpandto(arg->text, "export") ||
+	    mustexpandto(arg->text, "readonly") ||
+	    (mustexpandto(arg->text, "local") &&
+		(have_command || !isfunc("local"))));
+}
+
+static void
+xtracecommand(struct arglist *varlist, struct arglist *arglist)
+{
+	struct strlist *sp;
+	char sep = 0;
+	const char *p, *ps4;
+
+	ps4 = expandstr(ps4val());
+	out2str(ps4 != NULL ? ps4 : ps4val());
+	for (sp = varlist->list ; sp ; sp = sp->next) {
+		if (sep != 0)
+			out2c(' ');
+		p = strchr(sp->text, '=');
+		if (p != NULL) {
+			p++;
+			outbin(sp->text, p - sp->text, out2);
+			out2qstr(p);
+		} else
+			out2qstr(sp->text);
+		sep = ' ';
+	}
+	for (sp = arglist->list ; sp ; sp = sp->next) {
+		if (sep != 0)
+			out2c(' ');
+		/* Disambiguate command looking like assignment. */
+		if (sp == arglist->list &&
+				strchr(sp->text, '=') != NULL &&
+				strchr(sp->text, '\'') == NULL) {
+			out2c('\'');
+			out2str(sp->text);
+			out2c('\'');
+		} else
+			out2qstr(sp->text);
+		sep = ' ';
+	}
+	out2c('\n');
+	flushout(&errout);
+}
+
 /*
  * Check if a builtin can safely be executed in the same process,
  * even though it should be in a subshell (command substitution).
@@ -691,7 +822,6 @@
 static void
 evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
 {
-	struct stackmark smark;
 	union node *argp;
 	struct arglist arglist;
 	struct arglist varlist;
@@ -718,7 +848,6 @@
 
 	/* First expand the arguments. */
 	TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
-	setstackmark(&smark);
 	arglist.lastp = &arglist.list;
 	varlist.lastp = &varlist.list;
 	varflag = 1;
@@ -728,11 +857,12 @@
 	exitstatus = 0;
 	for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
 		if (varflag && isassignment(argp->narg.text)) {
-			expandarg(argp, &varlist, EXP_VARTILDE);
+			expandarg(argp, varflag == 1 ? &varlist : &arglist,
+			    EXP_VARTILDE);
 			continue;
-		}
+		} else if (varflag == 1)
+			varflag = isdeclarationcmd(&argp->narg) ? 2 : 0;
 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
-		varflag = 0;
 	}
 	*arglist.lastp = NULL;
 	*varlist.lastp = NULL;
@@ -755,40 +885,8 @@
 	argv -= argc;
 
 	/* Print the command if xflag is set. */
-	if (xflag) {
-		char sep = 0;
-		const char *p, *ps4;
-		ps4 = expandstr(ps4val());
-		out2str(ps4 != NULL ? ps4 : ps4val());
-		for (sp = varlist.list ; sp ; sp = sp->next) {
-			if (sep != 0)
-				out2c(' ');
-			p = strchr(sp->text, '=');
-			if (p != NULL) {
-				p++;
-				outbin(sp->text, p - sp->text, out2);
-				out2qstr(p);
-			} else
-				out2qstr(sp->text);
-			sep = ' ';
-		}
-		for (sp = arglist.list ; sp ; sp = sp->next) {
-			if (sep != 0)
-				out2c(' ');
-			/* Disambiguate command looking like assignment. */
-			if (sp == arglist.list &&
-					strchr(sp->text, '=') != NULL &&
-					strchr(sp->text, '\'') == NULL) {
-				out2c('\'');
-				out2str(sp->text);
-				out2c('\'');
-			} else
-				out2qstr(sp->text);
-			sep = ' ';
-		}
-		out2c('\n');
-		flushout(&errout);
-	}
+	if (xflag)
+		xtracecommand(&varlist, &arglist);
 
 	/* Now locate the command. */
 	if (argc == 0) {
@@ -976,7 +1074,7 @@
 		funcnest--;
 		popredir();
 		INTON;
-		if (evalskip == SKIPFUNC) {
+		if (evalskip == SKIPRETURN) {
 			evalskip = 0;
 			skipcount = 0;
 		}
@@ -1008,6 +1106,7 @@
 		}
 		handler = &jmploc;
 		redirect(cmd->ncmd.redirect, mode);
+		outclearerror(out1);
 		/*
 		 * If there is no command word, redirection errors should
 		 * not be fatal but assignment errors should.
@@ -1023,6 +1122,11 @@
 		builtin_flags = flags;
 		exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
 		flushall();
+		if (outiserror(out1)) {
+			warning("write error on stdout");
+			if (exitstatus == 0 || exitstatus == 1)
+				exitstatus = 2;
+		}
 cmddone:
 		if (argc > 0)
 			bltinunsetlocale();
@@ -1082,7 +1186,6 @@
 		setvar("_", lastarg, 0);
 	if (do_clearcmdentry)
 		clearcmdentry();
-	popstackmark(&smark);
 }
 
 
@@ -1161,7 +1264,7 @@
  * The `command' command.
  */
 int
-commandcmd(int argc, char **argv)
+commandcmd(int argc __unused, char **argv __unused)
 {
 	const char *path;
 	int ch;
@@ -1169,9 +1272,7 @@
 
 	path = bltinlookup("PATH", 1);
 
-	optind = optreset = 1;
-	opterr = 0;
-	while ((ch = getopt(argc, argv, "pvV")) != -1) {
+	while ((ch = nextopt("pvV")) != '\0') {
 		switch (ch) {
 		case 'p':
 			path = _PATH_STDPATH;
@@ -1182,20 +1283,15 @@
 		case 'V':
 			cmd = TYPECMD_BIGV;
 			break;
-		case '?':
-		default:
-			error("unknown option: -%c", optopt);
 		}
 	}
-	argc -= optind;
-	argv += optind;
 
 	if (cmd != -1) {
-		if (argc != 1)
+		if (*argptr == NULL || argptr[1] != NULL)
 			error("wrong number of arguments");
-		return typecmd_impl(2, argv - 1, cmd, path);
+		return typecmd_impl(2, argptr - 1, cmd, path);
 	}
-	if (argc != 0)
+	if (*argptr != NULL)
 		error("commandcmd bad call");
 
 	/*
@@ -1215,14 +1311,8 @@
 {
 	int ret = argc > 1 ? number(argv[1]) : oexitstatus;
 
-	if (funcnest) {
-		evalskip = SKIPFUNC;
-		skipcount = 1;
-	} else {
-		/* skip the rest of the file */
-		evalskip = SKIPFILE;
-		skipcount = 1;
-	}
+	evalskip = SKIPRETURN;
+	skipcount = 1;
 	return ret;
 }
 

Modified: trunk/bin/sh/eval.h
===================================================================
--- trunk/bin/sh/eval.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/eval.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)eval.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/eval.h 255215 2013-09-04 22:10:16Z jilles $
  */
 
 extern char *commandname;	/* currently executing command */
@@ -46,6 +47,8 @@
 	struct job *jp;		/* job structure for command */
 };
 
+void reseteval(void);
+
 /* flags in argument to evaltree/evalstring */
 #define EV_EXIT 01		/* exit after evaluating tree */
 #define EV_TESTED 02		/* exit status is checked; ignore -e flag */
@@ -65,5 +68,4 @@
 /* reasons for skipping commands (see comment on breakcmd routine) */
 #define SKIPBREAK	1
 #define SKIPCONT	2
-#define SKIPFUNC	3
-#define SKIPFILE	4
+#define SKIPRETURN	3

Modified: trunk/bin/sh/exec.c
===================================================================
--- trunk/bin/sh/exec.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/exec.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/exec.c 286813 2015-08-15 19:58:00Z jilles $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -70,7 +71,6 @@
 #include "syntax.h"
 #include "memalloc.h"
 #include "error.h"
-#include "init.h"
 #include "mystring.h"
 #include "show.h"
 #include "jobs.h"
@@ -78,7 +78,6 @@
 
 
 #define CMDTABLESIZE 31		/* should be prime */
-#define ARB 1			/* actual size determined at run time */
 
 
 
@@ -86,13 +85,13 @@
 	struct tblentry *next;	/* next entry in hash chain */
 	union param param;	/* definition of builtin function */
 	int special;		/* flag for special builtin commands */
-	short cmdtype;		/* index identifying command */
-	char rehash;		/* if set, cd done since entry created */
-	char cmdname[ARB];	/* name of command */
+	signed char cmdtype;	/* index identifying command */
+	char cmdname[];		/* name of command */
 };
 
 
 static struct tblentry *cmdtable[CMDTABLESIZE];
+static int cmdtable_cd = 0;	/* cmdtable contains cd-dependent entries */
 int exerrno = 0;			/* Last exec error */
 
 
@@ -166,7 +165,7 @@
 			}
 		}
 		*argv = cmd;
-		*--argv = _PATH_BSHELL;
+		*--argv = __DECONST(char *, _PATH_BSHELL);
 		execve(_PATH_BSHELL, argv, envp);
 	}
 	errno = e;
@@ -189,7 +188,7 @@
 {
 	const char *p, *start;
 	char *q;
-	int len;
+	size_t len, namelen;
 
 	if (*path == NULL)
 		return NULL;
@@ -196,7 +195,8 @@
 	start = *path;
 	for (p = start; *p && *p != ':' && *p != '%'; p++)
 		; /* nothing */
-	len = p - start + strlen(name) + 2;	/* "2" is for '/' and '\0' */
+	namelen = strlen(name);
+	len = p - start + namelen + 2;	/* "2" is for '/' and '\0' */
 	STARTSTACKSTR(q);
 	CHECKSTRSPACE(len, q);
 	if (p != start) {
@@ -204,7 +204,7 @@
 		q += p - start;
 		*q++ = '/';
 	}
-	strcpy(q, name);
+	memcpy(q, name, namelen + 1);
 	pathopt = NULL;
 	if (*p == '%') {
 		pathopt = ++p;
@@ -231,7 +231,9 @@
 	int verbose;
 	struct cmdentry entry;
 	char *name;
+	int errors;
 
+	errors = 0;
 	verbose = 0;
 	while ((c = nextopt("rv")) != '\0') {
 		if (c == 'r') {
@@ -254,19 +256,21 @@
 		 && cmdp->cmdtype == CMDNORMAL)
 			delete_cmd_entry();
 		find_command(name, &entry, DO_ERR, pathval());
-		if (verbose) {
-			if (entry.cmdtype != CMDUNKNOWN) {	/* if no error msg */
-				cmdp = cmdlookup(name, 0);
-				if (cmdp != NULL)
-					printentry(cmdp, verbose);
-				else
-					outfmt(out2, "%s: not found\n", name);
+		if (entry.cmdtype == CMDUNKNOWN)
+			errors = 1;
+		else if (verbose) {
+			cmdp = cmdlookup(name, 0);
+			if (cmdp != NULL)
+				printentry(cmdp, verbose);
+			else {
+				outfmt(out2, "%s: not found\n", name);
+				errors = 1;
 			}
 			flushall();
 		}
 		argptr++;
 	}
-	return 0;
+	return errors;
 }
 
 
@@ -302,8 +306,6 @@
 		error("internal error: cmdtype %d", cmdp->cmdtype);
 #endif
 	}
-	if (cmdp->rehash)
-		out1c('*');
 	out1c('\n');
 }
 
@@ -320,12 +322,12 @@
 {
 	struct tblentry *cmdp, loc_cmd;
 	int idx;
-	int prev;
 	char *fullname;
 	struct stat statb;
 	int e;
 	int i;
 	int spec;
+	int cd;
 
 	/* If name contains a slash, don't use the hash table */
 	if (strchr(name, '/') != NULL) {
@@ -334,8 +336,10 @@
 		return;
 	}
 
+	cd = 0;
+
 	/* 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) {
 		if (cmdp->cmdtype == CMDFUNCTION && act & DO_NOFUNC)
 			cmdp = NULL;
 		else
@@ -356,13 +360,6 @@
 	}
 
 	/* We have to search path. */
-	prev = -1;		/* where to start */
-	if (cmdp) {		/* doing a rehash */
-		if (cmdp->cmdtype == CMDBUILTIN)
-			prev = -1;
-		else
-			prev = cmdp->param.index;
-	}
 
 	e = ENOENT;
 	idx = -1;
@@ -377,13 +374,8 @@
 				goto loop;	/* ignore unimplemented options */
 			}
 		}
-		/* if rehash, don't redo absolute path names */
-		if (fullname[0] == '/' && idx <= prev) {
-			if (idx < prev)
-				goto loop;
-			TRACE(("searchexec \"%s\": no change\n", name));
-			goto success;
-		}
+		if (fullname[0] != '/')
+			cd = 1;
 		if (stat(fullname, &statb) < 0) {
 			if (errno != ENOENT && errno != ENOTDIR)
 				e = errno;
@@ -423,9 +415,6 @@
 		goto success;
 	}
 
-	/* We failed.  If there was an entry for this command, delete it */
-	if (cmdp && cmdp->cmdtype != CMDFUNCTION)
-		delete_cmd_entry();
 	if (act & DO_ERR) {
 		if (e == ENOENT || e == ENOTDIR)
 			outfmt(out2, "%s: not found\n", name);
@@ -437,7 +426,8 @@
 	return;
 
 success:
-	cmdp->rehash = 0;
+	if (cd)
+		cmdtable_cd = 1;
 	entry->cmdtype = cmdp->cmdtype;
 	entry->u = cmdp->param;
 	entry->special = cmdp->special;
@@ -466,22 +456,15 @@
 
 
 /*
- * Called when a cd is done.  Marks all commands so the next time they
- * are executed they will be rehashed.
+ * Called when a cd is done.  If any entry in cmdtable depends on the current
+ * directory, simply clear cmdtable completely.
  */
 
 void
 hashcd(void)
 {
-	struct tblentry **pp;
-	struct tblentry *cmdp;
-
-	for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
-		for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
-			if (cmdp->cmdtype == CMDNORMAL)
-				cmdp->rehash = 1;
-		}
-	}
+	if (cmdtable_cd)
+		clearcmdentry();
 }
 
 
@@ -493,7 +476,7 @@
  */
 
 void
-changepath(const char *newval)
+changepath(const char *newval __unused)
 {
 	clearcmdentry();
 }
@@ -523,6 +506,7 @@
 			}
 		}
 	}
+	cmdtable_cd = 0;
 	INTON;
 }
 
@@ -541,16 +525,16 @@
 static struct tblentry *
 cmdlookup(const char *name, int add)
 {
-	int hashval;
+	unsigned int hashval;
 	const char *p;
 	struct tblentry *cmdp;
 	struct tblentry **pp;
+	size_t len;
 
 	p = name;
-	hashval = *p << 4;
+	hashval = (unsigned char)*p << 4;
 	while (*p)
 		hashval += *p++;
-	hashval &= 0x7FFF;
 	pp = &cmdtable[hashval % CMDTABLESIZE];
 	for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
 		if (equal(cmdp->cmdname, name))
@@ -559,12 +543,11 @@
 	}
 	if (add && cmdp == NULL) {
 		INTOFF;
-		cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
-					+ strlen(name) + 1);
+		len = strlen(name);
+		cmdp = *pp = ckmalloc(sizeof (struct tblentry) + len + 1);
 		cmdp->next = NULL;
 		cmdp->cmdtype = CMDUNKNOWN;
-		cmdp->rehash = 0;
-		strcpy(cmdp->cmdname, name);
+		memcpy(cmdp->cmdname, name, len + 1);
 		INTON;
 	}
 	lastcmdentry = pp;
@@ -629,6 +612,7 @@
 
 /*
  * Delete a function if it exists.
+ * Called with interrupts off.
  */
 
 int
@@ -644,7 +628,20 @@
 	return (0);
 }
 
+
 /*
+ * Check if a function by a certain name exists.
+ */
+int
+isfunc(const char *name)
+{
+	struct tblentry *cmdp;
+	cmdp = cmdlookup(name, 0);
+	return (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION);
+}
+
+
+/*
  * Shared code for the following builtin commands:
  *    type, command -v, command -V
  */
@@ -678,9 +675,11 @@
 
 		/* Then look at the aliases */
 		if ((ap = lookupalias(argv[i], 1)) != NULL) {
-			if (cmd == TYPECMD_SMALLV)
-				out1fmt("alias %s='%s'\n", argv[i], ap->val);
-			else
+			if (cmd == TYPECMD_SMALLV) {
+				out1fmt("alias %s=", argv[i]);
+				out1qstr(ap->val);
+				outcslow('\n', out1);
+			} else
 				out1fmt("%s is an alias for %s\n", argv[i],
 				    ap->val);
 			continue;
@@ -768,5 +767,7 @@
 int
 typecmd(int argc, char **argv)
 {
+	if (argc > 2 && strcmp(argv[1], "--") == 0)
+		argc--, argv++;
 	return typecmd_impl(argc, argv, TYPECMD_TYPE, bltinlookup("PATH", 1));
 }

Modified: trunk/bin/sh/exec.h
===================================================================
--- trunk/bin/sh/exec.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/exec.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)exec.h	8.3 (Berkeley) 6/8/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/exec.h 238468 2012-07-15 10:19:43Z jilles $
  */
 
 /* values of cmdtype */
@@ -72,5 +73,6 @@
 void changepath(const char *);
 void defun(const char *, union node *);
 int unsetfunc(const char *);
+int isfunc(const char *);
 int typecmd_impl(int, char **, int, const char *);
 void clearcmdentry(void);

Modified: trunk/bin/sh/expand.c
===================================================================
--- trunk/bin/sh/expand.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/expand.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -38,7 +39,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/expand.c 320510 2017-06-30 21:32:48Z jilles $");
 
 #include <sys/types.h>
 #include <sys/time.h>
@@ -98,17 +99,19 @@
 static struct ifsregion *ifslastp;	/* last struct in list */
 static struct arglist exparg;		/* holds expanded arg list */
 
-static void argstr(char *, int);
+static char *argstr(char *, int);
 static char *exptilde(char *, int);
+static char *expari(char *);
 static void expbackq(union node *, int, int);
 static int subevalvar(char *, char *, int, int, int, int, int);
 static char *evalvar(char *, int);
-static int varisset(char *, int);
-static void varvalue(char *, int, int, int);
+static int varisset(const char *, int);
+static void strtodest(const char *, int, int, int);
+static void varvalue(const char *, int, int, int);
 static void recordregion(int, int, int);
 static void removerecordregions(int);
 static void ifsbreakup(char *, struct arglist *);
-static void expandmeta(struct strlist *, int);
+static void expandmeta(struct strlist *);
 static void expmeta(char *, char *);
 static void addfname(char *);
 static struct strlist *expsort(struct strlist *);
@@ -127,19 +130,6 @@
 	return (wcscoll(s1, s2));
 }
 
-/*
- * Expand shell variables and backquotes inside a here document.
- *	union node *arg		the document
- *	int fd;			where to write the expanded version
- */
-
-void
-expandhere(union node *arg, int fd)
-{
-	expandarg(arg, (struct arglist *)NULL, 0);
-	xwrite(fd, stackblock(), expdest - stackblock());
-}
-
 static char *
 stputs_quotes(const char *data, const char *syntax, char *p)
 {
@@ -183,17 +173,12 @@
 	STPUTC('\0', expdest);
 	p = grabstackstr(expdest);
 	exparg.lastp = &exparg.list;
-	/*
-	 * TODO - EXP_REDIR
-	 */
 	if (flag & EXP_FULL) {
 		ifsbreakup(p, &exparg);
 		*exparg.lastp = NULL;
 		exparg.lastp = &exparg.list;
-		expandmeta(exparg.list, flag);
+		expandmeta(exparg.list);
 	} else {
-		if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
-			rmescapes(p);
 		sp = (struct strlist *)stalloc(sizeof (struct strlist));
 		sp->text = p;
 		*exparg.lastp = sp;
@@ -219,17 +204,17 @@
 /*
  * Perform parameter expansion, command substitution and arithmetic
  * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
- * Processing ends at a CTLENDVAR character as well as '\0'.
+ * Processing ends at a CTLENDVAR or CTLENDARI character as well as '\0'.
  * This is used to expand word in ${var+word} etc.
- * If EXP_FULL, EXP_CASE or EXP_REDIR are set, keep and/or generate CTLESC
+ * If EXP_FULL or EXP_CASE are set, keep and/or generate CTLESC
  * characters to allow for further processing.
  * If EXP_FULL is set, also preserve CTLQUOTEMARK characters.
  */
-static void
+static char *
 argstr(char *p, int flag)
 {
 	char c;
-	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);	/* do CTLESC */
+	int quotes = flag & (EXP_FULL | EXP_CASE);	/* do CTLESC */
 	int firsteq = 1;
 	int split_lit;
 	int lit_quoted;
@@ -243,8 +228,10 @@
 		CHECKSTRSPACE(2, expdest);
 		switch (c = *p++) {
 		case '\0':
+			return (p - 1);
 		case CTLENDVAR:
-			goto breakloop;
+		case CTLENDARI:
+			return (p);
 		case CTLQUOTEMARK:
 			lit_quoted = 1;
 			/* "$@" syntax adherence hack */
@@ -274,8 +261,8 @@
 			expbackq(argbackq->n, c & CTLQUOTE, flag);
 			argbackq = argbackq->next;
 			break;
-		case CTLENDARI:
-			expari(flag);
+		case CTLARI:
+			p = expari(p);
 			break;
 		case ':':
 		case '=':
@@ -301,7 +288,6 @@
 				    expdest - stackblock(), 0);
 		}
 	}
-breakloop:;
 }
 
 /*
@@ -314,9 +300,9 @@
 	char c, *startp = p;
 	struct passwd *pw;
 	char *home;
-	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
 
-	while ((c = *p) != '\0') {
+	for (;;) {
+		c = *p;
 		switch(c) {
 		case CTLESC: /* This means CTL* are always considered quoted. */
 		case CTLVAR:
@@ -327,36 +313,27 @@
 		case CTLQUOTEMARK:
 			return (startp);
 		case ':':
-			if (flag & EXP_VARTILDE)
-				goto done;
-			break;
+			if ((flag & EXP_VARTILDE) == 0)
+				break;
+			/* FALLTHROUGH */
+		case '\0':
 		case '/':
 		case CTLENDVAR:
-			goto done;
+			*p = '\0';
+			if (*(startp+1) == '\0') {
+				home = lookupvar("HOME");
+			} else {
+				pw = getpwnam(startp+1);
+				home = pw != NULL ? pw->pw_dir : NULL;
+			}
+			*p = c;
+			if (home == NULL || *home == '\0')
+				return (startp);
+			strtodest(home, flag, VSNORMAL, 1);
+			return (p);
 		}
 		p++;
 	}
-done:
-	*p = '\0';
-	if (*(startp+1) == '\0') {
-		if ((home = lookupvar("HOME")) == NULL)
-			goto lose;
-	} else {
-		if ((pw = getpwnam(startp+1)) == NULL)
-			goto lose;
-		home = pw->pw_dir;
-	}
-	if (*home == '\0')
-		goto lose;
-	*p = c;
-	if (quotes)
-		STPUTS_QUOTES(home, SQSYNTAX, expdest);
-	else
-		STPUTS(home, expdest);
-	return (p);
-lose:
-	*p = c;
-	return (startp);
 }
 
 
@@ -400,59 +377,40 @@
 }
 
 /*
- * Expand arithmetic expression.  Backup to start of expression,
- * evaluate, place result in (backed up) result, adjust string position.
+ * Expand arithmetic expression.
+ * Note that flag is not required as digits never require CTLESC characters.
  */
-void
-expari(int flag)
+static char *
+expari(char *p)
 {
-	char *p, *q, *start;
+	char *q, *start;
 	arith_t result;
 	int begoff;
-	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
 	int quoted;
+	int adj;
 
-	/*
-	 * 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.  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.
-	 */
-	CHECKSTRSPACE(DIGITS(result) - 2, expdest);
-	USTPUTC('\0', expdest);
-	start = stackblock();
-	p = expdest - 2;
-	while (p >= start && *p != CTLARI)
-		--p;
-	if (p < start || *p != CTLARI)
-		error("missing CTLARI (shouldn't happen)");
-	if (p > start && *(p - 1) == CTLESC)
-		for (p = start; *p != CTLARI; p++)
-			if (*p == CTLESC)
-				p++;
+	quoted = *p++ == '"';
+	begoff = expdest - stackblock();
+	p = argstr(p, 0);
+	removerecordregions(begoff);
+	STPUTC('\0', expdest);
+	start = stackblock() + begoff;
 
-	if (p[1] == '"')
-		quoted=1;
-	else
-		quoted=0;
-	begoff = p - start;
-	removerecordregions(begoff);
-	if (quotes)
-		rmescapes(p+2);
 	q = grabstackstr(expdest);
-	result = arith(p+2);
+	result = arith(start);
 	ungrabstackstr(q, expdest);
-	fmtstr(p, DIGITS(result), ARITH_FORMAT_STR, result);
-	while (*p++)
-		;
-	if (quoted == 0)
-		recordregion(begoff, p - 1 - start, 0);
-	result = expdest - p + 1;
-	STADJUST(-result, expdest);
+
+	start = stackblock() + begoff;
+	adj = start - expdest;
+	STADJUST(adj, expdest);
+
+	CHECKSTRSPACE((int)(DIGITS(result) + 1), expdest);
+	fmtstr(expdest, DIGITS(result), ARITH_FORMAT_STR, result);
+	adj = strlen(expdest);
+	STADJUST(adj, expdest);
+	if (!quoted)
+		recordregion(begoff, expdest - stackblock(), 0);
+	return p;
 }
 
 
@@ -472,8 +430,8 @@
 	char lastc;
 	int startloc = dest - stackblock();
 	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
-	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
-	int nnl;
+	int quotes = flag & (EXP_FULL | EXP_CASE);
+	size_t nnl;
 
 	INTOFF;
 	saveifs = ifsfirst;
@@ -482,9 +440,6 @@
 	p = grabstackstr(dest);
 	evalbackcmd(cmd, &in);
 	ungrabstackstr(p, dest);
-	ifsfirst = saveifs;
-	ifslastp = savelastp;
-	argbackq = saveargbackq;
 
 	p = in.buf;
 	lastc = '\0';
@@ -522,14 +477,20 @@
 		close(in.fd);
 	if (in.buf)
 		ckfree(in.buf);
-	if (in.jp)
+	if (in.jp) {
+		p = grabstackstr(dest);
 		exitstatus = waitforjob(in.jp, (int *)NULL);
-	if (quoted == 0)
-		recordregion(startloc, dest - stackblock(), 0);
+		ungrabstackstr(p, dest);
+	}
 	TRACE(("expbackq: size=%td: \"%.*s\"\n",
 		((dest - stackblock()) - startloc),
 		(int)((dest - stackblock()) - startloc),
 		stackblock() + startloc));
+	ifsfirst = saveifs;
+	ifslastp = savelastp;
+	if (quoted == 0)
+		recordregion(startloc, dest - stackblock(), 0);
+	argbackq = saveargbackq;
 	expdest = dest;
 	INTON;
 }
@@ -536,6 +497,17 @@
 
 
 
+static void
+recordleft(const char *str, const char *loc, char *startp)
+{
+	int amount;
+
+	amount = ((str - 1) - (loc - startp)) - expdest;
+	STADJUST(amount, expdest);
+	while (loc != str - 1)
+		*startp++ = *loc++;
+}
+
 static int
 subevalvar(char *p, char *str, int strloc, int subtype, int startloc,
   int varflags, int quotes)
@@ -580,7 +552,8 @@
 			*loc = '\0';
 			if (patmatch(str, startp, quotes)) {
 				*loc = c;
-				goto recordleft;
+				recordleft(str, loc, startp);
+				return 1;
 			}
 			*loc = c;
 			if (quotes && *loc == CTLESC)
@@ -594,7 +567,8 @@
 			*loc = '\0';
 			if (patmatch(str, startp, quotes)) {
 				*loc = c;
-				goto recordleft;
+				recordleft(str, loc, startp);
+				return 1;
 			}
 			*loc = c;
 			loc--;
@@ -642,13 +616,6 @@
 	default:
 		abort();
 	}
-
-recordleft:
-	amount = ((str - 1) - (loc - startp)) - expdest;
-	STADJUST(amount, expdest);
-	while (loc != str - 1)
-		*startp++ = *loc++;
-	return 1;
 }
 
 
@@ -663,7 +630,7 @@
 	int subtype;
 	int varflags;
 	char *var;
-	char *val;
+	const char *val;
 	int patloc;
 	int c;
 	int set;
@@ -672,7 +639,8 @@
 	int varlen;
 	int varlenb;
 	int easy;
-	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
+	int quotes = flag & (EXP_FULL | EXP_CASE);
+	int record = 0;
 
 	varflags = (unsigned char)*p++;
 	subtype = varflags & VSTYPE;
@@ -684,10 +652,8 @@
 again: /* jump here after setting a variable with ${var=text} */
 	if (varflags & VSLINENO) {
 		set = 1;
-		special = 0;
-		val = var;
-		p[-1] = '\0';	/* temporarily overwrite '=' to have \0
-				   terminated string */
+		special = 1;
+		val = NULL;
 	} else if (special) {
 		set = varisset(var, varflags & VSNUL);
 		val = NULL;
@@ -716,7 +682,10 @@
 	if (set && subtype != VSPLUS) {
 		/* insert the value of the variable */
 		if (special) {
-			varvalue(var, varflags & VSQUOTE, subtype, flag);
+			if (varflags & VSLINENO)
+				STPUTBIN(var, p - var - 1, expdest);
+			else
+				varvalue(var, varflags & VSQUOTE, subtype, flag);
 			if (subtype == VSLENGTH) {
 				varlenb = expdest - stackblock() - startloc;
 				varlen = varlenb;
@@ -729,9 +698,6 @@
 				STADJUST(-varlenb, expdest);
 			}
 		} else {
-			char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX
-								  : BASESYNTAX;
-
 			if (subtype == VSLENGTH) {
 				for (;*val; val++)
 					if (!localeisutf8 ||
@@ -738,13 +704,9 @@
 					    (*val & 0xC0) != 0x80)
 						varlen++;
 			}
-			else {
-				if (quotes)
-					STPUTS_QUOTES(val, syntax, expdest);
-				else
-					STPUTS(val, expdest);
-
-			}
+			else
+				strtodest(val, flag, subtype,
+				    varflags & VSQUOTE);
 		}
 	}
 
@@ -758,15 +720,11 @@
 	switch (subtype) {
 	case VSLENGTH:
 		expdest = cvtnum(varlen, expdest);
-		goto record;
+		record = 1;
+		break;
 
 	case VSNORMAL:
-		if (!easy)
-			break;
-record:
-		recordregion(startloc, expdest - stackblock(),
-		    varflags & VSQUOTE || (ifsset() && ifsval()[0] == '\0' &&
-		    (*var == '@' || *var == '*')));
+		record = easy;
 		break;
 
 	case VSPLUS:
@@ -776,8 +734,7 @@
 			    (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0));
 			break;
 		}
-		if (easy)
-			goto record;
+		record = easy;
 		break;
 
 	case VSTRIMLEFT:
@@ -784,8 +741,10 @@
 	case VSTRIMLEFTMAX:
 	case VSTRIMRIGHT:
 	case VSTRIMRIGHTMAX:
-		if (!set)
+		if (!set) {
+			set = 1;
 			break;
+		}
 		/*
 		 * Terminate the string and start recording the pattern
 		 * right after it
@@ -799,7 +758,8 @@
 		}
 		/* Remove any recorded regions beyond start of variable */
 		removerecordregions(startloc);
-		goto record;
+		record = 1;
+		break;
 
 	case VSASSIGN:
 	case VSQUESTION:
@@ -816,8 +776,7 @@
 			}
 			break;
 		}
-		if (easy)
-			goto record;
+		record = easy;
 		break;
 
 	case VSERROR:
@@ -828,8 +787,12 @@
 	default:
 		abort();
 	}
-	p[-1] = '=';	/* recover overwritten '=' */
 
+	if (record)
+		recordregion(startloc, expdest - stackblock(),
+		    varflags & VSQUOTE || (ifsset() && ifsval()[0] == '\0' &&
+		    (*var == '@' || *var == '*')));
+
 	if (subtype != VSNORMAL) {	/* skip to end of alternative */
 		int nesting = 1;
 		for (;;) {
@@ -857,7 +820,7 @@
  */
 
 static int
-varisset(char *name, int nulok)
+varisset(const char *name, int nulok)
 {
 
 	if (*name == '!')
@@ -876,9 +839,11 @@
 		}
 	} else if (is_digit(*name)) {
 		char *ap;
-		int num = atoi(name);
+		long num;
 
-		if (num > shellparam.nparam)
+		errno = 0;
+		num = strtol(name, NULL, 10);
+		if (errno != 0 || num > shellparam.nparam)
 			return 0;
 
 		if (num == 0)
@@ -906,7 +871,7 @@
  */
 
 static void
-varvalue(char *name, int quoted, int subtype, int flag)
+varvalue(const char *name, int quoted, int subtype, int flag)
 {
 	int num;
 	char *p;
@@ -986,6 +951,7 @@
 {
 	struct ifsregion *ifsp;
 
+	INTOFF;
 	if (ifslastp == NULL) {
 		ifsp = &ifsfirst;
 	} else {
@@ -993,6 +959,7 @@
 		    && ifslastp->inquotes == inquotes) {
 			/* extend previous area */
 			ifslastp->endoff = end;
+			INTON;
 			return;
 		}
 		ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
@@ -1003,6 +970,7 @@
 	ifslastp->begoff = start;
 	ifslastp->endoff = end;
 	ifslastp->inquotes = inquotes;
+	INTON;
 }
 
 
@@ -1127,13 +1095,12 @@
  * The results are stored in the list exparg.
  */
 static void
-expandmeta(struct strlist *str, int flag __unused)
+expandmeta(struct strlist *str)
 {
 	char *p;
 	struct strlist **savelastp;
 	struct strlist *sp;
 	char c;
-	/* TODO - EXP_REDIR */
 
 	while (str) {
 		if (fflag)
@@ -1176,9 +1143,9 @@
 static void
 expmeta(char *enddir, char *name)
 {
-	char *p;
-	char *q;
-	char *start;
+	const char *p;
+	const char *q;
+	const char *start;
 	char *endname;
 	int metaflag;
 	struct stat statb;
@@ -1187,6 +1154,7 @@
 	int atend;
 	int matchdot;
 	int esc;
+	int namlen;
 
 	metaflag = 0;
 	start = name;
@@ -1241,7 +1209,7 @@
 			addfname(expdir);
 		return;
 	}
-	endname = p;
+	endname = name + (p - name);
 	if (start != name) {
 		p = name;
 		while (p < start) {
@@ -1285,17 +1253,22 @@
 		if (dp->d_name[0] == '.' && ! matchdot)
 			continue;
 		if (patmatch(start, dp->d_name, 0)) {
-			if (enddir + dp->d_namlen + 1 > expdir_end)
+			namlen = dp->d_namlen;
+			if (enddir + namlen + 1 > expdir_end)
 				continue;
-			memcpy(enddir, dp->d_name, dp->d_namlen + 1);
+			memcpy(enddir, dp->d_name, namlen + 1);
 			if (atend)
 				addfname(expdir);
 			else {
-				if (enddir + dp->d_namlen + 2 > expdir_end)
+				if (dp->d_type != DT_UNKNOWN &&
+				    dp->d_type != DT_DIR &&
+				    dp->d_type != DT_LNK)
 					continue;
-				enddir[dp->d_namlen] = '/';
-				enddir[dp->d_namlen + 1] = '\0';
-				expmeta(enddir + dp->d_namlen + 1, endname);
+				if (enddir + namlen + 2 > expdir_end)
+					continue;
+				enddir[namlen] = '/';
+				enddir[namlen + 1] = '\0';
+				expmeta(enddir + namlen + 1, endname);
 			}
 		}
 	}
@@ -1315,8 +1288,7 @@
 	char *p;
 	struct strlist *sp;
 
-	p = stalloc(strlen(name) + 1);
-	scopy(name, p);
+	p = stsavestr(name);
 	sp = (struct strlist *)stalloc(sizeof *sp);
 	sp->text = p;
 	*exparg.lastp = sp;
@@ -1419,7 +1391,8 @@
 	*end = NULL;
 	p++;
 	nameend = strstr(p, ":]");
-	if (nameend == NULL || nameend - p >= sizeof(name) || nameend == p)
+	if (nameend == NULL || (size_t)(nameend - p) >= sizeof(name) ||
+	    nameend == p)
 		return 0;
 	memcpy(name, p, nameend - p);
 	name[nameend - p] = '\0';
@@ -1498,23 +1471,11 @@
 			bt_q = q;
 			break;
 		case '[': {
-			const char *endp;
+			const char *savep, *saveq;
 			int invert, found;
 			wchar_t chr;
 
-			endp = p;
-			if (*endp == '!' || *endp == '^')
-				endp++;
-			for (;;) {
-				while (*endp == CTLQUOTEMARK)
-					endp++;
-				if (*endp == 0)
-					goto dft;		/* no matching ] */
-				if (*endp == CTLESC)
-					endp++;
-				if (*++endp == ']')
-					break;
-			}
+			savep = p, saveq = q;
 			invert = 0;
 			if (*p == '!' || *p == '^') {
 				invert++;
@@ -1533,6 +1494,11 @@
 				chr = (unsigned char)*q++;
 			c = *p++;
 			do {
+				if (c == '\0') {
+					p = savep, q = saveq;
+					c = '[';
+					goto dft;
+				}
 				if (c == CTLQUOTEMARK)
 					continue;
 				if (c == '[' && *p == ':') {
@@ -1697,3 +1663,57 @@
 		outbin(argv[i], strlen(argv[i]) + 1, out1);
         return (0);
 }
+
+/*
+ * Do most of the work for wordexp(3), new version.
+ */
+
+int
+freebsd_wordexpcmd(int argc __unused, char **argv __unused)
+{
+	struct arglist arglist;
+	union node *args, *n;
+	struct strlist *sp;
+	size_t count, len;
+	int ch;
+	int protected = 0;
+	int fd = -1;
+
+	while ((ch = nextopt("f:p")) != '\0') {
+		switch (ch) {
+		case 'f':
+			fd = number(shoptarg);
+			break;
+		case 'p':
+			protected = 1;
+			break;
+		}
+	}
+	if (*argptr != NULL)
+		error("wrong number of arguments");
+	if (fd < 0)
+		error("missing fd");
+	INTOFF;
+	setinputfd(fd, 1);
+	INTON;
+	args = parsewordexp();
+	popfile(); /* will also close fd */
+	if (protected)
+		for (n = args; n != NULL; n = n->narg.next) {
+			if (n->narg.backquote != NULL) {
+				outcslow('C', out1);
+				error("command substitution disabled");
+			}
+		}
+	outcslow(' ', out1);
+	arglist.lastp = &arglist.list;
+	for (n = args; n != NULL; n = n->narg.next)
+		expandarg(n, &arglist, EXP_FULL | EXP_TILDE);
+	*arglist.lastp = NULL;
+	for (sp = arglist.list, count = len = 0; sp; sp = sp->next)
+		count++, len += strlen(sp->text);
+	out1fmt("%016zx %016zx", count, len);
+	for (sp = arglist.list; sp; sp = sp->next)
+		outbin(sp->text, strlen(sp->text) + 1, out1);
+	return (0);
+}

Modified: trunk/bin/sh/expand.h
===================================================================
--- trunk/bin/sh/expand.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/expand.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)expand.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/expand.h 276365 2014-12-29 15:33:20Z jilles $
  */
 
 struct strlist {
@@ -50,7 +51,6 @@
 #define EXP_FULL	0x1	/* perform word splitting & file globbing */
 #define EXP_TILDE	0x2	/* do normal tilde expansion */
 #define	EXP_VARTILDE	0x4	/* expand tildes in an assignment */
-#define	EXP_REDIR	0x8	/* file glob for a redirection (1 match only) */
 #define EXP_CASE	0x10	/* keeps quotes around for CASE pattern */
 #define EXP_SPLIT_LIT	0x20	/* IFS split literal text ${v+-a b c} */
 #define EXP_LIT_QUOTED	0x40	/* for EXP_SPLIT_LIT, start off quoted */
@@ -57,8 +57,6 @@
 
 
 union node;
-void expandhere(union node *, int);
 void expandarg(union node *, struct arglist *, int);
-void expari(int);
 void rmescapes(char *);
 int casematch(union node *, const char *);

Modified: trunk/bin/sh/funcs/cmv
===================================================================
--- trunk/bin/sh/funcs/cmv	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/funcs/cmv	2018-06-02 21:06:59 UTC (rev 10240)
@@ -32,7 +32,7 @@
 # SUCH DAMAGE.
 #
 #	@(#)cmv	8.2 (Berkeley) 5/4/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/funcs/cmv 139969 2005-01-10 08:39:26Z imp $
 
 # Conditional move--don't replace an existing file.
 


Property changes on: trunk/bin/sh/funcs/cmv
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/funcs/dirs
===================================================================
--- trunk/bin/sh/funcs/dirs	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/funcs/dirs	2018-06-02 21:06:59 UTC (rev 10240)
@@ -32,7 +32,7 @@
 # SUCH DAMAGE.
 #
 #	@(#)dirs	8.2 (Berkeley) 5/4/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/funcs/dirs 139969 2005-01-10 08:39:26Z imp $
 
 # pushd, popd, and dirs --- written by Chris Bertin
 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris


Property changes on: trunk/bin/sh/funcs/dirs
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/funcs/login
===================================================================
--- trunk/bin/sh/funcs/login	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/funcs/login	2018-06-02 21:06:59 UTC (rev 10240)
@@ -32,7 +32,7 @@
 # SUCH DAMAGE.
 #
 #	@(#)login	8.2 (Berkeley) 5/4/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/funcs/login 139969 2005-01-10 08:39:26Z imp $
 
 # replaces the login builtin in the BSD shell
 login () exec login "$@"


Property changes on: trunk/bin/sh/funcs/login
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/funcs/newgrp
===================================================================
--- trunk/bin/sh/funcs/newgrp	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/funcs/newgrp	2018-06-02 21:06:59 UTC (rev 10240)
@@ -32,6 +32,6 @@
 # SUCH DAMAGE.
 #
 #	@(#)newgrp	8.2 (Berkeley) 5/4/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/funcs/newgrp 139969 2005-01-10 08:39:26Z imp $
 
 newgrp() exec newgrp "$@"


Property changes on: trunk/bin/sh/funcs/newgrp
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/funcs/popd
===================================================================
--- trunk/bin/sh/funcs/popd	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/funcs/popd	2018-06-02 21:06:59 UTC (rev 10240)
@@ -32,7 +32,7 @@
 # SUCH DAMAGE.
 #
 #	@(#)popd	8.2 (Berkeley) 5/4/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/funcs/popd 139969 2005-01-10 08:39:26Z imp $
 
 # pushd, popd, and dirs --- written by Chris Bertin
 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris


Property changes on: trunk/bin/sh/funcs/popd
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/funcs/pushd
===================================================================
--- trunk/bin/sh/funcs/pushd	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/funcs/pushd	2018-06-02 21:06:59 UTC (rev 10240)
@@ -32,7 +32,7 @@
 # SUCH DAMAGE.
 #
 #	@(#)pushd	8.2 (Berkeley) 5/4/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/funcs/pushd 139969 2005-01-10 08:39:26Z imp $
 
 # pushd, popd, and dirs --- written by Chris Bertin
 # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris


Property changes on: trunk/bin/sh/funcs/pushd
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/funcs/suspend
===================================================================
--- trunk/bin/sh/funcs/suspend	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/funcs/suspend	2018-06-02 21:06:59 UTC (rev 10240)
@@ -30,7 +30,7 @@
 # SUCH DAMAGE.
 #
 #	@(#)suspend	8.2 (Berkeley) 5/4/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/funcs/suspend 215268 2010-11-13 22:20:46Z jilles $
 
 suspend() {
 	local -


Property changes on: trunk/bin/sh/funcs/suspend
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/histedit.c
===================================================================
--- trunk/bin/sh/histedit.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/histedit.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/histedit.c 240541 2012-09-15 21:56:30Z jilles $");
 
 #include <sys/param.h>
 #include <limits.h>
@@ -160,8 +161,7 @@
 
 
 void
-sethistsize(hs)
-	const char *hs;
+sethistsize(const char *hs)
 {
 	int histsize;
 	HistEvent he;
@@ -183,7 +183,7 @@
 }
 
 int
-histcmd(int argc, char **argv)
+histcmd(int argc, char **argv __unused)
 {
 	int ch;
 	const char *editor = NULL;
@@ -207,13 +207,10 @@
 	if (argc == 1)
 		error("missing history argument");
 
-	optreset = 1; optind = 1; /* initialize getopt */
-	opterr = 0;
-	while (not_fcnumber(argv[optind]) &&
-	      (ch = getopt(argc, argv, ":e:lnrs")) != -1)
+	while (not_fcnumber(*argptr) && (ch = nextopt("e:lnrs")) != '\0')
 		switch ((char)ch) {
 		case 'e':
-			editor = optarg;
+			editor = shoptarg;
 			break;
 		case 'l':
 			lflg = 1;
@@ -227,13 +224,7 @@
 		case 's':
 			sflg = 1;
 			break;
-		case ':':
-			error("option -%c expects argument", optopt);
-		case '?':
-		default:
-			error("unknown option: -%c", optopt);
 		}
-	argc -= optind, argv += optind;
 
 	savehandler = handler;
 	/*
@@ -277,31 +268,26 @@
 	/*
 	 * If executing, parse [old=new] now
 	 */
-	if (lflg == 0 && argc > 0 &&
-	     ((repl = strchr(argv[0], '=')) != NULL)) {
-		pat = argv[0];
+	if (lflg == 0 && *argptr != NULL &&
+	     ((repl = strchr(*argptr, '=')) != NULL)) {
+		pat = *argptr;
 		*repl++ = '\0';
-		argc--, argv++;
+		argptr++;
 	}
 	/*
 	 * determine [first] and [last]
 	 */
-	switch (argc) {
-	case 0:
+	if (*argptr == NULL) {
 		firststr = lflg ? "-16" : "-1";
 		laststr = "-1";
-		break;
-	case 1:
-		firststr = argv[0];
-		laststr = lflg ? "-1" : argv[0];
-		break;
-	case 2:
-		firststr = argv[0];
-		laststr = argv[1];
-		break;
-	default:
+	} else if (argptr[1] == NULL) {
+		firststr = argptr[0];
+		laststr = lflg ? "-1" : argptr[0];
+	} else if (argptr[2] == NULL) {
+		firststr = argptr[0];
+		laststr = argptr[1];
+	} else
 		error("too many arguments");
-	}
 	/*
 	 * Turn into event numbers.
 	 */

Modified: trunk/bin/sh/input.c
===================================================================
--- trunk/bin/sh/input.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/input.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/input.c 262951 2014-03-09 17:04:31Z jmmv $");
 
 #include <stdio.h>	/* defines BUFSIZ */
 #include <fcntl.h>
@@ -64,10 +65,9 @@
 
 #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
 
-MKINIT
 struct strpush {
 	struct strpush *prev;	/* preceding string on stack */
-	char *prevstring;
+	const char *prevstring;
 	int prevnleft;
 	int prevlleft;
 	struct alias *ap;	/* if push was associated with an alias */
@@ -78,7 +78,6 @@
  * contains information about the current file being read.
  */
 
-MKINIT
 struct parsefile {
 	struct parsefile *prev;	/* preceding file on stack */
 	int linno;		/* current line */
@@ -85,7 +84,7 @@
 	int fd;			/* file descriptor (or -1 if string) */
 	int nleft;		/* number of chars left in this line */
 	int lleft;		/* number of lines left in this buffer */
-	char *nextc;		/* next char in buffer */
+	const char *nextc;	/* next char in buffer */
 	char *buf;		/* input buffer */
 	struct strpush *strpush; /* for pushing strings at this level */
 	struct strpush basestrpush; /* so pushing one is fast */
@@ -94,12 +93,14 @@
 
 int plinno = 1;			/* input line number */
 int parsenleft;			/* copy of parsefile->nleft */
-MKINIT int parselleft;		/* copy of parsefile->lleft */
-char *parsenextc;		/* copy of parsefile->nextc */
-MKINIT struct parsefile basepf;	/* top level input file */
-char basebuf[BUFSIZ];		/* buffer for top level input file */
+static int parselleft;		/* copy of parsefile->lleft */
+const char *parsenextc;		/* copy of parsefile->nextc */
+static char basebuf[BUFSIZ + 1];/* buffer for top level input file */
+static struct parsefile basepf = {	/* top level input file */
+	.nextc = basebuf,
+	.buf = basebuf
+};
 static struct parsefile *parsefile = &basepf;	/* current input file */
-int init_editline = 0;		/* editline library initialized? */
 int whichprompt;		/* 1 == PS1, 2 == PS2 */
 
 EditLine *el;			/* cookie for editline package */
@@ -108,21 +109,12 @@
 static int preadfd(void);
 static void popstring(void);
 
-#ifdef mkinit
-INCLUDE "input.h"
-INCLUDE "error.h"
-
-MKINIT char basebuf[];
-
-INIT {
-	basepf.nextc = basepf.buf = basebuf;
-}
-
-RESET {
+void
+resetinput(void)
+{
 	popallfiles();
 	parselleft = parsenleft = 0;	/* clear input buffer */
 }
-#endif
 
 
 /*
@@ -171,12 +163,6 @@
 	int nr;
 	parsenextc = parsefile->buf;
 
-#ifndef NO_HISTORY
-	if (el != NULL && gotwinch) {
-		gotwinch = 0;
-		el_resize(el);
-	}
-#endif
 retry:
 #ifndef NO_HISTORY
 	if (parsefile->fd == 0 && el) {
@@ -183,15 +169,17 @@
 		static const char *rl_cp;
 		static int el_len;
 
-		if (rl_cp == NULL)
+		if (rl_cp == NULL) {
+			el_resize(el);
 			rl_cp = el_gets(el, &el_len);
+		}
 		if (rl_cp == NULL)
 			nr = el_len == 0 ? 0 : -1;
 		else {
 			nr = el_len;
-			if (nr > BUFSIZ - 1)
-				nr = BUFSIZ - 1;
-			memcpy(parsenextc, rl_cp, nr);
+			if (nr > BUFSIZ)
+				nr = BUFSIZ;
+			memcpy(parsefile->buf, rl_cp, nr);
 			if (nr != el_len) {
 				el_len -= nr;
 				rl_cp += nr;
@@ -200,7 +188,7 @@
 		}
 	} else
 #endif
-		nr = read(parsefile->fd, parsenextc, BUFSIZ - 1);
+		nr = read(parsefile->fd, parsefile->buf, BUFSIZ);
 
 	if (nr <= 0) {
                 if (nr < 0) {
@@ -237,10 +225,16 @@
 {
 	char *p, *q;
 	int more;
-	int something;
 	char savec;
 
-	if (parsefile->strpush) {
+	while (parsefile->strpush) {
+		/*
+		 * Add a space to the end of an alias to ensure that the
+		 * alias remains in use while parsing its last word.
+		 * This avoids alias recursions.
+		 */
+		if (parsenleft == -1 && parsefile->strpush->ap != NULL)
+			return ' ';
 		popstring();
 		if (--parsenleft >= 0)
 			return (*parsenextc++);
@@ -258,10 +252,9 @@
 		}
 	}
 
-	q = p = parsenextc;
+	q = p = parsefile->buf + (parsenextc - parsefile->buf);
 
 	/* delete nul characters */
-	something = 0;
 	for (more = 1; more;) {
 		switch (*p) {
 		case '\0':
@@ -268,10 +261,6 @@
 			p++;	/* Skip nul */
 			goto check;
 
-		case '\t':
-		case ' ':
-			break;
-
 		case '\n':
 			parsenleft = q - parsenextc;
 			more = 0; /* Stop processing here */
@@ -278,7 +267,6 @@
 			break;
 
 		default:
-			something = 1;
 			break;
 		}
 
@@ -297,7 +285,8 @@
 	*q = '\0';
 
 #ifndef NO_HISTORY
-	if (parsefile->fd == 0 && hist && something) {
+	if (parsefile->fd == 0 && hist &&
+	    parsenextc[strspn(parsenextc, " \t\n")] != '\0') {
 		HistEvent he;
 		INTOFF;
 		history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
@@ -350,7 +339,7 @@
  * We handle aliases this way.
  */
 void
-pushstring(char *s, int len, void *ap)
+pushstring(char *s, int len, struct alias *ap)
 {
 	struct strpush *sp;
 
@@ -365,9 +354,9 @@
 	sp->prevstring = parsenextc;
 	sp->prevnleft = parsenleft;
 	sp->prevlleft = parselleft;
-	sp->ap = (struct alias *)ap;
+	sp->ap = ap;
 	if (ap)
-		((struct alias *)ap)->flag |= ALIASINUSE;
+		ap->flag |= ALIASINUSE;
 	parsenextc = s;
 	parsenleft = len;
 	INTON;
@@ -379,12 +368,16 @@
 	struct strpush *sp = parsefile->strpush;
 
 	INTOFF;
+	if (sp->ap) {
+		if (parsenextc != sp->ap->val &&
+		    (parsenextc[-1] == ' ' || parsenextc[-1] == '\t'))
+			forcealias();
+		sp->ap->flag &= ~ALIASINUSE;
+	}
 	parsenextc = sp->prevstring;
 	parsenleft = sp->prevnleft;
 	parselleft = sp->prevlleft;
 /*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
-	if (sp->ap)
-		sp->ap->flag &= ~ALIASINUSE;
 	parsefile->strpush = sp->prev;
 	if (sp != &(parsefile->basestrpush))
 		ckfree(sp);
@@ -403,10 +396,10 @@
 	int fd2;
 
 	INTOFF;
-	if ((fd = open(fname, O_RDONLY)) < 0)
+	if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0)
 		error("cannot open %s: %s", fname, strerror(errno));
 	if (fd < 10) {
-		fd2 = fcntl(fd, F_DUPFD, 10);
+		fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10);
 		close(fd);
 		if (fd2 < 0)
 			error("Out of file descriptors");
@@ -418,23 +411,22 @@
 
 
 /*
- * Like setinputfile, but takes an open file descriptor.  Call this with
- * interrupts off.
+ * Like setinputfile, but takes an open file descriptor (which should have
+ * its FD_CLOEXEC flag already set).  Call this with interrupts off.
  */
 
 void
 setinputfd(int fd, int push)
 {
-	(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
 	if (push) {
 		pushfile();
-		parsefile->buf = ckmalloc(BUFSIZ);
+		parsefile->buf = ckmalloc(BUFSIZ + 1);
 	}
 	if (parsefile->fd > 0)
 		close(parsefile->fd);
 	parsefile->fd = fd;
 	if (parsefile->buf == NULL)
-		parsefile->buf = ckmalloc(BUFSIZ);
+		parsefile->buf = ckmalloc(BUFSIZ + 1);
 	parselleft = parsenleft = 0;
 	plinno = 1;
 }
@@ -445,7 +437,7 @@
  */
 
 void
-setinputstring(char *string, int push)
+setinputstring(const char *string, int push)
 {
 	INTOFF;
 	if (push)

Modified: trunk/bin/sh/input.h
===================================================================
--- trunk/bin/sh/input.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/input.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)input.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/input.h 253650 2013-07-25 15:08:41Z jilles $
  */
 
 /* PEOF (the end of file marker) is defined in syntax.h */
@@ -42,20 +43,21 @@
  */
 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 */
+extern const char *parsenextc;	/* next character in input buffer */
 
+struct alias;
 struct parsefile;
 
+void resetinput(void);
 char *pfgets(char *, int);
 int pgetc(void);
 int preadbuffer(void);
 int preadateof(void);
 void pungetc(void);
-void pushstring(char *, int, void *);
+void pushstring(char *, int, struct alias *);
 void setinputfile(const char *, int);
 void setinputfd(int, int);
-void setinputstring(char *, int);
+void setinputstring(const char *, int);
 void popfile(void);
 struct parsefile *getcurrentfile(void);
 void popfilesupto(struct parsefile *);

Modified: trunk/bin/sh/jobs.c
===================================================================
--- trunk/bin/sh/jobs.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/jobs.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/jobs.c 287750 2015-09-13 13:43:08Z jilles $");
 
 #include <sys/ioctl.h>
 #include <sys/param.h>
@@ -77,24 +78,28 @@
 
 static struct job *jobtab;	/* array of jobs */
 static int njobs;		/* size of array */
-MKINIT pid_t backgndpid = -1;	/* pid of last background process */
-MKINIT struct job *bgjob = NULL; /* last background process */
+static pid_t backgndpid = -1;	/* pid of last background process */
+static struct job *bgjob = NULL; /* last background process */
 #if JOBS
 static struct job *jobmru;	/* most recently used job list */
 static pid_t initialpgrp;	/* pgrp of shell on invocation */
 #endif
-int in_waitcmd = 0;		/* are we in waitcmd()? */
-int in_dowait = 0;		/* are we in dowait()? */
-volatile sig_atomic_t breakwaitcmd = 0;	/* should wait be terminated? */
 static int ttyfd = -1;
 
+/* mode flags for dowait */
+#define DOWAIT_BLOCK	0x1 /* wait until a child exits */
+#define DOWAIT_SIG	0x2 /* if DOWAIT_BLOCK, abort on SIGINT/SIGQUIT */
+#define DOWAIT_SIG_ANY	0x4 /* if DOWAIT_SIG, abort on any signal */
+
 #if JOBS
 static void restartjob(struct job *);
 #endif
 static void freejob(struct job *);
-static struct job *getjob(char *);
+static int waitcmdloop(struct job *);
+pid_t getjobpgrp(char *);
+static struct job *getjob_nonotfound(const char *);
+static struct job *getjob(const char *);
 static pid_t dowait(int, struct job *);
-static pid_t waitproc(int, int *);
 static void checkzombies(void);
 static void cmdtxt(union node *);
 static void cmdputs(const char *);
@@ -111,7 +116,7 @@
  * Turn job control on and off.
  */
 
-MKINIT int jobctl;
+static int jobctl;
 
 #if JOBS
 void
@@ -124,11 +129,12 @@
 	if (on) {
 		if (ttyfd != -1)
 			close(ttyfd);
-		if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) {
+		if ((ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC)) < 0) {
 			i = 0;
 			while (i <= 2 && !isatty(i))
 				i++;
-			if (i > 2 || (ttyfd = fcntl(i, F_DUPFD, 10)) < 0)
+			if (i > 2 ||
+			    (ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0)
 				goto out;
 		}
 		if (ttyfd < 10) {
@@ -136,7 +142,7 @@
 			 * Keep our TTY file descriptor out of the way of
 			 * the user's redirections.
 			 */
-			if ((i = fcntl(ttyfd, F_DUPFD, 10)) < 0) {
+			if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC, 10)) < 0) {
 				close(ttyfd);
 				ttyfd = -1;
 				goto out;
@@ -144,11 +150,6 @@
 			close(ttyfd);
 			ttyfd = i;
 		}
-		if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) {
-			close(ttyfd);
-			ttyfd = -1;
-			goto out;
-		}
 		do { /* while we are in the background */
 			initialpgrp = tcgetpgrp(ttyfd);
 			if (initialpgrp < 0) {
@@ -182,13 +183,14 @@
 
 #if JOBS
 int
-fgcmd(int argc __unused, char **argv)
+fgcmd(int argc __unused, char **argv __unused)
 {
 	struct job *jp;
 	pid_t pgrp;
 	int status;
 
-	jp = getjob(argv[1]);
+	nextopt("");
+	jp = getjob(*argptr);
 	if (jp->jobctl == 0)
 		error("job not created under job control");
 	printjobcmd(jp);
@@ -209,8 +211,9 @@
 {
 	struct job *jp;
 
+	nextopt("");
 	do {
-		jp = getjob(*++argv);
+		jp = getjob(*argptr);
 		if (jp->jobctl == 0)
 			error("job not created under job control");
 		if (jp->state == JOBDONE)
@@ -219,7 +222,7 @@
 		jp->foreground = 0;
 		out1fmt("[%td] ", jp - jobtab + 1);
 		printjobcmd(jp);
-	} while (--argc > 1);
+	} while (*argptr != NULL && *++argptr != NULL);
 	return 0;
 }
 
@@ -247,15 +250,13 @@
 
 
 int
-jobscmd(int argc, char *argv[])
+jobscmd(int argc __unused, char *argv[] __unused)
 {
 	char *id;
 	int ch, mode;
 
-	optind = optreset = 1;
-	opterr = 0;
 	mode = SHOWJOBS_DEFAULT;
-	while ((ch = getopt(argc, argv, "lps")) != -1) {
+	while ((ch = nextopt("lps")) != '\0') {
 		switch (ch) {
 		case 'l':
 			mode = SHOWJOBS_VERBOSE;
@@ -266,18 +267,13 @@
 		case 's':
 			mode = SHOWJOBS_PIDS;
 			break;
-		case '?':
-		default:
-			error("unknown option: -%c", optopt);
 		}
 	}
-	argc -= optind;
-	argv += optind;
 
-	if (argc == 0)
+	if (*argptr == NULL)
 		showjobs(0, mode);
 	else
-		while ((id = *argv++) != NULL)
+		while ((id = *argptr++) != NULL)
 			showjob(getjob(id), mode);
 
 	return (0);
@@ -302,6 +298,7 @@
 {
 	char s[64];
 	char statestr[64];
+	const char *sigstr;
 	struct procstat *ps;
 	struct job *j;
 	int col, curr, i, jobno, prev, procno;
@@ -328,8 +325,9 @@
 			i = WSTOPSIG(ps->status);
 		else
 			i = -1;
-		if (i > 0 && i < sys_nsig && sys_siglist[i])
-			strcpy(statestr, sys_siglist[i]);
+		sigstr = strsignal(i);
+		if (sigstr != NULL)
+			strcpy(statestr, sigstr);
 		else
 			strcpy(statestr, "Suspended");
 #endif
@@ -341,21 +339,22 @@
 			    WEXITSTATUS(ps->status));
 	} else {
 		i = WTERMSIG(ps->status);
-		if (i > 0 && i < sys_nsig && sys_siglist[i])
-			strcpy(statestr, sys_siglist[i]);
+		sigstr = strsignal(i);
+		if (sigstr != NULL)
+			strcpy(statestr, sigstr);
 		else
-			fmtstr(statestr, 64, "Signal %d", i);
+			strcpy(statestr, "Unknown signal");
 		if (WCOREDUMP(ps->status))
 			strcat(statestr, " (core dumped)");
 	}
 
-	for (ps = jp->ps ; ; ps++) {	/* for each process */
+	for (ps = jp->ps ; procno > 0 ; ps++, procno--) { /* for each process */
 		if (mode == SHOWJOBS_PIDS || mode == SHOWJOBS_PGIDS) {
 			out1fmt("%d\n", (int)ps->pid);
-			goto skip;
+			continue;
 		}
 		if (mode != SHOWJOBS_VERBOSE && ps != jp->ps)
-			goto skip;
+			continue;
 		if (jobno == curr && ps == jp->ps)
 			c = '+';
 		else if (jobno == prev && ps == jp->ps)
@@ -386,8 +385,6 @@
 			out1c('\n');
 		} else
 			printjobcmd(jp);
-skip:		if (--procno <= 0)
-			break;
 	}
 }
 
@@ -418,13 +415,15 @@
 		if (change && ! jp->changed)
 			continue;
 		showjob(jp, mode);
-		jp->changed = 0;
-		/* Hack: discard jobs for which $! has not been referenced
-		 * in interactive mode when they terminate.
-		 */
-		if (jp->state == JOBDONE && !jp->remembered &&
-				(iflag || jp != bgjob)) {
-			freejob(jp);
+		if (mode == SHOWJOBS_DEFAULT || mode == SHOWJOBS_VERBOSE) {
+			jp->changed = 0;
+			/* Hack: discard jobs for which $! has not been
+			 * referenced in interactive mode when they terminate.
+			 */
+			if (jp->state == JOBDONE && !jp->remembered &&
+					(iflag || jp != bgjob)) {
+				freejob(jp);
+			}
 		}
 	}
 }
@@ -462,32 +461,41 @@
 waitcmd(int argc __unused, char **argv __unused)
 {
 	struct job *job;
-	int status, retval;
-	struct job *jp;
+	int retval;
 
 	nextopt("");
-	if (*argptr != NULL) {
-		job = getjob(*argptr);
-	} else {
-		job = NULL;
-	}
+	if (*argptr == NULL)
+		return (waitcmdloop(NULL));
 
+	do {
+		job = getjob_nonotfound(*argptr);
+		if (job == NULL)
+			retval = 127;
+		else
+			retval = waitcmdloop(job);
+		argptr++;
+	} while (*argptr != NULL);
+
+	return (retval);
+}
+
+static int
+waitcmdloop(struct job *job)
+{
+	int status, retval, sig;
+	struct job *jp;
+
 	/*
 	 * Loop until a process is terminated or stopped, or a SIGINT is
 	 * received.
 	 */
 
-	in_waitcmd++;
 	do {
 		if (job != NULL) {
-			if (job->state) {
+			if (job->state == JOBDONE) {
 				status = job->ps[job->nprocs - 1].status;
 				if (WIFEXITED(status))
 					retval = WEXITSTATUS(status);
-#if JOBS
-				else if (WIFSTOPPED(status))
-					retval = WSTOPSIG(status) + 128;
-#endif
 				else
 					retval = WTERMSIG(status) + 128;
 				if (! iflag || ! job->changed)
@@ -497,7 +505,6 @@
 					if (job == bgjob)
 						bgjob = NULL;
 				}
-				in_waitcmd--;
 				return retval;
 			}
 		} else {
@@ -513,7 +520,6 @@
 				}
 			for (jp = jobtab ; ; jp++) {
 				if (jp >= jobtab + njobs) {	/* no running procs */
-					in_waitcmd--;
 					return 0;
 				}
 				if (jp->used && jp->state == 0)
@@ -520,21 +526,23 @@
 					break;
 			}
 		}
-	} while (dowait(1, (struct job *)NULL) != -1);
-	in_waitcmd--;
+	} while (dowait(DOWAIT_BLOCK | DOWAIT_SIG, (struct job *)NULL) != -1);
 
-	return 0;
+	sig = pendingsig_waitcmd;
+	pendingsig_waitcmd = 0;
+	return sig + 128;
 }
 
 
 
 int
-jobidcmd(int argc __unused, char **argv)
+jobidcmd(int argc __unused, char **argv __unused)
 {
 	struct job *jp;
 	int i;
 
-	jp = getjob(argv[1]);
+	nextopt("");
+	jp = getjob(*argptr);
 	for (i = 0 ; i < jp->nprocs ; ) {
 		out1fmt("%d", (int)jp->ps[i].pid);
 		out1c(++i < jp->nprocs? ' ' : '\n');
@@ -549,7 +557,7 @@
  */
 
 static struct job *
-getjob(char *name)
+getjob_nonotfound(const char *name)
 {
 	int jobno;
 	struct job *found, *jp;
@@ -614,12 +622,22 @@
 				return jp;
 		}
 	}
-	error("No such job: %s", name);
-	/*NOTREACHED*/
 	return NULL;
 }
 
 
+static struct job *
+getjob(const char *name)
+{
+	struct job *jp;
+
+	jp = getjob_nonotfound(name);
+	if (jp == NULL)
+		error("No such job: %s", name);
+	return (jp);
+}
+
+
 pid_t
 getjobpgrp(char *name)
 {
@@ -669,7 +687,8 @@
 				jobtab = jp;
 			}
 			jp = jobtab + njobs;
-			for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
+			for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0)
+				;
 			INTON;
 			break;
 		}
@@ -958,7 +977,6 @@
 waitforjob(struct job *jp, int *origstatus)
 {
 #if JOBS
-	pid_t mypgrp = getpgrp();
 	int propagate_int = jp->jobctl && jp->foreground;
 #endif
 	int status;
@@ -967,11 +985,12 @@
 	INTOFF;
 	TRACE(("waitforjob(%%%td) called\n", jp - jobtab + 1));
 	while (jp->state == 0)
-		if (dowait(1, jp) == -1)
+		if (dowait(DOWAIT_BLOCK | (Tflag ? DOWAIT_SIG |
+		    DOWAIT_SIG_ANY : 0), jp) == -1)
 			dotrap();
 #if JOBS
 	if (jp->jobctl) {
-		if (tcsetpgrp(ttyfd, mypgrp) < 0)
+		if (tcsetpgrp(ttyfd, rootpid) < 0)
 			error("tcsetpgrp failed, errno=%d\n", errno);
 	}
 	if (jp->state == JOBSTOPPED)
@@ -1005,6 +1024,10 @@
 }
 
 
+static void
+dummy_handler(int sig __unused)
+{
+}
 
 /*
  * Wait for a process to terminate.
@@ -1011,32 +1034,67 @@
  */
 
 static pid_t
-dowait(int block, struct job *job)
+dowait(int mode, struct job *job)
 {
+	struct sigaction sa, osa;
+	sigset_t mask, omask;
 	pid_t pid;
 	int status;
 	struct procstat *sp;
 	struct job *jp;
 	struct job *thisjob;
+	const char *sigstr;
 	int done;
 	int stopped;
 	int sig;
 	int coredump;
+	int wflags;
+	int restore_sigchld;
 
-	in_dowait++;
-	TRACE(("dowait(%d) called\n", block));
+	TRACE(("dowait(%d, %p) called\n", mode, job));
+	restore_sigchld = 0;
+	if ((mode & DOWAIT_SIG) != 0) {
+		sigfillset(&mask);
+		sigprocmask(SIG_BLOCK, &mask, &omask);
+		INTOFF;
+		if (!issigchldtrapped()) {
+			restore_sigchld = 1;
+			sa.sa_handler = dummy_handler;
+			sa.sa_flags = 0;
+			sigemptyset(&sa.sa_mask);
+			sigaction(SIGCHLD, &sa, &osa);
+		}
+	}
 	do {
-		pid = waitproc(block, &status);
+#if JOBS
+		if (iflag)
+			wflags = WUNTRACED | WCONTINUED;
+		else
+#endif
+			wflags = 0;
+		if ((mode & (DOWAIT_BLOCK | DOWAIT_SIG)) != DOWAIT_BLOCK)
+			wflags |= WNOHANG;
+		pid = wait3(&status, wflags, (struct rusage *)NULL);
 		TRACE(("wait returns %d, status=%d\n", (int)pid, status));
-	} while ((pid == -1 && errno == EINTR && breakwaitcmd == 0) ||
-		 (pid > 0 && WIFSTOPPED(status) && !iflag));
-	in_dowait--;
+		if (pid == 0 && (mode & DOWAIT_SIG) != 0) {
+			pid = -1;
+			if (((mode & DOWAIT_SIG_ANY) != 0 ?
+			    pendingsig : pendingsig_waitcmd) != 0) {
+				errno = EINTR;
+				break;
+			}
+			sigsuspend(&omask);
+			if (int_pending())
+				break;
+		}
+	} while (pid == -1 && errno == EINTR);
 	if (pid == -1 && errno == ECHILD && job != NULL)
 		job->state = JOBDONE;
-	if (breakwaitcmd != 0) {
-		breakwaitcmd = 0;
-		if (pid <= 0)
-			return -1;
+	if ((mode & DOWAIT_SIG) != 0) {
+		if (restore_sigchld)
+			sigaction(SIGCHLD, &osa, NULL);
+		sigprocmask(SIG_SETMASK, &omask, NULL);
+		INTON;
 	}
 	if (pid <= 0)
 		return pid;
@@ -1053,7 +1111,11 @@
 					TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
 						   (int)pid, sp->status,
 						   status));
-					sp->status = status;
+					if (WIFCONTINUED(status)) {
+						sp->status = -1;
+						jp->state = 0;
+					} else
+						sp->status = status;
 					thisjob = jp;
 				}
 				if (sp->status == -1)
@@ -1092,10 +1154,11 @@
 				coredump = WCOREDUMP(sp->status);
 			}
 		if (sig > 0 && sig != SIGINT && sig != SIGPIPE) {
-			if (sig < sys_nsig && sys_siglist[sig])
-				out2str(sys_siglist[sig]);
+			sigstr = strsignal(sig);
+			if (sigstr != NULL)
+				out2str(sigstr);
 			else
-				outfmt(out2, "Signal %d", sig);
+				out2str("Unknown signal");
 			if (coredump)
 				out2str(" (core dumped)");
 			out2c('\n');
@@ -1111,26 +1174,6 @@
 
 
 /*
- * Do a wait system call.  If job control is compiled in, we accept
- * stopped processes.  If block is zero, we return a value of zero
- * rather than blocking.
- */
-static pid_t
-waitproc(int block, int *status)
-{
-	int flags;
-
-#if JOBS
-	flags = WUNTRACED;
-#else
-	flags = 0;
-#endif
-	if (block == 0)
-		flags |= WNOHANG;
-	return wait3(status, flags, (struct rusage *)NULL);
-}
-
-/*
  * return 1 if there are stopped jobs, otherwise 0
  */
 int job_warning = 0;
@@ -1276,6 +1319,10 @@
 		cmdputs(n->narg.text);
 		cmdputs("() ...");
 		break;
+	case NNOT:
+		cmdputs("! ");
+		cmdtxt(n->nnot.com);
+		break;
 	case NCMD:
 		for (np = n->ncmd.args ; np ; np = np->narg.next) {
 			cmdtxt(np);

Modified: trunk/bin/sh/jobs.h
===================================================================
--- trunk/bin/sh/jobs.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/jobs.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)jobs.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/jobs.h 255157 2013-09-02 21:57:46Z jilles $
  */
 
 /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
@@ -84,9 +84,6 @@
 };
 
 extern int job_warning;		/* user was warned about stopped jobs */
-extern int in_waitcmd;		/* are we in waitcmd()? */
-extern int in_dowait;		/* are we in dowait()? */
-extern volatile sig_atomic_t breakwaitcmd; /* break wait to process traps? */
 
 void setjobctl(int);
 void showjobs(int, int);

Modified: trunk/bin/sh/mail.c
===================================================================
--- trunk/bin/sh/mail.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/mail.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/mail.c 213760 2010-10-13 04:01:01Z obrien $");
 
 /*
  * Routines to check for mail.  (Perhaps make part of main.c?)

Modified: trunk/bin/sh/mail.h
===================================================================
--- trunk/bin/sh/mail.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/mail.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)mail.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/mail.h 127958 2004-04-06 20:06:54Z markm $
  */
 
 void chkmail(int);

Modified: trunk/bin/sh/main.c
===================================================================
--- trunk/bin/sh/main.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/main.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -42,7 +43,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/main.c 255215 2013-09-04 22:10:16Z jilles $");
 
 #include <stdio.h>
 #include <signal.h>
@@ -68,10 +69,10 @@
 #include "show.h"
 #include "memalloc.h"
 #include "error.h"
-#include "init.h"
 #include "mystring.h"
 #include "exec.h"
 #include "cd.h"
+#include "redir.h"
 #include "builtins.h"
 
 int rootpid;
@@ -79,8 +80,9 @@
 struct jmploc main_handler;
 int localeisutf8, initial_localeisutf8;
 
+static void reset(void);
 static void cmdloop(int);
-static void read_profile(char *);
+static void read_profile(const char *);
 static char *find_dot_file(char *);
 
 /*
@@ -139,7 +141,7 @@
 #endif
 	rootpid = getpid();
 	rootshell = 1;
-	init();
+	initvar();
 	setstackmark(&smark);
 	setstackmark(&smark2);
 	procargs(argc, argv);
@@ -170,8 +172,8 @@
 	if (minusc) {
 		evalstring(minusc, sflag ? 0 : EV_EXIT);
 	}
+state4:
 	if (sflag || minusc == NULL) {
-state4:	/* XXX ??? - why isn't this before the "if" statement */
 		cmdloop(1);
 	}
 	exitshell(exitstatus);
@@ -179,6 +181,12 @@
 	return 0;
 }
 
+static void
+reset(void)
+{
+	reseteval();
+	resetinput();
+}
 
 /*
  * Read and execute commands.  "Top" is nonzero for the top level command
@@ -196,7 +204,7 @@
 	TRACE(("cmdloop(%d) called\n", top));
 	setstackmark(&smark);
 	for (;;) {
-		if (pendingsigs)
+		if (pendingsig)
 			dotrap();
 		inter = 0;
 		if (iflag && top) {
@@ -224,7 +232,7 @@
 		popstackmark(&smark);
 		setstackmark(&smark);
 		if (evalskip != 0) {
-			if (evalskip == SKIPFILE)
+			if (evalskip == SKIPRETURN)
 				evalskip = 0;
 			break;
 		}
@@ -239,7 +247,7 @@
  */
 
 static void
-read_profile(char *name)
+read_profile(const char *name)
 {
 	int fd;
 	const char *expandedname;
@@ -248,7 +256,7 @@
 	if (expandedname == NULL)
 		return;
 	INTOFF;
-	if ((fd = open(expandedname, O_RDONLY)) >= 0)
+	if ((fd = open(expandedname, O_RDONLY | O_CLOEXEC)) >= 0)
 		setinputfd(fd, 1);
 	INTON;
 	if (fd < 0)

Modified: trunk/bin/sh/main.h
===================================================================
--- trunk/bin/sh/main.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/main.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)main.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/main.h 229220 2012-01-01 22:17:12Z jilles $
  */
 
 extern int rootpid;	/* pid of main shell */

Modified: trunk/bin/sh/memalloc.c
===================================================================
--- trunk/bin/sh/memalloc.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/memalloc.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/memalloc.c 297749 2016-04-09 14:09:14Z jilles $");
 
 #include <sys/param.h>
 #include "shell.h"
@@ -98,9 +99,11 @@
 savestr(const char *s)
 {
 	char *p;
+	size_t len;
 
-	p = ckmalloc(strlen(s) + 1);
-	scopy(s, p);
+	len = strlen(s);
+	p = ckmalloc(len + 1);
+	memcpy(p, s, len + 1);
 	return p;
 }
 
@@ -124,7 +127,6 @@
 #define SPACE(sp)	((char*)(sp) + ALIGN(sizeof(struct stack_block)))
 
 static struct stack_block *stackp;
-static struct stackmark *markp;
 char *stacknxt;
 int stacknleft;
 char *sstrend;
@@ -179,7 +181,19 @@
 }
 
 
+char *
+stsavestr(const char *s)
+{
+	char *p;
+	size_t len;
 
+	len = strlen(s);
+	p = stalloc(len + 1);
+	memcpy(p, s, len + 1);
+	return p;
+}
+
+
 void
 setstackmark(struct stackmark *mark)
 {
@@ -186,8 +200,9 @@
 	mark->stackp = stackp;
 	mark->stacknxt = stacknxt;
 	mark->stacknleft = stacknleft;
-	mark->marknext = markp;
-	markp = mark;
+	/* Ensure this block stays in place. */
+	if (stackp != NULL && stacknxt == SPACE(stackp))
+		stalloc(1);
 }
 
 
@@ -197,7 +212,6 @@
 	struct stack_block *sp;
 
 	INTOFF;
-	markp = mark->marknext;
 	while (stackp != mark->stackp) {
 		sp = stackp;
 		stackp = sp->prev;
@@ -229,11 +243,11 @@
 	int oldlen;
 	struct stack_block *sp;
 	struct stack_block *oldstackp;
-	struct stackmark *xmark;
 
 	if (min < stacknleft)
 		min = stacknleft;
-	if (min >= INT_MAX / 2 - ALIGN(sizeof(struct stack_block)))
+	if ((unsigned int)min >=
+	    INT_MAX / 2 - ALIGN(sizeof(struct stack_block)))
 		error("Out of space");
 	min += stacknleft;
 	min += ALIGN(sizeof(struct stack_block));
@@ -253,18 +267,6 @@
 		stacknxt = SPACE(sp);
 		stacknleft = newlen - (stacknxt - (char*)sp);
 		sstrend = stacknxt + stacknleft;
-
-		/*
-		 * Stack marks pointing to the start of the old block
-		 * must be relocated to point to the new block
-		 */
-		xmark = markp;
-		while (xmark != NULL && xmark->stackp == oldstackp) {
-			xmark->stackp = stackp;
-			xmark->stacknxt = stacknxt;
-			xmark->stacknleft = stacknleft;
-			xmark = xmark->marknext;
-		}
 		INTON;
 	} else {
 		newlen -= ALIGN(sizeof(struct stack_block));
@@ -327,7 +329,7 @@
 
 
 char *
-stputbin(const char *data, int len, char *p)
+stputbin(const char *data, size_t len, char *p)
 {
 	CHECKSTRSPACE(len, p);
 	memcpy(p, data, len);

Modified: trunk/bin/sh/memalloc.h
===================================================================
--- trunk/bin/sh/memalloc.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/memalloc.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)memalloc.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/memalloc.h 297749 2016-04-09 14:09:14Z jilles $
  */
 
 #include <string.h>
@@ -39,7 +40,6 @@
 	struct stack_block *stackp;
 	char *stacknxt;
 	int stacknleft;
-        struct stackmark *marknext;
 };
 
 
@@ -53,11 +53,12 @@
 char *savestr(const char *);
 pointer stalloc(int);
 void stunalloc(pointer);
+char *stsavestr(const char *);
 void setstackmark(struct stackmark *);
 void popstackmark(struct stackmark *);
 char *growstackstr(void);
 char *makestrspace(int, char *);
-char *stputbin(const char *data, int len, char *p);
+char *stputbin(const char *data, size_t len, char *p);
 char *stputs(const char *data, char *p);
 
 
@@ -67,7 +68,7 @@
 #define grabstackblock(n) stalloc(n)
 #define STARTSTACKSTR(p)	p = stackblock()
 #define STPUTC(c, p)	do { if (p == sstrend) p = growstackstr(); *p++ = (c); } while(0)
-#define CHECKSTRSPACE(n, p)	{ if (sstrend - p < n) p = makestrspace(n, p); }
+#define CHECKSTRSPACE(n, p)	{ if ((size_t)(sstrend - p) < n) p = makestrspace(n, p); }
 #define USTPUTC(c, p)	(*p++ = (c))
 /*
  * STACKSTRNUL's use is where we want to be able to turn a stack

Modified: trunk/bin/sh/miscbltin.c
===================================================================
--- trunk/bin/sh/miscbltin.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/miscbltin.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/miscbltin.c 250214 2013-05-03 15:28:31Z jilles $");
 
 /*
  * Miscellaneous builtins.
@@ -47,12 +48,10 @@
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <unistd.h>
-#include <ctype.h>
 #include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <termios.h>
 
 #include "shell.h"
 #include "options.h"
@@ -61,6 +60,8 @@
 #include "memalloc.h"
 #include "error.h"
 #include "mystring.h"
+#include "syntax.h"
+#include "trap.h"
 
 #undef eflag
 
@@ -103,6 +104,8 @@
 	struct timeval tv;
 	char *tvptr;
 	fd_set ifds;
+	ssize_t nread;
+	int sig;
 
 	rflag = 0;
 	prompt = NULL;
@@ -157,8 +160,10 @@
 		/*
 		 * If there's nothing ready, return an error.
 		 */
-		if (status <= 0)
-			return(1);
+		if (status <= 0) {
+			sig = pendingsig;
+			return (128 + (sig != 0 ? sig : SIGALRM));
+		}
 	}
 
 	status = 0;
@@ -166,7 +171,19 @@
 	backslash = 0;
 	STARTSTACKSTR(p);
 	for (;;) {
-		if (read(STDIN_FILENO, &c, 1) != 1) {
+		nread = read(STDIN_FILENO, &c, 1);
+		if (nread == -1) {
+			if (errno == EINTR) {
+				sig = pendingsig;
+				if (sig == 0)
+					continue;
+				status = 128 + sig;
+				break;
+			}
+			warning("read error: %s", strerror(errno));
+			status = 2;
+			break;
+		} else if (nread != 1) {
 			status = 1;
 			break;
 		}
@@ -308,7 +325,7 @@
 			out1fmt("%.4o\n", mask);
 		}
 	} else {
-		if (isdigit(*ap)) {
+		if (is_digit(*ap)) {
 			mask = 0;
 			do {
 				if (*ap >= '8' || *ap < '0')
@@ -389,9 +406,6 @@
 #ifdef RLIMIT_NPTS
 	{ "pseudo-terminals",	(char *)0,	RLIMIT_NPTS,	   1, 'p' },
 #endif
-#ifdef RLIMIT_KQUEUES
-	{ "kqueues",		(char *)0,	RLIMIT_KQUEUES,	   1, 'k' },
-#endif
 	{ (char *) 0,		(char *)0,	0,		   0, '\0' }
 };
 
@@ -408,7 +422,7 @@
 	struct rlimit	limit;
 
 	what = 'f';
-	while ((optc = nextopt("HSatfdsmcnuvlbpwk")) != '\0')
+	while ((optc = nextopt("HSatfdsmcnuvlbpw")) != '\0')
 		switch (optc) {
 		case 'H':
 			how = HARD;

Modified: trunk/bin/sh/mkbuiltins
===================================================================
--- trunk/bin/sh/mkbuiltins	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/mkbuiltins	2018-06-02 21:06:59 UTC (rev 10240)
@@ -32,20 +32,20 @@
 # SUCH DAMAGE.
 #
 #	@(#)mkbuiltins	8.2 (Berkeley) 5/4/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/mkbuiltins 235927 2012-05-24 19:48:15Z marcel $
 
 temp=`/usr/bin/mktemp -t ka`
-havejobs=0
-if grep '^#define[	 ]*JOBS[	 ]*1' shell.h > /dev/null
-then	havejobs=1
-fi
 havehist=1
 if [ "X$1" = "X-h" ]; then
 	havehist=0
 	shift
 fi
-objdir=$1
-exec > ${objdir}/builtins.c
+srcdir=$1
+havejobs=0
+if grep '^#define[	 ]*JOBS[	 ]*1' $srcdir/shell.h > /dev/null
+then	havejobs=1
+fi
+exec > builtins.c
 cat <<\!
 /*
  * This file was generated by the mkbuiltins program.
@@ -57,7 +57,7 @@
 
 !
 awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \
-    print $0}' builtins.def | sed 's/-[hj]//' > $temp
+    print $0}' $srcdir/builtins.def | sed 's/-[hj]//' > $temp
 echo 'int (*const builtinfunc[])(int, char **) = {'
 awk '/^[^#]/ {	printf "\t%s,\n", $1}' $temp
 echo '};
@@ -74,7 +74,7 @@
 echo '	{ NULL, 0, 0 }
 };'
 
-exec > ${objdir}/builtins.h
+exec > builtins.h
 cat <<\!
 /*
  * This file was generated by the mkbuiltins program.


Property changes on: trunk/bin/sh/mkbuiltins
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Modified: trunk/bin/sh/mknodes.c
===================================================================
--- trunk/bin/sh/mknodes.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/mknodes.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -43,7 +43,7 @@
 #endif /* not lint */
 #endif
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/mknodes.c 292786 2015-12-27 17:53:39Z jilles $");
 
 /*
  * This program reads the nodetypes file and nodes.c.pat file.  It generates
@@ -90,7 +90,6 @@
 static int nstr;			/* number of structures */
 static struct str str[MAXTYPES];	/* the structures */
 static struct str *curstr;		/* current structure */
-static FILE *infp;
 static char line[1024];
 static int linno;
 static char *linep;
@@ -103,7 +102,7 @@
 static void indent(int, FILE *);
 static int nextfield(char *);
 static void skipbl(void);
-static int readline(void);
+static int readline(FILE *);
 static void error(const char *, ...) __printf0like(1, 2) __dead2;
 static char *savestr(const char *);
 
@@ -111,17 +110,19 @@
 int
 main(int argc, char *argv[])
 {
+	FILE *infp;
+
 	if (argc != 3)
 		error("usage: mknodes file");
-	infp = stdin;
 	if ((infp = fopen(argv[1], "r")) == NULL)
 		error("Can't open %s: %s", argv[1], strerror(errno));
-	while (readline()) {
+	while (readline(infp)) {
 		if (line[0] == ' ' || line[0] == '\t')
 			parsefield();
 		else if (line[0] != '\0')
 			parsenode();
 	}
+	fclose(infp);
 	output(argv[2]);
 	exit(0);
 }
@@ -254,6 +255,10 @@
 	fputs("union node *getfuncnode(struct funcdef *);\n", hfile);
 	fputs("void reffunc(struct funcdef *);\n", hfile);
 	fputs("void unreffunc(struct funcdef *);\n", hfile);
+	if (ferror(hfile))
+		error("Can't write to nodes.h");
+	if (fclose(hfile))
+		error("Can't close nodes.h");
 
 	fputs(writer, cfile);
 	while (fgets(line, sizeof line, patfile) != NULL) {
@@ -267,6 +272,11 @@
 		else
 			fputs(line, cfile);
 	}
+	fclose(patfile);
+	if (ferror(cfile))
+		error("Can't write to nodes.c");
+	if (fclose(cfile))
+		error("Can't close nodes.c");
 }
 
 
@@ -402,7 +412,7 @@
 
 
 static int
-readline(void)
+readline(FILE *infp)
 {
 	char *p;
 

Modified: trunk/bin/sh/mksyntax.c
===================================================================
--- trunk/bin/sh/mksyntax.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/mksyntax.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -43,7 +43,7 @@
 #endif /* not lint */
 #endif
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/mksyntax.c 246522 2013-02-07 22:42:33Z jilles $");
 
 /*
  * This program creates syntax.h and syntax.c.
@@ -190,8 +190,8 @@
 	add("`", "CBQUOTE");
 	add("$", "CVAR");
 	add("}", "CENDVAR");
-	/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
-	add("!*?[=~:/-", "CCTL");
+	/* ':/' for tilde expansion, '-^]' for [a\-x] pattern ranges */
+	add("!*?[]=~:/-^", "CCTL");
 	finish();
 
 	fputs("\n/* syntax table used when in single quotes */\n", cfile);
@@ -200,8 +200,8 @@
 	add("\n", "CNL");
 	add("\\", "CSBACK");
 	add("'", "CENDQUOTE");
-	/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
-	add("!*?[=~:/-", "CCTL");
+	/* ':/' for tilde expansion, '-^]' for [a\-x] pattern ranges */
+	add("!*?[]=~:/-^", "CCTL");
 	finish();
 
 	fputs("\n/* syntax table used when in arithmetic */\n", cfile);

Modified: trunk/bin/sh/mktokens
===================================================================
--- trunk/bin/sh/mktokens	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/mktokens	2018-06-02 21:06:59 UTC (rev 10240)
@@ -32,7 +32,7 @@
 # SUCH DAMAGE.
 #
 #	@(#)mktokens	8.1 (Berkeley) 5/31/93
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/mktokens 223186 2011-06-17 13:03:49Z jilles $
 
 # The following is a list of tokens.  The second column is nonzero if the
 # token marks the end of a list.  The third column is the name to print in


Property changes on: trunk/bin/sh/mktokens
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/myhistedit.h
===================================================================
--- trunk/bin/sh/myhistedit.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/myhistedit.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -28,7 +28,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)myhistedit.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/myhistedit.h 229220 2012-01-01 22:17:12Z jilles $
  */
 
 #include <histedit.h>

Modified: trunk/bin/sh/mystring.c
===================================================================
--- trunk/bin/sh/mystring.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/mystring.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,13 +37,12 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/mystring.c 262951 2014-03-09 17:04:31Z jmmv $");
 
 /*
  * String functions.
  *
  *	equal(s1, s2)		Return true if strings are equal.
- *	scopy(from, to)		Copy a string.
  *	number(s)		Convert a string of digits to an integer.
  *	is_number(s)		Return true if s is a string of digits.
  */
@@ -60,11 +60,7 @@
  * equal - #defined in mystring.h
  */
 
-/*
- * scopy - #defined in mystring.h
- */
 
-
 /*
  * prefix -- see if pfx is a prefix of string.
  */

Modified: trunk/bin/sh/mystring.h
===================================================================
--- trunk/bin/sh/mystring.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/mystring.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)mystring.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/mystring.h 262951 2014-03-09 17:04:31Z jmmv $
  */
 
 #include <string.h>
@@ -40,4 +41,3 @@
 int is_number(const char *);
 
 #define equal(s1, s2)	(strcmp(s1, s2) == 0)
-#define scopy(s1, s2)	((void)strcpy(s2, s1))

Modified: trunk/bin/sh/nodes.c.pat
===================================================================
--- trunk/bin/sh/nodes.c.pat	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/nodes.c.pat	2018-06-02 21:06:59 UTC (rev 10240)
@@ -30,7 +30,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)nodes.c.pat	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/nodes.c.pat 249235 2013-04-07 16:28:36Z jilles $
  */
 
 #include <sys/param.h>
@@ -58,7 +58,7 @@
 static void sizenodelist(struct nodelist *);
 static union node *copynode(union node *);
 static struct nodelist *copynodelist(struct nodelist *);
-static char *nodesavestr(char *);
+static char *nodesavestr(const char *);
 
 
 struct funcdef {
@@ -147,9 +147,9 @@
 
 
 static char *
-nodesavestr(char *s)
+nodesavestr(const char *s)
 {
-	char *p = s;
+	const char *p = s;
 	char *q = funcstring;
 	char   *rtn = funcstring;
 


Property changes on: trunk/bin/sh/nodes.c.pat
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/nodetypes
===================================================================
--- trunk/bin/sh/nodetypes	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/nodetypes	2018-06-02 21:06:59 UTC (rev 10240)
@@ -30,7 +30,7 @@
 # SUCH DAMAGE.
 #
 #	@(#)nodetypes	8.2 (Berkeley) 5/4/95
-# $MidnightBSD$
+# $FreeBSD: stable/10/bin/sh/nodetypes 262951 2014-03-09 17:04:31Z jmmv $
 
 # This file describes the nodes used in parse trees.  Unindented lines
 # contain a node type followed by a structure tag.  Subsequent indented
@@ -118,8 +118,8 @@
 NAPPEND nfile			# fd>> fname
 NCLOBBER nfile			# fd>| fname
 	type	  int
+	fd	  int			# file descriptor being redirected
 	next	  nodeptr		# next redirection in list
-	fd	  int			# file descriptor being redirected
 	fname	  nodeptr		# file name, in a NARG node
 	expfname  temp	char *expfname	# actual file name
 
@@ -126,8 +126,8 @@
 NTOFD ndup			# fd<&dupfd
 NFROMFD ndup			# fd>&dupfd
 	type	  int
+	fd	  int			# file descriptor being redirected
 	next	  nodeptr		# next redirection in list
-	fd	  int			# file descriptor being redirected
 	dupfd	  int			# file descriptor to duplicate
 	vname	  nodeptr		# file name if fd>&$var
 
@@ -135,9 +135,10 @@
 NHERE nhere			# fd<<\!
 NXHERE nhere			# fd<<!
 	type	  int
+	fd	  int			# file descriptor being redirected
 	next	  nodeptr		# next redirection in list
-	fd	  int			# file descriptor being redirected
 	doc	  nodeptr		# input to command (NARG node)
+	expdoc    temp	char *expdoc	# actual document (for NXHERE)
 
 NNOT nnot			# ! command  (actually pipeline)
 	type	int


Property changes on: trunk/bin/sh/nodetypes
___________________________________________________________________
Added: mnbsd:nokeywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/options.c
===================================================================
--- trunk/bin/sh/options.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/options.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/options.c 240247 2012-09-08 19:24:03Z jilles $");
 
 #include <signal.h>
 #include <unistd.h>
@@ -401,9 +402,10 @@
 void
 getoptsreset(const char *value)
 {
-	if (number(value) == 1) {
+	while (*value == '0')
+		value++;
+	if (strcmp(value, "1") == 0)
 		shellparam.reset = 1;
-	}
 }
 
 /*
@@ -530,10 +532,6 @@
 }
 
 /*
- * XXX - should get rid of.  have all builtins use getopt(3).  the
- * library getopt must have the BSD extension static variable "optreset"
- * otherwise it can't be used within the shell safely.
- *
  * Standard option processing (a la getopt) for builtin routines.  The
  * only argument that is passed to nextopt is the option string; the
  * other arguments are unnecessary.  It return the character, or '\0' on

Modified: trunk/bin/sh/options.h
===================================================================
--- trunk/bin/sh/options.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/options.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)options.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/options.h 223281 2011-06-18 23:43:28Z jilles $
  */
 
 struct shparam {

Modified: trunk/bin/sh/output.c
===================================================================
--- trunk/bin/sh/output.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/output.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/output.c 253649 2013-07-25 13:09:17Z jilles $");
 
 /*
  * Shell output routines.  We use our own output routines because:
@@ -75,25 +76,6 @@
 struct output *out1 = &output;
 struct output *out2 = &errout;
 
-
-
-#ifdef mkinit
-
-INCLUDE "output.h"
-INCLUDE "memalloc.h"
-
-RESET {
-	out1 = &output;
-	out2 = &errout;
-	if (memout.buf != NULL) {
-		ckfree(memout.buf);
-		memout.buf = NULL;
-	}
-}
-
-#endif
-
-
 void
 outcslow(int c, struct output *file)
 {
@@ -239,7 +221,21 @@
 }
 
 
+int
+outiserror(struct output *file)
+{
+	return (file->flags & OUTPUT_ERR);
+}
+
+
 void
+outclearerror(struct output *file)
+{
+	file->flags &= ~OUTPUT_ERR;
+}
+
+
+void
 outfmt(struct output *file, const char *fmt, ...)
 {
 	va_list ap;

Modified: trunk/bin/sh/output.h
===================================================================
--- trunk/bin/sh/output.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/output.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)output.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/output.h 244162 2012-12-12 22:01:10Z jilles $
  */
 
 #ifndef OUTPUT_INCL
@@ -66,6 +67,8 @@
 void flushall(void);
 void flushout(struct output *);
 void freestdout(void);
+int outiserror(struct output *);
+void outclearerror(struct output *);
 void outfmt(struct output *, const char *, ...) __printflike(2, 3);
 void out1fmt(const char *, ...) __printflike(1, 2);
 void out2fmt_flush(const char *, ...) __printflike(1, 2);

Modified: trunk/bin/sh/parser.c
===================================================================
--- trunk/bin/sh/parser.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/parser.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/parser.c 301571 2016-06-08 01:17:22Z truckman $");
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -97,9 +97,9 @@
 static int doprompt;		/* if set, prompt the user */
 static int needprompt;		/* true if interactive and at start of line */
 static int lasttoken;		/* last token read */
-MKINIT int tokpushback;		/* last token pushed back */
+static int tokpushback;		/* last token pushed back */
 static char *wordtext;		/* text of last word returned by readtoken */
-MKINIT int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
+static int checkkwd;
 static struct nodelist *backquotelist;
 static union node *redirnode;
 static struct heredoc *heredoc;
@@ -109,19 +109,21 @@
 static struct parser_temp *parser_temp;
 
 
-static union node *list(int, int);
+static union node *list(int);
 static union node *andor(void);
 static union node *pipeline(void);
 static union node *command(void);
 static union node *simplecmd(union node **, union node *);
 static union node *makename(void);
+static union node *makebinary(int type, union node *n1, union node *n2);
 static void parsefname(void);
 static void parseheredoc(void);
 static int peektoken(void);
 static int readtoken(void);
 static int xxreadtoken(void);
-static int readtoken1(int, char const *, char *, int);
+static int readtoken1(int, const char *, const char *, int);
 static int noexpand(char *);
+static void consumetoken(int);
 static void synexpect(int) __dead2;
 static void synerror(const char *) __dead2;
 static void setprompt(int);
@@ -211,6 +213,7 @@
 	heredoclist = NULL;
 
 	tokpushback = 0;
+	checkkwd = 0;
 	doprompt = interact;
 	if (doprompt)
 		setprompt(1);
@@ -223,18 +226,51 @@
 	if (t == TNL)
 		return NULL;
 	tokpushback++;
-	return list(1, 1);
+	return list(1);
 }
 
 
+/*
+ * Read and parse words for wordexp.
+ * Returns a list of NARG nodes; NULL if there are no words.
+ */
+union node *
+parsewordexp(void)
+{
+	union node *n, *first = NULL, **pnext;
+	int t;
+
+	/* This assumes the parser is not re-entered,
+	 * which could happen if we add command substitution on PS1/PS2.
+	 */
+	parser_temp_free_all();
+	heredoclist = NULL;
+
+	tokpushback = 0;
+	checkkwd = 0;
+	doprompt = 0;
+	setprompt(0);
+	needprompt = 0;
+	pnext = &first;
+	while ((t = readtoken()) != TEOF) {
+		if (t != TWORD)
+			synexpect(TWORD);
+		n = makename();
+		*pnext = n;
+		pnext = &n->narg.next;
+	}
+	return first;
+}
+
+
 static union node *
-list(int nlflag, int erflag)
+list(int nlflag)
 {
 	union node *ntop, *n1, *n2, *n3;
 	int tok;
 
 	checkkwd = CHKNL | CHKKWD | CHKALIAS;
-	if (!nlflag && !erflag && tokendlist[peektoken()])
+	if (!nlflag && tokendlist[peektoken()])
 		return NULL;
 	ntop = n1 = NULL;
 	for (;;) {
@@ -256,17 +292,11 @@
 		if (ntop == NULL)
 			ntop = n2;
 		else if (n1 == NULL) {
-			n1 = (union node *)stalloc(sizeof (struct nbinary));
-			n1->type = NSEMI;
-			n1->nbinary.ch1 = ntop;
-			n1->nbinary.ch2 = n2;
+			n1 = makebinary(NSEMI, ntop, n2);
 			ntop = n1;
 		}
 		else {
-			n3 = (union node *)stalloc(sizeof (struct nbinary));
-			n3->type = NSEMI;
-			n3->nbinary.ch1 = n1->nbinary.ch2;
-			n3->nbinary.ch2 = n2;
+			n3 = makebinary(NSEMI, n1->nbinary.ch2, n2);
 			n1->nbinary.ch2 = n3;
 			n1 = n3;
 		}
@@ -287,7 +317,7 @@
 				tokpushback++;
 			}
 			checkkwd = CHKNL | CHKKWD | CHKALIAS;
-			if (!nlflag && !erflag && tokendlist[peektoken()])
+			if (!nlflag && tokendlist[peektoken()])
 				return ntop;
 			break;
 		case TEOF:
@@ -297,7 +327,7 @@
 				pungetc();		/* push back EOF on input */
 			return ntop;
 		default:
-			if (nlflag || erflag)
+			if (nlflag)
 				synexpect(-1);
 			tokpushback++;
 			return ntop;
@@ -310,10 +340,10 @@
 static union node *
 andor(void)
 {
-	union node *n1, *n2, *n3;
+	union node *n;
 	int t;
 
-	n1 = pipeline();
+	n = pipeline();
 	for (;;) {
 		if ((t = readtoken()) == TAND) {
 			t = NAND;
@@ -321,14 +351,9 @@
 			t = NOR;
 		} else {
 			tokpushback++;
-			return n1;
+			return n;
 		}
-		n2 = pipeline();
-		n3 = (union node *)stalloc(sizeof (struct nbinary));
-		n3->type = t;
-		n3->nbinary.ch1 = n1;
-		n3->nbinary.ch2 = n2;
-		n1 = n3;
+		n = makebinary(t, n, pipeline());
 	}
 }
 
@@ -410,49 +435,39 @@
 	case TIF:
 		n1 = (union node *)stalloc(sizeof (struct nif));
 		n1->type = NIF;
-		if ((n1->nif.test = list(0, 0)) == NULL)
+		if ((n1->nif.test = list(0)) == NULL)
 			synexpect(-1);
-		if (readtoken() != TTHEN)
-			synexpect(TTHEN);
-		n1->nif.ifpart = list(0, 0);
+		consumetoken(TTHEN);
+		n1->nif.ifpart = list(0);
 		n2 = n1;
 		while (readtoken() == TELIF) {
 			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
 			n2 = n2->nif.elsepart;
 			n2->type = NIF;
-			if ((n2->nif.test = list(0, 0)) == NULL)
+			if ((n2->nif.test = list(0)) == NULL)
 				synexpect(-1);
-			if (readtoken() != TTHEN)
-				synexpect(TTHEN);
-			n2->nif.ifpart = list(0, 0);
+			consumetoken(TTHEN);
+			n2->nif.ifpart = list(0);
 		}
 		if (lasttoken == TELSE)
-			n2->nif.elsepart = list(0, 0);
+			n2->nif.elsepart = list(0);
 		else {
 			n2->nif.elsepart = NULL;
 			tokpushback++;
 		}
-		if (readtoken() != TFI)
-			synexpect(TFI);
+		consumetoken(TFI);
 		checkkwd = CHKKWD | CHKALIAS;
 		break;
 	case TWHILE:
-	case TUNTIL: {
-		int got;
-		n1 = (union node *)stalloc(sizeof (struct nbinary));
-		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
-		if ((n1->nbinary.ch1 = list(0, 0)) == NULL)
+	case TUNTIL:
+		t = lasttoken;
+		if ((n1 = list(0)) == NULL)
 			synexpect(-1);
-		if ((got=readtoken()) != TDO) {
-TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
-			synexpect(TDO);
-		}
-		n1->nbinary.ch2 = list(0, 0);
-		if (readtoken() != TDONE)
-			synexpect(TDONE);
+		consumetoken(TDO);
+		n1 = makebinary((t == TWHILE)? NWHILE : NUNTIL, n1, list(0));
+		consumetoken(TDONE);
 		checkkwd = CHKKWD | CHKALIAS;
 		break;
-	}
 	case TFOR:
 		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
 			synerror("Bad for loop variable");
@@ -464,10 +479,7 @@
 		if (lasttoken == TWORD && ! quoteflag && equal(wordtext, "in")) {
 			app = ≈
 			while (readtoken() == TWORD) {
-				n2 = (union node *)stalloc(sizeof (struct narg));
-				n2->type = NARG;
-				n2->narg.text = wordtext;
-				n2->narg.backquote = backquotelist;
+				n2 = makename();
 				*app = n2;
 				app = &n2->narg.next;
 			}
@@ -499,21 +511,15 @@
 			t = TEND;
 		else
 			synexpect(-1);
-		n1->nfor.body = list(0, 0);
-		if (readtoken() != t)
-			synexpect(t);
+		n1->nfor.body = list(0);
+		consumetoken(t);
 		checkkwd = CHKKWD | CHKALIAS;
 		break;
 	case TCASE:
 		n1 = (union node *)stalloc(sizeof (struct ncase));
 		n1->type = NCASE;
-		if (readtoken() != TWORD)
-			synexpect(TWORD);
-		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
-		n2->type = NARG;
-		n2->narg.text = wordtext;
-		n2->narg.backquote = backquotelist;
-		n2->narg.next = NULL;
+		consumetoken(TWORD);
+		n1->ncase.expr = makename();
 		while (readtoken() == TNL);
 		if (lasttoken != TWORD || ! equal(wordtext, "in"))
 			synerror("expecting \"in\"");
@@ -526,10 +532,7 @@
 			if (lasttoken == TLP)
 				readtoken();
 			for (;;) {
-				*app = ap = (union node *)stalloc(sizeof (struct narg));
-				ap->type = NARG;
-				ap->narg.text = wordtext;
-				ap->narg.backquote = backquotelist;
+				*app = ap = makename();
 				checkkwd = CHKNL | CHKKWD;
 				if (readtoken() != TPIPE)
 					break;
@@ -539,7 +542,7 @@
 			ap->narg.next = NULL;
 			if (lasttoken != TRP)
 				synexpect(TRP);
-			cp->nclist.body = list(0, 0);
+			cp->nclist.body = list(0);
 
 			checkkwd = CHKNL | CHKKWD | CHKALIAS;
 			if ((t = readtoken()) != TESAC) {
@@ -559,34 +562,31 @@
 	case TLP:
 		n1 = (union node *)stalloc(sizeof (struct nredir));
 		n1->type = NSUBSHELL;
-		n1->nredir.n = list(0, 0);
+		n1->nredir.n = list(0);
 		n1->nredir.redirect = NULL;
-		if (readtoken() != TRP)
-			synexpect(TRP);
+		consumetoken(TRP);
 		checkkwd = CHKKWD | CHKALIAS;
 		is_subshell = 1;
 		break;
 	case TBEGIN:
-		n1 = list(0, 0);
-		if (readtoken() != TEND)
-			synexpect(TEND);
+		n1 = list(0);
+		consumetoken(TEND);
 		checkkwd = CHKKWD | CHKALIAS;
 		break;
-	/* Handle an empty command like other simple commands.  */
+	/* A simple command must have at least one redirection or word. */
 	case TBACKGND:
 	case TSEMI:
 	case TAND:
 	case TOR:
-		/*
-		 * An empty command before a ; doesn't make much sense, and
-		 * should certainly be disallowed in the case of `if ;'.
-		 */
+	case TPIPE:
+	case TENDCASE:
+	case TFALLTHRU:
+	case TEOF:
+	case TNL:
+	case TRP:
 		if (!redir)
 			synexpect(-1);
-	case TNL:
-	case TEOF:
 	case TWORD:
-	case TRP:
 		tokpushback++;
 		n1 = simplecmd(rpp, redir);
 		return n1;
@@ -644,10 +644,7 @@
 	for (;;) {
 		checkkwd = savecheckkwd;
 		if (readtoken() == TWORD) {
-			n = (union node *)stalloc(sizeof (struct narg));
-			n->type = NARG;
-			n->narg.text = wordtext;
-			n->narg.backquote = backquotelist;
+			n = makename();
 			*app = n;
 			app = &n->narg.next;
 			if (savecheckkwd != 0 && !isassignment(wordtext))
@@ -659,8 +656,7 @@
 		} else if (lasttoken == TLP && app == &args->narg.next
 					    && rpp == orig_rpp) {
 			/* We have a function */
-			if (readtoken() != TRP)
-				synexpect(TRP);
+			consumetoken(TRP);
 			funclinno = plinno;
 			/*
 			 * - Require plain text.
@@ -708,7 +704,25 @@
 	return n;
 }
 
+static union node *
+makebinary(int type, union node *n1, union node *n2)
+{
+	union node *n;
+
+	n = (union node *)stalloc(sizeof (struct nbinary));
+	n->type = type;
+	n->nbinary.ch1 = n1;
+	n->nbinary.ch2 = n2;
+	return (n);
+}
+
 void
+forcealias(void)
+{
+	checkkwd |= CHKALIAS;
+}
+
+void
 fixredir(union node *n, const char *text, int err)
 {
 	TRACE(("Fix redir %s %d\n", text, err));
@@ -734,8 +748,7 @@
 {
 	union node *n = redirnode;
 
-	if (readtoken() != TWORD)
-		synexpect(-1);
+	consumetoken(TWORD);
 	if (n->type == NHERE) {
 		struct heredoc *here = heredoc;
 		struct heredoc *p;
@@ -786,11 +799,7 @@
 		}
 		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
 				here->eofmark, here->striptabs);
-		n = (union node *)stalloc(sizeof (struct narg));
-		n->narg.type = NARG;
-		n->narg.next = NULL;
-		n->narg.text = wordtext;
-		n->narg.backquote = backquotelist;
+		n = makename();
 		here->here->nhere.doc = n;
 	}
 }
@@ -983,7 +992,7 @@
 	char *volatile str;
 	struct jmploc jmploc;
 	struct jmploc *const savehandler = handler;
-	int savelen;
+	size_t savelen;
 	int saveprompt;
 	const int bq_startlinno = plinno;
 	char *volatile ostr = NULL;
@@ -1090,14 +1099,14 @@
 		doprompt = 0;
 	}
 
-	n = list(0, oldstyle);
+	n = list(0);
 
-	if (oldstyle)
+	if (oldstyle) {
+		if (peektoken() != TEOF)
+			synexpect(-1);
 		doprompt = saveprompt;
-	else {
-		if (readtoken() != TRP)
-			synexpect(TRP);
-	}
+	} else
+		consumetoken(TRP);
 
 	(*nlpp)->n = n;
         if (oldstyle) {
@@ -1300,7 +1309,8 @@
 #define	PARSEARITH()	{goto parsearith; parsearith_return:;}
 
 static int
-readtoken1(int firstc, char const *initialsyntax, char *eofmark, int striptabs)
+readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
+    int striptabs)
 {
 	int c = firstc;
 	char *out;
@@ -1521,7 +1531,7 @@
 		}
 		if (c == *eofmark) {
 			if (pfgets(line, sizeof line) != NULL) {
-				char *p, *q;
+				const char *p, *q;
 
 				p = line;
 				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
@@ -1695,7 +1705,7 @@
 				pungetc();
 			else if (c == '\n' || c == PEOF)
 				synerror("Unexpected end of line in substitution");
-			else
+			else if (BASESYNTAX[c] != CCTL)
 				USTPUTC(c, out);
 		}
 		if (subtype == 0) {
@@ -1711,7 +1721,8 @@
 						synerror("Unexpected end of line in substitution");
 					if (flags == VSNUL)
 						STPUTC(':', out);
-					STPUTC(c, out);
+					if (BASESYNTAX[c] != CCTL)
+						STPUTC(c, out);
 					subtype = VSERROR;
 				} else
 					subtype = p - types + VSNORMAL;
@@ -1818,14 +1829,6 @@
 } /* end of readtoken */
 
 
-
-#ifdef mkinit
-RESET {
-	tokpushback = 0;
-	checkkwd = 0;
-}
-#endif
-
 /*
  * Returns true if the text contains nothing to expand (no dollar signs
  * or backquotes).
@@ -1887,6 +1890,14 @@
 }
 
 
+static void
+consumetoken(int token)
+{
+	if (readtoken() != token)
+		synexpect(token);
+}
+
+
 /*
  * Called when an unexpected token is read during the parse.  The argument
  * is the token that is expected, or -1 if more than one type of token can
@@ -1964,7 +1975,7 @@
 	/*
 	 * Format prompt string.
 	 */
-	for (i = 0; (i < 127) && (*fmt != '\0'); i++, fmt++)
+	for (i = 0; (i < PROMPTLEN - 1) && (*fmt != '\0'); i++, fmt++)
 		if (*fmt == '\\')
 			switch (*++fmt) {
 
@@ -1977,11 +1988,13 @@
 			case 'h':
 			case 'H':
 				ps[i] = '\0';
-				gethostname(&ps[i], PROMPTLEN - i);
+				gethostname(&ps[i], PROMPTLEN - i - 1);
+				ps[PROMPTLEN - 1] = '\0';
 				/* Skip to end of hostname. */
 				trim = (*fmt == 'h') ? '.' : '\0';
-				while ((ps[i+1] != '\0') && (ps[i+1] != trim))
+				while ((ps[i] != '\0') && (ps[i] != trim))
 					i++;
+				--i;
 				break;
 
 				/*
@@ -1993,7 +2006,7 @@
 			case 'W':
 			case 'w':
 				pwd = lookupvar("PWD");
-				if (pwd == NULL)
+				if (pwd == NULL || *pwd == '\0')
 					pwd = "?";
 				if (*fmt == 'W' &&
 				    *pwd == '/' && pwd[1] != '\0')
@@ -2026,8 +2039,9 @@
 				 * Emit unrecognized formats verbatim.
 				 */
 			default:
-				ps[i++] = '\\';
-				ps[i] = *fmt;
+				ps[i] = '\\';
+				if (i < PROMPTLEN - 2)
+					ps[++i] = *fmt;
 				break;
 			}
 		else
@@ -2038,7 +2052,7 @@
 
 
 const char *
-expandstr(char *ps)
+expandstr(const char *ps)
 {
 	union node n;
 	struct jmploc jmploc;

Modified: trunk/bin/sh/parser.h
===================================================================
--- trunk/bin/sh/parser.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/parser.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)parser.h	8.3 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/parser.h 289938 2015-10-25 17:17:50Z jilles $
  */
 
 /* control characters in argument strings */
@@ -69,18 +69,18 @@
 
 /*
  * NEOF is returned by parsecmd when it encounters an end of file.  It
- * must be distinct from NULL, so we use the address of a variable that
- * happens to be handy.
+ * must be distinct from NULL.
  */
-extern int tokpushback;
-#define NEOF ((union node *)&tokpushback)
+#define NEOF ((union node *)-1)
 extern int whichprompt;		/* 1 == PS1, 2 == PS2 */
 extern const char *const parsekwd[];
 
 
 union node *parsecmd(int);
+union node *parsewordexp(void);
+void forcealias(void);
 void fixredir(union node *, const char *, int);
 int goodname(const char *);
 int isassignment(const char *);
 char *getprompt(void *);
-const char *expandstr(char *);
+const char *expandstr(const char *);

Modified: trunk/bin/sh/redir.c
===================================================================
--- trunk/bin/sh/redir.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/redir.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/redir.c 287750 2015-09-13 13:43:08Z jilles $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -64,17 +65,16 @@
 
 #define EMPTY -2		/* marks an unused slot in redirtab */
 #define CLOSED -1		/* fd was not open before redir */
-#define PIPESIZE 4096		/* amount of buffering in a pipe */
 
 
-MKINIT
 struct redirtab {
 	struct redirtab *next;
 	int renamed[10];
+	int fd0_redirected;
 };
 
 
-MKINIT struct redirtab *redirlist;
+static struct redirtab *redirlist;
 
 /*
  * We keep track of whether or not fd0 has been redirected.  This is for
@@ -93,6 +93,13 @@
  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
  * standard output, and the standard error if it becomes a duplicate of
  * stdout, is saved in memory.
+*
+ * We suppress interrupts so that we won't leave open file
+ * descriptors around.  Because the signal handler remains
+ * installed and we do not use system call restart, interrupts
+ * will still abort blocking opens such as fifos (they will fail
+ * with EINTR). There is, however, a race condition if an interrupt
+ * arrives after INTOFF and before open blocks.
  */
 
 void
@@ -104,6 +111,7 @@
 	int fd;
 	char memory[10];	/* file descriptors to write to memory */
 
+	INTOFF;
 	for (i = 10 ; --i >= 0 ; )
 		memory[i] = 0;
 	memory[1] = flags & REDIR_BACKQ;
@@ -111,11 +119,14 @@
 		sv = ckmalloc(sizeof (struct redirtab));
 		for (i = 0 ; i < 10 ; i++)
 			sv->renamed[i] = EMPTY;
+		sv->fd0_redirected = fd0_redirected;
 		sv->next = redirlist;
 		redirlist = sv;
 	}
 	for (n = redir ; n ; n = n->nfile.next) {
 		fd = n->nfile.fd;
+		if (fd == 0)
+			fd0_redirected = 1;
 		if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
 		    n->ndup.dupfd == fd)
 			continue; /* redirect from/to same file descriptor */
@@ -122,7 +133,7 @@
 
 		if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
 			INTOFF;
-			if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
+			if ((i = fcntl(fd, F_DUPFD_CLOEXEC, 10)) == -1) {
 				switch (errno) {
 				case EBADF:
 					i = CLOSED;
@@ -132,19 +143,19 @@
 					error("%d: %s", fd, strerror(errno));
 					break;
 				}
-			} else
-				(void)fcntl(i, F_SETFD, FD_CLOEXEC);
+			}
 			sv->renamed[fd] = i;
 			INTON;
 		}
-		if (fd == 0)
-			fd0_redirected++;
 		openredirect(n, memory);
+		INTON;
+		INTOFF;
 	}
 	if (memory[1])
 		out1 = &memout;
 	if (memory[2])
 		out2 = &memout;
+	INTON;
 }
 
 
@@ -153,19 +164,10 @@
 {
 	struct stat sb;
 	int fd = redir->nfile.fd;
-	char *fname;
+	const char *fname;
 	int f;
 	int e;
 
-	/*
-	 * We suppress interrupts so that we won't leave open file
-	 * descriptors around.  Because the signal handler remains
-	 * installed and we do not use system call restart, interrupts
-	 * will still abort blocking opens such as fifos (they will fail
-	 * with EINTR). There is, however, a race condition if an interrupt
-	 * arrives after INTOFF and before open blocks.
-	 */
-	INTOFF;
 	memory[fd] = 0;
 	switch (redir->nfile.type) {
 	case NFROM:
@@ -172,21 +174,12 @@
 		fname = redir->nfile.expfname;
 		if ((f = open(fname, O_RDONLY)) < 0)
 			error("cannot open %s: %s", fname, strerror(errno));
-movefd:
-		if (f != fd) {
-			if (dup2(f, fd) == -1) {
-				e = errno;
-				close(f);
-				error("%d: %s", fd, strerror(e));
-			}
-			close(f);
-		}
 		break;
 	case NFROMTO:
 		fname = redir->nfile.expfname;
 		if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
 			error("cannot create %s: %s", fname, strerror(errno));
-		goto movefd;
+		break;
 	case NTO:
 		if (Cflag) {
 			fname = redir->nfile.expfname;
@@ -204,7 +197,7 @@
 			} else
 				error("cannot create %s: %s", fname,
 				    strerror(EEXIST));
-			goto movefd;
+			break;
 		}
 		/* FALLTHROUGH */
 	case NCLOBBER:
@@ -211,12 +204,12 @@
 		fname = redir->nfile.expfname;
 		if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
 			error("cannot create %s: %s", fname, strerror(errno));
-		goto movefd;
+		break;
 	case NAPPEND:
 		fname = redir->nfile.expfname;
 		if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
 			error("cannot create %s: %s", fname, strerror(errno));
-		goto movefd;
+		break;
 	case NTOFD:
 	case NFROMFD:
 		if (redir->ndup.dupfd >= 0) {	/* if not ">&-" */
@@ -230,15 +223,22 @@
 		} else {
 			close(fd);
 		}
-		break;
+		return;
 	case NHERE:
 	case NXHERE:
 		f = openhere(redir);
-		goto movefd;
+		break;
 	default:
 		abort();
 	}
-	INTON;
+	if (f != fd) {
+		if (dup2(f, fd) == -1) {
+			e = errno;
+			close(f);
+			error("%d: %s", fd, strerror(e));
+		}
+		close(f);
+	}
 }
 
 
@@ -251,18 +251,32 @@
 static int
 openhere(union node *redir)
 {
+	const char *p;
 	int pip[2];
-	int len = 0;
+	size_t len = 0;
+	int flags;
+	ssize_t written = 0;
 
 	if (pipe(pip) < 0)
 		error("Pipe call failed: %s", strerror(errno));
-	if (redir->type == NHERE) {
-		len = strlen(redir->nhere.doc->narg.text);
-		if (len <= PIPESIZE) {
-			xwrite(pip[1], redir->nhere.doc->narg.text, len);
+
+	if (redir->type == NXHERE)
+		p = redir->nhere.expdoc;
+	else
+		p = redir->nhere.doc->narg.text;
+	len = strlen(p);
+	if (len == 0)
+		goto out;
+	flags = fcntl(pip[1], F_GETFL, 0);
+	if (flags != -1 && fcntl(pip[1], F_SETFL, flags | O_NONBLOCK) != -1) {
+		written = write(pip[1], p, len);
+		if (written < 0)
+			written = 0;
+		if ((size_t)written == len)
 			goto out;
-		}
+		fcntl(pip[1], F_SETFL, flags);
 	}
+
 	if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
 		close(pip[0]);
 		signal(SIGINT, SIG_IGN);
@@ -270,10 +284,7 @@
 		signal(SIGHUP, SIG_IGN);
 		signal(SIGTSTP, SIG_IGN);
 		signal(SIGPIPE, SIG_DFL);
-		if (redir->type == NHERE)
-			xwrite(pip[1], redir->nhere.doc->narg.text, len);
-		else
-			expandhere(redir->nhere.doc, pip[1]);
+		xwrite(pip[1], p + written, len - written);
 		_exit(0);
 	}
 out:
@@ -295,8 +306,6 @@
 
 	for (i = 0 ; i < 10 ; i++) {
 		if (rp->renamed[i] != EMPTY) {
-                        if (i == 0)
-                                fd0_redirected--;
 			if (rp->renamed[i] >= 0) {
 				dup2(rp->renamed[i], i);
 				close(rp->renamed[i]);
@@ -306,26 +315,12 @@
 		}
 	}
 	INTOFF;
+	fd0_redirected = rp->fd0_redirected;
 	redirlist = rp->next;
 	ckfree(rp);
 	INTON;
 }
 
-/*
- * Undo all redirections.  Called on error or interrupt.
- */
-
-#ifdef mkinit
-
-INCLUDE "redir.h"
-
-RESET {
-	while (redirlist)
-		popredir();
-}
-
-#endif
-
 /* Return true if fd 0 has already been redirected at least once.  */
 int
 fd0_redirected_p(void)

Modified: trunk/bin/sh/redir.h
===================================================================
--- trunk/bin/sh/redir.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/redir.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)redir.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/redir.h 254426 2013-08-16 20:24:41Z jilles $
  */
 
 /* flags passed to redirect */

Modified: trunk/bin/sh/sh.1
===================================================================
--- trunk/bin/sh/sh.1	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/sh.1	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+.\" $MidnightBSD$
 .\"-
 .\" Copyright (c) 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -30,10 +31,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"	from: @(#)sh.1	8.6 (Berkeley) 5/4/95
-.\" $FreeBSD: release/9.2.0/bin/sh/sh.1 252611 2013-07-03 21:31:13Z jilles $
-.\" $MidnightBSD$
+.\" $FreeBSD: stable/10/bin/sh/sh.1 302334 2016-07-04 14:23:36Z wblock $
 .\"
-.Dd June 14, 2013
+.Dd May 30, 2016
 .Dt SH 1
 .Os
 .Sh NAME
@@ -41,7 +41,7 @@
 .Nd command interpreter (shell)
 .Sh SYNOPSIS
 .Nm
-.Op Fl /+abCEefIimnPpTuVvx
+.Op Fl /+abCEefhIimnPpTuVvx
 .Op Fl /+o Ar longname
 .Oo
 .Ar script
@@ -48,7 +48,7 @@
 .Op Ar arg ...
 .Oc
 .Nm
-.Op Fl /+abCEefIimnPpTuVvx
+.Op Fl /+abCEefhIimnPpTuVvx
 .Op Fl /+o Ar longname
 .Fl c Ar string
 .Oo
@@ -56,7 +56,7 @@
 .Op Ar arg ...
 .Oc
 .Nm
-.Op Fl /+abCEefIimnPpTuVvx
+.Op Fl /+abCEefhIimnPpTuVvx
 .Op Fl /+o Ar longname
 .Fl s
 .Op Ar arg ...
@@ -139,10 +139,10 @@
 .Pa .profile
 in the home directory,
 substituting for
-.Pa .shinit
+.Pa .shrc
 the filename desired:
 .Pp
-.Dl "ENV=$HOME/.shinit; export ENV"
+.Dl "ENV=$HOME/.shrc; export ENV"
 .Pp
 The first non-option argument specified on the command line
 will be treated as the
@@ -236,10 +236,16 @@
 .Dq Li ||
 operator; or if the command is a pipeline preceded by the
 .Ic !\&
-operator.
+keyword.
 If a shell function is executed and its exit status is explicitly
 tested, all commands of the function are considered to be tested as
 well.
+.Pp
+It is recommended to check for failures explicitly
+instead of relying on
+.Fl e
+because it tends to behave in unexpected ways,
+particularly in larger scripts.
 .It Fl f Li noglob
 Disable pathname expansion.
 .It Fl h Li trackall
@@ -376,13 +382,13 @@
 .Bl -tag -width indent
 .It Control operators:
 .Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
-.It Li & Ta Li && Ta Li ( Ta Li ) Ta Li \en
-.It Li ;; Ta Li ;& Ta Li ; Ta Li | Ta Li ||
+.It Li & Ta Li && Ta Li \&( Ta Li \&) Ta Li \en
+.It Li ;; Ta Li ;& Ta Li \&; Ta Li \&| Ta Li ||
 .El
 .It Redirection operators:
 .Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
 .It Li < Ta Li > Ta Li << Ta Li >> Ta Li <>
-.It Li <& Ta Li >& Ta Li <<- Ta Li >|
+.It Li <& Ta Li >& Ta Li <<- Ta Li >| Ta \&
 .El
 .El
 .Pp
@@ -488,8 +494,9 @@
 The backslash inside double quotes is historically weird.
 It remains literal unless it precedes the following characters,
 which it serves to quote:
+.Pp
 .Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
-.It Li $ Ta Li ` Ta Li \&" Ta Li \e\  Ta Li \en
+.It Li $ Ta Li ` Ta Li \&" Ta Li \e Ta Li \en
 .El
 .It Backslash
 A backslash preserves the literal meaning of the following
@@ -527,6 +534,20 @@
 .Pp
 .Dl "ls -F foobar"
 .Pp
+Aliases are also recognized after an alias
+whose value ends with a space or tab.
+For example, if there is also an alias called
+.Dq Li nohup
+with the value
+.Dq Li "nohup " ,
+then the input
+.Pp
+.Dl "nohup lf foobar"
+.Pp
+would become
+.Pp
+.Dl "nohup ls -F foobar"
+.Pp
 Aliases provide a convenient way for naive users to
 create shorthands for commands without having to learn how
 to create functions with arguments.
@@ -564,7 +585,8 @@
 Leading words of the form
 .Dq Li name=value
 are stripped off and assigned to the environment of
-the simple command.
+the simple command
+(they do not affect expansions).
 Redirection operators and
 their arguments (as described below) are stripped
 off and saved for processing.
@@ -649,8 +671,8 @@
 .Dq here-document .
 .Bd -unfilled -offset indent
 .Oo Ar n Oc Ns Li << Ar delimiter
-.D1 Ar here-doc-text
-.D1 ...
+.Ar here-doc-text
+.Ar ...
 .Ar delimiter
 .Ed
 .Pp
@@ -1028,7 +1050,6 @@
 .Pp
 The first form executes the commands in a subshell environment.
 A subshell environment has its own copy of:
-.Pp
 .Bl -enum
 .It
 The current working directory as set by
@@ -1146,8 +1167,10 @@
 .Pp
 .D1 Ic return Op Ar exitstatus
 .Pp
-It terminates the current executional scope, returning from the previous
-nested function, sourced script, or shell instance, in that order.
+It terminates the current executional scope, returning from the closest
+nested function or sourced script;
+if no function or sourced script is being executed,
+it exits the shell instance.
 The
 .Ic return
 command is implemented as a special built-in command.
@@ -1172,6 +1195,20 @@
 tilde expansion is also performed after the equals sign and after any colon
 and usernames are also terminated by colons,
 and field splitting and pathname expansion are not performed.
+.Pp
+This special expansion applies not only to assignments that form a simple
+command by themselves or precede a command word,
+but also to words passed to the
+.Ic export ,
+.Ic local
+or
+.Ic readonly
+built-in commands that have this form.
+For this, the builtin's name must be literal
+(not the result of an expansion)
+and may optionally be preceded by one or more literal instances of
+.Ic command
+without options.
 .Ss Positional Parameters
 A positional parameter is a parameter denoted by a number greater than zero.
 The shell sets these initially to the values of its command line
@@ -1330,9 +1367,33 @@
 .Dq Li "$ " ,
 unless you are the superuser, in which case it defaults to
 .Dq Li "# " .
+.Va PS1
+may include any of the following formatting sequences,
+which are replaced by the given information:
+.Bl -tag -width indent
+.It Li \eH
+This system's fully-qualified hostname (FQDN).
+.It Li \eh
+This system's hostname.
+.It Li \eW
+The final component of the current working directory.
+.It Li \ew
+The entire path of the current working directory.
+.It Li \e$
+Superuser status.
+.Dq Li "$ "
+for normal users and
+.Dq Li "# "
+for superusers.
+.It Li \e\e
+A literal backslash.
+.El
 .It Va PS2
 The secondary prompt string, which defaults to
 .Dq Li "> " .
+.Va PS2
+may include any of the formatting sequences from
+.Va PS1 .
 .It Va PS4
 The prefix for the trace output (if
 .Fl x
@@ -2222,10 +2283,6 @@
 With no arguments whatsoever, the
 .Ic hash
 command prints out the contents of this table.
-Entries which have not been looked at since the last
-.Ic cd
-command are marked with an asterisk;
-it is possible for these entries to be invalid.
 .Pp
 With arguments, the
 .Ic hash
@@ -2342,7 +2399,9 @@
 elapses before a complete line of input is supplied,
 the
 .Ic read
-command will return an exit status of 1 without assigning any values.
+command will return an exit status as if terminated by
+.Dv SIGALRM
+without assigning any values.
 The
 .Ar timeout
 value may optionally be followed by one of
@@ -2358,6 +2417,11 @@
 The
 .Fl e
 option exists only for backward compatibility with older scripts.
+.Pp
+The exit status is 0 on success, 1 on end of file,
+between 2 and 128 if an error occurs
+and greater than 128 if a trapped signal interrupts
+.Ic read .
 .It Ic readonly Oo Fl p Oc Op Ar name ...
 Each specified
 .Ar name
@@ -2453,7 +2517,8 @@
 decreasing the value of
 .Li $#
 by one.
-If there are zero positional parameters, shifting does not do anything.
+For portability, shifting if there are zero positional parameters
+should be avoided, since the shell may abort.
 .It Ic test
 A built-in equivalent of
 .Xr test 1 .
@@ -2605,12 +2670,17 @@
 option is specified, the
 .Ar name
 arguments are treated as function names.
-.It Ic wait Op Ar job
-Wait for the specified
+.It Ic wait Op Ar job ...
+Wait for each specified
 .Ar job
 to complete and return the exit status of the last process in the
+last specified
 .Ar job .
-If the argument is omitted, wait for all jobs to complete
+If any
+.Ar job
+specified is unknown to the shell, it is treated as if it
+were a known job that exited with exit status 127.
+If no operands are given, wait for all jobs to complete
 and return an exit status of zero.
 .El
 .Ss Commandline Editing
@@ -2681,6 +2751,17 @@
 at startup,
 which may affect the shell as described under
 .Sx Special Variables .
+.Sh FILES
+.Bl -tag -width "/etc/suid_profileXX" -compact
+.It Pa ~/.profile
+User's login profile.
+.It Pa /etc/profile
+System login profile.
+.It Pa /etc/shells
+Shell database.
+.It Pa /etc/suid_profile
+Privileged shell profile.
+.El
 .Sh EXIT STATUS
 Errors that are detected by the shell, such as a syntax error, will
 cause the shell to exit with a non-zero exit status.
@@ -2706,7 +2787,8 @@
 .Xr getrlimit 2 ,
 .Xr umask 2 ,
 .Xr wctype 3 ,
-.Xr editrc 5
+.Xr editrc 5 ,
+.Xr shells 5
 .Sh HISTORY
 A
 .Nm


Property changes on: trunk/bin/sh/sh.1
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/bin/sh/shell.h
===================================================================
--- trunk/bin/sh/shell.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/shell.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)shell.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/shell.h 253658 2013-07-25 19:48:15Z jilles $
  */
 
 #ifndef SHELL_H_
@@ -63,7 +64,6 @@
 #define	ARITH_MAX INTMAX_MAX
 
 typedef void *pointer;
-#define MKINIT  /* empty */
 
 #include <sys/cdefs.h>
 

Modified: trunk/bin/sh/show.c
===================================================================
--- trunk/bin/sh/show.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/show.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/show.c 262951 2014-03-09 17:04:31Z jmmv $");
 
 #include <fcntl.h>
 #include <stdio.h>
@@ -390,11 +391,11 @@
 			else
 				p = "/tmp";
 		}
-		scopy(p, s);
+		strcpy(s, p);
 		strcat(s, "/trace");
 	}
 #else
-	scopy("./trace", s);
+	strcpy(s, "./trace");
 #endif /* not_this_way */
 	if ((tracefile = fopen(s, "a")) == NULL) {
 		fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));

Modified: trunk/bin/sh/show.h
===================================================================
--- trunk/bin/sh/show.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/show.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1995
  *      The Regents of the University of California.  All rights reserved.
@@ -27,7 +28,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)show.h	1.1 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/show.h 200956 2009-12-24 18:41:14Z jilles $
  */
 
 void showtree(union node *);

Modified: trunk/bin/sh/trap.c
===================================================================
--- trunk/bin/sh/trap.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/trap.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -36,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/trap.c 297750 2016-04-09 14:24:17Z jilles $");
 
 #include <signal.h>
 #include <unistd.h>
@@ -72,14 +73,14 @@
 #define S_RESET 5		/* temporary - to reset a hard ignored sig */
 
 
-MKINIT char sigmode[NSIG];	/* current value of signal */
-int pendingsigs;		/* indicates some signal received */
+static char sigmode[NSIG];	/* current value of signal */
+volatile sig_atomic_t pendingsig;	/* indicates some signal received */
+volatile sig_atomic_t pendingsig_waitcmd;	/* indicates SIGINT/SIGQUIT received */
 int in_dotrap;			/* do we execute in a trap handler? */
 static char *volatile trap[NSIG];	/* trap handler commands */
 static volatile sig_atomic_t gotsig[NSIG];
 				/* indicates specified signal received */
 static int ignore_sigchld;	/* Used while handling SIGCHLD traps. */
-volatile sig_atomic_t gotwinch;
 static int last_trapsig;
 
 static int exiting;		/* exitshell() has been called */
@@ -150,7 +151,7 @@
  * The trap builtin.
  */
 int
-trapcmd(int argc, char **argv)
+trapcmd(int argc __unused, char **argv)
 {
 	char *action;
 	int signo;
@@ -292,12 +293,6 @@
 				action = S_IGN;
 			break;
 #endif
-#ifndef NO_HISTORY
-		case SIGWINCH:
-			if (rootshell && iflag)
-				action = S_CATCH;
-			break;
-#endif
 		}
 	}
 
@@ -361,13 +356,23 @@
 ignoresig(int signo)
 {
 
+	if (sigmode[signo] == 0)
+		setsignal(signo);
 	if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
 		signal(signo, SIG_IGN);
+		sigmode[signo] = S_IGN;
 	}
-	sigmode[signo] = S_HARD_IGN;
 }
 
 
+int
+issigchldtrapped(void)
+{
+
+	return (trap[SIGCHLD] != NULL && *trap[SIGCHLD] != '\0');
+}
+
+
 /*
  * Signal handler.
  */
@@ -380,27 +385,15 @@
 		return;
 	}
 
-	if (signo != SIGCHLD || !ignore_sigchld)
-		gotsig[signo] = 1;
-	pendingsigs++;
-
 	/* If we are currently in a wait builtin, prepare to break it */
-	if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0)
-		breakwaitcmd = 1;
-	/*
-	 * If a trap is set, not ignored and not the null command, we need
-	 * to make sure traps are executed even when a child blocks signals.
-	 */
-	if (Tflag &&
-	    trap[signo] != NULL &&
-	    ! (trap[signo][0] == '\0') &&
-	    ! (trap[signo][0] == ':' && trap[signo][1] == '\0'))
-		breakwaitcmd = 1;
+	if (signo == SIGINT || signo == SIGQUIT)
+		pendingsig_waitcmd = signo;
 
-#ifndef NO_HISTORY
-	if (signo == SIGWINCH)
-		gotwinch = 1;
-#endif
+	if (trap[signo] != NULL && trap[signo][0] != '\0' &&
+	    (signo != SIGCHLD || !ignore_sigchld)) {
+		gotsig[signo] = 1;
+		pendingsig = signo;
+	}
 }
 
 
@@ -411,11 +404,14 @@
 void
 dotrap(void)
 {
+	struct stackmark smark;
 	int i;
 	int savestatus, prev_evalskip, prev_skipcount;
 
 	in_dotrap++;
 	for (;;) {
+		pendingsig = 0;
+		pendingsig_waitcmd = 0;
 		for (i = 1; i < NSIG; i++) {
 			if (gotsig[i]) {
 				gotsig[i] = 0;
@@ -442,8 +438,9 @@
 
 					last_trapsig = i;
 					savestatus = exitstatus;
-					evalstring(trap[i], 0);
-					exitstatus = savestatus;
+					setstackmark(&smark);
+					evalstring(stsavestr(trap[i]), 0);
+					popstackmark(&smark);
 
 					/*
 					 * If such a command was not
@@ -452,9 +449,11 @@
 					 * trap action to have an effect
 					 * outside of it.
 					 */
-					if (prev_evalskip != 0) {
+					if (evalskip == 0 ||
+					    prev_evalskip != 0) {
 						evalskip  = prev_evalskip;
 						skipcount = prev_skipcount;
+						exitstatus = savestatus;
 					}
 
 					if (i == SIGCHLD)
@@ -467,7 +466,6 @@
 			break;
 	}
 	in_dotrap--;
-	pendingsigs = 0;
 }
 
 
@@ -484,9 +482,6 @@
 	setsignal(SIGINT);
 	setsignal(SIGQUIT);
 	setsignal(SIGTERM);
-#ifndef NO_HISTORY
-	setsignal(SIGWINCH);
-#endif
 	is_interactive = on;
 }
 
@@ -519,28 +514,25 @@
 			exiting_exitstatus = oexitstatus;
 	}
 	exitstatus = oexitstatus = exiting_exitstatus;
-	if (setjmp(loc1.loc)) {
-		goto l1;
+	if (!setjmp(loc1.loc)) {
+		handler = &loc1;
+		if ((p = trap[0]) != NULL && *p != '\0') {
+			/*
+			 * Reset evalskip, or the trap on EXIT could be
+			 * interrupted if the last command was a "return".
+			 */
+			evalskip = 0;
+			trap[0] = NULL;
+			evalstring(p, 0);
+		}
 	}
-	if (setjmp(loc2.loc)) {
-		goto l2;
-	}
-	handler = &loc1;
-	if ((p = trap[0]) != NULL && *p != '\0') {
-		/*
-		 * Reset evalskip, or the trap on EXIT could be
-		 * interrupted if the last command was a "return".
-		 */
-		evalskip = 0;
-		trap[0] = NULL;
-		evalstring(p, 0);
-	}
-l1:   handler = &loc2;			/* probably unnecessary */
-	flushall();
+	if (!setjmp(loc2.loc)) {
+		handler = &loc2;		/* probably unnecessary */
+		flushall();
 #if JOBS
-	setjobctl(0);
+		setjobctl(0);
 #endif
-l2:
+	}
 	if (sig != 0 && sig != SIGSTOP && sig != SIGTSTP && sig != SIGTTIN &&
 	    sig != SIGTTOU) {
 		signal(sig, SIG_DFL);

Modified: trunk/bin/sh/trap.h
===================================================================
--- trunk/bin/sh/trap.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/trap.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,17 +31,18 @@
  * SUCH DAMAGE.
  *
  *	@(#)trap.h	8.3 (Berkeley) 6/5/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/trap.h 262951 2014-03-09 17:04:31Z jmmv $
  */
 
-extern int pendingsigs;
+extern volatile sig_atomic_t pendingsig;
+extern volatile sig_atomic_t pendingsig_waitcmd;
 extern int in_dotrap;
-extern volatile sig_atomic_t gotwinch;
 
 void clear_traps(void);
 int have_traps(void);
 void setsignal(int);
 void ignoresig(int);
+int issigchldtrapped(void);
 void onsig(int);
 void dotrap(void);
 void setinteractive(int);

Modified: trunk/bin/sh/var.c
===================================================================
--- trunk/bin/sh/var.c	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/var.c	2018-06-02 21:06:59 UTC (rev 10240)
@@ -37,7 +37,7 @@
 #endif
 #endif /* not lint */
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/bin/sh/var.c 320531 2017-07-01 12:57:00Z jilles $");
 
 #include <unistd.h>
 #include <stdlib.h>
@@ -89,11 +89,9 @@
 struct var vmail;
 struct var vmpath;
 struct var vpath;
-struct var vppid;
 struct var vps1;
 struct var vps2;
 struct var vps4;
-struct var vvers;
 static struct var voptind;
 struct var vdisvfork;
 
@@ -112,8 +110,6 @@
 	  NULL },
 	{ &vpath,	0,				"PATH=" _PATH_DEFPATH,
 	  changepath },
-	{ &vppid,	VUNSET,				"PPID=",
-	  NULL },
 	/*
 	 * vps1 depends on uid
 	 */
@@ -147,29 +143,11 @@
 static struct var *find_var(const char *, struct var ***, int *);
 static int localevar(const char *);
 
-/*
- * Initialize the variable symbol tables and import the environment.
- */
+extern char **environ;
 
-#ifdef mkinit
-INCLUDE "var.h"
-MKINIT char **environ;
-INIT {
-	char **envp;
-
-	initvar();
-	for (envp = environ ; *envp ; envp++) {
-		if (strchr(*envp, '=')) {
-			setvareq(*envp, VEXPORT|VTEXTFIXED);
-		}
-	}
-}
-#endif
-
-
 /*
- * This routine initializes the builtin variables.  It is called when the
- * shell is initialized.
+ * This routine initializes the builtin variables and imports the environment.
+ * It is called when the shell is initialized.
  */
 
 void
@@ -179,6 +157,7 @@
 	const struct varinit *ip;
 	struct var *vp;
 	struct var **vpp;
+	char **envp;
 
 	for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
 		if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
@@ -198,10 +177,14 @@
 		vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# ");
 		vps1.flags = VSTRFIXED|VTEXTFIXED;
 	}
-	if ((vppid.flags & VEXPORT) == 0) {
-		fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
-		setvarsafe("PPID", ppid, 0);
+	fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
+	setvarsafe("PPID", ppid, 0);
+	for (envp = environ ; *envp ; envp++) {
+		if (strchr(*envp, '=')) {
+			setvareq(*envp, VEXPORT|VTEXTFIXED);
+		}
 	}
+	setvareq("OPTIND=1", VTEXTFIXED);
 }
 
 /*
@@ -237,8 +220,9 @@
 setvar(const char *name, const char *val, int flags)
 {
 	const char *p;
-	int len;
-	int namelen;
+	size_t len;
+	size_t namelen;
+	size_t vallen;
 	char *nameeq;
 	int isbad;
 
@@ -257,21 +241,25 @@
 	}
 	namelen = p - name;
 	if (isbad)
-		error("%.*s: bad variable name", namelen, name);
+		error("%.*s: bad variable name", (int)namelen, name);
 	len = namelen + 2;		/* 2 is space for '=' and '\0' */
 	if (val == NULL) {
 		flags |= VUNSET;
+		vallen = 0;
 	} else {
-		len += strlen(val);
+		vallen = strlen(val);
+		len += vallen;
 	}
+	INTOFF;
 	nameeq = ckmalloc(len);
 	memcpy(nameeq, name, namelen);
 	nameeq[namelen] = '=';
 	if (val)
-		scopy(val, nameeq + namelen + 1);
+		memcpy(nameeq + namelen + 1, val, vallen + 1);
 	else
 		nameeq[namelen + 1] = '\0';
 	setvareq(nameeq, flags);
+	INTON;
 }
 
 static int
@@ -304,6 +292,7 @@
 	char *eqp;
 	char *ss;
 
+	INTOFF;
 	ss = savestr(s);
 	if ((eqp = strchr(ss, '=')) != NULL)
 		*eqp = '\0';
@@ -312,6 +301,7 @@
 	else
 		(void) unsetenv(ss);
 	ckfree(ss);
+	INTON;
 
 	return;
 }
@@ -336,10 +326,16 @@
 		mklocal(s);
 	vp = find_var(s, &vpp, &nlen);
 	if (vp != NULL) {
-		if (vp->flags & VREADONLY)
-			error("%.*s: is read only", vp->name_len, s);
-		if (flags & VNOSET)
+		if (vp->flags & VREADONLY) {
+			if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+				ckfree(s);
+			error("%.*s: is read only", vp->name_len, vp->text);
+		}
+		if (flags & VNOSET) {
+			if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+				ckfree(s);
 			return;
+		}
 		INTOFF;
 
 		if (vp->func && (flags & VNOFUNC) == 0)
@@ -357,7 +353,7 @@
 		 * a regular variable function callback, but why bother?
 		 *
 		 * Note: this assumes iflag is not set to 1 initially.
-		 * As part of init(), this is called before arguments
+		 * As part of initvar(), this is called before arguments
 		 * are looked at.
 		 */
 		if ((vp == &vmpath || (vp == &vmail && ! mpathset())) &&
@@ -372,8 +368,12 @@
 		return;
 	}
 	/* not found */
-	if (flags & VNOSET)
+	if (flags & VNOSET) {
+		if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+			ckfree(s);
 		return;
+	}
+	INTOFF;
 	vp = ckmalloc(sizeof (*vp));
 	vp->flags = flags;
 	vp->text = s;
@@ -380,7 +380,6 @@
 	vp->name_len = nlen;
 	vp->next = *vpp;
 	vp->func = NULL;
-	INTOFF;
 	*vpp = vp;
 	if ((vp->flags & VEXPORT) && localevar(s)) {
 		change_env(s, 1);
@@ -508,7 +507,7 @@
 		if (localevar(lp->text)) {
 			setlocale(LC_ALL, "");
 			updatecharset();
-			return;
+			break;
 		}
 	}
 	INTON;
@@ -641,10 +640,11 @@
  */
 
 int
-exportcmd(int argc, char **argv)
+exportcmd(int argc __unused, char **argv)
 {
 	struct var **vpp;
 	struct var *vp;
+	char **ap;
 	char *name;
 	char *p;
 	char *cmdname;
@@ -652,26 +652,19 @@
 	int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
 
 	cmdname = argv[0];
-	optreset = optind = 1;
-	opterr = 0;
 	values = 0;
-	while ((ch = getopt(argc, argv, "p")) != -1) {
+	while ((ch = nextopt("p")) != '\0') {
 		switch (ch) {
 		case 'p':
 			values = 1;
 			break;
-		case '?':
-		default:
-			error("unknown option: -%c", optopt);
 		}
 	}
-	argc -= optind;
-	argv += optind;
 
-	if (values && argc != 0)
+	if (values && *argptr != NULL)
 		error("-p requires no arguments");
-	if (argc != 0) {
-		while ((name = *argv++) != NULL) {
+	if (*argptr != NULL) {
+		for (ap = argptr; (name = *ap) != NULL; ap++) {
 			if ((p = strchr(name, '=')) != NULL) {
 				p++;
 			} else {
@@ -729,6 +722,7 @@
 {
 	char *name;
 
+	nextopt("");
 	if (! in_function())
 		error("Not in a function");
 	while ((name = *argptr++) != NULL) {
@@ -793,6 +787,7 @@
 	struct localvar *lvp;
 	struct var *vp;
 
+	INTOFF;
 	while ((lvp = localvars) != NULL) {
 		localvars = lvp->next;
 		vp = lvp->vp;
@@ -810,6 +805,7 @@
 		}
 		ckfree(lvp);
 	}
+	INTON;
 }
 
 
@@ -848,6 +844,7 @@
 	if (flg_func == 0 && flg_var == 0)
 		flg_var = 1;
 
+	INTOFF;
 	for (ap = argptr; *ap ; ap++) {
 		if (flg_func)
 			ret |= unsetfunc(*ap);
@@ -854,6 +851,7 @@
 		if (flg_var)
 			ret |= unsetvar(*ap);
 	}
+	INTON;
 	return ret;
 }
 
@@ -860,6 +858,7 @@
 
 /*
  * Unset the specified variable.
+ * Called with interrupts off.
  */
 
 int
@@ -873,7 +872,6 @@
 		return (0);
 	if (vp->flags & VREADONLY)
 		return (1);
-	INTOFF;
 	if (vp->text[vp->name_len + 1] != '\0')
 		setvar(s, nullstr, 0);
 	if ((vp->flags & VEXPORT) && localevar(vp->text)) {
@@ -889,7 +887,6 @@
 		*vpp = vp->next;
 		ckfree(vp);
 	}
-	INTON;
 	return (0);
 }
 
@@ -896,7 +893,7 @@
 
 
 /*
- * Returns true if the two strings specify the same varable.  The first
+ * Returns true if the two strings specify the same variable.  The first
  * variable name is terminated by '='; the second may be terminated by
  * either '=' or '\0'.
  */
@@ -917,7 +914,7 @@
  * Search for a variable.
  * 'name' may be terminated by '=' or a NUL.
  * vppp is set to the pointer to vp, or the list head if vp isn't found
- * lenp is set to the number of charactets in 'name'
+ * lenp is set to the number of characters in 'name'
  */
 
 static struct var *

Modified: trunk/bin/sh/var.h
===================================================================
--- trunk/bin/sh/var.h	2018-06-02 21:03:56 UTC (rev 10239)
+++ trunk/bin/sh/var.h	2018-06-02 21:06:59 UTC (rev 10240)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -30,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)var.h	8.2 (Berkeley) 5/4/95
- * $MidnightBSD$
+ * $FreeBSD: stable/10/bin/sh/var.h 262951 2014-03-09 17:04:31Z jmmv $
  */
 
 /*
@@ -75,7 +76,6 @@
 extern struct var vmail;
 extern struct var vmpath;
 extern struct var vpath;
-extern struct var vppid;
 extern struct var vps1;
 extern struct var vps2;
 extern struct var vps4;



More information about the Midnightbsd-cvs mailing list