summaryrefslogtreecommitdiff
path: root/system/dash
diff options
context:
space:
mode:
Diffstat (limited to 'system/dash')
-rw-r--r--system/dash/README11
-rw-r--r--system/dash/dash.SlackBuild12
-rw-r--r--system/dash/dash.info10
-rw-r--r--system/dash/patches/dash-0.5.8-git_d7582e6.diff2371
4 files changed, 2397 insertions, 7 deletions
diff --git a/system/dash/README b/system/dash/README
index c41d3417a6..4daf9c0301 100644
--- a/system/dash/README
+++ b/system/dash/README
@@ -1,4 +1,13 @@
DASH is a POSIX-compliant implementation of /bin/sh that aims to be as
small as possible. It does this without sacrificing speed where possible.
In fact, it is significantly faster than bash (the GNU Bourne-Again SHell)
-for most tasks.
+for most tasks.
+
+To patch in fixes from current git, add 'USE_GIT_PATCH=yes' to the command
+line when building, like this:
+
+# USE_GIT_PATCH=yes sh dash.Slackbuild
+
+or, if you use fakeroot to build:
+
+$ fakeroot env USE_GIT_PATCH=yes sh dash.SlackBuild
diff --git a/system/dash/dash.SlackBuild b/system/dash/dash.SlackBuild
index 47b9200929..f0c362a7d5 100644
--- a/system/dash/dash.SlackBuild
+++ b/system/dash/dash.SlackBuild
@@ -5,9 +5,11 @@
# Written by Vincent Batts, http://hashbangbash.com/
PRGNAM=dash
-VERSION=${VERSION:-0.5.6.1}
+VERSION=${VERSION:-0.5.8}
+_PATCH_VERS=${PATCH_VERS:-git_d7582e6}
BUILD=${BUILD:-1}
TAG=${TAG:-_SBo}
+USE_GIT_PATCH=${USE_GIT_PATCH:-no}
if [ -z "$ARCH" ]; then
case "$( uname -m )" in
@@ -44,6 +46,14 @@ cd $TMP
rm -rf $PRGNAM-$VERSION
tar xvf $CWD/$PRGNAM-$VERSION.tar.gz
cd $PRGNAM-$VERSION
+
+# add fixes from upstream devel, if requested
+if [ "$USE_GIT_PATCH" = "yes" ] && \
+ [ -f $CWD/patches/dash-${VERSION}-${_PATCH_VERS}.diff ]; then
+ patch -p1 < $CWD/patches/dash-${VERSION}-${_PATCH_VERS}.diff
+ VERSION="${VERSION}.${_PATCH_VERS}"
+fi
+
chown -R root:root .
find -L . \
\( -perm 777 -o -perm 775 -o -perm 750 -o -perm 711 -o -perm 555 -o -perm 511 \) \
diff --git a/system/dash/dash.info b/system/dash/dash.info
index 3e3ed5c887..6d206c8caa 100644
--- a/system/dash/dash.info
+++ b/system/dash/dash.info
@@ -1,10 +1,10 @@
PRGNAM="dash"
-VERSION="0.5.6.1"
+VERSION="0.5.8"
HOMEPAGE="http://gondor.apana.org.au/~herbert/dash/"
-DOWNLOAD="http://gondor.apana.org.au/~herbert/dash/files/dash-0.5.6.1.tar.gz"
-MD5SUM="1c846f4f5a33c0050b2045a6f7037e56"
+DOWNLOAD="http://gondor.apana.org.au/~herbert/dash/files/dash-0.5.8.tar.gz"
+MD5SUM="5c152209680dab3c319e8923f6c51378"
DOWNLOAD_x86_64=""
MD5SUM_x86_64=""
REQUIRES=""
-MAINTAINER="Vincent Batts"
-EMAIL="vbatts@hashbangbash.com"
+MAINTAINER="John Vogel"
+EMAIL="jvogel4@stny.rr.com"
diff --git a/system/dash/patches/dash-0.5.8-git_d7582e6.diff b/system/dash/patches/dash-0.5.8-git_d7582e6.diff
new file mode 100644
index 0000000000..ac5c6903d5
--- /dev/null
+++ b/system/dash/patches/dash-0.5.8-git_d7582e6.diff
@@ -0,0 +1,2371 @@
+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);