Please review changes against upstream code using SCM,
see the Vcs-* tags in debian/control for its location.

--- mksh-56c.orig/Build.sh
+++ mksh-56c/Build.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.731 2018/01/13 21:38:06 tg Exp $'
+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.732 2018/01/25 12:33:54 tg Exp $'
 #-
 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #		2011, 2012, 2013, 2014, 2015, 2016, 2017
@@ -1060,11 +1060,12 @@ AIX)
 Darwin)
 	vv '|' "hwprefs machine_type os_type os_class >&2"
 	vv '|' "sw_vers >&2"
-	vv '|' "system_profiler SPSoftwareDataType SPHardwareDataType >&2"
+	vv '|' "system_profiler -detailLevel mini SPSoftwareDataType SPHardwareDataType >&2"
 	vv '|' "/bin/sh --version >&2"
 	vv '|' "xcodebuild -version >&2"
 	vv '|' "uname -a >&2"
-	vv '|' "sysctl kern.version hw.machine hw.model hw.memsize hw.availcpu hw.cpufrequency hw.byteorder hw.cpu64bit_capable >&2"
+	vv '|' "sysctl kern.version hw.machine hw.model hw.memsize hw.availcpu hw.ncpu hw.cpufrequency hw.byteorder hw.cpu64bit_capable >&2"
+	vv '|' "sysctl hw.cpufrequency hw.byteorder hw.cpu64bit_capable hw.ncpu >&2"
 	;;
 IRIX*)
 	vv '|' "uname -a >&2"
--- mksh-56c.orig/check.t
+++ mksh-56c/check.t
@@ -1,8 +1,8 @@
-# $MirOS: src/bin/mksh/check.t,v 1.801 2018/01/14 01:47:33 tg Exp $
+# $MirOS: src/bin/mksh/check.t,v 1.809 2018/10/20 18:48:26 tg Exp $
 # -*- mode: sh -*-
 #-
 # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-#	      2011, 2012, 2013, 2014, 2015, 2016, 2017
+#	      2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
 #	mirabilos <m@mirbsd.org>
 #
 # Provided that these terms and disclaimer and all copyright notices
@@ -30,7 +30,7 @@
 # (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
 
 expected-stdout:
-	@(#)MIRBSD KSH R56 2018/01/14
+	@(#)MIRBSD KSH R56 2018/10/20
 description:
 	Check base version of full shell
 stdin:
@@ -39,7 +39,7 @@ name: KSH_VERSION
 category: !shell:legacy-yes
 ---
 expected-stdout:
-	@(#)LEGACY KSH R56 2018/01/14
+	@(#)LEGACY KSH R56 2018/10/20
 description:
 	Check base version of legacy shell
 stdin:
@@ -162,6 +162,38 @@ stdin:
 expected-stdout:
 	;
 ---
+name: selftest-tty-absent
+description:
+	Check that a controlling tty is not present as regress:no-ctty was used
+	(if this test fails for you DO NOT PASS regress:no-ctty and fix every
+	other test that fails: why u use it if u haz ctty?)
+category: regress:no-ctty
+env-setup: !ENV=./envf!
+file-setup: file 644 "envf"
+	PS1=X
+arguments: !-i!
+stdin:
+	echo ok
+expected-stdout:
+	ok
+expected-stderr-pattern:
+	/mksh: warning: won't have full job control\nXX/
+---
+name: selftest-tty-present
+description:
+	Check that a controlling tty is present as regress:no-ctty was not used
+need-ctty: yes
+env-setup: !ENV=./envf!
+file-setup: file 644 "envf"
+	PS1=X
+arguments: !-i!
+stdin:
+	echo ok
+expected-stdout:
+	ok
+expected-stderr: !
+	XX
+---
 name: alias-1
 description:
 	Check that recursion is detected/avoided in aliases.
@@ -2455,7 +2487,7 @@ expected-stdout:
 name: glob-range-3
 description:
 	Check that globbing matches the right things...
-# breaks on Mac OSX (HFS+ non-standard Unicode canonical decomposition)
+# breaks on Mac OSX (HFS+ non-standard UTF-8 canonical decomposition)
 # breaks on Cygwin 1.7 (files are now UTF-16 or something)
 # breaks on QNX 6.4.1 (says RT)
 category: !os:cygwin,!os:darwin,!os:msys,!os:nto,!os:os2,!os:os390
@@ -3033,6 +3065,19 @@ expected-stdout:
 	got four on fd#4
 	got five on fd#5
 ---
+name: heredoc-15
+description:
+	Check high-bit7 separators work
+stdin:
+	u=ä
+	tr a-z A-Z <<-…
+		m${u}h
+	…
+	echo ok
+expected-stdout:
+	MäH
+	ok
+---
 name: heredoc-comsub-1
 description:
 	Tests for here documents in COMSUB, taken from Austin ML
@@ -3526,6 +3571,25 @@ stdin:
 expected-stdout:
 	'blah  1'
 ---
+name: single-quotes-in-heredoc-trim
+description:
+	In some cases, single quotes inside {} in heredoc are not normal
+stdin:
+	x=notOK
+	cat <<EOF
+	1: ${x#not} ${x:+${x#not}}
+	2: ${x#\n\o\t} ${x:+${x#\n\o\t}}
+	3: ${x#"not"} ${x:+${x#"not"}}
+	4: ${x#'not'} ${x:+${x#'not'}}
+	5: ${x#$'not'} ${x:+${x#$'not'}}
+	EOF
+expected-stdout:
+	1: OK OK
+	2: OK OK
+	3: OK OK
+	4: OK OK
+	5: OK OK
+---
 name: history-basic
 description:
 	See if we can test history at all
@@ -6835,6 +6899,21 @@ expected-stdout:
 	3 10 .
 	4 -2147483646 .
 ---
+name: export-1
+description:
+	Check allexport works, basic
+stdin:
+	qa=1
+	set -A qb 2 3
+	set -a
+	qc=4
+	set -A qd 5 6
+	export -p | grep '^export q'
+expected-stdout:
+	export qc=4
+	export qd[0]=5
+	export qd[1]=6
+---
 name: readonly-0
 description:
 	Ensure readonly is honoured for assignments and unset
@@ -7179,6 +7258,32 @@ expected-stdout:
 	HI
 	2 4
 ---
+name: xxx-substitution-eval-order-2
+description:
+	Check some corner cases
+stdin:
+	unset var
+	i=42
+	: ${var+${q[i=777]}} required to be lazy by POSIX
+	echo 1=$i
+	var=meow
+	i=42
+	: ${var+${q[i=777]}} eval since var is now set
+	echo 2=$i
+	unset var
+	i=42
+	: ${var#${q[i=777]}} pattern is needed even if var is empty
+	echo 3=$i
+	var=meow
+	i=42
+	: ${var#${q[i=777]}}
+	echo 4=$i
+expected-stdout:
+	1=42
+	2=777
+	3=777
+	4=777
+---
 name: xxx-set-option-1
 description:
 	Check option parsing in set
@@ -8444,12 +8549,32 @@ stdin:
 expected-stdout:
 	<16#1     > <     16#1> <16#000001> <16#1     > <     16#1> <0000016#1>
 ---
+name: typeset-padding-3
+description:
+	Check for a regression in which UTF-8 wasn’t left-padded right
+stdin:
+	set -U
+	nl=$'\n'
+	typeset -L20 x='.  ak'
+	typeset -R20 y='.  ak'
+	print -r -- "<$x> (1$nl<12345678910 345678920$nl<$y> 1)"
+	typeset -L20 x='.  aẞ'
+	typeset -R20 y='.  aẞ'
+	print -r -- "<$x> (2$nl<12345678910 345678920$nl<$y> 2)"
+expected-stdout:
+	<.  ak               > (1
+	<12345678910 345678920
+	<               .  ak> 1)
+	<.  aẞ               > (2
+	<12345678910 345678920
+	<               .  aẞ> 2)
+---
 name: utf8bom-1
 description:
 	Check that the UTF-8 Byte Order Mark is ignored as the first
 	multibyte character of the shell input (with -c, from standard
 	input, as file, or as eval argument), but nowhere else
-# breaks on Mac OSX (HFS+ non-standard Unicode canonical decomposition)
+# breaks on Mac OSX (HFS+ non-standard UTF-8 canonical decomposition)
 category: !os:darwin,!shell:ebcdic-yes
 stdin:
 	mkdir foo
@@ -10328,7 +10453,7 @@ expected-stdout:
 ---
 name: integer-base-one-3Ws
 description:
-	some sample code for hexdumping Unicode
+	some sample code for hexdumping UCS-2
 	not NUL safe; input lines must be NL terminated
 stdin:
 	set -U
@@ -10496,7 +10621,7 @@ expected-stdout:
 ---
 name: integer-base-one-3Wr
 description:
-	some sample code for hexdumping Unicode; NUL and binary safe
+	some sample code for hexdumping UCS-2; NUL and binary safe
 stdin:
 	set -U
 	{
@@ -10616,7 +10741,7 @@ expected-stdout:
 ---
 name: integer-base-one-5A
 description:
-	Check to see that we’re NUL and Unicode safe
+	Check to see that we’re NUL and UCS safe
 category: !shell:ebcdic-yes
 stdin:
 	set +U
@@ -10630,7 +10755,7 @@ expected-stdout:
 ---
 name: integer-base-one-5E
 description:
-	Check to see that we’re NUL and Unicode safe
+	Check to see that we’re NUL and UCS safe
 category: !shell:ebcdic-no
 stdin:
 	set +U
@@ -10644,7 +10769,7 @@ expected-stdout:
 ---
 name: integer-base-one-5W
 description:
-	Check to see that we’re NUL and Unicode safe
+	Check to see that we’re NUL and UCS safe
 stdin:
 	set -U
 	print 'a\0b€c' >x
--- mksh-56c.orig/edit.c
+++ mksh-56c/edit.c
@@ -28,7 +28,7 @@
 
 #ifndef MKSH_NO_CMDLINE_EDITING
 
-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.342 2018/01/14 00:03:00 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.343 2018/07/15 16:16:38 tg Exp $");
 
 /*
  * in later versions we might use libtermcap for this, but since external
@@ -3831,7 +3831,7 @@ vi_hook(int ch)
 			vs = save_es;
 
 			i = (unsigned)srchlen;
-			while (--i >= n)
+			while (i-- > n)
 				vs->linelen -= char_len(locpat[i]);
 			srchlen = (int)n;
 			vs->cursor = vs->linelen;
--- mksh-56c.orig/exec.c
+++ mksh-56c/exec.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.201 2017/10/11 21:09:24 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.202 2018/10/07 01:10:11 tg Exp $");
 
 #ifndef MKSH_DEFAULT_EXECSHELL
 #define MKSH_DEFAULT_EXECSHELL	MKSH_UNIXROOT "/bin/sh"
@@ -1011,7 +1011,7 @@ scriptexec(struct op *tp, const char **a
 	cap.ro = ap;
 	execve(args.rw[0], args.rw, cap.rw);
 
-	/* report both the programme that was run and the bogus interpreter */
+	/* report both the program that was run and the bogus interpreter */
 	errorf(Tf_sD_sD_s, tp->str, sh, cstrerror(errno));
 }
 
--- mksh-56c.orig/expr.c
+++ mksh-56c/expr.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.103 2018/01/14 01:29:47 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.105 2018/08/10 02:53:33 tg Exp $");
 
 #define EXPRTOK_DEFNS
 #include "exprtok.h"
@@ -885,7 +885,7 @@ static int mb_ucsbsearch(const struct mb
     unsigned int val) MKSH_A_PURE;
 
 /*
- * Generated from the Unicode Character Database, Version 10.0.0, by
+ * Generated from the UCD 11.0.0 by
  * MirOS: contrib/code/Snippets/eawparse,v 1.12 2017/09/06 16:05:45 tg Exp $
  */
 
@@ -909,12 +909,13 @@ static const struct mb_ucsrange mb_ucs_c
 	{ 0x0730, 0x074A },
 	{ 0x07A6, 0x07B0 },
 	{ 0x07EB, 0x07F3 },
+	{ 0x07FD, 0x07FD },
 	{ 0x0816, 0x0819 },
 	{ 0x081B, 0x0823 },
 	{ 0x0825, 0x0827 },
 	{ 0x0829, 0x082D },
 	{ 0x0859, 0x085B },
-	{ 0x08D4, 0x08E1 },
+	{ 0x08D3, 0x08E1 },
 	{ 0x08E3, 0x0902 },
 	{ 0x093A, 0x093A },
 	{ 0x093C, 0x093C },
@@ -927,6 +928,7 @@ static const struct mb_ucsrange mb_ucs_c
 	{ 0x09C1, 0x09C4 },
 	{ 0x09CD, 0x09CD },
 	{ 0x09E2, 0x09E3 },
+	{ 0x09FE, 0x09FE },
 	{ 0x0A01, 0x0A02 },
 	{ 0x0A3C, 0x0A3C },
 	{ 0x0A41, 0x0A42 },
@@ -953,6 +955,7 @@ static const struct mb_ucsrange mb_ucs_c
 	{ 0x0BC0, 0x0BC0 },
 	{ 0x0BCD, 0x0BCD },
 	{ 0x0C00, 0x0C00 },
+	{ 0x0C04, 0x0C04 },
 	{ 0x0C3E, 0x0C40 },
 	{ 0x0C46, 0x0C48 },
 	{ 0x0C4A, 0x0C4D },
@@ -1072,6 +1075,7 @@ static const struct mb_ucsrange mb_ucs_c
 	{ 0xA825, 0xA826 },
 	{ 0xA8C4, 0xA8C5 },
 	{ 0xA8E0, 0xA8F1 },
+	{ 0xA8FF, 0xA8FF },
 	{ 0xA926, 0xA92D },
 	{ 0xA947, 0xA951 },
 	{ 0xA980, 0xA982 },
@@ -1173,7 +1177,7 @@ mb_ucsbsearch(const struct mb_ucsrange a
 	return (0);
 }
 
-/* Unix column width of a wide character (Unicode code point, really) */
+/* Unix column width of a wide character (UCS code point, really) */
 int
 utf_wcwidth(unsigned int wc)
 {
--- mksh-56c.orig/funcs.c
+++ mksh-56c/funcs.c
@@ -38,7 +38,7 @@
 #endif
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.353 2018/01/14 01:26:49 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.355 2018/10/20 21:04:28 tg Exp $");
 
 #if HAVE_KILLPG
 /*
@@ -493,7 +493,7 @@ c_print(const char **wp)
 						Xput(xs, xp, '\\');
 					}
 				} else if ((unsigned int)c > 0xFF) {
-					/* generic function returned Unicode */
+					/* generic function returned UCS */
 					po.ts[utf_wctomb(po.ts, c - 0x100)] = 0;
 					c = 0;
 					do {
@@ -2964,6 +2964,37 @@ test_eval(Test_env *te, Test_op op, cons
 	case TO_STGT:
 		return (strcmp(opnd1, opnd2) > 0);
 
+	/* -nt */
+	case TO_FILNT:
+		/*
+		 * ksh88/ksh93 succeed if file2 can't be stated
+		 * (subtly different from 'does not exist').
+		 */
+		return (stat(opnd1, &b1) == 0 &&
+		    (((s = stat(opnd2, &b2)) == 0 &&
+		    b1.st_mtime > b2.st_mtime) || s < 0));
+
+	/* -ot */
+	case TO_FILOT:
+		/*
+		 * ksh88/ksh93 succeed if file1 can't be stated
+		 * (subtly different from 'does not exist').
+		 */
+		return (stat(opnd2, &b2) == 0 &&
+		    (((s = stat(opnd1, &b1)) == 0 &&
+		    b1.st_mtime < b2.st_mtime) || s < 0));
+
+	/* -ef */
+	case TO_FILEQ:
+		return (stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 &&
+		    b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino);
+
+	/* all other cases */
+	case TO_NONOP:
+	case TO_NONNULL:
+		/* throw the error */
+		break;
+
 	/* -eq */
 	case TO_INTEQ:
 	/* -ne */
@@ -3000,37 +3031,6 @@ test_eval(Test_env *te, Test_op op, cons
 			break;
 		}
 		/* NOTREACHED */
-
-	/* -nt */
-	case TO_FILNT:
-		/*
-		 * ksh88/ksh93 succeed if file2 can't be stated
-		 * (subtly different from 'does not exist').
-		 */
-		return (stat(opnd1, &b1) == 0 &&
-		    (((s = stat(opnd2, &b2)) == 0 &&
-		    b1.st_mtime > b2.st_mtime) || s < 0));
-
-	/* -ot */
-	case TO_FILOT:
-		/*
-		 * ksh88/ksh93 succeed if file1 can't be stated
-		 * (subtly different from 'does not exist').
-		 */
-		return (stat(opnd2, &b2) == 0 &&
-		    (((s = stat(opnd1, &b1)) == 0 &&
-		    b1.st_mtime < b2.st_mtime) || s < 0));
-
-	/* -ef */
-	case TO_FILEQ:
-		return (stat (opnd1, &b1) == 0 && stat (opnd2, &b2) == 0 &&
-		    b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino);
-
-	/* all other cases */
-	case TO_NONOP:
-	case TO_NONNULL:
-		/* throw the error */
-		break;
 	}
 	(*te->error)(te, 0, "internal error: unknown op");
 	return (1);
--- mksh-56c.orig/histrap.c
+++ mksh-56c/histrap.c
@@ -3,7 +3,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2014, 2015, 2016, 2017
+ *		 2011, 2012, 2014, 2015, 2016, 2017, 2018
  *	mirabilos <m@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -27,7 +27,7 @@
 #include <sys/file.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.166 2017/08/07 23:25:09 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.167 2018/04/28 17:16:54 tg Exp $");
 
 Trap sigtraps[ksh_NSIG + 1];
 static struct sigaction Sigact_ign;
@@ -879,7 +879,8 @@ hist_persist_init(void)
 		}
 	}
  hist_trunc_done:
-	histfsize = lseek(histfd, (off_t)0, SEEK_END);
+	if ((histfsize = lseek(histfd, (off_t)0, SEEK_END)) < 0)
+		goto hist_init_fail;
  hist_init_tail:
 	mksh_unlkfd(histfd);
 }
@@ -962,8 +963,9 @@ writehistfile(int lno, const char *cmd)
 	unsigned char *base, *news;
 
 	mksh_lockfd(histfd);
-	sizenow = lseek(histfd, (off_t)0, SEEK_END);
-	if (sizenow < histfsize) {
+	if ((sizenow = lseek(histfd, (off_t)0, SEEK_END)) < 0)
+		goto bad;
+	else if (sizenow < histfsize) {
 		/* the file has shrunk; trust it just appending the new data */
 		/* well, for now, anyway… since mksh strdups all into memory */
 		/* we can use a nicer approach some time later… */
@@ -998,7 +1000,8 @@ writehistfile(int lno, const char *cmd)
 		hist_finish();
 		return;
 	}
-	histfsize = lseek(histfd, (off_t)0, SEEK_END);
+	if ((histfsize = lseek(histfd, (off_t)0, SEEK_END)) < 0)
+		goto bad;
 	mksh_unlkfd(histfd);
 }
 
--- mksh-56c.orig/jobs.c
+++ mksh-56c/jobs.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.125 2018/01/05 20:08:34 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.127 2018/07/15 16:23:10 tg Exp $");
 
 #if HAVE_KILLPG
 #define mksh_killpg		killpg
@@ -169,12 +169,6 @@ static void tty_init_state(void);
 void
 j_init(void)
 {
-#ifndef MKSH_UNEMPLOYED
-	bool mflagset = Flag(FMONITOR) != 127;
-
-	Flag(FMONITOR) = 0;
-#endif
-
 #ifndef MKSH_NOPROSPECTOFWORK
 	(void)sigemptyset(&sm_default);
 	sigprocmask(SIG_SETMASK, &sm_default, NULL);
@@ -190,8 +184,8 @@ j_init(void)
 #endif
 
 #ifndef MKSH_UNEMPLOYED
-	if (!mflagset && Flag(FTALKING))
-		Flag(FMONITOR) = 1;
+	if (Flag(FMONITOR) == 127)
+		Flag(FMONITOR) = Flag(FTALKING);
 
 	/*
 	 * shl_j is used to do asynchronous notification (used in
@@ -1932,7 +1926,7 @@ tty_init_talking(void)
 		break;
 	case 2:
 #ifndef MKSH_DISABLE_TTY_WARNING
-		warningf(false, Tf_sD_s_s, Tcant_find, Ttty_fd,
+		warningf(false, Tf_s_sD_s, Tcant_find, Ttty_fd,
 		    cstrerror(errno));
 #endif
 		break;
--- mksh-56c.orig/lex.c
+++ mksh-56c/lex.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.247 2018/01/14 01:44:01 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.250 2018/10/20 18:34:14 tg Exp $");
 
 /*
  * states while lexing word
@@ -77,12 +77,17 @@ typedef struct lex_state {
 	short nparen;
 	/* type of this state */
 	uint8_t type;
+	/* extra flags */
+	uint8_t ls_flags;
 } Lex_state;
 #define ls_base		u.base
 #define ls_start	u.start
 #define ls_bool		u.abool
 #define ls_adelim	u.adelim
 
+/* ls_flags */
+#define LS_HEREDOC	BIT(0)
+
 typedef struct {
 	Lex_state *base;
 	Lex_state *end;
@@ -147,9 +152,11 @@ getsc_r(int c)
 #define STATE_BSIZE	8
 
 #define PUSH_STATE(s)	do {					\
+	uint8_t state_flags = statep->ls_flags;			\
 	if (++statep == state_info.end)				\
 		statep = push_state_i(&state_info, statep);	\
 	state = statep->type = (s);				\
+	statep->ls_flags = state_flags;				\
 } while (/* CONSTCOND */ 0)
 
 #define POP_STATE()	do {					\
@@ -242,6 +249,7 @@ yylex(int cf)
 
 	/* Initial state: one of SWORD SLETPAREN SHEREDELIM SBASE */
 	statep->type = state;
+	statep->ls_flags = (cf & HEREDOC) ? LS_HEREDOC : 0;
 
 	/* collect non-special or quoted characters to form word */
 	while (!((c = getsc()) == 0 ||
@@ -319,7 +327,7 @@ yylex(int cf)
 				break;
 			case ORD('\''):
  open_ssquote_unless_heredoc:
-				if ((cf & HEREDOC))
+				if ((statep->ls_flags & LS_HEREDOC))
 					goto store_char;
 				*wp++ = OQUOTE;
 				ignore_backslash_newline++;
@@ -357,7 +365,7 @@ yylex(int cf)
 				c = getsc();
 				switch (c) {
 				case ORD('"'):
-					if ((cf & HEREDOC))
+					if ((statep->ls_flags & LS_HEREDOC))
 						goto heredocquote;
 					/* FALLTHROUGH */
 				case ORD('\\'):
@@ -388,6 +396,8 @@ yylex(int cf)
 					if ((unsigned int)c == ORD('(' /*)*/)) {
 						*wp++ = EXPRSUB;
 						PUSH_SRETRACE(SASPAREN);
+						/* unneeded? */
+						/*statep->ls_flags &= ~LS_HEREDOC;*/
 						statep->nparen = 2;
 						*retrace_info->xp++ = '(';
 					} else {
@@ -434,6 +444,8 @@ yylex(int cf)
 							*wp++ = ADELIM;
 							*wp++ = ':';
 							PUSH_STATE(SBRACE);
+							/* perhaps unneeded? */
+							statep->ls_flags &= ~LS_HEREDOC;
 							PUSH_STATE(SADELIM);
 							statep->ls_adelim.delimiter = ':';
 							statep->ls_adelim.num = 1;
@@ -449,6 +461,8 @@ yylex(int cf)
 							}
 							ungetsc(c);
 							PUSH_STATE(SBRACE);
+							/* perhaps unneeded? */
+							statep->ls_flags &= ~LS_HEREDOC;
 							PUSH_STATE(SADELIM);
 							statep->ls_adelim.delimiter = ':';
 							statep->ls_adelim.num = 2;
@@ -466,6 +480,8 @@ yylex(int cf)
 						} else
 							ungetsc(c);
 						PUSH_STATE(SBRACE);
+						/* perhaps unneeded? */
+						statep->ls_flags &= ~LS_HEREDOC;
 						PUSH_STATE(SADELIM);
 						statep->ls_adelim.delimiter = '/';
 						statep->ls_adelim.num = 1;
@@ -489,6 +505,8 @@ yylex(int cf)
 							PUSH_STATE(STBRACEBOURNE);
 						else
 							PUSH_STATE(STBRACEKORN);
+						/* single-quotes-in-heredoc-trim */
+						statep->ls_flags &= ~LS_HEREDOC;
 					} else {
 						ungetsc(c);
 						if (state == SDQUOTE ||
@@ -496,6 +514,8 @@ yylex(int cf)
 							PUSH_STATE(SQBRACE);
 						else
 							PUSH_STATE(SBRACE);
+						/* here no LS_HEREDOC removal */
+						/* single-quotes-in-heredoc-braces */
 					}
 				} else if (ctype(c, C_ALPHX)) {
 					*wp++ = OSUBST;
@@ -601,7 +621,8 @@ yylex(int cf)
 		case SSQUOTE:
 			if ((unsigned int)c == ORD('\'')) {
 				POP_STATE();
-				if ((cf & HEREDOC) || state == SQBRACE)
+				if ((statep->ls_flags & LS_HEREDOC) ||
+				    state == SQBRACE)
 					goto store_char;
 				*wp++ = CQUOTE;
 				ignore_backslash_newline--;
@@ -1155,7 +1176,7 @@ readhere(struct ioword *iop)
 			/* Newline terminates here document marker */
 			goto heredoc_found_terminator;
 		}
-	} else if (c == *eofp++)
+	} else if ((unsigned int)c == ord(*eofp++))
 		/* store; then read and compare next character */
 		goto heredoc_store_and_loop;
 	/* nope, mismatch; read until end of line */
@@ -1338,7 +1359,7 @@ getsc_line(Source *s)
 {
 	char *xp = Xstring(s->xs, xp), *cp;
 	bool interactive = Flag(FTALKING) && s->type == SSTDIN;
-	bool have_tty = tobool(interactive && (s->flags & SF_TTY));
+	bool have_tty = interactive && (s->flags & SF_TTY) && tty_hasstate;
 
 	/* Done here to ensure nothing odd happens when a timeout occurs */
 	XcheckN(s->xs, xp, LINE);
--- mksh-56c.orig/lksh.1
+++ mksh-56c/lksh.1
@@ -1,4 +1,4 @@
-.\" $MirOS: src/bin/mksh/lksh.1,v 1.23 2017/04/02 13:38:02 tg Exp $
+.\" $MirOS: src/bin/mksh/lksh.1,v 1.24 2018/07/15 13:57:18 tg Exp $
 .\"-
 .\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016, 2017
 .\"	mirabilos <m@mirbsd.org>
@@ -74,7 +74,7 @@
 .\" with -mandoc, it might implement .Mx itself, but we want to
 .\" use our own definition. And .Dd must come *first*, always.
 .\"
-.Dd $Mdocdate: April 2 2017 $
+.Dd $Mdocdate: July 15 2018 $
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
@@ -304,9 +304,11 @@ is not exactly specified.
 .Pp
 Talk to the
 .Mx
-development team using the mailing list at
-.Aq miros\-mksh@mirbsd.org
-or the
+development team and users using the mailing list at
+.Aq Mt miros\-mksh@mirbsd.org
+(please note the EU-DSGVO/GDPR notice on
+.Pa http://www.mirbsd.org/rss.htm#lists
+and in the SMTP banner!) or the
 .Li \&#\&!/bin/mksh
 .Pq or Li \&#ksh
 IRC channel at
--- mksh-56c.orig/main.c
+++ mksh-56c/main.c
@@ -34,7 +34,7 @@
 #include <locale.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.347 2018/01/13 21:45:07 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.349 2018/05/08 17:37:36 tg Exp $");
 
 #ifndef MKSHRC_PATH
 #define MKSHRC_PATH	"~/.mkshrc"
@@ -457,7 +457,7 @@ main_init(int argc, const char *argv[],
 	/* Set this before parsing arguments */
 	Flag(FPRIVILEGED) = (kshuid != ksheuid || kshgid != kshegid) ? 2 : 0;
 
-	/* this to note if monitor is set on command line (see below) */
+	/* record if monitor is set on command line (see j_init() in jobs.c) */
 #ifndef MKSH_UNEMPLOYED
 	Flag(FMONITOR) = 127;
 #endif
@@ -1959,7 +1959,7 @@ x_mkraw(int fd, mksh_ttyst *ocb, bool fo
 	/* OSF/1 processes lnext when ~icanon */
 	cb.c_cc[VLNEXT] = _POSIX_VDISABLE;
 #endif
-	/* SunOS 4.1.x & OSF/1 processes discard(flush) when ~icanon */
+	/* SunOS 4.1.x and OSF/1 process discard(flush) when ~icanon */
 #if defined(VDISCARD) && defined(_POSIX_VDISABLE)
 	cb.c_cc[VDISCARD] = _POSIX_VDISABLE;
 #endif
--- mksh-56c.orig/misc.c
+++ mksh-56c/misc.c
@@ -32,7 +32,7 @@
 #include <grp.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.291 2018/01/14 00:03:03 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.293 2018/08/10 02:53:35 tg Exp $");
 
 #define KSH_CHVT_FLAG
 #ifdef MKSH_SMALL
@@ -1346,7 +1346,14 @@ print_value_quoted(struct shf *shf, cons
 	const unsigned char *p = (const unsigned char *)s;
 	bool inquote = true;
 
-	/* first, check whether any quotes are needed */
+	/* first, special-case empty strings (for re-entrancy) */
+	if (!*s) {
+		shf_putc('\'', shf);
+		shf_putc('\'', shf);
+		return;
+	}
+
+	/* non-empty; check whether any quotes are needed */
 	while (rtt2asc(c = *p++) >= 32)
 		if (ctype(c, C_QUOTE | C_SPC))
 			inquote = false;
@@ -2449,7 +2456,7 @@ getrusage(int what, struct rusage *ru)
  * and fp (put back a char) for backslash escapes,
  * assuming the first call to *fg gets the char di-
  * rectly after the backslash; return the character
- * (0..0xFF), Unicode (wc + 0x100), or -1 if no known
+ * (0..0xFF), UCS (wc + 0x100), or -1 if no known
  * escape sequence was found
  */
 int
@@ -2531,9 +2538,9 @@ unbksl(bool cstyle, int (*fg)(void), voi
 		/**
 		 * x:	look for a hexadecimal number with up to
 		 *	two (C style: arbitrary) digits; convert
-		 *	to raw octet (C style: Unicode if >0xFF)
+		 *	to raw octet (C style: UCS if >0xFF)
 		 * u/U:	look for a hexadecimal number with up to
-		 *	four (U: eight) digits; convert to Unicode
+		 *	four (U: eight) digits; convert to UCS
 		 */
 		wc = 0;
 		n = 0;
@@ -2555,7 +2562,7 @@ unbksl(bool cstyle, int (*fg)(void), voi
 		if (!n)
 			goto unknown_escape;
 		if ((cstyle && wc > 0xFF) || fc != 'x')
-			/* Unicode marker */
+			/* UCS marker */
 			wc += 0x100;
 		break;
 	case '\'':
--- mksh-56c.orig/mksh.1
+++ mksh-56c/mksh.1
@@ -1,8 +1,9 @@
-.\" $MirOS: src/bin/mksh/mksh.1,v 1.451 2017/08/16 21:40:14 tg Exp $
+.\" $MirOS: src/bin/mksh/mksh.1,v 1.460 2018/08/17 20:33:08 tg Exp $
 .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $
 .\"-
 .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-.\"		2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
+.\"		2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
+.\"		2018
 .\"	mirabilos <m@mirbsd.org>
 .\"
 .\" Provided that these terms and disclaimer and all copyright notices
@@ -76,7 +77,7 @@
 .\" with -mandoc, it might implement .Mx itself, but we want to
 .\" use our own definition. And .Dd must come *first*, always.
 .\"
-.Dd $Mdocdate: August 16 2017 $
+.Dd $Mdocdate: August 17 2018 $
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
@@ -1046,7 +1047,7 @@ and
 .Dq Li \eu#### ,
 .Dq #
 means a hexadecimal digit, of which there may be none up to four or eight;
-these escapes translate a Unicode codepoint to UTF-8.
+these escapes translate a Universal Coded Character Set codepoint to UTF-8.
 Furthermore,
 .Dq Li \eE
 and
@@ -1082,7 +1083,7 @@ and yield raw octets; hexadecimal sequen
 greedily eat up as many hexadecimal digits
 .Dq #
 as they can and terminate with the first non-hexadecimal digit;
-these translate a Unicode codepoint to UTF-8.
+these translate a Universal Coded Character Set codepoint to UTF-8.
 The sequence
 .Dq Li \ec# ,
 where
@@ -1364,6 +1365,10 @@ or
 where
 .Ar name
 is a parameter name.
+Substitutions of an an array in scalar context, i.e. without an
+.Ar expr
+in the latter form mentioned above, expand the element with the key
+.Dq 0 .
 Substitution of all array elements with
 .Pf ${ Ns Ar name Ns \&[*]}
 and
@@ -1519,11 +1524,7 @@ on it; if
 .Ar word
 is not needed, it is not evaluated.
 .Pp
-The following forms of parameter substitution can also be used (if
-.Ar name
-is an array, the element with the key
-.Dq 0
-will be substituted in scalar context):
+The following forms of parameter substitution can also be used:
 .Pp
 .Bl -tag -width Ds -compact
 .It Pf ${# Ns Ar name Ns \&}
@@ -1823,10 +1824,10 @@ built-in command will display the result
 in any search path other than the empty path.
 .It Ev COLUMNS
 Set to the number of columns on the terminal or window.
-Always set, defaults to 80, unless the
-value as reported by
+If never unset and not imported, always set dynamically;
+unless the value as reported by
 .Xr stty 1
-is non-zero and sane enough (minimum is 12x3); similar for
+is non-zero and sane enough (minimum is 12x3), defaults to 80; similar for
 .Ev LINES .
 This parameter is used by the interactive line editing modes and by the
 .Ic select ,
@@ -1995,7 +1996,7 @@ The line number of the function or shell
 executed.
 .It Ev LINES
 Set to the number of lines on the terminal or window.
-Always set, defaults to 24.
+Defaults to 24; always set, unless imported or unset.
 See
 .Ev COLUMNS .
 .It Ev OLDPWD
@@ -2651,7 +2652,8 @@ as required by the standard), as that's
 As a special
 .Nm mksh
 extension, numbers to the base of one are treated as either (8-bit
-transparent) ASCII or Unicode codepoints, depending on the shell's
+transparent) ASCII or Universal Coded Character Set codepoints,
+depending on the shell's
 .Ic utf8\-mode
 flag (current setting).
 The
@@ -2664,7 +2666,7 @@ instead of
 is also supported.
 Note that NUL bytes (integral value of zero) cannot be used.
 An unset or empty parameter evaluates to 0 in integer context.
-In Unicode mode, raw octets are mapped into the range EF80..EFFF as in
+In UTF-8 mode, raw octets are mapped into the range EF80..EFFF as in
 OPTU-8, which is in the PUA and has been assigned by CSUR for this use.
 If more than one octet in ASCII mode, or a sequence of more than one
 octet not forming a valid and minimal CESU-8 sequence is passed, the
@@ -2903,8 +2905,6 @@ option is turned on for the function's d
 The
 .Dq export
 attribute of functions is currently not used.
-In the original Korn shell,
-exported functions are visible to shell scripts that are executed.
 .Pp
 Since functions are executed in the current shell environment, parameter
 assignments made inside functions are visible after the function completes.
@@ -4667,15 +4667,15 @@ the user CPU time (time spent running in
 (time spent running in kernel mode).
 Times are reported to standard error; the format of the output is:
 .Pp
-.Dl "0m0.00s real     0m0.00s user     0m0.00s system"
+.Dl "0m0.03s real     0m0.02s user     0m0.01s system"
 .Pp
 If the
 .Fl p
 option is given the output is slightly longer:
 .Bd -literal -offset indent
-real     0.00
-user     0.00
-sys      0.00
+real     0.03
+user     0.02
+sys      0.01
 .Ed
 .Pp
 It is an error to specify the
@@ -4700,8 +4700,8 @@ Print the accumulated user and system ti
 and by processes that the shell started which have exited.
 The format of the output is:
 .Bd -literal -offset indent
-0m0.00s 0m0.00s
-0m0.00s 0m0.00s
+0m0.01s 0m0.00s
+0m0.04s 0m0.02s
 .Ed
 .Pp
 .It Ic trap Ar n Op Ar signal ...
@@ -4932,9 +4932,9 @@ when used with the
 .Fl i
 option which meant upper case letters would never be used for bases greater
 than 10.
-See the
+See
 .Fl U
-option.)
+above.)
 .Pp
 For functions,
 .Fl u
@@ -4944,9 +4944,9 @@ See
 above for the implications of this.
 .It Fl x
 Export attribute.
-Parameters (or functions) are placed in the environment of
-any executed commands.
-Exported functions are not yet implemented.
+Parameters are placed in the environment of any executed commands.
+Functions cannot be exported for security reasons
+.Pq Dq shellshock .
 .It Fl Z Ns Op Ar n
 Zero fill attribute.
 If not combined with
@@ -4954,7 +4954,7 @@ If not combined with
 this is the same as
 .Fl R ,
 except zero padding is used instead of space padding.
-For integers, the number instead of the base is padded.
+For integers, the number is padded, not the base.
 .El
 .Pp
 If any of the
@@ -5211,14 +5211,12 @@ or
 .Ic set Fl o Ic monitor ) ,
 as it is for interactive shells, the processes of a job are placed in their
 own process group.
-Foreground jobs can be stopped by typing the suspend
-character from the terminal (normally \*(haZ), jobs can be restarted in either the
-foreground or background using the
+Foreground jobs can be stopped by typing the suspend character from
+the terminal (normally \*(haZ); jobs can be restarted in either the
+foreground or background using the commands
 .Ic fg
 and
-.Ic bg
-commands, and the state of the terminal is saved or restored when a foreground
-job is stopped or restarted, respectively.
+.Ic bg .
 .Pp
 Note that only commands that create processes (e.g. asynchronous commands,
 subshell commands and non-built-in, non-function commands) can be stopped;
@@ -5332,6 +5330,17 @@ If another attempt
 is immediately made to exit the shell, the running jobs are sent a
 .Dv SIGHUP
 signal and the shell exits.
+.Ss Terminal state
+The state of the controlling terminal can be modified by a command
+executed in the foreground, whether or not job control is enabled, but
+the modified terminal state is only kept past the job's lifetime and used
+for later command invocations if the command exits successfully (i.e.\&
+with an exit status of 0).
+When such a job is momentarily stopped or restarted, the terminal state
+is saved and restored, respectively, but it will not be kept afterwards.
+In interactive mode, when line editing is enabled, the terminal state is
+saved before being reconfigured by the shell for the line editor, then
+restored before running a command.
 .Ss POSIX mode
 Entering
 .Ic set Fl o Ic posix
@@ -6650,7 +6659,7 @@ locale.
 .Ic utf8\-mode
 .Em must
 be disabled in POSIX mode, and it
-only supports the Unicode BMP (Basic Multilingual Plane) and maps
+only supports the BMP (Basic Multilingual Plane) of UCS and maps
 raw octets into the U+EF80..U+EFFF wide character range; compare
 .Sx Arithmetic expressions .
 The following
@@ -6671,7 +6680,7 @@ case ${KSH_VERSION:\-} in
 	esac ;;
 esac
 .Ed
-In near future, (Unicode) locale tracking will be implemented though.
+In near future, (UTF-8) locale tracking will be implemented though.
 .Pp
 See also the FAQ below.
 .Sh BUGS
@@ -6697,7 +6706,7 @@ for the in-memory portion of the history
 .Xr memmove 3 .
 .Pp
 This document attempts to describe
-.Nm mksh\ R56
+.Nm mksh\ R57
 and up,
 .\" with vendor patches from insert-your-name-here,
 compiled without any options impacting functionality, such as
@@ -6713,10 +6722,11 @@ for an operating environment supporting
 .Pp
 Please report bugs in
 .Nm
-to the
+to the public development mailing list at
 .Aq Mt miros\-mksh@mirbsd.org
-mailing list
-or in the
+(please note the EU-DSGVO/GDPR notice on
+.Pa http://www.mirbsd.org/rss.htm#lists
+and in the SMTP banner!) or in the
 .Li \&#\&!/bin/mksh
 .Pq or Li \&#ksh
 IRC channel at
--- mksh-56c.orig/sh.h
+++ mksh-56c/sh.h
@@ -182,9 +182,9 @@
 #endif
 
 #ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.858 2018/01/14 01:47:36 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.866 2018/10/20 18:45:58 tg Exp $");
 #endif
-#define MKSH_VERSION "R56 2018/01/14"
+#define MKSH_VERSION "R56 2018/10/20"
 
 /* arithmetic types: C implementation */
 #if !HAVE_CAN_INTTYPES
@@ -783,7 +783,7 @@ enum sh_flag {
 };
 
 #define Flag(f)	(shell_flags[(int)(f)])
-#define UTFMODE	Flag(FUNICODE)
+#define UTFMODE	Flag(FUNNYCODE)
 
 /*
  * parsing & execution environment
@@ -2637,7 +2637,7 @@ const char *wdscan(const char *, int);
 #define WDS_TPUTS	BIT(0)		/* tputS (dumpwdvar) mode */
 char *wdstrip(const char *, int);
 void tfree(struct op *, Area *);
-void dumpchar(struct shf *, int);
+void dumpchar(struct shf *, unsigned char);
 void dumptree(struct shf *, struct op *);
 void dumpwdvar(struct shf *, const char *);
 void dumpioact(struct shf *shf, struct op *t);
--- mksh-56c.orig/sh_flags.opt
+++ mksh-56c/sh_flags.opt
@@ -19,7 +19,7 @@
  */
 
 @SHFLAGS_DEFNS
-__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.5 2017/02/18 02:33:15 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.6 2018/08/10 02:53:39 tg Exp $");
 @SHFLAGS_ENUMS
 #define FN(sname,cname,flags,ochar)	cname,
 #define F0(sname,cname,flags,ochar)	cname = 0,
@@ -153,7 +153,7 @@ FN("trackall", FTRACKALL, OF_ANY
 
 /* -U	enable UTF-8 processing (non-standard) */
 >U|
-FN("utf8-mode", FUNICODE, OF_ANY
+FN("utf8-mode", FUNNYCODE, OF_ANY
 
 /* -v	echo input */
 >v|
--- mksh-56c.orig/shf.c
+++ mksh-56c/shf.c
@@ -27,7 +27,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.97 2018/01/14 01:28:16 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.98 2018/08/10 02:53:39 tg Exp $");
 
 /* flags to shf_emptybuf() */
 #define EB_READSW	0x01	/* about to switch to reading */
@@ -1304,7 +1304,7 @@ ebcdic_init(void)
 		 * and the C1 control characters other than NEL are
 		 * hopeless, but we map EBCDIC NEL to ASCII LF so we
 		 * cannot even use C1 NEL.
-		 * If ever we map to Unicode, bump the table width to
+		 * If ever we map to UCS, bump the table width to
 		 * an unsigned int, and or the raw unconverted EBCDIC
 		 * values with 0x01000000 instead.
 		 */
--- mksh-56c.orig/tree.c
+++ mksh-56c/tree.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.95 2018/01/14 00:03:05 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.97 2018/10/20 18:46:00 tg Exp $");
 
 #define INDENT	8
 
@@ -808,7 +808,7 @@ vistree(char *dst, size_t sz, struct op
 		c = ksh_unctrl(c);
 	} else if (UTFMODE && rtt2asc(c) > 0x7F) {
 		/* better not try to display broken multibyte chars */
-		/* also go easy on the Unicode: no U+FFFD here */
+		/* also go easy on the UCS: no U+FFFD here */
 		c = ORD('?');
 	}
 	*dst++ = c;
@@ -821,7 +821,7 @@ vistree(char *dst, size_t sz, struct op
 
 #ifdef DEBUG
 void
-dumpchar(struct shf *shf, int c)
+dumpchar(struct shf *shf, unsigned char c)
 {
 	if (ksh_isctrl(c)) {
 		/* C0 or C1 control character or DEL */
--- mksh-56c.orig/var.c
+++ mksh-56c/var.c
@@ -28,7 +28,7 @@
 #include <sys/sysctl.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.223 2018/01/13 23:55:15 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.226 2018/07/15 17:21:24 tg Exp $");
 
 /*-
  * Variables
@@ -54,7 +54,7 @@ static int special(const char *);
 static void unspecial(const char *);
 static void getspec(struct tbl *);
 static void setspec(struct tbl *);
-static void unsetspec(struct tbl *);
+static void unsetspec(struct tbl *, bool);
 static int getint(struct tbl *, mksh_ari_u *, bool);
 static const char *array_index_calc(const char *, bool *, uint32_t *);
 
@@ -105,7 +105,7 @@ popblock(void)
 			if ((vq = global(vp->name))->flag & ISSET)
 				setspec(vq);
 			else
-				unsetspec(vq);
+				unsetspec(vq, false);
 		}
 	if (l->flags & BF_DOGETOPTS)
 		user_opt = l->getopts_state;
@@ -707,7 +707,7 @@ formatstr(struct tbl *vp, const char *s)
 			if (vp->flag & ZEROFIL)
 				while (*s == '0')
 					s++;
-			shf_snprintf(p, nlen + 1, "%-*.*s",
+			shf_snprintf(p, psiz, "%-*.*s",
 				vp->u2.field, vp->u2.field, s);
 		}
 	} else
@@ -1054,7 +1054,7 @@ unset(struct tbl *vp, int flags)
 	vp->flag &= SPECIAL | ((flags & 1) ? 0 : ARRAY|DEFINED);
 	if (vp->flag & SPECIAL)
 		/* responsible for 'unspecial'ing var */
-		unsetspec(vp);
+		unsetspec(vp, true);
 }
 
 /*
@@ -1441,7 +1441,7 @@ setspec(struct tbl *vp)
 }
 
 static void
-unsetspec(struct tbl *vp)
+unsetspec(struct tbl *vp, bool dounset)
 {
 	/*
 	 * AT&T ksh man page says OPTIND, OPTARG and _ lose special
@@ -1466,13 +1466,13 @@ unsetspec(struct tbl *vp)
 #endif
 	case V_IFS:
 		set_ifs(TC_IFSWS);
-		break;
+		return;
 	case V_PATH:
 		afree(path, APERM);
 		strdupx(path, def_path, APERM);
 		/* clear tracked aliases */
 		flushcom(true);
-		break;
+		return;
 #ifndef MKSH_NO_CMDLINE_EDITING
 	case V_TERM:
 		x_initterm(null);
@@ -1484,14 +1484,14 @@ unsetspec(struct tbl *vp)
 			afree(tmpdir, APERM);
 			tmpdir = NULL;
 		}
-		break;
+		return;
 	case V_LINENO:
 	case V_RANDOM:
 	case V_SECONDS:
 	case V_TMOUT:
 		/* AT&T ksh leaves previous value in place */
 		unspecial(vp->name);
-		break;
+		return;
 #ifdef MKSH_EARLY_LOCALE_TRACKING
 	case V_LANG:
 	case V_LC_ALL:
@@ -1499,6 +1499,12 @@ unsetspec(struct tbl *vp)
 		recheck_ctype();
 		return;
 #endif
+	/* should not become unspecial, but allow unsetting */
+	case V_COLUMNS:
+	case V_LINES:
+		if (dounset)
+			unspecial(vp->name);
+		return;
 	}
 }
 
@@ -1617,6 +1623,9 @@ set_array(const char *var, bool reset, c
 		unset(vp, 1);
 		/* allocate-by-access the [0] element to keep in scope */
 		arraysearch(vp, 0);
+		/* honour set -o allexport */
+		if (Flag(FEXPORT))
+			typeset(ccp, EXPORT, 0, 0, 0);
 	}
 	/*
 	 * TODO: would be nice for assignment to completely succeed or
