summaryrefslogtreecommitdiffstats
path: root/system/dash/patches/dash-0.5.8-git_d7582e6.diff
blob: ac5c6903d572be16440bb124a4fae955dd28eb1c (plain)
diff -Naur dash-0.5.8/ChangeLog dash-0.5.8-git_d7582e6/ChangeLog
--- dash-0.5.8/ChangeLog	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/ChangeLog	2015-08-05 13:55:25.055358032 -0400
@@ -1,3 +1,73 @@
+2014-11-17  Stéphane Aulery <saulery@free.fr>
+
+	* Correct typo in manual page.
+	* Document redirection file descriptor limitation.
+
+2014-10-30  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Catch variable length expansions on non-existant specials.
+
+2014-10-28  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Removed unnecessary pungetc on EOF from parser.
+	* Simplify EOF/newline handling in list parser.
+
+2014-10-27  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Add printf support for format string a, A, and F.
+	* Handle embedded NULs correctly in printf.
+	* Replace open-coded flushall in preadbuffer.
+	* Add likely tag in outmem.
+	* Add ifdefs around MEM_OUT handling in outmem.
+	* Remove unnecessary restoration of format string in printf.
+	* Remove getintmax in printf.
+	* Use error instead of warnx for fatal errors in printf.
+	* Optimise handling of backslash octals in printf.
+	* Simplify echo command.
+	* Handle -- in dotcmd.
+
+2014-10-13  Eric Blake <eblake@redhat.com>
+
+	* cd: support drive letters on Cygwin.
+
+2014-10-08  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Split unquoted $@/$* correctly when IFS is set but empty.
+	* Do not split quoted VSLENGTH and VSTRIM.
+	* Optimise nulonly away and just use quoted as before.
+
+2014-10-07  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Use setvareq to set OPTIND initially.
+
+2014-10-06  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Exit without arguments in a trap should use status outside traps.
+	* Do not allow break to break across function calls.
+	* Move common skipcount logic into skiploop.
+	* Allow return in loop conditional to set exit status.
+	* Return without arguments in a trap should use status outside traps.
+
+2014-10-03  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Do not clobber exitstatus in evalcommand.
+
+2014-10-02  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Fix use-after-free in dotrap/evalstring.
+	* Make sure evalskip is zero before running traps.
+	* Set exitstatus in onint.
+
+2014-09-29  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Kill pgetc_macro.
+	* Handle backslash newlines properly after dollar sign.
+	* Add nlprompt/nlnoprompt helpers.
+
+2014-09-28  Herbert Xu <herbert@gondor.apana.org.au>
+
+	* Correctly handle test ! ! = !.
+
 2014-09-26  Herbert Xu <herbert@gondor.apana.org.au>
 
 	* Small optimisation of command -pv change.
diff -Naur dash-0.5.8/Makefile.in dash-0.5.8-git_d7582e6/Makefile.in
--- dash-0.5.8/Makefile.in	2014-09-28 04:19:40.000000000 -0400
+++ dash-0.5.8-git_d7582e6/Makefile.in	2015-08-05 13:57:40.555361584 -0400
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# Makefile.in generated by automake 1.11.5 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -527,7 +527,7 @@
 	*.zip*) \
 	  unzip $(distdir).zip ;;\
 	esac
-	chmod -R a-w $(distdir); chmod u+w $(distdir)
+	chmod -R a-w $(distdir); chmod a+w $(distdir)
 	mkdir $(distdir)/_build
 	mkdir $(distdir)/_inst
 	chmod a-w $(distdir)
diff -Naur dash-0.5.8/aclocal.m4 dash-0.5.8-git_d7582e6/aclocal.m4
--- dash-0.5.8/aclocal.m4	2014-09-28 04:19:39.000000000 -0400
+++ dash-0.5.8-git_d7582e6/aclocal.m4	2015-08-05 13:57:39.728694896 -0400
@@ -1,4 +1,4 @@
-# generated automatically by aclocal 1.11.6 -*- Autoconf -*-
+# generated automatically by aclocal 1.11.5 -*- Autoconf -*-
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
 # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
@@ -38,7 +38,7 @@
 [am__api_version='1.11'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.11.6], [],
+m4_if([$1], [1.11.5], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -54,7 +54,7 @@
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.11.6])dnl
+[AM_AUTOMAKE_VERSION([1.11.5])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
diff -Naur dash-0.5.8/config.h.in dash-0.5.8-git_d7582e6/config.h.in
--- dash-0.5.8/config.h.in	2014-09-28 04:19:39.000000000 -0400
+++ dash-0.5.8-git_d7582e6/config.h.in	2015-08-05 13:57:40.062028238 -0400
@@ -88,6 +88,9 @@
 /* Define to 1 if you have the <sys/types.h> header file. */
 #undef HAVE_SYS_TYPES_H
 
+/* Define if your faccessat tells root all files are executable */
+#undef HAVE_TRADITIONAL_FACCESSAT
+
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
diff -Naur dash-0.5.8/configure dash-0.5.8-git_d7582e6/configure
--- dash-0.5.8/configure	2014-09-28 04:19:40.000000000 -0400
+++ dash-0.5.8-git_d7582e6/configure	2015-08-05 13:57:40.772028257 -0400
@@ -714,6 +714,7 @@
 enable_static
 enable_fnmatch
 enable_glob
+enable_test_workaround
 with_libedit
 enable_lineno
 '
@@ -1347,6 +1348,9 @@
   --enable-static         Build statical linked program
   --enable-fnmatch        Use fnmatch(3) from libc
   --enable-glob           Use glob(3) from libc
+  --enable-test-workaround
+                          Guard against faccessat(2) that tells root all files
+                          are executable
   --disable-lineno        Disable LINENO support
 
 Optional Packages:
@@ -4614,6 +4618,29 @@
 done
 
 
+
+# Check whether --enable-test-workaround was given.
+if test "${enable_test_workaround+set}" = set; then :
+  enableval=$enable_test_workaround;
+else
+  enable_test_workaround=auto
+fi
+
+
+if test "enable_test_workaround" = "auto" &&
+   test "$ac_cv_func_faccessat" = yes; then
+	case `uname -s 2>/dev/null` in
+	GNU/kFreeBSD | \
+	FreeBSD)
+		enable_test_workaround=yes
+	esac
+fi
+if test "$enable_test_workaround" = "yes"; then
+
+$as_echo "#define HAVE_TRADITIONAL_FACCESSAT 1" >>confdefs.h
+
+fi
+
 if test "$enable_fnmatch" = yes; then
 	use_fnmatch=
 	for ac_func in fnmatch
diff -Naur dash-0.5.8/configure.ac dash-0.5.8-git_d7582e6/configure.ac
--- dash-0.5.8/configure.ac	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/configure.ac	2015-08-05 13:55:25.055358032 -0400
@@ -90,6 +90,37 @@
 	       sigsetmask stpcpy strchrnul strsignal strtod strtoimax \
 	       strtoumax sysconf)
 
+dnl Check whether it's worth working around FreeBSD PR kern/125009.
+dnl The traditional behavior of access/faccessat is crazy, but
+dnl POSIX.1-2008 explicitly allows those functions to misbehave.
+dnl
+dnl Unaffected kernels:
+dnl
+dnl - all versions of Linux
+dnl - NetBSD sys/kern/vfs_subr.c 1.64, 1997-04-23
+dnl - FreeBSD 9 (r212002), 2010-09-10
+dnl - OpenBSD sys/kern/vfs_subr.c 1.166, 2008-06-09
+dnl
+dnl Also worked around in Debian's libc0.1 2.13-19 when using
+dnl kFreeBSD 8.
+
+AC_ARG_ENABLE(test-workaround, AS_HELP_STRING(--enable-test-workaround, \
+	[Guard against faccessat(2) that tells root all files are executable]),,
+	[enable_test_workaround=auto])
+
+if test "enable_test_workaround" = "auto" &&
+   test "$ac_cv_func_faccessat" = yes; then
+	case `uname -s 2>/dev/null` in
+	GNU/kFreeBSD | \
+	FreeBSD)
+		enable_test_workaround=yes
+	esac
+fi
+if test "$enable_test_workaround" = "yes"; then
+	AC_DEFINE([HAVE_TRADITIONAL_FACCESSAT], [1],
+		[Define if your faccessat tells root all files are executable])
+fi
+
 if test "$enable_fnmatch" = yes; then
 	use_fnmatch=
 	AC_CHECK_FUNCS(fnmatch, use_fnmatch=yes)
diff -Naur dash-0.5.8/src/Makefile.am dash-0.5.8-git_d7582e6/src/Makefile.am
--- dash-0.5.8/src/Makefile.am	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/Makefile.am	2015-08-05 13:55:25.058691365 -0400
@@ -26,7 +26,7 @@
 dash_SOURCES = \
 	$(dash_CFILES) \
 	alias.h arith_yacc.h bltin/bltin.h cd.h error.h eval.h exec.h \
-	expand.h hetio.h \
+	expand.h \
 	init.h input.h jobs.h machdep.h mail.h main.h memalloc.h miscbltin.h \
 	myhistedit.h mystring.h options.h output.h parser.h redir.h shell.h \
 	show.h system.h trap.h var.h
diff -Naur dash-0.5.8/src/Makefile.in dash-0.5.8-git_d7582e6/src/Makefile.in
--- dash-0.5.8/src/Makefile.in	2014-09-28 04:19:40.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/Makefile.in	2015-08-05 13:57:40.525361584 -0400
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11.6 from Makefile.am.
+# Makefile.in generated by automake 1.11.5 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -236,7 +236,7 @@
 dash_SOURCES = \
 	$(dash_CFILES) \
 	alias.h arith_yacc.h bltin/bltin.h cd.h error.h eval.h exec.h \
-	expand.h hetio.h \
+	expand.h \
 	init.h input.h jobs.h machdep.h mail.h main.h memalloc.h miscbltin.h \
 	myhistedit.h mystring.h options.h output.h parser.h redir.h shell.h \
 	show.h system.h trap.h var.h
diff -Naur dash-0.5.8/src/bltin/printf.c dash-0.5.8-git_d7582e6/src/bltin/printf.c
--- dash-0.5.8/src/bltin/printf.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/bltin/printf.c	2015-08-05 13:55:25.058691365 -0400
@@ -40,12 +40,11 @@
 #include <string.h>
 #include <unistd.h>
 
-static int	 conv_escape_str(char *);
+static int	 conv_escape_str(char *, char **);
 static char	*conv_escape(char *, int *);
 static int	 getchr(void);
 static double	 getdouble(void);
-static intmax_t	 getintmax(void);
-static uintmax_t getuintmax(void);
+static uintmax_t getuintmax(int);
 static char	*getstr(void);
 static char	*mklong(const char *, const char *);
 static void      check_conversion(const char *, const char *);
@@ -73,6 +72,53 @@
 	} \
 }
 
+#define ASPF(sp, f, func) ({ \
+	int ret; \
+	switch ((char *)param - (char *)array) { \
+	default: \
+		ret = xasprintf(sp, f, array[0], array[1], func); \
+		break; \
+	case sizeof(*param): \
+		ret = xasprintf(sp, f, array[0], func); \
+		break; \
+	case 0: \
+		ret = xasprintf(sp, f, func); \
+		break; \
+	} \
+	ret; \
+})
+
+
+static int print_escape_str(const char *f, int *param, int *array, char *s)
+{
+	struct stackmark smark;
+	char *p, *q;
+	int done;
+	int len;
+	int total;
+
+	setstackmark(&smark);
+	done = conv_escape_str(s, &p);
+	q = stackblock();
+	len = p - q;
+
+	p = makestrspace(len, p);
+	memset(p, 'X', len - 1);
+	p[len - 1] = 0;
+
+	q = stackblock();
+	total = ASPF(&p, f, p);
+
+	len = strchrnul(p, 'X') - p;
+	memcpy(p + len, q, strchrnul(p + len, ' ') - (p + len));
+
+	out1mem(p, total);
+
+	popstackmark(&smark);
+	return done;
+}
+
+
 int printfcmd(int argc, char *argv[])
 {
 	char *fmt;
@@ -86,10 +132,8 @@
 	argv = argptr;
 	format = *argv;
 
-	if (!format) {
-		warnx("usage: printf format [arg ...]");
-		goto err;
-	}
+	if (!format)
+		error("usage: printf format [arg ...]");
 
 	gargv = ++argv;
 
@@ -132,39 +176,33 @@
 			/* skip to field width */
 			fmt += strspn(fmt, SKIP1);
 			if (*fmt == '*')
-				*param++ = getintmax();
+				*param++ = getuintmax(1);
 
 			/* skip to possible '.', get following precision */
 			fmt += strspn(fmt, SKIP2);
 			if (*fmt == '.')
 				++fmt;
 			if (*fmt == '*')
-				*param++ = getintmax();
+				*param++ = getuintmax(1);
 
 			fmt += strspn(fmt, SKIP2);
 
 			ch = *fmt;
-			if (!ch) {
-				warnx("missing format character");
-				goto err;
-			}
+			if (!ch)
+				error("missing format character");
 			/* null terminate format string to we can use it
 			   as an argument to printf. */
 			nextch = fmt[1];
 			fmt[1] = 0;
 			switch (ch) {
 
-			case 'b': {
-				int done = conv_escape_str(getstr());
-				char *p = stackblock();
+			case 'b':
 				*fmt = 's';
-				PF(start, p);
 				/* escape if a \c was encountered */
-				if (done)
+				if (print_escape_str(start, param, array,
+						     getstr()))
 					goto out;
-				*fmt = 'b';
 				break;
-			}
 			case 'c': {
 				int p = getchr();
 				PF(start, p);
@@ -177,23 +215,26 @@
 			}
 			case 'd':
 			case 'i': {
-				intmax_t p = getintmax();
-				char *f = mklong(start, fmt);
-				PF(f, p);
+				uintmax_t p = getuintmax(1);
+				start = mklong(start, fmt);
+				PF(start, p);
 				break;
 			}
 			case 'o':
 			case 'u':
 			case 'x':
 			case 'X': {
-				uintmax_t p = getuintmax();
-				char *f = mklong(start, fmt);
-				PF(f, p);
+				uintmax_t p = getuintmax(0);
+				start = mklong(start, fmt);
+				PF(start, p);
 				break;
 			}
+			case 'a':
+			case 'A':
 			case 'e':
 			case 'E':
 			case 'f':
+			case 'F':
 			case 'g':
 			case 'G': {
 				double p = getdouble();
@@ -201,8 +242,7 @@
 				break;
 			}
 			default:
-				warnx("%s: invalid directive", start);
-				goto err;
+				error("%s: invalid directive", start);
 			}
 			*++fmt = nextch;
 		}
@@ -210,8 +250,6 @@
 
 out:
 	return rval;
-err:
-	return 1;
 }
 
 
@@ -220,8 +258,9 @@
  *	Halts processing string if a \c escape is encountered.
  */
 static int
-conv_escape_str(char *str)
+conv_escape_str(char *str, char **sp)
 {
+	int c;
 	int ch;
 	char *cp;
 
@@ -229,16 +268,14 @@
 	STARTSTACKSTR(cp);
 
 	do {
-		int c;
-
-		ch = *str++;
+		c = ch = *str++;
 		if (ch != '\\')
 			continue;
 
-		ch = *str++;
-		if (ch == 'c') {
+		c = *str++;
+		if (c == 'c') {
 			/* \c as in SYSV echo - abort all processing.... */
-			ch = 0x100;
+			c = ch = 0x100;
 			continue;
 		}
 
@@ -247,25 +284,14 @@
 		 * They start with a \0, and are followed by 0, 1, 2, 
 		 * or 3 octal digits. 
 		 */
-		if (ch == '0') {
-			unsigned char i;
-			i = 3;
-			ch = 0;
-			do {
-				unsigned k = octtobin(*str);
-				if (k > 7)
-					break;
-				str++;
-				ch <<= 3;
-				ch += k;
-			} while (--i);
-			continue;
-		}
+		if (c == '0' && isodigit(*str))
+			str++;
 
 		/* Finally test for sequences valid in the format string */
 		str = conv_escape(str - 1, &c);
-		ch = c;
-	} while (STPUTC(ch, cp), (char)ch);
+	} while (STPUTC(c, cp), (char)ch);
+
+	*sp = cp;
 
 	return ch;
 }
@@ -283,12 +309,11 @@
 
 	switch (ch) {
 	default:
-	case 0:
-		value = '\\';
-		goto out;
+		if (!isodigit(*str)) {
+			value = '\\';
+			goto out;
+		}
 
-	case '0': case '1': case '2': case '3':
-	case '4': case '5': case '6': case '7':
 		ch = 3;
 		value = 0;
 		do {
@@ -357,30 +382,8 @@
 	return val;
 }
 
-static intmax_t
-getintmax(void)
-{
-	intmax_t val = 0;
-	char *cp, *ep;
-
-	cp = *gargv;
-	if (cp == NULL)
-		goto out;
-	gargv++;
-
-	val = (unsigned char) cp[1];
-	if (*cp == '\"' || *cp == '\'')
-		goto out;
-
-	errno = 0;
-	val = strtoimax(cp, &ep, 0);
-	check_conversion(cp, ep);
-out:
-	return val;
-}
-
 static uintmax_t
-getuintmax(void)
+getuintmax(int sign)
 {
 	uintmax_t val = 0;
 	char *cp, *ep;
@@ -395,7 +398,7 @@
 		goto out;
 
 	errno = 0;
-	val = strtoumax(cp, &ep, 0);
+	val = sign ? strtoimax(cp, &ep, 0) : strtoumax(cp, &ep, 0);
 	check_conversion(cp, ep);
 out:
 	return val;
@@ -439,34 +442,21 @@
 int
 echocmd(int argc, char **argv)
 {
-	int nonl = 0;
-	struct output *outs = out1;
+	int nonl;
 
-	if (!*++argv)
-		goto end;
-	if (equal(*argv, "-n")) {
-		nonl = ~nonl;
-		if (!*++argv)
-			goto end;
-	}
+	nonl = *++argv ? equal(*argv, "-n") : 0;
+	argv += nonl;
 
 	do {
 		int c;
 
-		nonl += conv_escape_str(*argv);
-		outstr(stackblock(), outs);
+		if (likely(*argv))
+			nonl += print_escape_str("%s", NULL, NULL, *argv++);
 		if (nonl > 0)
 			break;
 
-		c = ' ';
-		if (!*++argv) {
-end:
-			if (nonl) {
-				break;
-			}
-			c = '\n';
-		}
-		outc(c, outs);
+		c = *argv ? ' ' : '\n';
+		out1c(c);
 	} while (*argv);
 	return 0;
 }
diff -Naur dash-0.5.8/src/bltin/test.c dash-0.5.8-git_d7582e6/src/bltin/test.c
--- dash-0.5.8/src/bltin/test.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/bltin/test.c	2015-08-05 13:55:25.058691365 -0400
@@ -155,6 +155,14 @@
 static int bash_group_member(gid_t);
 #endif
 
+#ifdef HAVE_FACCESSAT
+# ifdef HAVE_TRADITIONAL_FACCESSAT
+static inline int faccessat_confused_about_superuser(void) { return 1; }
+# else
+static inline int faccessat_confused_about_superuser(void) { return 0; }
+# endif
+#endif
+
 static inline intmax_t getn(const char *s)
 {
 	return atomax10(s);
@@ -177,7 +185,7 @@
 {
 	const struct t_op *op;
 	enum token n;
-	int res;
+	int res = 1;
 
 	if (*argv[0] == '[') {
 		if (*argv[--argc] != ']')
@@ -185,11 +193,12 @@
 		argv[argc] = NULL;
 	}
 
+recheck:
 	argv++;
 	argc--;
 
 	if (argc < 1)
-		return 1;
+		return res;
 
 	/*
 	 * POSIX prescriptions: he who wrote this deserves the Nobel
@@ -209,6 +218,9 @@
 			argv[--argc] = NULL;
 			argv++;
 			argc--;
+		} else if (!strcmp(argv[0], "!")) {
+			res = 0;
+			goto recheck;
 		}
 	}
 
@@ -216,7 +228,7 @@
 
 eval:
 	t_wp = argv;
-	res = !oexpr(n);
+	res ^= oexpr(n);
 	argv = t_wp;
 
 	if (argv[0] != NULL && argv[1] != NULL)
@@ -489,8 +501,20 @@
 }
 
 #ifdef HAVE_FACCESSAT
+static int has_exec_bit_set(const char *path)
+{
+	struct stat64 st;
+
+	if (stat64(path, &st))
+		return 0;
+	return st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH);
+}
+
 static int test_file_access(const char *path, int mode)
 {
+	if (faccessat_confused_about_superuser() &&
+	    mode == X_OK && geteuid() == 0 && !has_exec_bit_set(path))
+		return 0;
 	return !faccessat(AT_FDCWD, path, mode, AT_EACCESS);
 }
 #else	/* HAVE_FACCESSAT */
diff -Naur dash-0.5.8/src/cd.c dash-0.5.8-git_d7582e6/src/cd.c
--- dash-0.5.8/src/cd.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/cd.c	2015-08-05 13:55:25.058691365 -0400
@@ -38,6 +38,9 @@
 #include <string.h>
 #include <unistd.h>
 #include <limits.h>
+#ifdef __CYGWIN__
+#include <sys/cygwin.h>
+#endif
 
 /*
  * The cd and pwd commands.
@@ -194,6 +197,17 @@
 	char *cdcomppath;
 	const char *lim;
 
+#ifdef __CYGWIN__
+	/* On cygwin, thanks to drive letters, some absolute paths do
+	   not begin with slash; but cygwin includes a function that
+	   forces normalization to the posix form */
+	char pathbuf[PATH_MAX];
+	if (cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, dir, pathbuf,
+			     sizeof(pathbuf)) < 0)
+		sh_error("can't normalize %s", dir);
+	dir = pathbuf;
+#endif
+
 	cdcomppath = sstrdup(dir);
 	STARTSTACKSTR(new);
 	if (*dir != '/') {
diff -Naur dash-0.5.8/src/dash.1 dash-0.5.8-git_d7582e6/src/dash.1
--- dash-0.5.8/src/dash.1	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/dash.1	2015-08-05 13:55:25.058691365 -0400
@@ -385,7 +385,7 @@
 Following is a list of the possible redirections.
 The
 .Bq n
-is an optional number, as in
+is an optional number between 0 and 9, as in
 .Sq 3
 (not
 .Sq Bq 3 ) ,
@@ -402,11 +402,13 @@
 .It [n] Ns \*[Lt] file
 Redirect standard input (or n) from file.
 .It [n1] Ns \*[Lt]& Ns n2
-Duplicate standard input (or n1) from file descriptor n2.
+Copy file descriptor n2 as stdout (or fd n1).
+fd n2.
 .It [n] Ns \*[Lt]&-
 Close standard input (or n).
 .It [n1] Ns \*[Gt]& Ns n2
-Duplicate standard output (or n1) to n2.
+Copy file descriptor n2 as stdin (or fd n1).
+fd n2.
 .It [n] Ns \*[Gt]&-
 Close standard output (or n).
 .It [n] Ns \*[Lt]\*[Gt] file
@@ -596,7 +598,7 @@
 characters.
 The commands in a list are executed in the order they are written.
 If command is followed by an ampersand, the shell starts the
-command and immediately proceed onto the next command; otherwise it waits
+command and immediately proceeds onto the next command; otherwise it waits
 for the command to terminate before proceeding to the next one.
 .Ss Short-Circuit List Operators
 .Dq &&
@@ -1400,14 +1402,9 @@
 .Va optstring
 all errors will be ignored.
 .Pp
-A nonzero value is returned when the last option is reached.
-If there are no remaining arguments,
+After the last option
 .Ic getopts
-will set
-.Va var
-to the special option,
-.Dq -- ,
-otherwise, it will set
+will return a non-zero value and set
 .Va var
 to
 .Dq \&? .
diff -Naur dash-0.5.8/src/error.c dash-0.5.8-git_d7582e6/src/error.c
--- dash-0.5.8/src/error.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/error.c	2015-08-05 13:55:25.058691365 -0400
@@ -105,6 +105,7 @@
 		signal(SIGINT, SIG_DFL);
 		raise(SIGINT);
 	}
+	exitstatus = SIGINT + 128;
 	exraise(EXINT);
 	/* NOTREACHED */
 }
diff -Naur dash-0.5.8/src/eval.c dash-0.5.8-git_d7582e6/src/eval.c
--- dash-0.5.8/src/eval.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/eval.c	2015-08-05 13:55:25.058691365 -0400
@@ -74,6 +74,7 @@
 char *commandname;
 int exitstatus;			/* exit status of last command */
 int back_exitstatus;		/* exit status of backquoted command */
+int savestatus = -1;		/* exit status of last command outside traps */
 
 
 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
@@ -114,6 +115,10 @@
 RESET {
 	evalskip = 0;
 	loopnest = 0;
+	if (savestatus >= 0) {
+		exitstatus = savestatus;
+		savestatus = -1;
+	}
 }
 #endif
 
@@ -160,6 +165,7 @@
 	struct stackmark smark;
 	int status;
 
+	s = sstrdup(s);
 	setinputstring(s);
 	setstackmark(&smark);
 
@@ -171,7 +177,9 @@
 		if (evalskip)
 			break;
 	}
+	popstackmark(&smark);
 	popfile();
+	stunalloc(s);
 
 	return status;
 }
@@ -194,6 +202,9 @@
 		TRACE(("evaltree(NULL) called\n"));
 		goto out;
 	}
+
+	dotrap();
+
 #ifndef SMALL
 	displayhist = 1;	/* show history substitutions done with fc */
 #endif
@@ -305,8 +316,7 @@
 	if (checkexit & exitstatus)
 		goto exexit;
 
-	if (pendingsigs)
-		dotrap();
+	dotrap();
 
 	if (flags & EV_EXIT) {
 exexit:
@@ -329,27 +339,45 @@
 #endif
 
 
+static int skiploop(void)
+{
+	int skip = evalskip;
+
+	switch (skip) {
+	case 0:
+		break;
+
+	case SKIPBREAK:
+	case SKIPCONT:
+		if (likely(--skipcount <= 0)) {
+			evalskip = 0;
+			break;
+		}
+
+		skip = SKIPBREAK;
+		break;
+	}
+
+	return skip;
+}
+
+
 STATIC void
 evalloop(union node *n, int flags)
 {
+	int skip;
 	int status;
 
 	loopnest++;
 	status = 0;
 	flags &= EV_TESTED;
-	for (;;) {
+	do {
 		int i;
 
 		evaltree(n->nbinary.ch1, EV_TESTED);
-		if (evalskip) {
-skipping:	  if (evalskip == SKIPCONT && --skipcount <= 0) {
-				evalskip = 0;
-				continue;
-			}
-			if (evalskip == SKIPBREAK && --skipcount <= 0)
-				evalskip = 0;
-			break;
-		}
+		skip = skiploop();
+		if (skip)
+			continue;
 		i = exitstatus;
 		if (n->type != NWHILE)
 			i = !i;
@@ -357,11 +385,11 @@
 			break;
 		evaltree(n->nbinary.ch2, flags);
 		status = exitstatus;
-		if (evalskip)
-			goto skipping;
-	}
+		skip = skiploop();
+	} while (!(skip & ~SKIPCONT));
+	if (skip != SKIPFUNC)
+		exitstatus = status;
 	loopnest--;
-	exitstatus = status;
 }
 
 
@@ -382,9 +410,6 @@
 	arglist.lastp = &arglist.list;
 	for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
-		/* XXX */
-		if (evalskip)
-			goto out;
 	}
 	*arglist.lastp = NULL;
 
@@ -394,18 +419,10 @@
 	for (sp = arglist.list ; sp ; sp = sp->next) {
 		setvar(n->nfor.var, sp->text, 0);
 		evaltree(n->nfor.body, flags);
-		if (evalskip) {
-			if (evalskip == SKIPCONT && --skipcount <= 0) {
-				evalskip = 0;
-				continue;
-			}
-			if (evalskip == SKIPBREAK && --skipcount <= 0)
-				evalskip = 0;
+		if (skiploop() & ~SKIPCONT)
 			break;
-		}
 	}
 	loopnest--;
-out:
 	popstackmark(&smark);
 }
 
@@ -848,21 +865,12 @@
 				listsetvar(varlist.list, VEXPORT);
 		}
 		if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
-			int status;
-			int i;
-
-			i = exception;
-			if (i == EXEXIT)
-				goto raise;
-
-			status = (i == EXINT) ? SIGINT + 128 : 2;
-			exitstatus = status;
-
-			if (i == EXINT || spclbltin > 0) {
-raise:
-				longjmp(handler->loc, 1);
+			if (exception == EXERROR && spclbltin <= 0) {
+				FORCEINTON;
+				break;
 			}
-			FORCEINTON;
+raise:
+			longjmp(handler->loc, 1);
 		}
 		break;
 
@@ -927,9 +935,11 @@
 	struct jmploc jmploc;
 	int e;
 	int savefuncline;
+	int saveloopnest;
 
 	saveparam = shellparam;
 	savefuncline = funcline;
+	saveloopnest = loopnest;
 	savehandler = handler;
 	if ((e = setjmp(jmploc.loc))) {
 		goto funcdone;
@@ -939,6 +949,7 @@
 	shellparam.malloc = 0;
 	func->count++;
 	funcline = func->n.ndefun.linno;
+	loopnest = 0;
 	INTON;
 	shellparam.nparam = argc - 1;
 	shellparam.p = argv + 1;
@@ -949,13 +960,14 @@
 	poplocalvars(0);
 funcdone:
 	INTOFF;
+	loopnest = saveloopnest;
 	funcline = savefuncline;
 	freefunc(func);
 	freeparam(&shellparam);
 	shellparam = saveparam;
 	handler = savehandler;
 	INTON;
-	evalskip &= ~SKIPFUNC;
+	evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
 	return e;
 }
 
@@ -1035,12 +1047,23 @@
 int
 returncmd(int argc, char **argv)
 {
+	int skip;
+	int status;
+
 	/*
 	 * If called outside a function, do what ksh does;
 	 * skip the rest of the file.
 	 */
-	evalskip = SKIPFUNC;
-	return argv[1] ? number(argv[1]) : exitstatus;
+	if (argv[1]) {
+		skip = SKIPFUNC;
+		status = number(argv[1]);
+	} else {
+		skip = SKIPFUNCDEF;
+		status = exitstatus;
+	}
+	evalskip = skip;
+
+	return status;
 }
 
 
diff -Naur dash-0.5.8/src/eval.h dash-0.5.8-git_d7582e6/src/eval.h
--- dash-0.5.8/src/eval.h	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/eval.h	2015-08-05 13:55:25.058691365 -0400
@@ -37,6 +37,7 @@
 extern char *commandname;	/* currently executing command */
 extern int exitstatus;		/* exit status of last command */
 extern int back_exitstatus;	/* exit status of backquoted command */
+extern int savestatus;		/* exit status of last command outside traps */
 
 
 struct backcmd {		/* result of evalbackcmd */
@@ -61,3 +62,4 @@
 #define SKIPBREAK	(1 << 0)
 #define SKIPCONT	(1 << 1)
 #define SKIPFUNC	(1 << 2)
+#define SKIPFUNCDEF	(1 << 3)
diff -Naur dash-0.5.8/src/expand.c dash-0.5.8-git_d7582e6/src/expand.c
--- dash-0.5.8/src/expand.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/expand.c	2015-08-05 13:55:25.058691365 -0400
@@ -116,7 +116,7 @@
 STATIC char *evalvar(char *, int);
 STATIC size_t strtodest(const char *, const char *, int);
 STATIC void memtodest(const char *, size_t, const char *, int);
-STATIC ssize_t varvalue(char *, int, int);
+STATIC ssize_t varvalue(char *, int, int, int *);
 STATIC void expandmeta(struct strlist *, int);
 #ifdef HAVE_GLOB
 STATIC void addglob(const glob_t *);
@@ -736,7 +736,7 @@
 	p = strchr(p, '=') + 1;
 
 again:
-	varlen = varvalue(var, varflags, flag);
+	varlen = varvalue(var, varflags, flag, &quoted);
 	if (varflags & VSNUL)
 		varlen--;
 
@@ -751,28 +751,22 @@
 			argstr(p, flag | EXP_TILDE | EXP_WORD);
 			goto end;
 		}
-		if (easy)
-			goto record;
-		goto end;
+		goto record;
 	}
 
 	if (subtype == VSASSIGN || subtype == VSQUESTION) {
-		if (varlen < 0) {
-			if (subevalvar(p, var, 0, subtype, startloc,
-				       varflags, flag & ~QUOTES_ESC)) {
-				varflags &= ~VSNUL;
-				/* 
-				 * Remove any recorded regions beyond 
-				 * start of variable 
-				 */
-				removerecordregions(startloc);
-				goto again;
-			}
-			goto end;
-		}
-		if (easy)
+		if (varlen >= 0)
 			goto record;
-		goto end;
+
+		subevalvar(p, var, 0, subtype, startloc, varflags,
+			   flag & ~QUOTES_ESC);
+		varflags &= ~VSNUL;
+		/* 
+		 * Remove any recorded regions beyond 
+		 * start of variable 
+		 */
+		removerecordregions(startloc);
+		goto again;
 	}
 
 	if (varlen < 0 && uflag)
@@ -784,9 +778,9 @@
 	}
 
 	if (subtype == VSNORMAL) {
+record:
 		if (!easy)
 			goto end;
-record:
 		recordregion(startloc, expdest - (char *)stackblock(), quoted);
 		goto end;
 	}
@@ -892,7 +886,7 @@
  */
 
 STATIC ssize_t
-varvalue(char *name, int varflags, int flags)
+varvalue(char *name, int varflags, int flags, int *quotedp)
 {
 	int num;
 	char *p;
@@ -901,13 +895,13 @@
 	char sepc;
 	char **ap;
 	char const *syntax;
-	int quoted = flags & EXP_QUOTED;
+	int quoted = *quotedp;
 	int subtype = varflags & VSTYPE;
 	int discard = subtype == VSPLUS || subtype == VSLENGTH;
 	int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
 	ssize_t len = 0;
 
-	sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
+	sep = (flags & EXP_FULL) << CHAR_BIT;
 	syntax = quoted ? DQSYNTAX : BASESYNTAX;
 
 	switch (*name) {
@@ -938,15 +932,18 @@
 		expdest = p;
 		break;
 	case '@':
-		if (sep)
+		if (quoted && sep)
 			goto param;
 		/* fall through */
 	case '*':
-		sep = ifsset() ? ifsval()[0] : ' ';
+		if (quoted)
+			sep = 0;
+		sep |= ifsset() ? ifsval()[0] : ' ';
 param:
+		sepc = sep;
+		*quotedp = !sepc;
 		if (!(ap = shellparam.p))
 			return -1;
-		sepc = sep;
 		while ((p = *ap++)) {
 			len += strtodest(p, syntax, quotes);
 
diff -Naur dash-0.5.8/src/hetio.h dash-0.5.8-git_d7582e6/src/hetio.h
--- dash-0.5.8/src/hetio.h	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/hetio.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,22 +0,0 @@
-/*
- * Termios command line History and Editting for NetBSD sh (ash)
- * Copyright (c) 1999
- *	Main code:	Adam Rogoyski <rogoyski@cs.utexas.edu> 
- *	Etc:		Dave Cinege <dcinege@psychosis.com>
- *
- * You may use this code as you wish, so long as the original author(s)
- * are attributed in any redistributions of the source code.
- * This code is 'as is' with no warranty.
- * This code may safely be consumed by a BSD or GPL license.
- *
- * v 0.5  19990328	Initial release 
- *
- * Future plans: Simple file and path name completion. (like BASH)
- *
- */
-
-void hetio_init(void);
-int hetio_read_input(int fd);
-void hetio_reset_term(void);
-
-extern int hetio_inter;
diff -Naur dash-0.5.8/src/histedit.c dash-0.5.8-git_d7582e6/src/histedit.c
--- dash-0.5.8/src/histedit.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/histedit.c	2015-08-05 13:55:25.062024698 -0400
@@ -372,8 +372,7 @@
 					out2str(s);
 				}
 
-				evalstring(strcpy(stalloc(strlen(s) + 1), s),
-					   0);
+				evalstring(s, 0);
 				if (displayhist && hist) {
 					/*
 					 *  XXX what about recursive and
diff -Naur dash-0.5.8/src/input.c dash-0.5.8-git_d7582e6/src/input.c
--- dash-0.5.8/src/input.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/input.c	2015-08-05 13:55:25.062024698 -0400
@@ -58,45 +58,10 @@
 #include "myhistedit.h"
 #endif
 
-#ifdef HETIO
-#include "hetio.h"
-#endif
-
 #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
 #define IBUFSIZ (BUFSIZ + 1)
 
-MKINIT
-struct strpush {
-	struct strpush *prev;	/* preceding string on stack */
-	char *prevstring;
-	int prevnleft;
-	struct alias *ap;	/* if push was associated with an alias */
-	char *string;		/* remember the string since it may change */
-};
-
-/*
- * The parsefile structure pointed to by the global variable parsefile
- * contains information about the current file being read.
- */
 
-MKINIT
-struct parsefile {
-	struct parsefile *prev;	/* preceding file on stack */
-	int linno;		/* current line */
-	int fd;			/* file descriptor (or -1 if string) */
-	int nleft;		/* number of chars left in this line */
-	int lleft;		/* number of chars left in this buffer */
-	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 */
-};
-
-
-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 */
 MKINIT char basebuf[IBUFSIZ];	/* buffer for top level input file */
 struct parsefile *parsefile = &basepf;	/* current input file */
@@ -109,6 +74,7 @@
 STATIC void pushfile(void);
 static int preadfd(void);
 static void setinputfd(int fd, int push);
+static int preadbuffer(void);
 
 #ifdef mkinit
 INCLUDE <stdio.h>
@@ -117,10 +83,12 @@
 
 INIT {
 	basepf.nextc = basepf.buf = basebuf;
+	basepf.linno = 1;
 }
 
 RESET {
-	parselleft = parsenleft = 0;	/* clear input buffer */
+	/* clear input buffer */
+	basepf.lleft = basepf.nleft = 0;
 	popallfiles();
 }
 #endif
@@ -134,7 +102,20 @@
 int
 pgetc(void)
 {
-	return pgetc_macro();
+	int c;
+
+	if (parsefile->unget)
+		return parsefile->lastc[--parsefile->unget];
+
+	if (--parsefile->nleft >= 0)
+		c = (signed char)*parsefile->nextc++;
+	else
+		c = preadbuffer();
+
+	parsefile->lastc[1] = parsefile->lastc[0];
+	parsefile->lastc[0] = c;
+
+	return c;
 }
 
 
@@ -147,7 +128,7 @@
 {
 	int c;
 	do {
-		c = pgetc_macro();
+		c = pgetc();
 	} while (c == PEOA);
 	return c;
 }
@@ -158,7 +139,7 @@
 {
 	int nr;
 	char *buf =  parsefile->buf;
-	parsenextc = buf;
+	parsefile->nextc = buf;
 
 retry:
 #ifndef SMALL
@@ -184,11 +165,6 @@
 
 	} else
 #endif
-
-#ifdef HETIO
-		nr = hetio_read_input(parsefile->fd);
-		if (nr == -255)
-#endif
 		nr = read(parsefile->fd, buf, IBUFSIZ - 1);
 
 
@@ -219,8 +195,7 @@
  * 4) Process input up to the next newline, deleting nul characters.
  */
 
-int
-preadbuffer(void)
+static int preadbuffer(void)
 {
 	char *q;
 	int more;
@@ -229,34 +204,33 @@
 #endif
 	char savec;
 
-	while (unlikely(parsefile->strpush)) {
+	if (unlikely(parsefile->strpush)) {
 		if (
-			parsenleft == -1 && parsefile->strpush->ap &&
-			parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
+			parsefile->nleft == -1 &&
+			parsefile->strpush->ap &&
+			parsefile->nextc[-1] != ' ' &&
+			parsefile->nextc[-1] != '\t'
 		) {
 			return PEOA;
 		}
 		popstring();
-		if (--parsenleft >= 0)
-			return (signed char)*parsenextc++;
+		return pgetc();
 	}
-	if (unlikely(parsenleft == EOF_NLEFT || parsefile->buf == NULL))
+	if (unlikely(parsefile->nleft == EOF_NLEFT ||
+		     parsefile->buf == NULL))
 		return PEOF;
-	flushout(&output);
-#ifdef FLUSHERR
-	flushout(&errout);
-#endif
+	flushall();
 
-	more = parselleft;
+	more = parsefile->lleft;
 	if (more <= 0) {
 again:
 		if ((more = preadfd()) <= 0) {
-			parselleft = parsenleft = EOF_NLEFT;
+			parsefile->lleft = parsefile->nleft = EOF_NLEFT;
 			return PEOF;
 		}
 	}
 
-	q = parsenextc;
+	q = parsefile->nextc;
 
 	/* delete nul characters */
 #ifndef SMALL
@@ -274,7 +248,7 @@
 			q++;
 
 			if (c == '\n') {
-				parsenleft = q - parsenextc - 1;
+				parsefile->nleft = q - parsefile->nextc - 1;
 				break;
 			}
 
@@ -291,13 +265,13 @@
 		}
 
 		if (more <= 0) {
-			parsenleft = q - parsenextc - 1;
-			if (parsenleft < 0)
+			parsefile->nleft = q - parsefile->nextc - 1;
+			if (parsefile->nleft < 0)
 				goto again;
 			break;
 		}
 	}
-	parselleft = more;
+	parsefile->lleft = more;
 
 	savec = *q;
 	*q = '\0';
@@ -307,13 +281,13 @@
 		HistEvent he;
 		INTOFF;
 		history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
-		    parsenextc);
+			parsefile->nextc);
 		INTON;
 	}
 #endif
 
 	if (vflag) {
-		out2str(parsenextc);
+		out2str(parsefile->nextc);
 #ifdef FLUSHERR
 		flushout(out2);
 #endif
@@ -321,19 +295,18 @@
 
 	*q = savec;
 
-	return (signed char)*parsenextc++;
+	return (signed char)*parsefile->nextc++;
 }
 
 /*
- * Undo the last call to pgetc.  Only one character may be pushed back.
+ * Undo a call to pgetc.  Only two characters may be pushed back.
  * PEOF may be pushed back.
  */
 
 void
 pungetc(void)
 {
-	parsenleft++;
-	parsenextc--;
+	parsefile->unget++;
 }
 
 /*
@@ -355,15 +328,18 @@
 		parsefile->strpush = sp;
 	} else
 		sp = parsefile->strpush = &(parsefile->basestrpush);
-	sp->prevstring = parsenextc;
-	sp->prevnleft = parsenleft;
+	sp->prevstring = parsefile->nextc;
+	sp->prevnleft = parsefile->nleft;
+	sp->unget = parsefile->unget;
+	memcpy(sp->lastc, parsefile->lastc, sizeof(sp->lastc));
 	sp->ap = (struct alias *)ap;
 	if (ap) {
 		((struct alias *)ap)->flag |= ALIASINUSE;
 		sp->string = s;
 	}
-	parsenextc = s;
-	parsenleft = len;
+	parsefile->nextc = s;
+	parsefile->nleft = len;
+	parsefile->unget = 0;
 	INTON;
 }
 
@@ -374,7 +350,8 @@
 
 	INTOFF;
 	if (sp->ap) {
-		if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
+		if (parsefile->nextc[-1] == ' ' ||
+		    parsefile->nextc[-1] == '\t') {
 			checkkwd |= CHKALIAS;
 		}
 		if (sp->string != sp->ap->val) {
@@ -385,8 +362,10 @@
 			unalias(sp->ap->name);
 		}
 	}
-	parsenextc = sp->prevstring;
-	parsenleft = sp->prevnleft;
+	parsefile->nextc = sp->prevstring;
+	parsefile->nleft = sp->prevnleft;
+	parsefile->unget = sp->unget;
+	memcpy(parsefile->lastc, sp->lastc, sizeof(sp->lastc));
 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
 	parsefile->strpush = sp->prev;
 	if (sp != &(parsefile->basestrpush))
@@ -435,7 +414,7 @@
 	parsefile->fd = fd;
 	if (parsefile->buf == NULL)
 		parsefile->buf = ckmalloc(IBUFSIZ);
-	parselleft = parsenleft = 0;
+	parsefile->lleft = parsefile->nleft = 0;
 	plinno = 1;
 }
 
@@ -449,8 +428,8 @@
 {
 	INTOFF;
 	pushfile();
-	parsenextc = string;
-	parsenleft = strlen(string);
+	parsefile->nextc = string;
+	parsefile->nleft = strlen(string);
 	parsefile->buf = NULL;
 	plinno = 1;
 	INTON;
@@ -468,15 +447,12 @@
 {
 	struct parsefile *pf;
 
-	parsefile->nleft = parsenleft;
-	parsefile->lleft = parselleft;
-	parsefile->nextc = parsenextc;
-	parsefile->linno = plinno;
 	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
 	pf->prev = parsefile;
 	pf->fd = -1;
 	pf->strpush = NULL;
 	pf->basestrpush.prev = NULL;
+	pf->unget = 0;
 	parsefile = pf;
 }
 
@@ -495,10 +471,6 @@
 		popstring();
 	parsefile = pf->prev;
 	ckfree(pf);
-	parsenleft = parsefile->nleft;
-	parselleft = parsefile->lleft;
-	parsenextc = parsefile->nextc;
-	plinno = parsefile->linno;
 	INTON;
 }
 
diff -Naur dash-0.5.8/src/input.h dash-0.5.8-git_d7582e6/src/input.h
--- dash-0.5.8/src/input.h	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/input.h	2015-08-05 13:55:25.062024698 -0400
@@ -41,18 +41,56 @@
 	INPUT_NOFILE_OK = 2,
 };
 
+struct alias;
+
+struct strpush {
+	struct strpush *prev;	/* preceding string on stack */
+	char *prevstring;
+	int prevnleft;
+	struct alias *ap;	/* if push was associated with an alias */
+	char *string;		/* remember the string since it may change */
+
+	/* Remember last two characters for pungetc. */
+	int lastc[2];
+
+	/* Number of outstanding calls to pungetc. */
+	int unget;
+};
+
+/*
+ * The parsefile structure pointed to by the global variable parsefile
+ * contains information about the current file being read.
+ */
+
+struct parsefile {
+	struct parsefile *prev;	/* preceding file on stack */
+	int linno;		/* current line */
+	int fd;			/* file descriptor (or -1 if string) */
+	int nleft;		/* number of chars left in this line */
+	int lleft;		/* number of chars left in this buffer */
+	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 */
+
+	/* Remember last two characters for pungetc. */
+	int lastc[2];
+
+	/* Number of outstanding calls to pungetc. */
+	int unget;
+};
+
+extern struct parsefile *parsefile;
+
 /*
  * The input line number.  Input.c just defines this variable, and saves
  * and restores it when files are pushed and popped.  The user of this
  * package must set its value.
  */
-extern int plinno;
-extern int parsenleft;		/* number of characters left in input buffer */
-extern char *parsenextc;	/* next character in input buffer */
+#define plinno (parsefile->linno)
 
 int pgetc(void);
 int pgetc2(void);
-int preadbuffer(void);
 void pungetc(void);
 void pushstring(char *, void *);
 void popstring(void);
@@ -61,6 +99,3 @@
 void popfile(void);
 void popallfiles(void);
 void closescript(void);
-
-#define pgetc_macro() \
-	(--parsenleft >= 0 ? (signed char)*parsenextc++ : preadbuffer())
diff -Naur dash-0.5.8/src/main.c dash-0.5.8-git_d7582e6/src/main.c
--- dash-0.5.8/src/main.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/main.c	2015-08-05 13:55:25.062024698 -0400
@@ -60,10 +60,6 @@
 #include "exec.h"
 #include "cd.h"
 
-#ifdef HETIO
-#include "hetio.h"
-#endif
-
 #define PROFILE 0
 
 int rootpid;
@@ -206,10 +202,6 @@
 	int numeof = 0;
 
 	TRACE(("cmdloop(%d) called\n", top));
-#ifdef HETIO
-	if(iflag && top)
-		hetio_init();
-#endif
 	for (;;) {
 		int skip;
 
@@ -242,7 +234,7 @@
 
 		skip = evalskip;
 		if (skip) {
-			evalskip &= ~SKIPFUNC;
+			evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
 			break;
 		}
 	}
@@ -321,15 +313,19 @@
 {
 	int status = 0;
 
-	if (argc >= 2) {		/* That's what SVR2 does */
+	nextopt(nullstr);
+	argv = argptr;
+
+	if (*argv) {
 		char *fullname;
 
-		fullname = find_dot_file(argv[1]);
+		fullname = find_dot_file(*argv);
 		setinputfile(fullname, INPUT_PUSH_FILE);
 		commandname = fullname;
 		status = cmdloop(0);
 		popfile();
 	}
+
 	return status;
 }
 
@@ -339,8 +335,15 @@
 {
 	if (stoppedjobs())
 		return 0;
-	if (argc > 1)
-		exitstatus = number(argv[1]);
+
+	if (argc > 1) {
+		int status = number(argv[1]);
+
+		exitstatus = status;
+		if (savestatus >= 0)
+			savestatus = status;
+	}
+
 	exraise(EXEXIT);
 	/* NOTREACHED */
 }
diff -Naur dash-0.5.8/src/mkbuiltins dash-0.5.8-git_d7582e6/src/mkbuiltins
--- dash-0.5.8/src/mkbuiltins	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/mkbuiltins	2015-08-05 13:55:25.062024698 -0400
@@ -69,7 +69,7 @@
 #include "builtins.h"
 
 !
-< $builtins sed '/^#/d; /^$/d' > $temp
+< $builtins sed '/^#/d; /^ *$/d' > $temp
 awk '{	printf "int %s(int, char **);\n", $1}' $temp
 echo '
 const struct builtincmd builtincmd[] = {'
@@ -78,7 +78,7 @@
 		if ($i ~ /^-/)
 			line = $(++i) "\t" line
 		print line
-	}}' $temp | LC_COLLATE=C sort -k 1,1 | tee $temp2 | awk '{
+	}}' $temp | LC_ALL= LC_COLLATE=C sort -k 1,1 | tee $temp2 | awk '{
 		opt = ""
 		if (NF > 2) {
 			opt = substr($2, 2)
@@ -97,8 +97,9 @@
  */
 
 !
-sed 's/	-[a-z]*//' $temp2 | nl -b a -v 0 | LC_COLLATE=C sort -u -k 3,3 |
-tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ |
+sed 's/	-[a-z]*//' $temp2 | nl -b a -v 0 |
+	LC_ALL= LC_COLLATE=C sort -u -k 3,3 |
+	tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ |
 	awk '{	printf "#define %s (builtincmd + %d)\n", $3, $1}'
 printf '\n#define NUMBUILTINS %d\n' $(wc -l < $temp2)
 echo '
diff -Naur dash-0.5.8/src/output.c dash-0.5.8-git_d7582e6/src/output.c
--- dash-0.5.8/src/output.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/output.c	2015-08-05 13:55:25.062024698 -0400
@@ -99,9 +99,6 @@
 struct output *out2 = &errout;
 
 
-#ifndef USE_GLIBC_STDIO
-static void __outstr(const char *, size_t, struct output *);
-#endif
 static int xvsnprintf(char *, size_t, const char *, va_list);
 
 
@@ -134,16 +131,20 @@
 #endif
 
 
-#ifndef USE_GLIBC_STDIO
-static void
-__outstr(const char *p, size_t len, struct output *dest)
+void
+outmem(const char *p, size_t len, struct output *dest)
 {
+#ifdef USE_GLIBC_STDIO
+	INTOFF;
+	fwrite(p, 1, len, dest->stream);
+	INTON;
+#else
 	size_t bufsize;
 	size_t offset;
 	size_t nleft;
 
 	nleft = dest->end - dest->nextc;
-	if (nleft >= len) {
+	if (likely(nleft >= len)) {
 buffered:
 		dest->nextc = mempcpy(dest->nextc, p, len);
 		return;
@@ -153,10 +154,13 @@
 	if (!bufsize) {
 		;
 	} else if (dest->buf == NULL) {
+#ifdef notyet
 		if (dest->fd == MEM_OUT && len > bufsize) {
 			bufsize = len;
 		}
+#endif
 		offset = 0;
+#ifdef notyet
 		goto alloc;
 	} else if (dest->fd == MEM_OUT) {
 		offset = bufsize;
@@ -168,6 +172,7 @@
 		if (bufsize < offset)
 			goto err;
 alloc:
+#endif
 		INTOFF;
 		dest->buf = ckrealloc(dest->buf, bufsize);
 		dest->bufsize = bufsize;
@@ -183,11 +188,13 @@
 		goto buffered;
 
 	if ((xwrite(dest->fd, p, len))) {
+#ifdef notyet
 err:
+#endif
 		dest->flags |= OUTPUT_ERR;
 	}
-}
 #endif
+}
 
 
 void
@@ -201,7 +208,7 @@
 	size_t len;
 
 	len = strlen(p);
-	__outstr(p, len, file);
+	outmem(p, len, file);
 #endif
 }
 
@@ -213,7 +220,7 @@
 outcslow(int c, struct output *dest)
 {
 	char buf = c;
-	__outstr(&buf, 1, dest);
+	outmem(&buf, 1, dest);
 }
 #endif
 
@@ -283,35 +290,58 @@
 }
 
 
+static int xvasprintf(char **sp, size_t size, const char *f, va_list ap)
+{
+	char *s;
+	int len;
+	va_list ap2;
+
+	va_copy(ap2, ap);
+	len = xvsnprintf(*sp, size, f, ap2);
+	va_end(ap2);
+	if (len < 0)
+		sh_error("xvsnprintf failed");
+	if (len < size)
+		return len;
+
+	s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1);
+	*sp = s;
+	len = xvsnprintf(s, len + 1, f, ap);
+	return len;
+}
+
+
+int xasprintf(char **sp, const char *f, ...)
+{
+	va_list ap;
+	int ret;
+
+	va_start(ap, f);
+	ret = xvasprintf(sp, 0, f, ap);
+	va_end(ap);
+	return ret;
+}
+
+
 #ifndef USE_GLIBC_STDIO
 void
 doformat(struct output *dest, const char *f, va_list ap)
 {
 	struct stackmark smark;
 	char *s;
-	int len, ret;
-	size_t size;
-	va_list ap2;
+	int len;
+	int olen;
 
-	va_copy(ap2, ap);
-	size = dest->end - dest->nextc;
-	len = xvsnprintf(dest->nextc, size, f, ap2);
-	va_end(ap2);
-	if (len < 0) {
-		dest->flags |= OUTPUT_ERR;
-		return;
-	}
-	if (len < size) {
+	setstackmark(&smark);
+	s = dest->nextc;
+	olen = dest->end - dest->nextc;
+	len = xvasprintf(&s, olen, f, ap);
+	if (likely(olen > len)) {
 		dest->nextc += len;
-		return;
+		goto out;
 	}
-	setstackmark(&smark);
-	s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1);
-	ret = xvsnprintf(s, len + 1, f, ap);
-	if (ret == len)
-		__outstr(s, len, dest);
-	else
-		dest->flags |= OUTPUT_ERR;
+	outmem(s, len, dest);
+out:
 	popstackmark(&smark);
 }
 #endif
diff -Naur dash-0.5.8/src/output.h dash-0.5.8-git_d7582e6/src/output.h
--- dash-0.5.8/src/output.h	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/output.h	2015-08-05 13:55:25.062024698 -0400
@@ -63,6 +63,7 @@
 extern struct output *out1;
 extern struct output *out2;
 
+void outmem(const char *, size_t, struct output *);
 void outstr(const char *, struct output *);
 #ifndef USE_GLIBC_STDIO
 void outcslow(int, struct output *);
@@ -75,6 +76,7 @@
     __attribute__((__format__(__printf__,1,2)));
 int fmtstr(char *, size_t, const char *, ...)
     __attribute__((__format__(__printf__,3,4)));
+int xasprintf(char **, const char *, ...);
 #ifndef USE_GLIBC_STDIO
 void doformat(struct output *, const char *, va_list);
 #endif
@@ -115,6 +117,7 @@
 #endif
 #define out1c(c)	outc((c), out1)
 #define out2c(c)	outcslow((c), out2)
+#define out1mem(s, l)	outmem((s), (l), out1)
 #define out1str(s)	outstr((s), out1)
 #define out2str(s)	outstr((s), out2)
 #define outerr(f)	(f)->flags
diff -Naur dash-0.5.8/src/parser.c dash-0.5.8-git_d7582e6/src/parser.c
--- dash-0.5.8/src/parser.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/parser.c	2015-08-05 13:55:25.062024698 -0400
@@ -135,19 +135,13 @@
 union node *
 parsecmd(int interact)
 {
-	int t;
-
 	tokpushback = 0;
+	checkkwd = 0;
+	heredoclist = 0;
 	doprompt = interact;
 	if (doprompt)
 		setprompt(doprompt);
 	needprompt = 0;
-	t = readtoken();
-	if (t == TEOF)
-		return NEOF;
-	if (t == TNL)
-		return NULL;
-	tokpushback++;
 	return list(1);
 }
 
@@ -158,11 +152,27 @@
 	union node *n1, *n2, *n3;
 	int tok;
 
-	checkkwd = CHKNL | CHKKWD | CHKALIAS;
-	if (nlflag == 2 && tokendlist[peektoken()])
-		return NULL;
 	n1 = NULL;
 	for (;;) {
+		switch (peektoken()) {
+		case TNL:
+			if (!(nlflag & 1))
+				break;
+			parseheredoc();
+			return n1;
+
+		case TEOF:
+			if (!n1 && (nlflag & 1))
+				n1 = NEOF;
+			parseheredoc();
+			return n1;
+		}
+
+		checkkwd = CHKNL | CHKKWD | CHKALIAS;
+		if (nlflag == 2 && tokendlist[peektoken()])
+			return n1;
+		nlflag |= 2;
+
 		n2 = andor();
 		tok = readtoken();
 		if (tok == TBACKGND) {
@@ -189,31 +199,15 @@
 			n1 = n3;
 		}
 		switch (tok) {
-		case TBACKGND:
-		case TSEMI:
-			tok = readtoken();
-			/* fall through */
 		case TNL:
-			if (tok == TNL) {
-				parseheredoc();
-				if (nlflag == 1)
-					return n1;
-			} else {
-				tokpushback++;
-			}
-			checkkwd = CHKNL | CHKKWD | CHKALIAS;
-			if (tokendlist[peektoken()])
-				return n1;
-			break;
 		case TEOF:
-			if (heredoclist)
-				parseheredoc();
-			else
-				pungetc();		/* push back EOF on input */
 			tokpushback++;
-			return n1;
+			/* fall through */
+		case TBACKGND:
+		case TSEMI:
+			break;
 		default:
-			if (nlflag == 1)
+			if ((nlflag & 1))
 				synexpect(-1);
 			tokpushback++;
 			return n1;
@@ -743,6 +737,19 @@
 	return (t);
 }
 
+static void nlprompt(void)
+{
+	plinno++;
+	if (doprompt)
+		setprompt(2);
+}
+
+static void nlnoprompt(void)
+{
+	plinno++;
+	needprompt = doprompt;
+}
+
 
 /*
  * Read the next input token.
@@ -775,7 +782,7 @@
 		setprompt(2);
 	}
 	for (;;) {	/* until token or start of word found */
-		c = pgetc_macro();
+		c = pgetc();
 		switch (c) {
 		case ' ': case '\t':
 		case PEOA:
@@ -786,16 +793,13 @@
 			continue;
 		case '\\':
 			if (pgetc() == '\n') {
-				plinno++;
-				if (doprompt)
-					setprompt(2);
+				nlprompt();
 				continue;
 			}
 			pungetc();
 			goto breakloop;
 		case '\n':
-			plinno++;
-			needprompt = doprompt;
+			nlnoprompt();
 			RETURN(TNL);
 		case PEOF:
 			RETURN(TEOF);
@@ -827,6 +831,22 @@
 #undef RETURN
 }
 
+static int pgetc_eatbnl(void)
+{
+	int c;
+
+	while ((c = pgetc()) == '\\') {
+		if (pgetc() != '\n') {
+			pungetc();
+			break;
+		}
+
+		nlprompt();
+	}
+
+	return c;
+}
+
 
 
 /*
@@ -895,9 +915,7 @@
 				if (syntax == BASESYNTAX)
 					goto endword;	/* exit outer loop */
 				USTPUTC(c, out);
-				plinno++;
-				if (doprompt)
-					setprompt(2);
+				nlprompt();
 				c = pgetc();
 				goto loop;		/* continue outer loop */
 			case CWORD:
@@ -916,9 +934,7 @@
 					USTPUTC('\\', out);
 					pungetc();
 				} else if (c == '\n') {
-					plinno++;
-					if (doprompt)
-						setprompt(2);
+					nlprompt();
 				} else {
 					if (
 						dblquote &&
@@ -1009,7 +1025,7 @@
 					USTPUTC(c, out);
 				}
 			}
-			c = pgetc_macro();
+			c = pgetc();
 		}
 	}
 endword:
@@ -1074,8 +1090,7 @@
 
 		if (c == '\n' || c == PEOF) {
 			c = PEOF;
-			plinno++;
-			needprompt = doprompt;
+			nlnoprompt();
 		} else {
 			int len;
 
@@ -1179,7 +1194,7 @@
 	char *p;
 	static const char types[] = "}-+?=";
 
-	c = pgetc();
+	c = pgetc_eatbnl();
 	if (
 		(checkkwd & CHKEOFMARK) ||
 		c <= PEOA  ||
@@ -1188,7 +1203,7 @@
 		USTPUTC('$', out);
 		pungetc();
 	} else if (c == '(') {	/* $(command) or $((arith)) */
-		if (pgetc() == '(') {
+		if (pgetc_eatbnl() == '(') {
 			PARSEARITH();
 		} else {
 			pungetc();
@@ -1200,25 +1215,24 @@
 		STADJUST(1, out);
 		subtype = VSNORMAL;
 		if (likely(c == '{')) {
-			c = pgetc();
+			c = pgetc_eatbnl();
 			subtype = 0;
 		}
 varname:
 		if (is_name(c)) {
 			do {
 				STPUTC(c, out);
-				c = pgetc();
+				c = pgetc_eatbnl();
 			} while (is_in_name(c));
 		} else if (is_digit(c)) {
 			do {
 				STPUTC(c, out);
-				c = pgetc();
+				c = pgetc_eatbnl();
 			} while (is_digit(c));
-		}
-		else if (is_special(c)) {
+		} else {
 			int cc = c;
 
-			c = pgetc();
+			c = pgetc_eatbnl();
 
 			if (!subtype && cc == '#') {
 				subtype = VSLENGTH;
@@ -1227,7 +1241,7 @@
 					goto varname;
 
 				cc = c;
-				c = pgetc();
+				c = pgetc_eatbnl();
 				if (cc == '}' || c != '}') {
 					pungetc();
 					subtype = 0;
@@ -1236,16 +1250,20 @@
 				}
 			}
 
+			if (!is_special(cc)) {
+				if (subtype == VSLENGTH)
+					subtype = 0;
+				goto badsub;
+			}
+
 			USTPUTC(cc, out);
 		}
-		else
-			goto badsub;
 
 		if (subtype == 0) {
 			switch (c) {
 			case ':':
 				subtype = VSNUL;
-				c = pgetc();
+				c = pgetc_eatbnl();
 				/*FALLTHROUGH*/
 			default:
 				p = strchr(types, c);
@@ -1259,7 +1277,7 @@
 					int cc = c;
 					subtype = c == '#' ? VSTRIMLEFT :
 							     VSTRIMRIGHT;
-					c = pgetc();
+					c = pgetc_eatbnl();
 					if (c == cc)
 						subtype++;
 					else
@@ -1324,9 +1342,7 @@
 
 			case '\\':
                                 if ((pc = pgetc()) == '\n') {
-					plinno++;
-					if (doprompt)
-						setprompt(2);
+					nlprompt();
 					/*
 					 * If eating a newline, avoid putting
 					 * the newline into the new character
@@ -1348,8 +1364,7 @@
 				synerror("EOF in backquote substitution");
 
 			case '\n':
-				plinno++;
-				needprompt = doprompt;
+				nlnoprompt();
 				break;
 
 			default:
@@ -1427,10 +1442,6 @@
 
 #ifdef mkinit
 INCLUDE "parser.h"
-RESET {
-	tokpushback = 0;
-	checkkwd = 0;
-}
 #endif
 
 
diff -Naur dash-0.5.8/src/trap.c dash-0.5.8-git_d7582e6/src/trap.c
--- dash-0.5.8/src/trap.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/trap.c	2015-08-05 13:55:25.062024698 -0400
@@ -51,10 +51,6 @@
 #include "trap.h"
 #include "mystring.h"
 
-#ifdef HETIO
-#include "hetio.h"
-#endif
-
 /*
  * Sigmode records the current value of the signal handlers for the various
  * modes.  A value of zero means that the current handler is not known.
@@ -314,25 +310,40 @@
 	char *p;
 	char *q;
 	int i;
-	int savestatus;
+	int status, last_status;
 
-	savestatus = exitstatus;
+	if (!pendingsigs)
+		return;
+
+	status = savestatus;
+	last_status = status;
+	if (likely(status < 0)) {
+		status = exitstatus;
+		savestatus = status;
+	}
 	pendingsigs = 0;
 	barrier();
 
 	for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
 		if (!*q)
 			continue;
+
+		if (evalskip) {
+			pendingsigs = i + 1;
+			break;
+		}
+
 		*q = 0;
 
 		p = trap[i + 1];
 		if (!p)
 			continue;
 		evalstring(p, 0);
-		exitstatus = savestatus;
-		if (evalskip)
-			break;
+		if (evalskip != SKIPFUNC)
+			exitstatus = status;
 	}
+
+	savestatus = last_status;
 }
 
 
@@ -366,18 +377,11 @@
 {
 	struct jmploc loc;
 	char *p;
-	volatile int status;
 
-#ifdef HETIO
-	hetio_reset_term();
-#endif
-	status = exitstatus;
-	TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
-	if (setjmp(loc.loc)) {
-		if (exception == EXEXIT)
-			status = exitstatus;
+	savestatus = exitstatus;
+	TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
+	if (setjmp(loc.loc))
 		goto out;
-	}
 	handler = &loc;
 	if ((p = trap[0])) {
 		trap[0] = NULL;
@@ -392,7 +396,7 @@
 	if (likely(!setjmp(loc.loc)))
 		setjobctl(0);
 	flushall();
-	_exit(status);
+	_exit(savestatus);
 	/* NOTREACHED */
 }
 
diff -Naur dash-0.5.8/src/var.c dash-0.5.8-git_d7582e6/src/var.c
--- dash-0.5.8/src/var.c	2014-09-28 04:19:32.000000000 -0400
+++ dash-0.5.8-git_d7582e6/src/var.c	2015-08-05 13:55:25.065358031 -0400
@@ -80,6 +80,7 @@
 #else
 const char defifs[] = " \t\n";
 #endif
+MKINIT char defoptindvar[] = "OPTIND=1";
 
 int lineno;
 char linenovar[sizeof("LINENO=")+sizeof(int)*CHAR_BIT/3+1] = "LINENO=";
@@ -100,7 +101,7 @@
 	{ 0,	VSTRFIXED|VTEXTFIXED,		"PS1=$ ",	0 },
 	{ 0,	VSTRFIXED|VTEXTFIXED,		"PS2=> ",	0 },
 	{ 0,	VSTRFIXED|VTEXTFIXED,		"PS4=+ ",	0 },
-	{ 0,	VSTRFIXED|VTEXTFIXED,		"OPTIND=1",	getoptsreset },
+	{ 0,	VSTRFIXED|VTEXTFIXED,		defoptindvar,	getoptsreset },
 #ifdef WITH_LINENO
 	{ 0,	VSTRFIXED|VTEXTFIXED,		linenovar,	0 },
 #endif
@@ -142,7 +143,7 @@
 		}
 	}
 
-	setvarint("OPTIND", 1, 0);
+	setvareq(defoptindvar, VTEXTFIXED);
 
 	fmtstr(ppid + 5, sizeof(ppid) - 5, "%ld", (long) getppid());
 	setvareq(ppid, VTEXTFIXED);