Merge "Upgrade to mksh 50f."
diff --git a/Android.mk b/Android.mk
index e208225..a78409f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -79,6 +79,6 @@
     -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 \
     -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \
     -DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 \
-    -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=505
+    -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=506
 
 include $(BUILD_EXECUTABLE)
diff --git a/Makefrag.inc b/Makefrag.inc
index c5d5f6d..9c3632b 100644
--- a/Makefrag.inc
+++ b/Makefrag.inc
@@ -1,4 +1,4 @@
-# Makefile fragment for building mksh R50 2015/03/01
+# Makefile fragment for building mksh R50 2015/04/19
 
 PROG=		mksh
 MAN=		mksh.1
@@ -10,7 +10,7 @@
 NONSRCS_NOINST=	Build.sh Makefile Rebuild.sh check.pl check.t test.sh
 CC=		/huge-ssd/aosp-arm64/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/*-gcc
 CFLAGS=		 -fno-exceptions -Wno-multichar -fpic -fPIE -ffunction-sections -fdata-sections -funwind-tables -fstack-protector -Wa,--noexecstack -Werror=format-security -fno-short-enums -Wno-unused-but-set-variable -fno-builtin-sin -fno-strict-volatile-bitfields -Wno-psabi -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -g -Wstrict-aliasing=2 -fgcse-after-reload -frerun-cse-after-loop -frename-registers -Os -fomit-frame-pointer -fno-strict-aliasing -Wno-deprecated-declarations -fno-asynchronous-unwind-tables -fstack-protector-strong -fwrapv
-CPPFLAGS=	-I. -I'../src'  -isystem /huge-ssd/aosp-arm64/bionic/libc/arch-arm64/include -isystem /huge-ssd/aosp-arm64/bionic/libc/include -isystem /huge-ssd/aosp-arm64/bionic/libc/kernel/uapi -isystem /huge-ssd/aosp-arm64/bionic/libc/kernel/uapi/asm-arm64 -isystem /huge-ssd/aosp-arm64/bionic/libm/include -isystem /huge-ssd/aosp-arm64/bionic/libm/include/arm64 -D_FORTIFY_SOURCE=2 -include /huge-ssd/aosp-arm64/build/core/combo/include/arch/linux-arm64/AndroidConfig.h -I/huge-ssd/aosp-arm64/build/core/combo/include/arch/linux-arm64/ -DANDROID -DNDEBUG -UDEBUG -DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_CONSERVATIVE_FDS -DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN -DHAVE_ATTRIBUTE_BOUNDED=0 -DHAVE_ATTRIBUTE_FORMAT=1 -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1 -DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1 -DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=1 -DHAVE_SYS_BSDTYPES_H=0 -DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SYSMACROS_H=1 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_LIBGEN_H=1 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 -DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 -DHAVE_CAN_INT8TYPE=1 -DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=1 -DHAVE_SIG_T=1 -DHAVE_SYS_ERRLIST=0 -DHAVE_SYS_SIGNAME=1 -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 -DHAVE_LOCK_FCNTL=1 -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_ISSETUGID=0 -DHAVE_KILLPG=1 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 -DHAVE_NICE=1 -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=0 -DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 -DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=505
+CPPFLAGS=	-I. -I'../src'  -isystem /huge-ssd/aosp-arm64/bionic/libc/arch-arm64/include -isystem /huge-ssd/aosp-arm64/bionic/libc/include -isystem /huge-ssd/aosp-arm64/bionic/libc/kernel/uapi -isystem /huge-ssd/aosp-arm64/bionic/libc/kernel/uapi/asm-arm64 -isystem /huge-ssd/aosp-arm64/bionic/libm/include -isystem /huge-ssd/aosp-arm64/bionic/libm/include/arm64 -D_FORTIFY_SOURCE=2 -include /huge-ssd/aosp-arm64/build/core/combo/include/arch/linux-arm64/AndroidConfig.h -I/huge-ssd/aosp-arm64/build/core/combo/include/arch/linux-arm64/ -DANDROID -DNDEBUG -UDEBUG -DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_CONSERVATIVE_FDS -DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN -DHAVE_ATTRIBUTE_BOUNDED=0 -DHAVE_ATTRIBUTE_FORMAT=1 -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1 -DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1 -DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=1 -DHAVE_SYS_BSDTYPES_H=0 -DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SYSMACROS_H=1 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_LIBGEN_H=1 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 -DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 -DHAVE_CAN_INT8TYPE=1 -DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=1 -DHAVE_SIG_T=1 -DHAVE_SYS_ERRLIST=0 -DHAVE_SYS_SIGNAME=1 -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 -DHAVE_LOCK_FCNTL=1 -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_ISSETUGID=0 -DHAVE_KILLPG=1 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 -DHAVE_NICE=1 -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=0 -DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 -DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=506
 LDFLAGS=	 -nostdlib -Bdynamic -fPIE -pie -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined /huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib/crtbegin_dynamic.o
 LIBS=		 -L/huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib -Wl,-rpath-link=/huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib -Wl,--no-whole-archive /huge-ssd/aosp-arm64/out/target/product/flounder/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a -lc /huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib/crtend_android.o
 
diff --git a/src/Build.sh b/src/Build.sh
index 5c90eb8..70c1d24 100644
--- a/src/Build.sh
+++ b/src/Build.sh
@@ -1,9 +1,9 @@
 #!/bin/sh
-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.669.2.2 2015/03/01 15:42:50 tg Exp $'
+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.669.2.4 2015/04/19 19:18:08 tg Exp $'
 #-
 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-#		2011, 2012, 2013, 2014
-#	Thorsten Glaser <tg@mirbsd.org>
+#		2011, 2012, 2013, 2014, 2015
+#	Thorsten “mirabilos” Glaser <tg@mirbsd.org>
 #
 # Provided that these terms and disclaimer and all copyright notices
 # are retained or reproduced in an accompanying document, permission
@@ -1692,6 +1692,7 @@
 	ac_testn can_lfs_aix '!' can_lfs 0 "... with -D_LARGE_FILES=1" <lft.c
 	test 1 = $HAVE_CAN_LFS_AIX || CPPFLAGS=$save_CPPFLAGS
 fi
+rm -f lft.c
 rmf lft*	# end of large file support test
 
 #
@@ -1780,12 +1781,12 @@
 	HAVE_LINK_WORKS=x
 	ac_testinit link_works '' 'checking if the final link command may succeed'
 	fv=1
-	cat >conftest.c <<-'EOF'
+	cat >conftest.c <<-EOF
 		#define EXTERN
 		#define MKSH_INCLUDES_ONLY
 		#include "sh.h"
-		__RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.669.2.2 2015/03/01 15:42:50 tg Exp $");
-		int main(void) { printf("Hello, World!\n"); return (isatty(0)); }
+		__RCSID("$srcversion");
+		int main(void) { printf("Hello, World!\\n"); return (isatty(0)); }
 EOF
 	case $cm in
 	llvm)
@@ -2150,9 +2151,9 @@
 cta(uari_wrap_32_bit,
     (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) >
     (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4));
-#define NUM 21
+#define NUM 22
 #else
-#define NUM 15
+#define NUM 16
 #endif
 /* these are always required */
 cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0);
@@ -2165,6 +2166,7 @@
 cta(sizet_funcptr_same_size, sizeof(size_t) == sizeof(void (*)(void)));
 /* our formatting routines assume this */
 cta(ptr_fits_in_long, sizeof(size_t) <= sizeof(long));
+cta(ari_fits_in_long, sizeof(mksh_ari_t) <= sizeof(long));
 /* for struct alignment people */
 		char padding[64 - NUM];
 	};
@@ -2325,7 +2327,7 @@
 addsrcs USE_PRINTF_BUILTIN printf.c
 test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
 test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
-add_cppflags -DMKSH_BUILD_R=505
+add_cppflags -DMKSH_BUILD_R=506
 
 $e $bi$me: Finished configuration testing, now producing output.$ao
 
diff --git a/src/check.pl b/src/check.pl
index d688509..ce45773 100644
--- a/src/check.pl
+++ b/src/check.pl
@@ -1,8 +1,8 @@
-# $MirOS: src/bin/mksh/check.pl,v 1.37 2014/08/19 07:43:32 tg Exp $
+# $MirOS: src/bin/mksh/check.pl,v 1.37.2.1 2015/04/12 22:32:16 tg Exp $
 # $OpenBSD: th,v 1.1 2013/12/02 20:39:44 millert Exp $
 #-
 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
-#		2012, 2013, 2014
+#		2012, 2013, 2014, 2015
 #	Thorsten Glaser <tg@mirbsd.org>
 #
 # Provided that these terms and disclaimer and all copyright notices
@@ -568,7 +568,7 @@
 	}
 	push(@argv, $temps) if defined $test{'script'};
 
-	#XXX realpathise, use which/whence -p, or sth. like that
+	#XXX realpathise, use command -v/whence -p/which, or sth. like that
 	#XXX if !$program_kludge, we get by with not doing it for now tho
 	$new_env{'__progname'} = $argv[0];
 
diff --git a/src/check.t b/src/check.t
index cd7c50d..1d59d38 100644
--- a/src/check.t
+++ b/src/check.t
Binary files differ
diff --git a/src/dot.mkshrc b/src/dot.mkshrc
index 4878fd7..f65eaa7 100644
--- a/src/dot.mkshrc
+++ b/src/dot.mkshrc
@@ -1,5 +1,5 @@
 # $Id$
-# $MirOS: src/bin/mksh/dot.mkshrc,v 1.89.2.1 2015/01/11 22:39:44 tg Exp $
+# $MirOS: src/bin/mksh/dot.mkshrc,v 1.89.2.3 2015/04/12 22:32:22 tg Exp $
 #-
 # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
 #		2011, 2012, 2013, 2014, 2015
@@ -22,21 +22,23 @@
 #-
 # ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells
 
-# catch non-mksh (including lksh) trying to shell this file
-case $KSH_VERSION in
+# catch non-mksh (including lksh) trying to run this file
+case ${KSH_VERSION:-} in
 *MIRBSD\ KSH*) ;;
 *) return 0 ;;
 esac
 
-PS1='#'; (( USER_ID )) && PS1='$'; [[ ${HOSTNAME:=$(ulimit -c 0; hostname -s \
-    2>/dev/null)} = *([	 ]|localhost) ]] && HOSTNAME=$(ulimit -c 0; hostname \
-    2>/dev/null); : ${EDITOR:=/bin/ed} ${HOSTNAME:=nil} ${TERM:=vt100}
-: ${MKSH:=$(whence -p mksh)}; PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
+PS1='#'; (( USER_ID )) && PS1='$'; : "${TERM:=vt100}${HOSTNAME:=$(ulimit -c \
+    0; hostname 2>/dev/null)}${EDITOR:=/bin/ed}${USER:=$(ulimit -c 0; id -un \
+    2>/dev/null || echo \?)}${MKSH:=$(whence -p mksh)}"
+HOSTNAME=${HOSTNAME%%*([	 ]).*}; HOSTNAME=${HOSTNAME##*([	 ])}
+[[ $HOSTNAME = ?(ip6-)localhost?(6) ]] && HOSTNAME=
+: "${HOSTNAME:=nil}${MKSH:=/bin/mksh}"; export EDITOR HOSTNAME MKSH TERM USER
+PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
 	local e=$?
 
 	(( e )) && REPLY+="$e|"
-	REPLY+=${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?)}
-	REPLY+=@${HOSTNAME%%.*}:
+	REPLY+=${USER}@${HOSTNAME%%.*}:
 
 	local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~}
 	local m=${%d} n p=...; (( m > 0 )) || m=${#d}
@@ -44,7 +46,7 @@
 	REPLY+=$p$d
 
 	return $e
-} '"$PS1 "; export EDITOR HOSTNAME MKSH TERM USER
+} '"$PS1 "
 alias ls=ls
 unalias ls
 alias l='ls -F'
@@ -52,10 +54,10 @@
 alias ll='l -l'
 alias lo='l -alo'
 alias doch='sudo mksh -c "$(fc -ln -1)"'
-whence -p rot13 >/dev/null || alias rot13='tr \
+command -v rot13 >/dev/null || alias rot13='tr \
     abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
     nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
-if whence -p hd >/dev/null; then :; elif whence -p hexdump >/dev/null; then
+if command -v hd >/dev/null; then :; elif command -v hexdump >/dev/null; then
 	function hd {
 		hexdump -e '"%08.8_ax  " 8/1 "%02X " " - " 8/1 "%02X "' \
 		    -e '"  |" "%_p"' -e '"|\n"' "$@"
@@ -72,7 +74,8 @@
 			while (( i < ${#line[*]} )); do
 				hv=${line[i++]}
 				if (( (pos & 15) == 0 )); then
-					(( pos )) && print -r -- "$dasc|"
+					(( pos )) && \
+					    print -r -- "$dasc|"
 					print -n "${pos#16#}  "
 					dasc=' |'
 				fi
@@ -82,11 +85,13 @@
 				else
 					dasc+=${line[i-1]#1#}
 				fi
-				(( (pos++ & 15) == 7 )) && print -n -- '- '
+				(( (pos++ & 15) == 7 )) && \
+				    print -n -- '- '
 			done
 			while (( pos & 15 )); do
 				print -n '   '
-				(( (pos++ & 15) == 7 )) && print -n -- '- '
+				(( (pos++ & 15) == 7 )) && \
+				    print -n -- '- '
 			done
 			(( hv == 2147483647 )) || print -r -- "$dasc|"
 		fi; }
@@ -95,10 +100,12 @@
 
 # Berkeley C shell compatible dirs, popd, and pushd functions
 # Z shell compatible chpwd() hook, used to update DIRSTACK[0]
-DIRSTACKBASE=$(realpath ~/. 2>/dev/null || print -nr -- "${HOME:-/}")
+DIRSTACKBASE=$(realpath ~/. 2>/dev/null || \
+    print -nr -- "${HOME:-/}")
 set -A DIRSTACK
 function chpwd {
-	DIRSTACK[0]=$(realpath . 2>/dev/null || print -r -- "$PWD")
+	DIRSTACK[0]=$(realpath . 2>/dev/null || \
+	    print -r -- "$PWD")
 	[[ $DIRSTACKBASE = ?(*/) ]] || \
 	    DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/~}
 	:
diff --git a/src/edit.c b/src/edit.c
index 9165ecd..4f9298c 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -1,6 +1,6 @@
-/*	$OpenBSD: edit.c,v 1.39 2013/12/17 16:37:05 deraadt Exp $	*/
+/*	$OpenBSD: edit.c,v 1.40 2015/03/12 10:20:30 sthen Exp $	*/
 /*	$OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $	*/
-/*	$OpenBSD: emacs.c,v 1.49 2015/02/16 01:44:41 tedu Exp $	*/
+/*	$OpenBSD: emacs.c,v 1.50 2015/03/25 12:10:52 jca Exp $	*/
 /*	$OpenBSD: vi.c,v 1.28 2013/12/18 16:45:46 deraadt Exp $	*/
 
 /*-
@@ -28,7 +28,7 @@
 
 #ifndef MKSH_NO_CMDLINE_EDITING
 
-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.276.2.3 2015/03/01 15:42:56 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.276.2.5 2015/04/12 22:32:22 tg Exp $");
 
 /*
  * in later versions we might use libtermcap for this, but since external
diff --git a/src/eval.c b/src/eval.c
index f9c189d..81240c5 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.158.2.4 2015/03/01 15:42:58 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.158.2.5 2015/04/12 22:32:24 tg Exp $");
 
 /*
  * string expansion
@@ -1353,7 +1353,7 @@
 		struct ioword *io = *t->ioact;
 		char *name;
 
-		if ((io->flag & IOTYPE) != IOREAD)
+		if ((io->ioflag & IOTYPE) != IOREAD)
 			errorf("%s: %s", "funny $() command",
 			    snptreef(NULL, 32, "%R", io));
 		shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
diff --git a/src/exec.c b/src/exec.c
index 9b94aaf..f9eeb4c 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: exec.c,v 1.50 2013/06/10 21:09:27 millert Exp $	*/
+/*	$OpenBSD: exec.c,v 1.51 2015/04/18 18:28:36 deraadt Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.137.2.2 2015/03/01 15:42:59 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.137.2.4 2015/04/19 19:18:15 tg Exp $");
 
 #ifndef MKSH_DEFAULT_EXECSHELL
 #define MKSH_DEFAULT_EXECSHELL	"/bin/sh"
@@ -92,7 +92,7 @@
 		    t->ioact != NULL && t->ioact[0] != NULL &&
 		    t->ioact[1] == NULL &&
 		    /* of type "here document" (or "here string") */
-		    (t->ioact[0]->flag & IOTYPE) == IOHERE &&
+		    (t->ioact[0]->ioflag & IOTYPE) == IOHERE &&
 		    /* the variable assignment begins with a valid varname */
 		    (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] &&
 		    /* and has no right-hand side (i.e. "varname=") */
@@ -786,8 +786,7 @@
 
 		/*
 		 * Were we deleted while executing? If so, free the
-		 * execution tree. TODO: Unfortunately, the table entry
-		 * is never re-used until the lookup table is expanded.
+		 * execution tree.
 		 */
 		if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
 			if (tp->flag & ALLOC) {
@@ -1317,7 +1316,7 @@
 {
 	int u = -1;
 	char *cp = iop->name;
-	int iotype = iop->flag & IOTYPE;
+	int iotype = iop->ioflag & IOTYPE;
 	bool do_open = true, do_close = false;
 	int flags = 0;
 	struct ioword iotmp;
@@ -1329,7 +1328,7 @@
 	/* Used for tracing and error messages to print expanded cp */
 	iotmp = *iop;
 	iotmp.name = (iotype == IOHERE) ? NULL : cp;
-	iotmp.flag |= IONAMEXP;
+	iotmp.ioflag |= IONAMEXP;
 
 	if (Flag(FXTRACE)) {
 		change_xtrace(2, false);
@@ -1352,7 +1351,7 @@
 		 * The stat() is here to allow redirections to
 		 * things like /dev/null without error.
 		 */
-		if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) &&
+		if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB) &&
 		    (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
 			flags |= O_EXCL;
 		break;
@@ -1377,7 +1376,7 @@
 			u = 1009;
 			do_close = true;
 		} else if ((u = check_fd(cp,
-		    X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
+		    X_OK | ((iop->ioflag & IORDUP) ? R_OK : W_OK),
 		    &emsg)) < 0) {
 			char *sp;
 
@@ -1386,7 +1385,7 @@
 			afree(sp, ATEMP);
 			return (-1);
 		}
-		if (u == iop->unit)
+		if (u == (int)iop->unit)
 			/* "dup from" == "dup to" */
 			return (0);
 		break;
@@ -1414,7 +1413,7 @@
 	/* Do not save if it has already been redirected (i.e. "cat >x >y"). */
 	if (e->savefd[iop->unit] == 0) {
 		/* If these are the same, it means unit was previously closed */
-		if (u == iop->unit)
+		if (u == (int)iop->unit)
 			e->savefd[iop->unit] = -1;
 		else
 			/*
@@ -1429,7 +1428,7 @@
 
 	if (do_close)
 		close(iop->unit);
-	else if (u != iop->unit) {
+	else if (u != (int)iop->unit) {
 		if (ksh_dup2(u, iop->unit, true) < 0) {
 			int eno;
 			char *sp;
@@ -1451,7 +1450,7 @@
 		 * causes the shell to close its copies
 		 */
 		else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
-			if (iop->flag & IORDUP)
+			if (iop->ioflag & IORDUP)
 				/* possible exec <&p */
 				coproc_read_close(u);
 			else
@@ -1520,7 +1519,7 @@
 	}
 
 	/* lexer substitution flags */
-	i = (iop->flag & IOEVAL) ? (ONEWORD | HEREDOC) : 0;
+	i = (iop->ioflag & IOEVAL) ? (ONEWORD | HEREDOC) : 0;
 
 	/* skip all the fd setup if we just want the value */
 	if (resbuf != NULL)
@@ -1587,9 +1586,9 @@
 		if (call_builtin(findcom("read", FC_BI), read_args, Tselect,
 		    false))
 			return (NULL);
-		s = str_val(global("REPLY"));
-		if (*s && getn(s, &i))
-			return ((i >= 1 && i <= argct) ? ap[i - 1] : null);
+		if (*(s = str_val(global("REPLY"))))
+			return ((getn(s, &i) && i >= 1 && i <= argct) ?
+			    ap[i - 1] : null);
 		print_menu = true;
 	}
 }
diff --git a/src/funcs.c b/src/funcs.c
index 9603aff..95187e6 100644
--- a/src/funcs.c
+++ b/src/funcs.c
@@ -38,7 +38,7 @@
 #endif
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.259.2.2 2015/01/25 15:35:44 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.259.2.5 2015/04/19 19:18:16 tg Exp $");
 
 #if HAVE_KILLPG
 /*
@@ -778,7 +778,7 @@
 
 	if (fieldstr && !bi_getn(fieldstr, &field))
 		return (1);
-	if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) {
+	if (basestr && (!getn(basestr, &base) || base < 1 || base > 36)) {
 		bi_errorf("%s: %s", "bad integer base", basestr);
 		return (1);
 	}
@@ -1817,9 +1817,10 @@
 c_read(const char **wp)
 {
 #define is_ifsws(c) (ctype((c), C_IFS) && ctype((c), C_IFSWS))
-	int c, fd = 0, rv = 0, lastparm = 0;
+	int c, fd = 0, rv = 0;
 	bool savehist = false, intoarray = false, aschars = false;
 	bool rawmode = false, expanding = false;
+	bool lastparmmode = false, lastparmused = false;
 	enum { LINES, BYTES, UPTO, READALL } readmode = LINES;
 	char delim = '\n';
 	size_t bytesleft = 128, bytesread;
@@ -1855,7 +1856,7 @@
 		if (!bi_getn(builtin_opt.optarg, &c))
 			return (2);
 		if (c == -1) {
-			readmode = READALL;
+			readmode = readmode == BYTES ? READALL : UPTO;
 			bytesleft = 1024;
 		} else
 			bytesleft = (unsigned int)c;
@@ -2123,7 +2124,7 @@
 	}
 
 	if (!intoarray && wp[1] == NULL)
-		lastparm = 1;
+		lastparmmode = true;
 
  c_read_splitlast:
 	/* copy until IFS character */
@@ -2148,16 +2149,23 @@
 	}
 	xsave = Xsavepos(xs, xp);
 	/* copy word delimiter: IFSWS+IFS,IFSWS */
+	expanding = false;
 	while (bytesread) {
 		char ch;
 
 		ch = *ccp;
 		if (!ctype(ch, C_IFS))
 			break;
-		Xcheck(xs, xp);
-		Xput(xs, xp, ch);
+		if (lastparmmode && !expanding && !rawmode && ch == '\\') {
+			expanding = true;
+		} else {
+			Xcheck(xs, xp);
+			Xput(xs, xp, ch);
+		}
 		++ccp;
 		--bytesread;
+		if (expanding)
+			continue;
 		if (!ctype(ch, C_IFSWS))
 			break;
 	}
@@ -2168,12 +2176,12 @@
 		--bytesread;
 	}
 	/* if no more parameters, rinse and repeat */
-	if (lastparm && bytesread) {
-		++lastparm;
+	if (lastparmmode && bytesread) {
+		lastparmused = true;
 		goto c_read_splitlast;
 	}
 	/* get rid of the delimiter unless we pack the rest */
-	if (lastparm < 2)
+	if (!lastparmused)
 		xp = Xrestpos(xs, xp, xsave);
  c_read_gotword:
 	Xput(xs, xp, '\0');
@@ -2321,13 +2329,9 @@
 		goto c_exitreturn_err;
 	arg = wp[builtin_opt.optind];
 
-	if (arg) {
-		if (!getn(arg, &n)) {
-			exstat = 1;
-			warningf(true, "%s: %s", arg, "bad number");
-		} else
-			exstat = n & 0xFF;
-	} else if (trap_exstat != -1)
+	if (arg)
+		exstat = bi_getn(arg, &n) ? (n & 0xFF) : 1;
+	else if (trap_exstat != -1)
 		exstat = trap_exstat;
 	if (wp[0][0] == 'r') {
 		/* return */
diff --git a/src/histrap.c b/src/histrap.c
index 6d2badf..0dfe1c2 100644
--- a/src/histrap.c
+++ b/src/histrap.c
@@ -27,7 +27,7 @@
 #include <sys/file.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134.2.3 2015/03/01 15:43:00 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134.2.5 2015/04/19 19:18:18 tg Exp $");
 
 Trap sigtraps[NSIG + 1];
 static struct sigaction Sigact_ign;
@@ -275,8 +275,9 @@
 		for (hp = rflag ? hlast : hfirst;
 		    hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1) {
 			if (!nflag)
-				shf_fprintf(shl_stdout, "%d",
-				    hist_source->line - (int)(histptr - hp));
+				shf_fprintf(shl_stdout, "%lu",
+				    (unsigned long)hist_source->line -
+				    (unsigned long)(histptr - hp));
 			shf_putc('\t', shl_stdout);
 			/* print multi-line commands correctly */
 			s = *hp;
@@ -563,7 +564,7 @@
 		return;
 
 	/* if the name is the same as the name we have */
-	if (hname && strcmp(hname, name) == 0)
+	if (hname && name && !strcmp(hname, name))
 		return;
 
 	/*
@@ -581,7 +582,8 @@
 		hist_source->line = 0;
 	}
 
-	hist_init(hist_source);
+	if (name)
+		hist_init(hist_source);
 }
 #endif
 
@@ -712,8 +714,10 @@
 	hist_source = s;
 
 #if HAVE_PERSISTENT_HISTORY
-	if ((hname = str_val(global("HISTFILE"))) == NULL)
+	if (((hname = str_val(global("HISTFILE"))) == NULL) || !*hname) {
+		hname = NULL;
 		return;
+	}
 	strdupx(hname, hname, APERM);
 	hs = hist_init_first;
 
diff --git a/src/jobs.c b/src/jobs.c
index d919c16..7a5b270 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -1,8 +1,8 @@
-/*	$OpenBSD: jobs.c,v 1.40 2013/09/04 15:49:18 millert Exp $	*/
+/*	$OpenBSD: jobs.c,v 1.41 2015/04/18 18:28:36 deraadt Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
- *		 2012, 2013, 2014
+ *		 2012, 2013, 2014, 2015
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.105.2.1 2015/01/25 15:44:06 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.105.2.2 2015/04/19 19:18:18 tg Exp $");
 
 #if HAVE_KILLPG
 #define mksh_killpg		killpg
@@ -1111,6 +1111,7 @@
     int flags,
     const char *where)
 {
+	Proc *p;
 	int rv;
 #ifdef MKSH_NO_SIGSUSPEND
 	sigset_t omask;
@@ -1238,9 +1239,10 @@
 	j_systime = j->systime;
 	rv = j->status;
 
-	if ((flags & JW_PIPEST) && (j->proc_list != NULL)) {
+	if (!(p = j->proc_list)) {
+		;	/* nothing */
+	} else if (flags & JW_PIPEST) {
 		uint32_t num = 0;
-		Proc *p = j->proc_list;
 		struct tbl *vp;
 
 		unset(vp_pipest, 1);
@@ -1270,15 +1272,13 @@
 				rv = vp->val.i;
 			p = p->next;
 		}
-	} else if (Flag(FPIPEFAIL) && (j->proc_list != NULL)) {
-		Proc *p = j->proc_list;
-		int i;
+	} else if (Flag(FPIPEFAIL)) {
+		do {
+			int i = proc_errorlevel(p);
 
-		while (p != NULL) {
-			if ((i = proc_errorlevel(p)))
+			if (i)
 				rv = i;
-			p = p->next;
-		}
+		} while ((p = p->next));
 	}
 
 	if (!(flags & JW_ASYNCNOTIFY)
@@ -1644,8 +1644,7 @@
 	size_t len;
 	int job = 0;
 
-	if (ksh_isdigit(*cp)) {
-		getn(cp, &job);
+	if (ksh_isdigit(*cp) && getn(cp, &job)) {
 		/* Look for last_proc->pid (what $! returns) first... */
 		for (j = job_list; j != NULL; j = j->next)
 			if (j->last_proc && j->last_proc->pid == job)
@@ -1657,11 +1656,10 @@
 		for (j = job_list; j != NULL; j = j->next)
 			if (j->pgrp && j->pgrp == job)
 				return (j);
-		if (ecodep)
-			*ecodep = JL_NOSUCH;
-		return (NULL);
+		goto j_lookup_nosuch;
 	}
 	if (*cp != '%') {
+ j_lookup_invalid:
 		if (ecodep)
 			*ecodep = JL_INVALID;
 		return (NULL);
@@ -1681,7 +1679,8 @@
 
 	case '0': case '1': case '2': case '3': case '4':
 	case '5': case '6': case '7': case '8': case '9':
-		getn(cp, &job);
+		if (!getn(cp, &job))
+			goto j_lookup_invalid;
 		for (j = job_list; j != NULL; j = j->next)
 			if (j->job == job)
 				return (j);
@@ -1721,6 +1720,7 @@
 			return (last_match);
 		break;
 	}
+ j_lookup_nosuch:
 	if (ecodep)
 		*ecodep = JL_NOSUCH;
 	return (NULL);
diff --git a/src/lex.c b/src/lex.c
index 502284a..305f5a4 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -2,7 +2,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013, 2014
+ *		 2011, 2012, 2013, 2014, 2015
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.193.2.1 2015/01/11 22:39:50 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.193.2.5 2015/04/19 19:18:19 tg Exp $");
 
 /*
  * states while lexing word
@@ -921,42 +921,41 @@
 			if (!ksh_isdigit(dp[c2 + 1]))
 				goto no_iop;
 			iop->unit = (iop->unit * 10) + dp[c2 + 1] - '0';
+			if (iop->unit >= FDBASE)
+				goto no_iop;
 		}
 
-		if (iop->unit >= FDBASE)
-			goto no_iop;
-
 		if (c == '&') {
 			if ((c2 = getsc()) != '>') {
 				ungetsc(c2);
 				goto no_iop;
 			}
 			c = c2;
-			iop->flag = IOBASH;
+			iop->ioflag = IOBASH;
 		} else
-			iop->flag = 0;
+			iop->ioflag = 0;
 
 		c2 = getsc();
 		/* <<, >>, <> are ok, >< is not */
 		if (c == c2 || (c == '<' && c2 == '>')) {
-			iop->flag |= c == c2 ?
+			iop->ioflag |= c == c2 ?
 			    (c == '>' ? IOCAT : IOHERE) : IORDWR;
-			if (iop->flag == IOHERE) {
+			if (iop->ioflag == IOHERE) {
 				if ((c2 = getsc()) == '-') {
-					iop->flag |= IOSKIP;
+					iop->ioflag |= IOSKIP;
 					c2 = getsc();
 				} else if (c2 == '<')
-					iop->flag |= IOHERESTR;
+					iop->ioflag |= IOHERESTR;
 				ungetsc(c2);
 				if (c2 == '\n')
-					iop->flag |= IONDELIM;
+					iop->ioflag |= IONDELIM;
 			}
 		} else if (c2 == '&')
-			iop->flag |= IODUP | (c == '<' ? IORDUP : 0);
+			iop->ioflag |= IODUP | (c == '<' ? IORDUP : 0);
 		else {
-			iop->flag |= c == '>' ? IOWRITE : IOREAD;
+			iop->ioflag |= c == '>' ? IOWRITE : IOREAD;
 			if (c == '>' && c2 == '|')
-				iop->flag |= IOCLOB;
+				iop->ioflag |= IOCLOB;
 			else
 				ungetsc(c2);
 		}
@@ -1044,13 +1043,16 @@
 	} else
 		while ((dp - ident) < IDENT && (c = *sp++) == CHAR)
 			*dp++ = *sp++;
-	/* make sure the ident array stays NUL padded */
-	memset(dp, 0, (ident + IDENT) - dp + 1);
 	if (c != EOS)
 		/* word is not unquoted */
-		*ident = '\0';
+		dp = ident;
+	/* make sure the ident array stays NUL padded */
+	memset(dp, 0, (ident + IDENT) - dp + 1);
 
-	if (*ident != '\0' && (cf & (KEYWORD | ALIAS))) {
+	if (!(cf & (KEYWORD | ALIAS)))
+		return (LWORD);
+
+	if (*ident != '\0') {
 		struct tbl *p;
 		uint32_t h = hash(ident);
 
@@ -1077,8 +1079,7 @@
 				 * pushed into an SREREAD) which is what
 				 * we want here anyway: find out whether
 				 * the alias name is followed by a POSIX
-				 * function definition (only the opening
-				 * parenthesis is checked though)
+				 * function definition
 				 */
 				++cp;
 			/* prefer functions over aliases */
@@ -1106,6 +1107,11 @@
 				goto Again;
 			}
 		}
+	} else if (cf & ALIAS) {
+		/* retain typeset et al. even when quoted */
+		if (assign_command((dp = wdstrip(yylval.cp, 0))))
+			strlcpy(ident, dp, sizeof(ident));
+		afree(dp, ATEMP);
 	}
 
 	return (LWORD);
@@ -1117,7 +1123,7 @@
 	struct ioword **p;
 
 	for (p = heres; p < herep; p++)
-		if (iseof && !((*p)->flag & IOHERESTR))
+		if (iseof && !((*p)->ioflag & IOHERESTR))
 			/* only here strings at EOF */
 			return;
 		else
@@ -1138,7 +1144,7 @@
 	char *xp;
 	int xpos;
 
-	if (iop->flag & IOHERESTR) {
+	if (iop->ioflag & IOHERESTR) {
 		/* process the here string */
 		iop->heredoc = xp = evalstr(iop->delim, DOBLANK);
 		xpos = strlen(xp) - 1;
@@ -1147,9 +1153,9 @@
 		return;
 	}
 
-	eof = iop->flag & IONDELIM ? "<<" : evalstr(iop->delim, 0);
+	eof = iop->ioflag & IONDELIM ? "<<" : evalstr(iop->delim, 0);
 
-	if (!(iop->flag & IOEVAL))
+	if (!(iop->ioflag & IOEVAL))
 		ignore_backslash_newline++;
 
 	Xinit(xs, xp, 256, ATEMP);
@@ -1158,10 +1164,10 @@
 	/* beginning of line */
 	eofp = eof;
 	xpos = Xsavepos(xs, xp);
-	if (iop->flag & IOSKIP) {
+	if (iop->ioflag & IOSKIP) {
 		/* skip over leading tabs */
 		while ((c = getsc()) == '\t')
-			/* nothing */;
+			;	/* nothing */
 		goto heredoc_parse_char;
 	}
  heredoc_read_char:
@@ -1220,7 +1226,7 @@
 	Xput(xs, xp, '\0');
 	iop->heredoc = Xclose(xs, xp);
 
-	if (!(iop->flag & IOEVAL))
+	if (!(iop->ioflag & IOEVAL))
 		ignore_backslash_newline--;
 }
 
@@ -1474,7 +1480,7 @@
 void
 set_prompt(int to, Source *s)
 {
-	cur_prompt = to;
+	cur_prompt = (uint8_t)to;
 
 	switch (to) {
 	/* command */
@@ -1497,8 +1503,8 @@
 				if (*ps1 != '!' || *++ps1 == '!')
 					shf_putchar(*ps1++, shf);
 				else
-					shf_fprintf(shf, "%d",
-						s ? s->line + 1 : 0);
+					shf_fprintf(shf, "%lu", s ?
+					    (unsigned long)s->line + 1 : 0UL);
 			ps1 = shf_sclose(shf);
 			saved_atemp = ATEMP;
 			newenv(E_ERRH);
diff --git a/src/lksh.1 b/src/lksh.1
index 31dc6ff..fe6d59d 100644
--- a/src/lksh.1
+++ b/src/lksh.1
@@ -1,6 +1,6 @@
-.\" $MirOS: src/bin/mksh/lksh.1,v 1.5 2013/05/22 18:18:06 tg Exp $
+.\" $MirOS: src/bin/mksh/lksh.1,v 1.5.2.1 2015/03/21 00:12:45 tg Exp $
 .\"-
-.\" Copyright (c) 2008, 2009, 2010, 2012, 2013
+.\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015
 .\"	Thorsten “mirabilos” Glaser <tg@mirbsd.org>
 .\"
 .\" Provided that these terms and disclaimer and all copyright notices
@@ -72,7 +72,7 @@
 .\" with -mandoc, it might implement .Mx itself, but we want to
 .\" use our own definition. And .Dd must come *first*, always.
 .\"
-.Dd $Mdocdate: May 22 2013 $
+.Dd $Mdocdate: March 21 2015 $
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
@@ -175,7 +175,7 @@
 since the MirBSD Korn Shell scripting language is much more consistent.
 .Sh LEGACY MODE
 .Nm
-has the following differences from
+currently has the following differences from
 .Nm mksh :
 .Bl -bullet
 .It
@@ -195,6 +195,11 @@
 .Dq LEGACY KSH
 instead of
 .Dq MIRBSD KSH .
+Note that the rest of the version string is identical between
+the two shell flavours, and the behaviour and differences can
+change between versions; see the accompanying manual page
+.Xr mksh 1
+for the versions this document applies to.
 .It
 .Nm
 only offers the traditional ten file descriptors to scripts.
@@ -245,11 +250,17 @@
 .Xr getopt 1
 command.
 .It
-.Nm lksh ,
-unlike
+Unlike
 .At
 .Nm ksh ,
-does not keep file descriptors \*(Gt 2 private.
+.Nm mksh
+in
+.Fl o Ic posix
+or
+.Fl o Ic sh
+mode and
+.Nm lksh
+do not keep file descriptors \*(Gt 2 private from sub-processes.
 .El
 .Sh SEE ALSO
 .Xr mksh 1
diff --git a/src/main.c b/src/main.c
index 59d0b1e..047aad1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -5,7 +5,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013, 2014
+ *		 2011, 2012, 2013, 2014, 2015
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -34,7 +34,7 @@
 #include <locale.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.285.2.2 2015/03/01 15:43:01 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.285.2.4 2015/04/19 19:18:20 tg Exp $");
 
 extern char **environ;
 
@@ -1286,8 +1286,9 @@
 	    strcmp(source->file, kshname) != 0)
 		shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
 	if (fileline && source && source->file != NULL) {
-		shf_fprintf(shl_out, "%s[%d]: ", source->file,
-		    source->errline > 0 ? source->errline : source->line);
+		shf_fprintf(shl_out, "%s[%lu]: ", source->file,
+		    (unsigned long)(source->errline ?
+		    source->errline : source->line));
 		source->errline = 0;
 	}
 }
@@ -1453,13 +1454,20 @@
 int
 check_fd(const char *name, int mode, const char **emsgp)
 {
-	int fd, fl;
+	int fd = 0, fl;
 
 	if (name[0] == 'p' && !name[1])
 		return (coproc_getfd(mode, emsgp));
-	for (fd = 0; ksh_isdigit(*name); ++name)
+	while (ksh_isdigit(*name)) {
 		fd = (fd * 10) + *name - '0';
-	if (*name || fd >= FDBASE) {
+		if (fd >= FDBASE) {
+			if (emsgp)
+				*emsgp = "file descriptor too large";
+			return (-1);
+		}
+		++name;
+	}
+	if (*name) {
 		if (emsgp)
 			*emsgp = "illegal file descriptor name";
 		return (-1);
diff --git a/src/misc.c b/src/misc.c
index 7c8d114..74bafbe 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: misc.c,v 1.39 2015/01/16 06:39:32 deraadt Exp $	*/
+/*	$OpenBSD: misc.c,v 1.40 2015/03/18 15:12:36 tedu Exp $	*/
 /*	$OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $	*/
 
 /*-
@@ -30,7 +30,7 @@
 #include <grp.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.219.2.2 2015/03/01 15:43:02 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.219.2.3 2015/03/20 22:21:04 tg Exp $");
 
 #define KSH_CHVT_FLAG
 #ifdef MKSH_SMALL
@@ -1289,32 +1289,27 @@
 	afree(str, ATEMP);
 }
 
-/* Strip any nul bytes from buf - returns new length (nbytes - # of nuls) */
+/* strip all NUL bytes from buf; output is NUL-terminated if stripped */
 void
-strip_nuls(char *buf, int nbytes)
+strip_nuls(char *buf, size_t len)
 {
-	char *dst;
+	char *cp, *dp, *ep;
 
-	/*
-	 * nbytes check because some systems (older FreeBSDs) have a
-	 * buggy memchr()
-	 */
-	if (nbytes && (dst = memchr(buf, '\0', nbytes))) {
-		char *end = buf + nbytes;
-		char *p, *q;
+	if (!len || !(dp = memchr(buf, '\0', len)))
+		return;
 
-		for (p = dst; p < end; p = q) {
-			/* skip a block of nulls */
-			while (++p < end && *p == '\0')
-				;
-			/* find end of non-null block */
-			if (!(q = memchr(p, '\0', end - p)))
-				q = end;
-			memmove(dst, p, q - p);
-			dst += q - p;
-		}
-		*dst = '\0';
-	}
+	ep = buf + len;
+	cp = dp;
+
+ cp_has_nul_byte:
+	while (cp++ < ep && *cp == '\0')
+		;	/* nothing */
+	while (cp < ep && *cp != '\0')
+		*dp++ = *cp++;
+	if (cp < ep)
+		goto cp_has_nul_byte;
+
+	*dp = '\0';
 }
 
 /*
diff --git a/src/mksh.1 b/src/mksh.1
index 5ad143c..5e41d13 100644
--- a/src/mksh.1
+++ b/src/mksh.1
@@ -1,5 +1,5 @@
-.\" $MirOS: src/bin/mksh/mksh.1,v 1.344.2.3 2015/03/01 15:43:03 tg Exp $
-.\" $OpenBSD: ksh.1,v 1.156 2015/01/16 15:32:32 schwarze Exp $
+.\" $MirOS: src/bin/mksh/mksh.1,v 1.344.2.5 2015/04/12 22:32:30 tg Exp $
+.\" $OpenBSD: ksh.1,v 1.159 2015/03/25 12:10:52 jca Exp $
 .\"-
 .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
 .\"		2010, 2011, 2012, 2013, 2014, 2015
@@ -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: March 1 2015 $
+.Dd $Mdocdate: April 12 2015 $
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
@@ -1125,11 +1125,12 @@
 hash=\*(aqalias \-t\*(aq
 history=\*(aqfc \-l\*(aq
 integer=\*(aqtypeset \-i\*(aq
-local=\*(aqtypeset\*(aq
+local=typeset
 login=\*(aqexec login\*(aq
 nameref=\*(aqtypeset \-n\*(aq
 nohup=\*(aqnohup \*(aq
 r=\*(aqfc \-e \-\*(aq
+source=\*(aqPATH=$PATH:. command .\*(aq
 stop=\*(aqkill \-STOP\*(aq
 type=\*(aqwhence \-v\*(aq
 .Ed
@@ -1203,7 +1204,7 @@
 .Ic return
 work, and in that
 .Ic exit
-terminates the parent shell.
+terminates the parent shell; shell options are shared.
 .Pp
 Another variant of substitution are the valsubs (value substitutions)
 .Pf ${\*(Ba\& Ns Ar command Ns \&;}
@@ -1254,10 +1255,8 @@
 .Sq D .
 Note that if the
 .Ev IFS
-parameter is set to the
-.Dv NULL
-string, no field splitting is done; if the parameter is unset, the default
-value of space, tab, and newline is used.
+parameter is set to the empty string, no field splitting is done;
+if it is unset, the default value of space, tab, and newline is used.
 .Pp
 Also, note that the field splitting applies only to the immediate result of
 the substitution.
@@ -1795,21 +1794,16 @@
 .It Ev BASHPID
 The PID of the shell or subshell.
 .It Ev CDPATH
-Search path for the
+Like
+.Ev PATH ,
+but used to resolve the argument to the
 .Ic cd
 built-in command.
-It works the same way as
-.Ev PATH
-for those directories not beginning with
-.Ql /
-in
-.Ic cd
-commands.
 Note that if
 .Ev CDPATH
 is set and does not contain
 .Sq \&.
-or contains an empty path, the current directory is not searched.
+or an empty string element, the current directory is not searched.
 Also, the
 .Ic cd
 built-in command will display the resulting directory when a match is found
@@ -1862,7 +1856,8 @@
 below for more information.
 .It Ev HISTFILE
 The name of the file used to store command history.
-When assigned to, history is loaded from the specified file.
+When assigned to or unset, the file is opened, history is truncated
+then loaded from the file; subsequent new lines are appended.
 Also, several invocations of the shell will share history if their
 .Ev HISTFILE
 parameters all point to the same file.
@@ -1870,7 +1865,7 @@
 .Sy Note :
 If
 .Ev HISTFILE
-isn't set, no history file is used.
+is unset or empty, no history file is used.
 This is different from
 .At
 .Nm ksh .
@@ -6490,6 +6485,24 @@
 or
 .Nm lksh )
 to behave more like the standard expects.
+.Pp
+For the purpose of
+.Tn POSIX ,
+.Nm mksh
+supports only the
+.Dq C
+locale.
+For users of UTF-8 locales, the following sh code makes the shell
+match the locale:
+.Bd -literal -offset indent
+case ${KSH_VERSION:\-} in
+*MIRBSD\ KSH*\*(Ba*LEGACY\ KSH*)
+	case ${LC_ALL:\-${LC_CTYPE:\-${LANG:\-}}} in
+	*[Uu][Tt][Ff]8*\*(Ba*[Uu][Tt][Ff]\-8*) set \-U ;;
+	*) set +U ;;
+	esac ;;
+esac
+.Ed
 .Sh BUGS
 Suspending (using \*(haZ) pipelines like the one below will only suspend
 the currently running part of the pipeline; in this example,
@@ -6500,9 +6513,22 @@
 $ /bin/sleep 666 && echo fubar
 .Ed
 .Pp
+The truncation process involved when changing
+.Ev HISTFILE
+does not free old history entries (leaks memory) and leaks
+old entries into the new history if their line numbers are
+not overwritten by same-numer entries from the persistent
+history file; truncating the on-disc file to
+.Ev HISTSIZE
+lines has always been broken and prone to history file corruption
+when multiple shells are accessing the file; the rollover process
+for the in-memory portion of the history is slow, should use
+.Xr memmove 3 .
+.Pp
 This document attempts to describe
 .Nm mksh\ R50e
 and up,
+.\" with vendor patches from insert-your-name-here,
 compiled without any options impacting functionality, such as
 .Dv MKSH_SMALL ,
 when not called as
diff --git a/src/sh.h b/src/sh.h
index d053ed2..91f8961 100644
--- a/src/sh.h
+++ b/src/sh.h
@@ -169,9 +169,9 @@
 #endif
 
 #ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.701.2.4 2015/03/01 15:43:05 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.701.2.7 2015/04/19 19:18:21 tg Exp $");
 #endif
-#define MKSH_VERSION "R50 2015/03/01"
+#define MKSH_VERSION "R50 2015/04/19"
 
 /* arithmetic types: C implementation */
 #if !HAVE_CAN_INTTYPES
@@ -537,7 +537,7 @@
 #define mkssert(e)	do { } while (/* CONSTCOND */ 0)
 #endif
 
-#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 505)
+#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 506)
 #error Must run Build.sh to compile this.
 extern void thiswillneverbedefinedIhope(void);
 int
@@ -1270,7 +1270,7 @@
 EXTERN const char *def_path;	/* path to use if PATH not set */
 EXTERN char *tmpdir;		/* TMPDIR value */
 EXTERN const char *prompt;
-EXTERN int cur_prompt;		/* PS1 or PS2 */
+EXTERN uint8_t cur_prompt;	/* PS1 or PS2 */
 EXTERN int current_lineno;	/* LINENO value */
 
 /*
@@ -1347,11 +1347,11 @@
  * IO redirection
  */
 struct ioword {
-	int	unit;		/* unit affected */
-	int	flag;		/* action (below) */
-	char	*name;		/* file name (unused if heredoc) */
-	char	*delim;		/* delimiter for <<,<<- */
-	char	*heredoc;	/* content of heredoc */
+	char *name;		/* filename (unused if heredoc) */
+	char *delim;		/* delimiter for <<, <<- */
+	char *heredoc;		/* content of heredoc */
+	unsigned short ioflag;	/* action (below) */
+	short unit;		/* unit (fd) affected */
 };
 
 /* ioword.flag - type of redirection */
@@ -1582,10 +1582,9 @@
 #define VARASN		BIT(5)	/* check for var=word */
 #define ARRAYVAR	BIT(6)	/* parse x[1 & 2] as one word */
 #define ESACONLY	BIT(7)	/* only accept esac keyword */
-#define CMDWORD		BIT(8)	/* parsing simple command (alias related) */
-#define HEREDELIM	BIT(9)	/* parsing <<,<<- delimiter */
-#define LQCHAR		BIT(10)	/* source string contains QCHAR */
-#define HEREDOC 	BIT(11)	/* parsing a here document body */
+#define HEREDELIM	BIT(8)	/* parsing <<,<<- delimiter */
+#define LQCHAR		BIT(9)	/* source string contains QCHAR */
+#define HEREDOC 	BIT(10)	/* parsing a here document body */
 
 #define HERES		10	/* max number of << in line */
 
@@ -1876,7 +1875,8 @@
 void print_columns(struct shf *, unsigned int,
     char *(*)(char *, size_t, unsigned int, const void *),
     const void *, size_t, size_t, bool);
-void strip_nuls(char *, int);
+void strip_nuls(char *, size_t)
+    MKSH_A_BOUNDED(__string__, 1, 2);
 ssize_t blocking_read(int, char *, size_t)
     MKSH_A_BOUNDED(__buffer__, 2, 3);
 int reset_nonblock(int);
@@ -1923,6 +1923,7 @@
 ssize_t shf_vfprintf(struct shf *, const char *, va_list)
     MKSH_A_FORMAT(__printf__, 2, 0);
 /* syn.c */
+int assign_command(const char *);
 void initkeywords(void);
 struct op *compile(Source *, bool);
 bool parse_usec(const char *, struct timeval *);
diff --git a/src/syn.c b/src/syn.c
index 0e6e677..67a8ed7 100644
--- a/src/syn.c
+++ b/src/syn.c
@@ -2,7 +2,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- *		 2011, 2012, 2013, 2014
+ *		 2011, 2012, 2013, 2014, 2015
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.94.2.1 2015/01/25 15:35:54 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.94.2.3 2015/04/12 22:32:35 tg Exp $");
 
 struct nesting_state {
 	int start_token;	/* token than began nesting (eg, FOR) */
@@ -58,7 +58,6 @@
 static void syntaxerr(const char *) MKSH_A_NORETURN;
 static void nesting_push(struct nesting_state *, int);
 static void nesting_pop(struct nesting_state *);
-static int assign_command(const char *);
 static int inalias(struct source *) MKSH_A_PURE;
 static Test_op dbtestp_isa(Test_env *, Test_meta);
 static const char *dbtestp_getopnd(Test_env *, Test_op, bool);
@@ -190,16 +189,16 @@
 		return (NULL);
 	ACCEPT;
 	iop = yylval.iop;
-	if (iop->flag & IONDELIM)
+	if (iop->ioflag & IONDELIM)
 		goto gotnulldelim;
-	ishere = (iop->flag & IOTYPE) == IOHERE;
+	ishere = (iop->ioflag & IOTYPE) == IOHERE;
 	musthave(LWORD, ishere ? HEREDELIM : 0);
 	if (ishere) {
 		iop->delim = yylval.cp;
 		if (*ident != 0) {
 			/* unquoted */
  gotnulldelim:
-			iop->flag |= IOEVAL;
+			iop->ioflag |= IOEVAL;
 		}
 		if (herep > &heres[HERES - 1])
 			yyerror("too many %ss\n", "<<");
@@ -207,7 +206,7 @@
 	} else
 		iop->name = yylval.cp;
 
-	if (iop->flag & IOBASH) {
+	if (iop->ioflag & IOBASH) {
 		char *cp;
 
 		nextiop = alloc(sizeof(*iop), ATEMP);
@@ -221,9 +220,9 @@
 		*cp++ = '0' + (iop->unit % 10);
 		*cp = EOS;
 
-		iop->flag &= ~IOBASH;
+		iop->ioflag &= ~IOBASH;
 		nextiop->unit = 2;
-		nextiop->flag = IODUP;
+		nextiop->ioflag = IODUP;
 		nextiop->delim = NULL;
 		nextiop->heredoc = NULL;
 	}
@@ -289,7 +288,7 @@
 		t->lineno = source->line;
 		while (/* CONSTCOND */ 1) {
 			cf = (t->u.evalflags ? ARRAYVAR : 0) |
-			    (XPsize(args) == 0 ? sALIAS|VARASN : CMDWORD);
+			    (XPsize(args) == 0 ? sALIAS|VARASN : 0);
 			switch (tpeek(cf)) {
 			case REDIR:
 				while ((iop = synio(cf)) != NULL) {
@@ -927,7 +926,7 @@
  *	a=a
  *	$
  */
-static int
+int
 assign_command(const char *s)
 {
 	if (!*s)
@@ -997,9 +996,10 @@
 		ret = c == /*(*/ ')' ? TO_NONNULL : TO_NONOP;
 	else if (meta == TM_UNOP || meta == TM_BINOP) {
 		if (meta == TM_BINOP && c == REDIR &&
-		    (yylval.iop->flag == IOREAD || yylval.iop->flag == IOWRITE)) {
+		    (yylval.iop->ioflag == IOREAD ||
+		    yylval.iop->ioflag == IOWRITE)) {
 			ret = TO_NONNULL;
-			save = wdcopy(yylval.iop->flag == IOREAD ?
+			save = wdcopy(yylval.iop->ioflag == IOREAD ?
 			    db_lthan : db_gthan, ATEMP);
 		} else if (uqword && (ret = test_isop(meta, ident)))
 			save = yylval.cp;
diff --git a/src/tree.c b/src/tree.c
index 8026f8b..3a79c15 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -2,7 +2,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013
+ *		 2011, 2012, 2013, 2015
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.72 2013/09/24 20:19:45 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.72.2.1 2015/04/12 22:32:35 tg Exp $");
 
 #define INDENT	8
 
@@ -69,7 +69,7 @@
 		    t->ioact != NULL && t->ioact[0] != NULL &&
 		    t->ioact[1] == NULL &&
 		    /* of type "here document" (or "here string") */
-		    (t->ioact[0]->flag & IOTYPE) == IOHERE) {
+		    (t->ioact[0]->ioflag & IOTYPE) == IOHERE) {
 			fptreef(shf, indent, "%S", t->vars[0]);
 			break;
 		}
@@ -221,12 +221,12 @@
 			struct ioword *iop = *ioact++;
 
 			/* heredoc is NULL when tracing (set -x) */
-			if ((iop->flag & (IOTYPE | IOHERESTR)) == IOHERE &&
+			if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE &&
 			    iop->heredoc) {
 				shf_putc('\n', shf);
 				shf_puts(iop->heredoc, shf);
 				fptreef(shf, indent, "%s",
-				    iop->flag & IONDELIM ? "<<" :
+				    iop->ioflag & IONDELIM ? "<<" :
 				    evalstr(iop->delim, 0));
 				need_nl = true;
 			}
@@ -246,16 +246,16 @@
 static void
 pioact(struct shf *shf, struct ioword *iop)
 {
-	int flag = iop->flag;
-	int type = flag & IOTYPE;
-	int expected;
+	unsigned short flag = iop->ioflag;
+	unsigned short type = flag & IOTYPE;
+	short expected;
 
 	expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
 	    (type == IOCAT || type == IOWRITE) ? 1 :
 	    (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
 	    iop->unit + 1;
 	if (iop->unit != expected)
-		shf_fprintf(shf, "%d", iop->unit);
+		shf_fprintf(shf, "%d", (int)iop->unit);
 
 	switch (type) {
 	case IOREAD:
@@ -285,10 +285,10 @@
 	if (type == IOHERE) {
 		if (iop->delim)
 			wdvarput(shf, iop->delim, 0, WDS_TPUTS);
-		if (iop->flag & IOHERESTR)
+		if (flag & IOHERESTR)
 			shf_putc(' ', shf);
 	} else if (iop->name) {
-		if (iop->flag & IONAMEXP)
+		if (flag & IONAMEXP)
 			print_value_quoted(shf, iop->name);
 		else
 			wdvarput(shf, iop->name, 0, WDS_TPUTS);
@@ -910,9 +910,9 @@
 
 	shf_puts("{IOACT", shf);
 	while ((iop = *ioact++) != NULL) {
-		int type = iop->flag & IOTYPE;
+		unsigned short type = iop->ioflag & IOTYPE;
 #define DT(x) case x: shf_puts(#x, shf); break;
-#define DB(x) if (iop->flag & x) shf_puts("|" #x, shf);
+#define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf);
 
 		shf_putc(';', shf);
 		switch (type) {
@@ -933,14 +933,14 @@
 		DB(IOBASH)
 		DB(IOHERESTR)
 		DB(IONDELIM)
-		shf_fprintf(shf, ",unit=%d", iop->unit);
+		shf_fprintf(shf, ",unit=%d", (int)iop->unit);
 		if (iop->delim) {
 			shf_puts(",delim<", shf);
 			dumpwdvar(shf, iop->delim);
 			shf_putc('>', shf);
 		}
 		if (iop->name) {
-			if (iop->flag & IONAMEXP) {
+			if (iop->ioflag & IONAMEXP) {
 				shf_puts(",name=", shf);
 				print_value_quoted(shf, iop->name);
 			} else {
diff --git a/src/var.c b/src/var.c
index 452b6e2..f4da69a 100644
--- a/src/var.c
+++ b/src/var.c
@@ -28,7 +28,7 @@
 #include <sys/sysctl.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.183.2.2 2015/03/01 15:43:07 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.183.2.4 2015/04/19 19:18:23 tg Exp $");
 
 /*-
  * Variables
@@ -481,41 +481,57 @@
 static int
 getint(struct tbl *vp, mksh_ari_u *nump, bool arith)
 {
-	mksh_uari_t c, num, base;
+	mksh_uari_t c, num = 0, base = 10;
 	const char *s;
 	bool have_base = false, neg = false;
 
-	if (vp->flag&SPECIAL)
+	if (vp->flag & SPECIAL)
 		getspec(vp);
 	/* XXX is it possible for ISSET to be set and val.s to be NULL? */
-	if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
+	if (!(vp->flag & ISSET) || (!(vp->flag & INTEGER) && vp->val.s == NULL))
 		return (-1);
-	if (vp->flag&INTEGER) {
+	if (vp->flag & INTEGER) {
 		nump->i = vp->val.i;
 		return (vp->type);
 	}
 	s = vp->val.s + vp->type;
-	base = 10;
-	num = 0;
-	if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') {
-		s += 2;
-		base = 16;
-		have_base = true;
+
+	do {
+		c = (unsigned char)*s++;
+	} while (ksh_isspace(c));
+
+	switch (c) {
+	case '-':
+		neg = true;
+		/* FALLTHROUGH */
+	case '+':
+		c = (unsigned char)*s++;
+		break;
 	}
-	if (Flag(FPOSIX) && arith && s[0] == '0' && ksh_isdigit(s[1]) &&
-	    !(vp->flag & ZEROFIL)) {
-		/* interpret as octal (deprecated) */
-		base = 8;
-		have_base = true;
+
+	if (c == '0' && arith) {
+		if ((s[0] | 0x20) == 'x') {
+			/* interpret as hexadecimal */
+			base = 16;
+			++s;
+			goto getint_c_style_base;
+		} else if (Flag(FPOSIX) && ksh_isdigit(s[0]) &&
+		    !(vp->flag & ZEROFIL)) {
+			/* interpret as octal (deprecated) */
+			base = 8;
+ getint_c_style_base:
+			have_base = true;
+			c = (unsigned char)*s++;
+		}
 	}
-	while ((c = (unsigned char)*s++)) {
-		if (c == '-') {
-			neg = true;
-			continue;
-		} else if (c == '#') {
-			if (have_base || num < 1 || num > 36)
+
+	do {
+		if (c == '#') {
+			/* ksh-style base determination */
+			if (have_base || num < 1)
 				return (-1);
 			if ((base = num) == 1) {
+				/* mksh-specific extension */
 				unsigned int wc;
 
 				if (!UTFMODE)
@@ -530,22 +546,26 @@
 					wc = 0xEF00 + *(const unsigned char *)s;
 				nump->u = (mksh_uari_t)wc;
 				return (1);
-			}
+			} else if (base > 36)
+				return (-1);
 			num = 0;
 			have_base = true;
 			continue;
-		} else if (ksh_isdigit(c))
+		}
+		if (ksh_isdigit(c))
 			c -= '0';
-		else if (ksh_islower(c))
+		else {
+			c |= 0x20;
+			if (!ksh_islower(c))
+				return (-1);
 			c -= 'a' - 10;
-		else if (ksh_isupper(c))
-			c -= 'A' - 10;
-		else
-			return (-1);
+		}
 		if (c >= base)
 			return (-1);
+		/* handle overflow as truncation */
 		num = num * base + c;
-	}
+	} while ((c = (unsigned char)*s++));
+
 	if (neg)
 		num = -num;
 	nump->u = num;
@@ -1144,7 +1164,7 @@
 }
 
 static time_t seconds;		/* time SECONDS last set */
-static int user_lineno;		/* what user set $LINENO to */
+static mksh_uari_t user_lineno;	/* what user set $LINENO to */
 
 static void
 getspec(struct tbl *vp)
@@ -1178,7 +1198,7 @@
 		num.i = histsize;
 		break;
 	case V_LINENO:
-		num.i = current_lineno + user_lineno;
+		num.u = (mksh_uari_t)current_lineno + user_lineno;
 		break;
 	case V_LINES:
 		num.i = x_lins;
@@ -1308,7 +1328,7 @@
 		break;
 	case V_LINENO:
 		/* The -1 is because line numbering starts at 1. */
-		user_lineno = num.u - current_lineno - 1;
+		user_lineno = num.u - (mksh_uari_t)current_lineno - 1;
 		break;
 	case V_LINES:
 		if (num.i >= MIN_LINS)
@@ -1350,6 +1370,11 @@
 	 */
 
 	switch (special(vp->name)) {
+#if HAVE_PERSISTENT_HISTORY
+	case V_HISTFILE:
+		sethistfile(NULL);
+		return;
+#endif
 	case V_IFS:
 		setctypes(TC_IFSWS, C_IFS);
 		ifs0 = ' ';