Merge "Upgrade to mksh 51."
diff --git a/Android.mk b/Android.mk
index a78409f..9b1d914 100644
--- a/Android.mk
+++ b/Android.mk
@@ -61,7 +61,7 @@
     -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_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_IO_H=0 -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 \
@@ -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=506
+    -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=511
 
 include $(BUILD_EXECUTABLE)
diff --git a/Makefrag.inc b/Makefrag.inc
index 9c3632b..0f29116 100644
--- a/Makefrag.inc
+++ b/Makefrag.inc
@@ -1,4 +1,4 @@
-# Makefile fragment for building mksh R50 2015/04/19
+# Makefile fragment for building mksh R51 2015/07/10
 
 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=506
+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_IO_H=0 -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=511
 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 70c1d24..d5884be 100644
--- a/src/Build.sh
+++ b/src/Build.sh
@@ -1,5 +1,5 @@
 #!/bin/sh
-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.669.2.4 2015/04/19 19:18:08 tg Exp $'
+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.689 2015/07/10 17:16:23 tg Exp $'
 #-
 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #		2011, 2012, 2013, 2014, 2015
@@ -314,6 +314,7 @@
 	vv ']' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN conftest.c $LIBS $ccpr"
 	test $tcfn = no && test -f a.out && tcfn=a.out
 	test $tcfn = no && test -f a.exe && tcfn=a.exe
+	test $tcfn = no && test -f conftest.exe && tcfn=conftest.exe
 	test $tcfn = no && test -f conftest && tcfn=conftest
 	if test -f $tcfn; then
 		test 1 = $fr || fv=1
@@ -577,8 +578,8 @@
 	echo "$me: Error: ./$tfn is a directory!" >&2
 	exit 1
 fi
-rmf a.exe* a.out* conftest.c *core core.* lft ${tfn}* no *.bc *.ll *.o *.gen \
-    Rebuild.sh signames.inc test.sh x vv.out
+rmf a.exe* a.out* conftest.c conftest.exe* *core core.* ${tfn}* *.bc *.dbg \
+    *.ll *.o *.gen Rebuild.sh lft no signames.inc test.sh x vv.out
 
 SRCS="lalloc.c eval.c exec.c expr.c funcs.c histrap.c jobs.c"
 SRCS="$SRCS lex.c main.c misc.c shf.c syn.c tree.c var.c"
@@ -682,14 +683,14 @@
 # Configuration depending on OS name
 case $TARGET_OS in
 386BSD)
-	: ${HAVE_CAN_OTWO=0}
+	: "${HAVE_CAN_OTWO=0}"
 	add_cppflags -DMKSH_NO_SIGSETJMP
 	add_cppflags -DMKSH_TYPEDEF_SIG_ATOMIC_T=int
 	add_cppflags -DMKSH_CONSERVATIVE_FDS
 	;;
 AIX)
 	add_cppflags -D_ALL_SOURCE
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 BeOS)
 	case $KSH_VERSION in
@@ -708,7 +709,7 @@
 	add_cppflags -DMKSH__NO_SETEUGID
 	;;
 BSD/OS)
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 Coherent)
 	oswarn="; it has major issues"
@@ -719,7 +720,7 @@
 	add_cppflags -DMKSH_DISABLE_TTY_WARNING
 	;;
 CYGWIN*)
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 Darwin)
 	add_cppflags -D_DARWIN_C_SOURCE
@@ -732,7 +733,7 @@
 	oswarn="; it has minor issues"
 	add_cppflags -D_GNU_SOURCE
 	add_cppflags -DMKSH_CONSERVATIVE_FDS
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 GNU)
 	case $CC in
@@ -757,11 +758,11 @@
 	ccpc='-X '
 	ccpl='-Y '
 	add_cppflags -D_ALL_SOURCE
-	: ${LIBS='-lcrypt'}
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${LIBS=-lcrypt}"
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 IRIX*)
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 Linux)
 	case $CC in
@@ -769,7 +770,7 @@
 	*) add_cppflags -D_GNU_SOURCE ;;
 	esac
 	add_cppflags -DSETUID_CAN_FAIL_WITH_EAGAIN
-	: ${HAVE_REVOKE=0}
+	: "${HAVE_REVOKE=0}"
 	;;
 LynxOS)
 	oswarn="; it has minor issues"
@@ -782,7 +783,7 @@
 	add_cppflags -DMKSH_CONSERVATIVE_FDS
 	add_cppflags -D_MINIX_SOURCE
 	oldish_ed=no-stderr-ed		# no /bin/ed, maybe see below
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 Minix3)
 	add_cppflags -DMKSH_UNEMPLOYED
@@ -790,23 +791,24 @@
 	add_cppflags -DMKSH_NO_LIMITS
 	add_cppflags -D_POSIX_SOURCE -D_POSIX_1_SOURCE=2 -D_MINIX
 	oldish_ed=no-stderr-ed		# /usr/bin/ed(!) is broken
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 MirBSD)
 	;;
 MSYS_*)
 	add_cppflags -DMKSH_ASSUME_UTF8=0; HAVE_ISSET_MKSH_ASSUME_UTF8=1
 	# almost same as CYGWIN* (from RT|Chatzilla)
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	# broken on this OE (from ir0nh34d)
-	: ${HAVE_STDINT_H=0}
+	: "${HAVE_STDINT_H=0}"
 	;;
 NetBSD)
 	;;
 NEXTSTEP)
 	add_cppflags -D_NEXT_SOURCE
 	add_cppflags -D_POSIX_SOURCE
-	: ${AWK=gawk} ${CC=cc -posix}
+	: "${AWK=gawk}"
+	: "${CC=cc -posix}"
 	add_cppflags -DMKSH_NO_SIGSETJMP
 	# NeXTstep cannot get a controlling tty
 	add_cppflags -DMKSH_UNEMPLOYED
@@ -827,7 +829,17 @@
 	oswarn="; it has unknown issues"
 	;;
 OpenBSD)
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
+	;;
+OS/2)
+	HAVE_TERMIOS_H=0
+	HAVE_MKNOD=0	# setmode() incompatible
+	oswarn="; it is currently being ported"
+	check_categories="$check_categories nosymlink"
+	: "${CC=gcc}"
+	: "${SIZE=: size}"
+	add_cppflags -DMKSH_UNEMPLOYED
+	add_cppflags -DMKSH_NOPROSPECTOFWORK
 	;;
 OSF1)
 	HAVE_SIG_T=0	# incompatible
@@ -835,7 +847,7 @@
 	add_cppflags -D_POSIX_C_SOURCE=200112L
 	add_cppflags -D_XOPEN_SOURCE=600
 	add_cppflags -D_XOPEN_SOURCE_EXTENDED
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 Plan9)
 	add_cppflags -D_POSIX_SOURCE
@@ -853,7 +865,7 @@
 PW32*)
 	HAVE_SIG_T=0	# incompatible
 	oswarn=' and will currently not work'
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 QNX)
 	add_cppflags -D__NO_EXT_QNX
@@ -863,7 +875,7 @@
 		oldish_ed=no-stderr-ed		# oldish /bin/ed is broken
 		;;
 	esac
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 SCO_SV)
 	case $TARGET_OSREV in
@@ -880,7 +892,7 @@
 		;;
 	esac
 	add_cppflags -DMKSH_CONSERVATIVE_FDS
-	: ${HAVE_SYS_SIGLIST=0} ${HAVE__SYS_SIGLIST=0}
+	: "${HAVE_SYS_SIGLIST=0}${HAVE__SYS_SIGLIST=0}"
 	;;
 skyos)
 	oswarn="; it has minor issues"
@@ -895,15 +907,15 @@
 	oswarn=' and will currently not work'
 	;;
 ULTRIX)
-	: ${CC=cc -YPOSIX}
+	: "${CC=cc -YPOSIX}"
 	add_cppflags -DMKSH_TYPEDEF_SSIZE_T=int
 	add_cppflags -DMKSH_CONSERVATIVE_FDS
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 UnixWare|UNIX_SV)
 	# SCO UnixWare
 	add_cppflags -DMKSH_CONSERVATIVE_FDS
-	: ${HAVE_SYS_SIGLIST=0} ${HAVE__SYS_SIGLIST=0}
+	: "${HAVE_SYS_SIGLIST=0}${HAVE__SYS_SIGLIST=0}"
 	;;
 UWIN*)
 	ccpc='-Yc,'
@@ -911,7 +923,7 @@
 	tsts=" 3<>/dev/tty"
 	oswarn="; it will compile, but the target"
 	oswarn="$oswarn${nl}platform itself is very flakey/unreliable"
-	: ${HAVE_SETLOCALE_CTYPE=0}
+	: "${HAVE_SETLOCALE_CTYPE=0}"
 	;;
 _svr4)
 	# generic target for SVR4 Unix with uname -s = uname -n
@@ -925,11 +937,11 @@
 	;;
 esac
 
-: ${HAVE_MKNOD=0}
+: "${HAVE_MKNOD=0}"
 
-: ${AWK=awk} ${CC=cc} ${NROFF=nroff} ${SIZE=size}
+: "${AWK=awk}${CC=cc}${NROFF=nroff}${SIZE=size}"
 test 0 = $r && echo | $NROFF -v 2>&1 | grep GNU >/dev/null 2>&1 && \
-    NROFF="$NROFF -c"
+    echo | $NROFF -c >/dev/null 2>&1 && NROFF="$NROFF -c"
 
 # this aids me in tracing FTBFSen without access to the buildd
 $e "Hi from$ao $bi$srcversion$ao on:"
@@ -1050,7 +1062,7 @@
 #endif
 ;
 const char *
-#if defined(__KLIBC__)
+#if defined(__KLIBC__) && !defined(__OS2__)
 et="klibc"
 #else
 et="unknown"
@@ -1194,7 +1206,7 @@
 	SCO_SV:3.2*)
 		# SCO OpenServer 5
 		CFLAGS="$CFLAGS -g"
-		: ${HAVE_CAN_OTWO=0} ${HAVE_CAN_OPTIMISE=0}
+		: "${HAVE_CAN_OTWO=0}${HAVE_CAN_OPTIMISE=0}"
 		;;
 	esac
 	vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN -V conftest.c $LIBS"
@@ -1233,7 +1245,7 @@
 	;;
 esac
 $e "$bi==> which compiler seems to be used...$ao $ui$ct${et+ on $et}$ao"
-rmf conftest.c conftest.o conftest a.out* a.exe* vv.out
+rmf conftest.c conftest.o conftest a.out* a.exe* conftest.exe* vv.out
 
 #
 # Compiler: works as-is, with -Wno-error and -Werror
@@ -1248,7 +1260,7 @@
 if ac_ifcpp 'if 0' compiler_fails '' \
     'if the compiler does not fail correctly'; then
 	save_CFLAGS=$CFLAGS
-	: ${HAVE_CAN_DELEXE=x}
+	: "${HAVE_CAN_DELEXE=x}"
 	case $ct in
 	dec)
 		CFLAGS="$CFLAGS ${ccpl}-non_shared"
@@ -1610,8 +1622,8 @@
 #
 if ac_ifcpp 'ifdef MKSH_SMALL' isset_MKSH_SMALL '' \
     "if a reduced-feature mksh is requested"; then
-	: ${HAVE_NICE=0}
-	: ${HAVE_PERSISTENT_HISTORY=0}
+	: "${HAVE_NICE=0}"
+	: "${HAVE_PERSISTENT_HISTORY=0}"
 	check_categories="$check_categories smksh"
 	HAVE_ISSET_MKSH_CONSERVATIVE_FDS=1	# from sh.h
 fi
@@ -1625,7 +1637,7 @@
     "if mksh will be built without job signals" && \
     check_categories="$check_categories arge nojsig"
 ac_ifcpp 'ifdef MKSH_ASSUME_UTF8' isset_MKSH_ASSUME_UTF8 '' \
-    'if the default UTF-8 mode is specified' && : ${HAVE_SETLOCALE_CTYPE=0}
+    'if the default UTF-8 mode is specified' && : "${HAVE_SETLOCALE_CTYPE=0}"
 ac_ifcpp 'ifdef MKSH_CONSERVATIVE_FDS' isset_MKSH_CONSERVATIVE_FDS '' \
     'if traditional/conservative fd use is requested' && \
     check_categories="$check_categories convfds"
@@ -1662,6 +1674,7 @@
 ac_header sys/sysmacros.h
 ac_header bstring.h
 ac_header grp.h sys/types.h
+ac_header io.h
 ac_header libgen.h
 ac_header libutil.h sys/types.h
 ac_header paths.h
@@ -2248,20 +2261,22 @@
 	sigseenone=:
 	sigseentwo=:
 	echo '#include <signal.h>
-#ifndef NSIG
-#if defined(_NSIG)
-#define NSIG _NSIG
+#if defined(NSIG_MAX)
+#define cfg_NSIG NSIG_MAX
+#elif defined(NSIG)
+#define cfg_NSIG NSIG
+#elif defined(_NSIG)
+#define cfg_NSIG _NSIG
 #elif defined(SIGMAX)
-#define NSIG (SIGMAX+1)
+#define cfg_NSIG (SIGMAX + 1)
 #elif defined(_SIGMAX)
-#define NSIG (_SIGMAX+1)
+#define cfg_NSIG (_SIGMAX + 1)
 #else
-/* XXX better error out, see sh.h */
-#define NSIG 64
-#endif
+/*XXX better error out, see sh.h */
+#define cfg_NSIG 64
 #endif
 int
-mksh_cfg= NSIG
+mksh_cfg= cfg_NSIG
 ;' >conftest.c
 	# GNU sed 2.03 segfaults when optimising this to sed -n
 	NSIG=`vq "$CPP $CFLAGS $CPPFLAGS $NOWARN conftest.c" | \
@@ -2283,8 +2298,8 @@
 	$printf "NSIG=$NSIG ... "
 	sigs="ABRT FPE ILL INT SEGV TERM ALRM BUS CHLD CONT HUP KILL PIPE QUIT"
 	sigs="$sigs STOP TSTP TTIN TTOU USR1 USR2 POLL PROF SYS TRAP URG VTALRM"
-	sigs="$sigs XCPU XFSZ INFO WINCH EMT IO DIL LOST PWR SAK CLD IOT RESV"
-	sigs="$sigs STKFLT UNUSED"
+	sigs="$sigs XCPU XFSZ INFO WINCH EMT IO DIL LOST PWR SAK CLD IOT STKFLT"
+	sigs="$sigs ABND DCE DUMP IOERR TRACE DANGER THCONT THSTOP RESV UNUSED"
 	test 1 = $HAVE_CPP_DD && test $NSIG -gt 1 && sigs="$sigs "`vq \
 	    "$CPP $CFLAGS $CPPFLAGS $NOWARN -dD conftest.c" | \
 	    grep '[	 ]SIG[A-Z0-9][A-Z0-9]*[	 ]' | \
@@ -2310,7 +2325,7 @@
 		    sed 's/^ *mksh_cfg *=[	 ]*\([0-9][0-9x]*\).*$/:\1 '$name/
 	done | sed -n '/^:[^ ]/s/^://p' | while read nr name; do
 		test $printf = echo || nr=`printf %d "$nr" 2>/dev/null`
-		test $nr -gt 0 && test $nr -le $NSIG || continue
+		test $nr -gt 0 && test $nr -lt $NSIG || continue
 		case $sigseentwo in
 		*:$nr:*) ;;
 		*)	echo "		{ \"$name\", $nr },"
@@ -2327,7 +2342,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=506
+add_cppflags -DMKSH_BUILD_R=511
 
 $e $bi$me: Finished configuration testing, now producing output.$ao
 
@@ -2335,8 +2350,13 @@
 objs=
 sp=
 case $tcfn in
-a.exe)	mkshexe=$tfn.exe ;;
-*)	mkshexe=$tfn ;;
+a.exe|conftest.exe)
+	mkshexe=$tfn.exe
+	add_cppflags -DMKSH_EXE_EXT
+	;;
+*)
+	mkshexe=$tfn
+	;;
 esac
 case $curdir in
 *\ *)	mkshshebang="#!./$mkshexe" ;;
@@ -2643,7 +2663,6 @@
 MKSH_NOPWNAM			skip PAM calls, for -static on glibc or Solaris
 MKSH_NO_CMDLINE_EDITING		disable command line editing code entirely
 MKSH_NO_DEPRECATED_WARNING	omit warning when deprecated stuff is run
-MKSH_NO_EXTERNAL_CAT		omit hack to skip cat builtin when flags passed
 MKSH_NO_LIMITS			omit ulimit code
 MKSH_NO_SIGSETJMP		define if sigsetjmp is broken or not available
 MKSH_NO_SIGSUSPEND		use sigprocmask+pause instead of sigsuspend
@@ -2670,4 +2689,7 @@
 http://anonscm.debian.org/cgit/collab-maint/mksh.git/plain/debian/.mkshrc
 and put dot.mkshrc as /etc/mkshrc so users need not keep up their HOME.
 
+You may also want to install the lksh binary (also as /bin/sh) built by:
+$ CPPFLAGS="$CPPFLAGS -DMKSH_BINSHPOSIX" sh Build.sh -L -r -c lto
+
 EOD
diff --git a/src/check.pl b/src/check.pl
index ce45773..4417f82 100644
--- a/src/check.pl
+++ b/src/check.pl
@@ -1,4 +1,4 @@
-# $MirOS: src/bin/mksh/check.pl,v 1.37.2.1 2015/04/12 22:32:16 tg Exp $
+# $MirOS: src/bin/mksh/check.pl,v 1.40 2015/07/10 19:36:31 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,
@@ -73,11 +73,12 @@
 #					the following minimal environment:
 #					    HOME, LD_LIBRARY_PATH, LOCPATH,
 #					    LOGNAME, PATH, SHELL, UNIXMODE,
-#					    USER
+#					    UNIXROOT, USER
 #					(values taken from the environment of
 #					the test harness).
 #					CYGWIN is set to nodosfilewarning.
 #					ENV is set to /nonexistant.
+#					PATHSEP is set to either : or ;.
 #					__progname is set to the -p argument.
 #					__perlname is set to $^X (perlexe).
 #	file-setup		mps	Used to create files, directories
@@ -275,11 +276,12 @@
 # Set up a very minimal environment
 %new_env = ();
 foreach $env (('HOME', 'LD_LIBRARY_PATH', 'LOCPATH', 'LOGNAME',
-  'PATH', 'SHELL', 'UNIXMODE', 'USER')) {
+  'PATH', 'SHELL', 'UNIXMODE', 'UNIXROOT', 'USER')) {
     $new_env{$env} = $ENV{$env} if defined $ENV{$env};
 }
 $new_env{'CYGWIN'} = 'nodosfilewarning';
 $new_env{'ENV'} = '/nonexistant';
+$new_env{'PATHSEP'} = $os eq 'os2' ? ';' : ':';
 if (($os eq 'VMS') || ($Config{perlpath} =~ m/$Config{_exe}$/i)) {
 	$new_env{'__perlname'} = $Config{perlpath};
 } else {
@@ -312,9 +314,10 @@
 die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd);
 
 if (!$program_kludge) {
-    $test_prog = "$pwd/$test_prog" if substr($test_prog, 0, 1) ne '/';
+    $test_prog = "$pwd/$test_prog" if (substr($test_prog, 0, 1) ne '/') &&
+      ($os ne 'os2' || substr($test_prog, 1, 1) ne ':');
     die "$prog: $test_prog is not executable - bye\n"
-	if (! -x $test_prog && $os ne 'os2');
+      if (! -x $test_prog && $os ne 'os2');
 }
 
 @trap_sigs = ('TERM', 'QUIT', 'INT', 'PIPE', 'HUP');
@@ -1165,7 +1168,7 @@
 		print STDERR "$prog:$test{':long-name'}: expected-exit value $val not in 0..255\n";
 		return undef;
 	    }
-	} elsif ($val !~ /^([\s<>+-=*%\/&|!()]|\b[wse]\b|\bSIG[A-Z][A-Z0-9]*\b)+$/) {
+	} elsif ($val !~ /^([\s\d<>+=*%\/&|!()-]|\b[wse]\b|\bSIG[A-Z][A-Z0-9]*\b)+$/) {
 	    print STDERR "$prog:$test{':long-name'}: bad expected-exit expression: $val\n";
 	    return undef;
 	}
diff --git a/src/check.t b/src/check.t
index 1d59d38..989722b 100644
--- a/src/check.t
+++ b/src/check.t
Binary files differ
diff --git a/src/dot.mkshrc b/src/dot.mkshrc
index f65eaa7..4c64395 100644
--- a/src/dot.mkshrc
+++ b/src/dot.mkshrc
@@ -1,5 +1,5 @@
 # $Id$
-# $MirOS: src/bin/mksh/dot.mkshrc,v 1.89.2.3 2015/04/12 22:32:22 tg Exp $
+# $MirOS: src/bin/mksh/dot.mkshrc,v 1.100 2015/07/10 19:36:33 tg Exp $
 #-
 # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
 #		2011, 2012, 2013, 2014, 2015
@@ -28,127 +28,129 @@
 *) return 0 ;;
 esac
 
-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)}"
+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:=$(\builtin whence -p mksh)}"
 HOSTNAME=${HOSTNAME%%*([	 ]).*}; HOSTNAME=${HOSTNAME##*([	 ])}
 [[ $HOSTNAME = ?(ip6-)localhost?(6) ]] && HOSTNAME=
-: "${HOSTNAME:=nil}${MKSH:=/bin/mksh}"; export EDITOR HOSTNAME MKSH TERM USER
+\: "${HOSTNAME:=nil}${MKSH:=/bin/mksh}"; \export EDITOR HOSTNAME MKSH TERM USER
 PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
-	local e=$?
+	\typeset e=$?
 
 	(( e )) && REPLY+="$e|"
 	REPLY+=${USER}@${HOSTNAME%%.*}:
 
-	local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~}
-	local m=${%d} n p=...; (( m > 0 )) || m=${#d}
+	\typeset d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~}
+	\typeset m=${%d} n p=...; (( m > 0 )) || m=${#d}
 	(( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
 	REPLY+=$p$d
 
-	return $e
+	\return $e
 } '"$PS1 "
-alias ls=ls
-unalias ls
-alias l='ls -F'
-alias la='l -a'
-alias ll='l -l'
-alias lo='l -alo'
-alias doch='sudo mksh -c "$(fc -ln -1)"'
-command -v rot13 >/dev/null || alias rot13='tr \
+\alias ls=ls
+\unalias ls
+\alias l='ls -F'
+\alias la='l -a'
+\alias ll='l -l'
+\alias lo='l -alo'
+\alias doch='sudo mksh -c "$(\builtin fc -ln -1)"'
+\command -v rot13 >/dev/null || \alias rot13='tr \
     abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
     nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
-if command -v hd >/dev/null; then :; elif command -v 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"' "$@"
 	}
 else
 	function hd {
-		local -Uui16 -Z11 pos=0
-		local -Uui16 -Z5 hv=2147483647
-		local dasc line i
+		\typeset -Uui16 -Z11 pos=0
+		\typeset -Uui16 -Z5 hv=2147483647
+		\typeset dasc line i
+		\set +U
 
-		cat "$@" | { set +U; if read -arN -1 line; then
-			typeset -i1 'line[*]'
+		\cat "$@" | if \read -arN -1 line; then
+			\typeset -i1 'line[*]'
 			i=0
 			while (( i < ${#line[*]} )); do
 				hv=${line[i++]}
 				if (( (pos & 15) == 0 )); then
 					(( pos )) && \
-					    print -r -- "$dasc|"
-					print -n "${pos#16#}  "
+					    \builtin print -r -- "$dasc|"
+					\builtin print -n "${pos#16#}  "
 					dasc=' |'
 				fi
-				print -n "${hv#16#} "
+				\builtin print -n "${hv#16#} "
+				#XXX EBCDIC, but we need [[:print:]] to fix this
 				if (( (hv < 32) || (hv > 126) )); then
 					dasc+=.
 				else
 					dasc+=${line[i-1]#1#}
 				fi
 				(( (pos++ & 15) == 7 )) && \
-				    print -n -- '- '
+				    \builtin print -n -- '- '
 			done
 			while (( pos & 15 )); do
-				print -n '   '
+				\builtin print -n '   '
 				(( (pos++ & 15) == 7 )) && \
-				    print -n -- '- '
+				    \builtin print -n -- '- '
 			done
-			(( hv == 2147483647 )) || print -r -- "$dasc|"
-		fi; }
+			(( hv == 2147483647 )) || \builtin print -r -- "$dasc|"
+		fi
 	}
 fi
 
 # 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=$(\builtin realpath ~/. 2>/dev/null || \
+    \builtin print -nr -- "${HOME:-/}")
 set -A DIRSTACK
 function chpwd {
-	DIRSTACK[0]=$(realpath . 2>/dev/null || \
-	    print -r -- "$PWD")
+	DIRSTACK[0]=$(\builtin realpath . 2>/dev/null || \
+	    \builtin print -r -- "$PWD")
 	[[ $DIRSTACKBASE = ?(*/) ]] || \
 	    DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/~}
-	:
+	\:
 }
-chpwd .
-function cd {
-	builtin cd "$@" || return $?
-	chpwd "$@"
+\chpwd .
+cd() {
+	\builtin cd "$@" || \return $?
+	\chpwd "$@"
 }
 function cd_csh {
-	local d t=${1/#~/$DIRSTACKBASE}
+	\typeset d t=${1/#~/$DIRSTACKBASE}
 
-	if ! d=$(builtin cd "$t" 2>&1); then
-		print -u2 "${1}: ${d##*cd: $t: }."
-		return 1
+	if ! d=$(\builtin cd "$t" 2>&1); then
+		\builtin print -u2 "${1}: ${d##*cd: $t: }."
+		\return 1
 	fi
-	cd "$t"
+	\cd "$t"
 }
 function dirs {
-	local d dwidth
-	local -i fl=0 fv=0 fn=0 cpos=0
+	\typeset d dwidth
+	\typeset -i fl=0 fv=0 fn=0 cpos=0
 
-	while getopts ":lvn" d; do
+	while \getopts ":lvn" d; do
 		case $d {
 		(l)	fl=1 ;;
 		(v)	fv=1 ;;
 		(n)	fn=1 ;;
-		(*)	print -u2 'Usage: dirs [-lvn].'
-			return 1 ;;
+		(*)	\builtin print -u2 'Usage: dirs [-lvn].'
+			\return 1 ;;
 		}
 	done
-	shift $((OPTIND - 1))
+	\shift $((OPTIND - 1))
 	if (( $# > 0 )); then
-		print -u2 'Usage: dirs [-lvn].'
-		return 1
+		\builtin print -u2 'Usage: dirs [-lvn].'
+		\return 1
 	fi
 	if (( fv )); then
 		fv=0
 		while (( fv < ${#DIRSTACK[*]} )); do
 			d=${DIRSTACK[fv]}
 			(( fl )) && d=${d/#~/$DIRSTACKBASE}
-			print -r -- "$fv	$d"
-			let fv++
+			\builtin print -r -- "$fv	$d"
+			\builtin let fv++
 		done
 	else
 		fv=0
@@ -158,138 +160,138 @@
 			(( dwidth = (${%d} > 0 ? ${%d} : ${#d}) ))
 			if (( fn && (cpos += dwidth + 1) >= 79 && \
 			    dwidth < 80 )); then
-				print
+				\builtin print
 				(( cpos = dwidth + 1 ))
 			fi
-			print -nr -- "$d "
-			let fv++
+			\builtin print -nr -- "$d "
+			\builtin let fv++
 		done
-		print
+		\builtin print
 	fi
-	return 0
+	\return 0
 }
 function popd {
-	local d fa
-	local -i n=1
+	\typeset d fa
+	\typeset -i n=1
 
-	while getopts ":0123456789lvn" d; do
+	while \getopts ":0123456789lvn" d; do
 		case $d {
 		(l|v|n)	fa+=" -$d" ;;
 		(+*)	n=2
-			break ;;
-		(*)	print -u2 'Usage: popd [-lvn] [+<n>].'
-			return 1 ;;
+			\break ;;
+		(*)	\builtin print -u2 'Usage: popd [-lvn] [+<n>].'
+			\return 1 ;;
 		}
 	done
-	shift $((OPTIND - n))
+	\shift $((OPTIND - n))
 	n=0
 	if (( $# > 1 )); then
-		print -u2 popd: Too many arguments.
-		return 1
+		\builtin print -u2 popd: Too many arguments.
+		\return 1
 	elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then
 		if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then
-			print -u2 popd: Directory stack not that deep.
-			return 1
+			\builtin print -u2 popd: Directory stack not that deep.
+			\return 1
 		fi
 	elif [[ -n $1 ]]; then
-		print -u2 popd: Bad directory.
-		return 1
+		\builtin print -u2 popd: Bad directory.
+		\return 1
 	fi
 	if (( ${#DIRSTACK[*]} < 2 )); then
-		print -u2 popd: Directory stack empty.
-		return 1
+		\builtin print -u2 popd: Directory stack empty.
+		\return 1
 	fi
-	unset DIRSTACK[n]
-	set -A DIRSTACK -- "${DIRSTACK[@]}"
-	cd_csh "${DIRSTACK[0]}" || return 1
-	dirs $fa
+	\unset DIRSTACK[n]
+	\set -A DIRSTACK -- "${DIRSTACK[@]}"
+	\cd_csh "${DIRSTACK[0]}" || \return 1
+	\dirs $fa
 }
 function pushd {
-	local d fa
-	local -i n=1
+	\typeset d fa
+	\typeset -i n=1
 
-	while getopts ":0123456789lvn" d; do
+	while \getopts ":0123456789lvn" d; do
 		case $d {
 		(l|v|n)	fa+=" -$d" ;;
 		(+*)	n=2
-			break ;;
-		(*)	print -u2 'Usage: pushd [-lvn] [<dir>|+<n>].'
-			return 1 ;;
+			\break ;;
+		(*)	\builtin print -u2 'Usage: pushd [-lvn] [<dir>|+<n>].'
+			\return 1 ;;
 		}
 	done
-	shift $((OPTIND - n))
+	\shift $((OPTIND - n))
 	if (( $# == 0 )); then
 		if (( ${#DIRSTACK[*]} < 2 )); then
-			print -u2 pushd: No other directory.
-			return 1
+			\builtin print -u2 pushd: No other directory.
+			\return 1
 		fi
 		d=${DIRSTACK[1]}
 		DIRSTACK[1]=${DIRSTACK[0]}
-		cd_csh "$d" || return 1
+		\cd_csh "$d" || \return 1
 	elif (( $# > 1 )); then
-		print -u2 pushd: Too many arguments.
-		return 1
+		\builtin print -u2 pushd: Too many arguments.
+		\return 1
 	elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then
 		if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then
-			print -u2 pushd: Directory stack not that deep.
-			return 1
+			\builtin print -u2 pushd: Directory stack not that deep.
+			\return 1
 		fi
 		while (( n-- )); do
 			d=${DIRSTACK[0]}
-			unset DIRSTACK[0]
-			set -A DIRSTACK -- "${DIRSTACK[@]}" "$d"
+			\unset DIRSTACK[0]
+			\set -A DIRSTACK -- "${DIRSTACK[@]}" "$d"
 		done
-		cd_csh "${DIRSTACK[0]}" || return 1
+		\cd_csh "${DIRSTACK[0]}" || \return 1
 	else
-		set -A DIRSTACK -- placeholder "${DIRSTACK[@]}"
-		cd_csh "$1" || return 1
+		\set -A DIRSTACK -- placeholder "${DIRSTACK[@]}"
+		\cd_csh "$1" || \return 1
 	fi
-	dirs $fa
+	\dirs $fa
 }
 
 # pager (not control character safe)
 function smores {
 	(
-		set +m
-		cat "$@" |&
-		trap "rv=\$?; kill $! >/dev/null 2>&1; exit \$rv" EXIT
-		while IFS= read -pr line; do
+		\set +m
+		\cat "$@" |&
+		\trap "rv=\$?; 'kill' $! >/dev/null 2>&1; 'exit' \$rv" EXIT
+		while IFS= \read -pr line; do
 			llen=${%line}
 			(( llen == -1 )) && llen=${#line}
 			(( llen = llen ? (llen + COLUMNS - 1) / COLUMNS : 1 ))
 			if (( (curlin += llen) >= LINES )); then
-				print -n -- '\033[7m--more--\033[0m'
-				read -u1 || exit $?
-				[[ $REPLY = [Qq]* ]] && exit 0
+				\builtin print -n -- '\e[7m--more--\e[0m'
+				\read -u1 || \exit $?
+				[[ $REPLY = [Qq]* ]] && \exit 0
 				curlin=$llen
 			fi
-			print -r -- "$line"
+			\builtin print -r -- "$line"
 		done
 	)
 }
 
-# base64 encoder and decoder, RFC compliant, NUL safe
+# base64 encoder and decoder, RFC compliant, NUL safe, not EBCDIC safe
 function Lb64decode {
-	[[ -o utf8-mode ]]; local u=$? c s="$*" t
-	set +U
-	[[ -n $s ]] || { s=$(cat; print x); s=${s%x}; }
-	local -i i=0 j=0 n=${#s} p=0 v x
-	local -i16 o
+	\set +U
+	\typeset c s="$*" t
+	[[ -n $s ]] || { s=$(\cat; \builtin print x); s=${s%x}; }
+	\typeset -i i=0 j=0 n=${#s} p=0 v x
+	\typeset -i16 o
 
 	while (( i < n )); do
 		c=${s:(i++):1}
 		case $c {
-		(=)	break ;;
+		(=)	\break ;;
 		([A-Z])	(( v = 1#$c - 65 )) ;;
 		([a-z])	(( v = 1#$c - 71 )) ;;
 		([0-9])	(( v = 1#$c + 4 )) ;;
 		(+)	v=62 ;;
 		(/)	v=63 ;;
-		(*)	continue ;;
+		(*)	\continue ;;
 		}
 		(( x = (x << 6) | v ))
 		case $((p++)) {
-		(0)	continue ;;
+		(0)	\continue ;;
 		(1)	(( o = (x >> 4) & 255 )) ;;
 		(2)	(( o = (x >> 2) & 255 )) ;;
 		(3)	(( o = x & 255 ))
@@ -297,26 +299,25 @@
 			;;
 		}
 		t+=\\x${o#16#}
-		(( ++j & 4095 )) && continue
-		print -n $t
+		(( ++j & 4095 )) && \continue
+		\builtin print -n $t
 		t=
 	done
-	print -n $t
-	(( u )) || set -U
+	\builtin print -n $t
 }
 
-set -A Lb64encode_code -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
+\set -A Lb64encode_tbl -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
     a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + /
 function Lb64encode {
-	[[ -o utf8-mode ]]; local u=$? c s t
-	set +U
+	\set +U
+	\typeset c s t
 	if (( $# )); then
-		read -raN-1 s <<<"$*"
-		unset s[${#s[*]}-1]
+		\read -raN-1 s <<<"$*"
+		\unset s[${#s[*]}-1]
 	else
-		read -raN-1 s
+		\read -raN-1 s
 	fi
-	local -i i=0 n=${#s[*]} j v
+	\typeset -i i=0 n=${#s[*]} j v
 
 	while (( i < n )); do
 		(( v = s[i++] << 16 ))
@@ -324,86 +325,277 @@
 		(( v |= j << 8 ))
 		(( j = i < n ? s[i++] : 0 ))
 		(( v |= j ))
-		t+=${Lb64encode_code[v >> 18]}${Lb64encode_code[v >> 12 & 63]}
-		c=${Lb64encode_code[v >> 6 & 63]}
+		t+=${Lb64encode_tbl[v >> 18]}${Lb64encode_tbl[v >> 12 & 63]}
+		c=${Lb64encode_tbl[v >> 6 & 63]}
 		if (( i <= n )); then
-			t+=$c${Lb64encode_code[v & 63]}
+			t+=$c${Lb64encode_tbl[v & 63]}
 		elif (( i == n + 1 )); then
 			t+=$c=
 		else
 			t+===
 		fi
 		if (( ${#t} == 76 || i >= n )); then
-			print $t
+			\builtin print $t
 			t=
 		fi
 	done
-	(( u )) || set -U
 }
 
 # Better Avalanche for the Jenkins Hash
-typeset -Z11 -Uui16 Lbafh_v
+\typeset -Z11 -Uui16 Lbafh_v
 function Lbafh_init {
 	Lbafh_v=0
 }
 function Lbafh_add {
-	[[ -o utf8-mode ]]; local u=$? s
-	set +U
+	\set +U
+	\typeset s
 	if (( $# )); then
-		read -raN-1 s <<<"$*"
-		unset s[${#s[*]}-1]
+		\read -raN-1 s <<<"$*"
+		\unset s[${#s[*]}-1]
 	else
-		read -raN-1 s
+		\read -raN-1 s
 	fi
-	local -i i=0 n=${#s[*]}
+	\typeset -i i=0 n=${#s[*]}
 
 	while (( i < n )); do
 		((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 ))
 		((# Lbafh_v ^= Lbafh_v >> 6 ))
 	done
-
-	(( u )) || set -U
 }
 function Lbafh_finish {
-	local -Ui t
+	\typeset -Ui t
 
 	((# t = (((Lbafh_v >> 7) & 0x01010101) * 0x1B) ^ \
 	    ((Lbafh_v << 1) & 0xFEFEFEFE) ))
 	((# Lbafh_v = t ^ (t >>> 8) ^ (Lbafh_v >>> 8) ^ \
 	    (Lbafh_v >>> 16) ^ (Lbafh_v >>> 24) ))
-	:
+	\:
 }
 
 # strip comments (and leading/trailing whitespace if IFS is set) from
 # any file(s) given as argument, or stdin if none, and spew to stdout
 function Lstripcom {
-	cat "$@" | { set -o noglob; while read _line; do
+	\set -o noglob
+	\cat "$@" | while \read _line; do
 		_line=${_line%%#*}
-		[[ -n $_line ]] && print -r -- $_line
-	done; }
+		[[ -n $_line ]] && \builtin print -r -- $_line
+	done
 }
 
 # give MidnightBSD's laffer1 a bit of csh feeling
 function setenv {
-	eval export "\"$1\""'="$2"'
+	\eval "'export' \"$1\""'="$2"'
 }
 
-: place customisations below this line
+# toggle built-in aliases and utilities, and aliases and functions from mkshrc
+function enable {
+	\typeset doprnt=0 mode=1 x y z rv=0
+	\typeset b_alias i_alias i_func nalias=0 nfunc=0 i_all
+	\set -A b_alias
+	\set -A i_alias
+	\set -A i_func
+
+	# accumulate mksh built-in aliases, in ASCIIbetical order
+	i_alias[nalias]=autoload; b_alias[nalias++]='\typeset -fu'
+	i_alias[nalias]=functions; b_alias[nalias++]='\typeset -f'
+	i_alias[nalias]=hash; b_alias[nalias++]='\builtin alias -t'
+	i_alias[nalias]=history; b_alias[nalias++]='\builtin fc -l'
+	i_alias[nalias]=integer; b_alias[nalias++]='\typeset -i'
+	i_alias[nalias]=local; b_alias[nalias++]='\typeset'
+	i_alias[nalias]=login; b_alias[nalias++]='\exec login'
+	i_alias[nalias]=nameref; b_alias[nalias++]='\typeset -n'
+	i_alias[nalias]=nohup; b_alias[nalias++]='nohup '
+	i_alias[nalias]=r; b_alias[nalias++]='\builtin fc -e -'
+	#XXX OS/2
+	i_alias[nalias]=source; b_alias[nalias++]='PATH=$PATH:. \command .'
+	i_alias[nalias]=stop; b_alias[nalias++]='\kill -STOP'
+	i_alias[nalias]=type; b_alias[nalias++]='\builtin whence -v'
+
+	# accumulate mksh built-in utilities, in definition order, even ifndef
+	i_func[nfunc++]=.
+	i_func[nfunc++]=:
+	i_func[nfunc++]='['
+	i_func[nfunc++]=alias
+	i_func[nfunc++]=break
+	i_func[nfunc++]=builtin
+	i_func[nfunc++]=cat
+	i_func[nfunc++]=cd
+	i_func[nfunc++]=chdir
+	i_func[nfunc++]=command
+	i_func[nfunc++]=continue
+	i_func[nfunc++]=echo
+	i_func[nfunc++]=eval
+	i_func[nfunc++]=exec
+	i_func[nfunc++]=exit
+	i_func[nfunc++]=export
+	i_func[nfunc++]=false
+	i_func[nfunc++]=fc
+	i_func[nfunc++]=getopts
+	i_func[nfunc++]=global
+	i_func[nfunc++]=jobs
+	i_func[nfunc++]=kill
+	i_func[nfunc++]=let
+	i_func[nfunc++]='let]'
+	i_func[nfunc++]=print
+	i_func[nfunc++]=pwd
+	i_func[nfunc++]=read
+	i_func[nfunc++]=readonly
+	i_func[nfunc++]=realpath
+	i_func[nfunc++]=rename
+	i_func[nfunc++]=return
+	i_func[nfunc++]=set
+	i_func[nfunc++]=shift
+	i_func[nfunc++]=suspend
+	i_func[nfunc++]=test
+	i_func[nfunc++]=times
+	i_func[nfunc++]=trap
+	i_func[nfunc++]=true
+	i_func[nfunc++]=typeset
+	i_func[nfunc++]=ulimit
+	i_func[nfunc++]=umask
+	i_func[nfunc++]=unalias
+	i_func[nfunc++]=unset
+	i_func[nfunc++]=wait
+	i_func[nfunc++]=whence
+	i_func[nfunc++]=bg
+	i_func[nfunc++]=fg
+	i_func[nfunc++]=bind
+	i_func[nfunc++]=mknod
+	i_func[nfunc++]=printf
+	i_func[nfunc++]=sleep
+	i_func[nfunc++]=domainname
+
+	# accumulate aliases from dot.mkshrc, in definition order
+	i_alias[nalias]=l; b_alias[nalias++]='ls -F'
+	i_alias[nalias]=la; b_alias[nalias++]='l -a'
+	i_alias[nalias]=ll; b_alias[nalias++]='l -l'
+	i_alias[nalias]=lo; b_alias[nalias++]='l -alo'
+	i_alias[nalias]=doch; b_alias[nalias++]='sudo mksh -c "$(\builtin fc -ln -1)"'
+	i_alias[nalias]=rot13; b_alias[nalias++]='tr abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
+	i_alias[nalias]=cls; b_alias[nalias++]='\builtin print -n \\ec'
+
+	# accumulate functions from dot.mkshrc, in definition order
+	i_func[nfunc++]=hd
+	i_func[nfunc++]=chpwd
+	i_func[nfunc++]=cd_csh
+	i_func[nfunc++]=dirs
+	i_func[nfunc++]=popd
+	i_func[nfunc++]=pushd
+	i_func[nfunc++]=smores
+	i_func[nfunc++]=Lb64decode
+	i_func[nfunc++]=Lb64encode
+	i_func[nfunc++]=Lbafh_init
+	i_func[nfunc++]=Lbafh_add
+	i_func[nfunc++]=Lbafh_finish
+	i_func[nfunc++]=Lstripcom
+	i_func[nfunc++]=setenv
+	i_func[nfunc++]=enable
+
+	# collect all identifiers, sorted ASCIIbetically
+	\set -sA i_all -- "${i_alias[@]}" "${i_func[@]}"
+
+	# handle options, we don't do dynamic loading
+	while \getopts "adf:nps" x; do
+		case $x {
+		(a)
+			mode=-1
+			;;
+		(d)
+			# deliberately causing an error, like bash-static
+			;|
+		(f)
+			\builtin print -u2 enable: dynamic loading not available
+			\return 2
+			;;
+		(n)
+			mode=0
+			;;
+		(p)
+			doprnt=1
+			;;
+		(s)
+			\set -sA i_all -- . : break continue eval exec exit \
+			    export readonly return set shift times trap unset
+			;;
+		(*)
+			\builtin print -u2 enable: usage: \
+			    "enable [-adnps] [-f filename] [name ...]"
+			return 2
+			;;
+		}
+	done
+	\shift $((OPTIND - 1))
+
+	# display builtins enabled/disabled/all/special?
+	if (( doprnt || ($# == 0) )); then
+		for x in "${i_all[@]}"; do
+			y=$(\alias "$x") || y=
+			[[ $y = "$x='\\builtin whence -p $x >/dev/null || (\\builtin print mksh: $x: not found; exit 127) && \$(\\builtin whence -p $x)'" ]]; z=$?
+			case $mode:$z {
+			(-1:0|0:0)
+				\print -r -- "enable -n $x"
+				;;
+			(-1:1|1:1)
+				\print -r -- "enable $x"
+				;;
+			}
+		done
+		\return 0
+	fi
+
+	for x in "$@"; do
+		z=0
+		for y in "${i_alias[@]}" "${i_func[@]}"; do
+			[[ $x = "$y" ]] || \continue
+			z=1
+			\break
+		done
+		if (( !z )); then
+			\builtin print -ru2 enable: "$x": not a shell builtin
+			rv=1
+			\continue
+		fi
+		if (( !mode )); then
+			# disable this
+			\alias "$x=\\builtin whence -p $x >/dev/null || (\\builtin print mksh: $x: not found; exit 127) && \$(\\builtin whence -p $x)"
+		else
+			# find out if this is an alias or not, first
+			z=0
+			y=-1
+			while (( ++y < nalias )); do
+				[[ $x = "${i_alias[y]}" ]] || \continue
+				z=1
+				\break
+			done
+			if (( z )); then
+				# re-enable the original alias body
+				\alias "$x=${b_alias[y]}"
+			else
+				# re-enable the original utility/function
+				\unalias "$x"
+			fi
+		fi
+	done
+	\return $rv
+}
+
+\: place customisations below this line
 
 for p in ~/.etc/bin ~/bin; do
-	[[ -d $p/. ]] || continue
+	[[ -d $p/. ]] || \continue
+	#XXX OS/2
 	[[ :$PATH: = *:$p:* ]] || PATH=$p:$PATH
 done
 
-export SHELL=$MKSH MANWIDTH=80 LESSHISTFILE=-
-alias cls='print -n \\033c'
+\export SHELL=$MKSH MANWIDTH=80 LESSHISTFILE=-
+\alias cls='\builtin print -n \\ec'
 
-#unset LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_IDENTIFICATION LC_MONETARY \
+#\unset LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_IDENTIFICATION LC_MONETARY \
 #    LC_NAME LC_NUMERIC LC_TELEPHONE LC_TIME
 #p=en_GB.UTF-8
-#set -U
-#export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
+#\set -U
+#\export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
 
-unset p
+\unset p
 
-: place customisations above this line
+\: place customisations above this line
diff --git a/src/edit.c b/src/edit.c
index 4f9298c..4578647 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -28,7 +28,7 @@
 
 #ifndef MKSH_NO_CMDLINE_EDITING
 
-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.276.2.5 2015/04/12 22:32:22 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.290 2015/07/10 19:36:34 tg Exp $");
 
 /*
  * in later versions we might use libtermcap for this, but since external
@@ -771,7 +771,7 @@
 	Xinit(xs, xp, patlen + 128, ATEMP);
 	while (sp) {
 		xp = Xstring(xs, xp);
-		if (!(p = cstrchr(sp, ':')))
+		if (!(p = cstrchr(sp, MKSH_PATHSEPC)))
 			p = sp + strlen(sp);
 		pathlen = p - sp;
 		if (pathlen) {
@@ -887,7 +887,7 @@
 /* Separator for motion */
 #define	is_mfs(c)	(!(ksh_isalnux(c) || (c) == '$' || ((c) & 0x80)))
 
-#define X_NTABS		3			/* normal, meta1, meta2 */
+#define X_NTABS		4			/* normal, meta1, meta2, pc */
 #define X_TABSZ		256			/* size of keydef tables etc */
 
 /*-
@@ -1099,8 +1099,28 @@
 	{ XFUNC_mv_end | 0x80,		2,	'8'	},
 	{ XFUNC_mv_end,			2,	'F'	},
 	{ XFUNC_del_char | 0x80,	2,	'3'	},
+	{ XFUNC_del_char,		2,	'P'	},
 	{ XFUNC_search_hist_up | 0x80,	2,	'5'	},
 	{ XFUNC_search_hist_dn | 0x80,	2,	'6'	},
+#endif
+	/* PC scancodes */
+#if !defined(MKSH_SMALL) || defined(__OS2__)
+	{ XFUNC_meta3,			0,	0	},
+	{ XFUNC_mv_begin,		3,	71	},
+	{ XFUNC_prev_com,		3,	72	},
+#ifndef MKSH_SMALL
+	{ XFUNC_search_hist_up,		3,	73	},
+#endif
+	{ XFUNC_mv_back,		3,	75	},
+	{ XFUNC_mv_forw,		3,	77	},
+	{ XFUNC_mv_end,			3,	79	},
+	{ XFUNC_next_com,		3,	80	},
+#ifndef MKSH_SMALL
+	{ XFUNC_search_hist_dn,		3,	81	},
+#endif
+	{ XFUNC_del_char,		3,	83	},
+#endif
+#ifndef MKSH_SMALL
 	/* more non-standard ones */
 	{ XFUNC_edit_line,		2,	'e'	}
 #endif
@@ -2215,6 +2235,13 @@
 }
 
 static int
+x_meta3(int c MKSH_A_UNUSED)
+{
+	x_curprefix = 3;
+	return (KSTD);
+}
+
+static int
 x_kill(int c MKSH_A_UNUSED)
 {
 	size_t col = xcp - xbuf;
@@ -2412,8 +2439,8 @@
 
 	if (prefix)
 		/* prefix == 1 || prefix == 2 */
-		shf_puts(x_mapout(prefix == 1 ?
-		    CTRL('[') : CTRL('X')), shl_stdout);
+		shf_puts(x_mapout(prefix == 1 ? CTRL('[') :
+		    prefix == 2 ? CTRL('X') : 0), shl_stdout);
 #ifdef MKSH_SMALL
 	shprintf("%s = ", x_mapout(key));
 #else
@@ -2478,6 +2505,8 @@
 			prefix = 1;
 		else if (f == XFUNC_meta2)
 			prefix = 2;
+		else if (f == XFUNC_meta3)
+			prefix = 3;
 		else
 			break;
 	}
@@ -2966,7 +2995,7 @@
 	/* strip command prefix */
 	c &= 255;
 	while (c >= 0 && ksh_isdigit(c)) {
-		n = n * 10 + (c - '0');
+		n = n * 10 + ksh_numdig(c);
 		if (n > LINE)
 			/* upper bound for repeat */
 			goto x_set_arg_too_big;
@@ -3053,7 +3082,7 @@
 		}
 		if (modified) {
 			*xep = '\0';
-			histsave(&source->line, xbuf, true, true);
+			histsave(&source->line, xbuf, HIST_STORE, true);
 			x_arg = 0;
 		} else
 			x_arg = source->line - (histptr - x_histp);
@@ -3290,8 +3319,23 @@
 		edchars.eof = tty_state.c_cc[VEOF];
 #ifdef VWERASE
 		edchars.werase = tty_state.c_cc[VWERASE];
+#else
+		edchars.werase = 0;
 #endif
 
+		if (!edchars.erase)
+			edchars.erase = CTRL('H');
+		if (!edchars.kill)
+			edchars.kill = CTRL('U');
+		if (!edchars.intr)
+			edchars.intr = CTRL('C');
+		if (!edchars.quit)
+			edchars.quit = CTRL('\\');
+		if (!edchars.eof)
+			edchars.eof = CTRL('D');
+		if (!edchars.werase)
+			edchars.werase = CTRL('W');
+
 #ifdef _POSIX_VDISABLE
 		/* Convert unset values to internal 'unset' value */
 		if (edchars.erase == _POSIX_VDISABLE)
@@ -3602,6 +3646,18 @@
 	switch (state) {
 
 	case VNORMAL:
+		/* PC scancodes */
+		if (!ch) switch (cmdlen = 0, (ch = x_getc())) {
+		case 71: ch = '0'; goto pseudo_vi_command;
+		case 72: ch = 'k'; goto pseudo_vi_command;
+		case 73: ch = 'A'; goto vi_xfunc_search_up;
+		case 75: ch = 'h'; goto pseudo_vi_command;
+		case 77: ch = 'l'; goto pseudo_vi_command;
+		case 79: ch = '$'; goto pseudo_vi_command;
+		case 80: ch = 'j'; goto pseudo_vi_command;
+		case 83: ch = 'x'; goto pseudo_vi_command;
+		default: ch = 0; goto vi_insert_failed;
+		}
 		if (insert != 0) {
 			if (ch == CTRL('v')) {
 				state = VLIT;
@@ -3609,6 +3665,7 @@
 			}
 			switch (vi_insert(ch)) {
 			case -1:
+ vi_insert_failed:
 				vi_error();
 				state = VNORMAL;
 				break;
@@ -3627,10 +3684,11 @@
 				return (1);
 			cmdlen = 0;
 			argc1 = 0;
-			if (ch >= '1' && ch <= '9') {
-				argc1 = ch - '0';
+			if (ch >= ord('1') && ch <= ord('9')) {
+				argc1 = ksh_numdig(ch);
 				state = VARG1;
 			} else {
+ pseudo_vi_command:
 				curcmd[cmdlen++] = ch;
 				state = nextstate(ch);
 				if (state == VSEARCH) {
@@ -3672,7 +3730,7 @@
 
 	case VARG1:
 		if (ksh_isdigit(ch))
-			argc1 = argc1 * 10 + ch - '0';
+			argc1 = argc1 * 10 + ksh_numdig(ch);
 		else {
 			curcmd[cmdlen++] = ch;
 			state = nextstate(ch);
@@ -3681,8 +3739,8 @@
 
 	case VEXTCMD:
 		argc2 = 0;
-		if (ch >= '1' && ch <= '9') {
-			argc2 = ch - '0';
+		if (ch >= ord('1') && ch <= ord('9')) {
+			argc2 = ksh_numdig(ch);
 			state = VARG2;
 			return (0);
 		} else {
@@ -3698,7 +3756,7 @@
 
 	case VARG2:
 		if (ksh_isdigit(ch))
-			argc2 = argc2 * 10 + ch - '0';
+			argc2 = argc2 * 10 + ksh_numdig(ch);
 		else {
 			if (argc1 == 0)
 				argc1 = argc2;
@@ -3799,6 +3857,7 @@
 		break;
 
 	case VPREFIX2:
+ vi_xfunc_search_up:
 		state = VFAIL;
 		switch (ch) {
 		case 'A':
@@ -4310,8 +4369,8 @@
 					return (-1);
 				if (modified) {
 					es->cbuf[es->linelen] = '\0';
-					histsave(&source->line, es->cbuf, true,
-					    true);
+					histsave(&source->line, es->cbuf,
+					    HIST_STORE, true);
 				} else
 					argcnt = source->line + 1 -
 					    (hlast - hnum);
diff --git a/src/emacsfn.h b/src/emacsfn.h
index 1333399..6e64cfb 100644
--- a/src/emacsfn.h
+++ b/src/emacsfn.h
@@ -1,5 +1,5 @@
 #if defined(EMACSFN_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/emacsfn.h,v 1.5 2010/07/17 22:09:33 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/emacsfn.h,v 1.6 2015/07/10 18:41:07 tg Exp $");
 #define FN(cname,sname,flags)	static int x_##cname(int);
 #elif defined(EMACSFN_ENUMS)
 #define FN(cname,sname,flags)	XFUNC_##cname,
@@ -52,6 +52,7 @@
 FN(literal, "quote", 0)
 FN(meta1, "prefix-1", XF_PREFIX)
 FN(meta2, "prefix-2", XF_PREFIX)
+FN(meta3, "prefix-3", XF_PREFIX)
 FN(meta_yank, "yank-pop", 0)
 FN(mv_back, "backward-char", XF_ARG)
 FN(mv_begin, "beginning-of-line", 0)
diff --git a/src/eval.c b/src/eval.c
index 81240c5..0b585bc 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.5 2015/04/12 22:32:24 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.170 2015/07/06 17:45:33 tg Exp $");
 
 /*
  * string expansion
@@ -291,21 +291,14 @@
 				c = *sp++;
 				break;
 			case OQUOTE:
-				switch (word) {
-				case IFS_QUOTE:
-					/* """something */
-					word = IFS_WORD;
-					break;
-				case IFS_WORD:
-					break;
-				default:
+				if (word != IFS_WORD)
 					word = IFS_QUOTE;
-					break;
-				}
 				tilde_ok = 0;
 				quote = 1;
 				continue;
 			case CQUOTE:
+				if (word == IFS_QUOTE)
+					word = IFS_WORD;
 				quote = st->quotew;
 				continue;
 			case COMSUB:
@@ -528,43 +521,27 @@
 						afree(tpat0, ATEMP);
 
 						/* check for special cases */
-						d = str_val(st->var);
 						switch (*pat) {
 						case '#':
-							/* anchor at begin */
-							tpat0 = pat + 1;
-							tpat1 = rrep;
-							tpat2 = d;
-							break;
 						case '%':
-							/* anchor at end */
 							tpat0 = pat + 1;
-							tpat1 = d;
-							tpat2 = rrep;
 							break;
 						case '\0':
-							/* empty pattern */
+							/* empty pattern, reject */
 							goto no_repl;
 						default:
 							tpat0 = pat;
-							/* silence gcc */
-							tpat1 = tpat2 = NULL;
 						}
 						if (gmatchx(null, tpat0, false)) {
 							/*
-							 * pattern matches
-							 * the empty string
+							 * pattern matches empty
+							 * string => don't loop
 							 */
-							if (tpat0 == pat)
-								goto no_repl;
-							/* but is anchored */
-							s = shf_smprintf("%s%s",
-							    tpat1, tpat2);
-							goto do_repl;
+							stype &= ~0x80;
 						}
 
 						/* prepare string on which to work */
-						strdupx(s, d, ATEMP);
+						strdupx(s, str_val(st->var), ATEMP);
 						sbeg = s;
 
 						/* first see if we have any match at all */
@@ -622,7 +599,6 @@
 							goto again_repl;
  end_repl:
 						afree(tpat1, ATEMP);
- do_repl:
 						x.str = s;
  no_repl:
 						afree(pat, ATEMP);
@@ -1734,7 +1710,7 @@
 		dp = str_val(global("HOME"));
 	else if (cp[0] == '+' && cp[1] == '\0')
 		dp = str_val(global("PWD"));
-	else if (cp[0] == '-' && cp[1] == '\0')
+	else if (ksh_isdash(cp))
 		dp = str_val(global("OLDPWD"));
 #ifndef MKSH_NOPWNAM
 	else
diff --git a/src/exec.c b/src/exec.c
index f9eeb4c..6a743a2 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -23,10 +23,10 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.137.2.4 2015/04/19 19:18:15 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.160 2015/07/10 19:36:35 tg Exp $");
 
 #ifndef MKSH_DEFAULT_EXECSHELL
-#define MKSH_DEFAULT_EXECSHELL	"/bin/sh"
+#define MKSH_DEFAULT_EXECSHELL	MKSH_UNIXROOT "/bin/sh"
 #endif
 
 static int comexec(struct op *, struct tbl * volatile, const char **,
@@ -41,8 +41,8 @@
 static void dbteste_error(Test_env *, int, const char *);
 static int search_access(const char *, int);
 /* XXX: horrible kludge to fit within the framework */
-static char *plain_fmt_entry(char *, size_t, unsigned int, const void *);
-static char *select_fmt_entry(char *, size_t, unsigned int, const void *);
+static void plain_fmt_entry(char *, size_t, unsigned int, const void *);
+static void select_fmt_entry(char *, size_t, unsigned int, const void *);
 
 /*
  * execute command tree
@@ -551,6 +551,12 @@
 			}
 			if ((tp = findcom(cp, FC_BI)) == NULL)
 				errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin");
+			if (tp->type == CSHELL && (tp->val.f == c_cat
+#ifdef MKSH_PRINTF_BUILTIN
+			    || tp->val.f == c_printf
+#endif
+			    ))
+				break;
 			continue;
 		} else if (tp->val.f == c_exec) {
 			if (ap[1] == NULL)
@@ -607,24 +613,28 @@
 				subst_exstat = 0;
 				break;
 			}
-#ifndef MKSH_NO_EXTERNAL_CAT
 		} else if (tp->val.f == c_cat) {
-			/*
-			 * if we have any flags, do not use the builtin
-			 * in theory, we could allow -u, but that would
-			 * mean to use ksh_getopt here and possibly ad-
-			 * ded complexity and more code and isn't worth
-			 * additional hassle (and the builtin must call
-			 * ksh_getopt already but can't come back here)
-			 */
+			/* if we have any flags, do not use the builtin */
 			if (ap[1] && ap[1][0] == '-' && ap[1][1] != '\0' &&
 			    /* argument, begins with -, is not - or -- */
-			    (ap[1][1] != '-' || ap[1][2] != '\0'))
-				/* don't look for builtins or functions */
-				fcflags = FC_PATH;
-			else
-				/* go on, use the builtin */
-				break;
+			    (ap[1][1] != '-' || ap[1][2] != '\0')) {
+				struct tbl *ext_cat;
+
+				ext_cat = findcom(Tcat, FC_PATH | FC_FUNC);
+				if (ext_cat && (ext_cat->type != CTALIAS ||
+				    (ext_cat->flag & ISSET)))
+					tp = ext_cat;
+			}
+			break;
+#ifdef MKSH_PRINTF_BUILTIN
+		} else if (tp->val.f == c_printf) {
+			struct tbl *ext_printf;
+
+			ext_printf = findcom(Tprintf, FC_PATH | FC_FUNC);
+			if (ext_printf && (ext_printf->type != CTALIAS ||
+			    (ext_printf->flag & ISSET)))
+				tp = ext_printf;
+			break;
 #endif
 		} else if (tp->val.f == c_trap) {
 			t->u.evalflags &= ~DOTCOMEXEC;
@@ -705,6 +715,7 @@
 
 	/* shell built-in */
 	case CSHELL:
+ do_call_builtin:
 		rv = call_builtin(tp, (const char **)ap, null, resetspec);
 		if (resetspec && tp->val.f == c_shift) {
 			l_expand->argc = l_assign->argc;
@@ -714,9 +725,9 @@
 
 	/* function call */
 	case CFUNC: {
-		volatile unsigned char old_xflag;
 		volatile uint32_t old_inuse;
 		const char * volatile old_kshname;
+		volatile uint8_t old_flags[FNFLAGS];
 
 		if (!(tp->flag & ISSET)) {
 			struct tbl *ftp;
@@ -729,6 +740,18 @@
 				break;
 			}
 			if (include(tp->u.fpath, 0, NULL, false) < 0) {
+				if (!strcmp(cp, Tcat)) {
+ no_cat_in_FPATH:
+					tp = findcom(Tcat, FC_BI);
+					goto do_call_builtin;
+				}
+#ifdef MKSH_PRINTF_BUILTIN
+				if (!strcmp(cp, Tprintf)) {
+ no_printf_in_FPATH:
+					tp = findcom(Tprintf, FC_BI);
+					goto do_call_builtin;
+				}
+#endif
 				warningf(true, "%s: %s %s %s: %s", cp,
 				    "can't open", "function definition file",
 				    tp->u.fpath, cstrerror(errno));
@@ -737,6 +760,12 @@
 			}
 			if (!(ftp = findfunc(cp, hash(cp), false)) ||
 			    !(ftp->flag & ISSET)) {
+				if (!strcmp(cp, Tcat))
+					goto no_cat_in_FPATH;
+#ifdef MKSH_PRINTF_BUILTIN
+				if (!strcmp(cp, Tprintf))
+					goto no_printf_in_FPATH;
+#endif
 				warningf(true, "%s: %s %s", cp,
 				    "function not defined by", tp->u.fpath);
 				rv = 127;
@@ -768,8 +797,9 @@
 			getopts_reset(1);
 		}
 
-		old_xflag = Flag(FXTRACE) ? 1 : 0;
-		change_xtrace((Flag(FXTRACEREC) ? old_xflag : 0) |
+		for (type_flags = 0; type_flags < FNFLAGS; ++type_flags)
+			old_flags[type_flags] = shell_flags[type_flags];
+		change_xtrace((Flag(FXTRACEREC) ? Flag(FXTRACE) : 0) |
 		    ((tp->flag & TRACE) ? 1 : 0), false);
 		old_inuse = tp->flag & FINUSE;
 		tp->flag |= FINUSE;
@@ -781,7 +811,15 @@
 		}
 
 		kshname = old_kshname;
-		change_xtrace(old_xflag, false);
+		change_xtrace(old_flags[(int)FXTRACE], false);
+#ifndef MKSH_LEGACY_MODE
+		if (tp->flag & FKSH) {
+			/* Korn style functions restore Flags on return */
+			old_flags[(int)FXTRACE] = Flag(FXTRACE);
+			for (type_flags = 0; type_flags < FNFLAGS; ++type_flags)
+				shell_flags[type_flags] = old_flags[type_flags];
+		}
+#endif
 		tp->flag = (tp->flag & ~FINUSE) | old_inuse;
 
 		/*
@@ -887,7 +925,7 @@
 	*tp->args-- = tp->str;
 
 #ifndef MKSH_SMALL
-	if ((fd = open(tp->str, O_RDONLY | O_BINARY)) >= 0) {
+	if ((fd = binopen2(tp->str, O_RDONLY)) >= 0) {
 		unsigned char *cp;
 		unsigned short m;
 		ssize_t n;
@@ -917,10 +955,15 @@
 		/* restore begin of shebang position (buf+0 or buf+3) */
 		cp = buf + n;
 		/* bail out if no shebang magic found */
-		if ((cp[0] != '#') || (cp[1] != '!'))
+		if (cp[0] == '#' && cp[1] == '!')
+			cp += 2;
+#ifdef __OS2__
+		else if (!strncmp(cp, Textproc, 7) &&
+		    (cp[7] == ' ' || cp[7] == '\t'))
+			cp += 8;
+#endif
+		else
 			goto noshebang;
-
-		cp += 2;
 		/* skip whitespace before shell name */
 		while (*cp == ' ' || *cp == '\t')
 			++cp;
@@ -955,7 +998,10 @@
 		    (m == /* ECOFF_I386 */ 0x4C01) ||
 		    (m == /* ECOFF_M68K */ 0x0150 || m == 0x5001) ||
 		    (m == /* ECOFF_SH */   0x0500 || m == 0x0005) ||
-		    (m == /* "MZ" */ 0x4D5A) ||
+		    (m == /* bzip */ 0x425A) || (m == /* "MZ" */ 0x4D5A) ||
+		    (m == /* "NE" */ 0x4E45) || (m == /* "LX" */ 0x4C58) ||
+		    (m == /* xz */ 0xFD37 && buf[2] == 'z' && buf[3] == 'X' &&
+		    buf[4] == 'Z') || (m == /* 7zip */ 0x377A) ||
 		    (m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D))
 			errorf("%s: not executable: magic %04X", tp->str, m);
  nomagic:
@@ -1019,11 +1065,13 @@
 
 	nhash = hash(name);
 
+#ifdef MKSH_LEGACY_MODE
 	if (t != NULL && !tobool(t->u.ksh_func)) {
 		/* drop same-name aliases for POSIX functions */
 		if ((tp = ktsearch(&aliases, name, nhash)))
 			ktdelete(tp);
 	}
+#endif
 
 	while (/* CONSTCOND */ 1) {
 		tp = findfunc(name, nhash, true);
@@ -1199,7 +1247,7 @@
 	struct tstate ts;
 
 	for (ktwalk(&ts, &taliases); (tp = ktnext(&ts)) != NULL; )
-		if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
+		if ((tp->flag&ISSET) && (all || !mksh_abspath(tp->val.s))) {
 			if (tp->flag&ALLOC) {
 				tp->flag &= ~(ALLOC|ISSET);
 				afree(tp->val.s, APERM);
@@ -1260,7 +1308,7 @@
 	sp = lpath;
 	while (sp != NULL) {
 		xp = Xstring(xs, xp);
-		if (!(p = cstrchr(sp, ':')))
+		if (!(p = cstrchr(sp, MKSH_PATHSEPC)))
 			p = sp + strlen(sp);
 		if (p != sp) {
 			XcheckN(xs, xp, p - sp);
@@ -1371,7 +1419,7 @@
 		const char *emsg;
 
 		do_open = false;
-		if (*cp == '-' && !cp[1]) {
+		if (ksh_isdash(cp)) {
 			/* prevent error return below */
 			u = 1009;
 			do_close = true;
@@ -1397,7 +1445,7 @@
 			warningf(true, "%s: %s", cp, "restricted");
 			return (-1);
 		}
-		u = open(cp, flags | O_BINARY, 0666);
+		u = binopen3(cp, flags, 0666);
 	}
 	if (u < 0) {
 		/* herein() may already have printed message */
@@ -1530,7 +1578,7 @@
 	 * so temp doesn't get removed too soon).
 	 */
 	h = maketemp(ATEMP, TT_HEREDOC_EXP, &e->temps);
-	if (!(shf = h->shf) || (fd = open(h->tffn, O_RDONLY | O_BINARY, 0)) < 0) {
+	if (!(shf = h->shf) || (fd = binopen3(h->tffn, O_RDONLY, 0)) < 0) {
 		i = errno;
 		warningf(true, "can't %s temporary file %s: %s",
 		    !shf ? "create" : "open", h->tffn, cstrerror(i));
@@ -1599,7 +1647,7 @@
 };
 
 /* format a single select menu item */
-static char *
+static void
 select_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
 {
 	const struct select_menu_info *smi =
@@ -1607,7 +1655,6 @@
 
 	shf_snprintf(buf, buflen, "%*u) %s",
 	    smi->num_width, i + 1, smi->args[i]);
-	return (buf);
 }
 
 /*
@@ -1653,11 +1700,10 @@
 	    true);
 }
 
-static char *
+static void
 plain_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
 {
 	strlcpy(buf, ((const char * const *)arg)[i], buflen);
-	return (buf);
 }
 
 void
diff --git a/src/expr.c b/src/expr.c
index 6b328ad..ef544df 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.76.2.1 2015/01/25 15:44:05 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.77 2014/12/15 23:26:36 tg Exp $");
 
 /* the order of these enums is constrained by the order of opinfo[] */
 enum token {
diff --git a/src/funcs.c b/src/funcs.c
index 95187e6..0d2aec3 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.5 2015/04/19 19:18:16 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.280 2015/07/09 20:52:39 tg Exp $");
 
 #if HAVE_KILLPG
 /*
@@ -99,7 +99,7 @@
 	{Talias, c_alias},
 	{"*=break", c_brkcont},
 	{Tgbuiltin, c_builtin},
-	{"cat", c_cat},
+	{Tcat, c_cat},
 	{"cd", c_cd},
 	/* dash compatibility hack */
 	{"chdir", c_cd},
@@ -138,7 +138,7 @@
 	{"ulimit", c_ulimit},
 	{"umask", c_umask},
 	{Tunalias, c_unalias},
-	{Tsgunset, c_unset},
+	{"*=unset", c_unset},
 	{"=wait", c_wait},
 	{"whence", c_whence},
 #ifndef MKSH_UNEMPLOYED
@@ -152,7 +152,7 @@
 	{"mknod", c_mknod},
 #endif
 #ifdef MKSH_PRINTF_BUILTIN
-	{"printf", c_printf},
+	{Tprintf, c_printf},
 #endif
 #if HAVE_SELECT
 	{"sleep", c_sleep},
@@ -161,6 +161,9 @@
 	/* alias to "true" for historical reasons */
 	{"domainname", c_true},
 #endif
+#ifdef __OS2__
+	{Textproc, c_true},
+#endif
 	{NULL, (int (*)(const char **))NULL}
 };
 
@@ -224,7 +227,7 @@
 static Test_op ptest_isa(Test_env *, Test_meta);
 static const char *ptest_getopnd(Test_env *, Test_op, bool);
 static void ptest_error(Test_env *, int, const char *);
-static char *kill_fmt_entry(char *, size_t, unsigned int, const void *);
+static void kill_fmt_entry(char *, size_t, unsigned int, const void *);
 static void p_time(struct shf *, bool, long, int, int,
     const char *, const char *);
 
@@ -442,7 +445,7 @@
 
 	if (flags & PO_HIST) {
 		Xput(xs, xp, '\0');
-		histsave(&source->line, Xstring(xs, xp), true, false);
+		histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
 		Xfree(xs, xp);
 	} else {
 		int len = Xlength(xs, xp);
@@ -538,7 +541,7 @@
 		uint32_t h = 0;
 
 		tp = NULL;
-		if ((iam_whence || vflag) && !pflag)
+		if (!pflag)
 			tp = ktsearch(&keywords, id, h = hash(id));
 		if (!tp && !pflag) {
 			tp = ktsearch(&aliases, id, h ? h : hash(id));
@@ -778,9 +781,13 @@
 
 	if (fieldstr && !bi_getn(fieldstr, &field))
 		return (1);
-	if (basestr && (!getn(basestr, &base) || base < 1 || base > 36)) {
-		bi_errorf("%s: %s", "bad integer base", basestr);
-		return (1);
+	if (basestr) {
+		if (!getn(basestr, &base)) {
+			bi_errorf("%s: %s", "bad integer base", basestr);
+			return (1);
+		}
+		if (base < 1 || base > 36)
+			base = 10;
 	}
 
 	if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] &&
@@ -1303,7 +1310,7 @@
 #endif
 
 /* format a single kill item */
-static char *
+static void
 kill_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
 {
 	const struct kill_info *ki = (const struct kill_info *)arg;
@@ -1313,7 +1320,6 @@
 	    ki->num_width, i,
 	    ki->name_width, sigtraps[i].name,
 	    sigtraps[i].mess);
-	return (buf);
 }
 
 int
@@ -1327,7 +1333,7 @@
 	/* assume old style options if -digits or -UPPERCASE */
 	if ((p = wp[1]) && *p == '-' && (ksh_isdigit(p[1]) ||
 	    ksh_isupper(p[1]))) {
-		if (!(t = gettrap(p + 1, false))) {
+		if (!(t = gettrap(p + 1, false, false))) {
 			bi_errorf("bad signal '%s'", p + 1);
 			return (1);
 		}
@@ -1341,7 +1347,8 @@
 				lflag = true;
 				break;
 			case 's':
-				if (!(t = gettrap(builtin_opt.optarg, true))) {
+				if (!(t = gettrap(builtin_opt.optarg,
+				    true, false))) {
 					bi_errorf("bad signal '%s'",
 					    builtin_opt.optarg);
 					return (1);
@@ -1367,24 +1374,25 @@
 			for (; wp[i]; i++) {
 				if (!bi_getn(wp[i], &n))
 					return (1);
-#if (NSIG < 128)
-				if (n > 128 && n < 128 + NSIG)
+#if (ksh_NSIG < 128)
+				if (n > 128 && n < 128 + ksh_NSIG)
 					n -= 128;
 #endif
-				if (n > 0 && n < NSIG)
+				if (n > 0 && n < ksh_NSIG)
 					shprintf("%s\n", sigtraps[n].name);
 				else
 					shprintf("%d\n", n);
 			}
 		} else {
-			ssize_t w, mess_cols, mess_octs;
-			int j;
-			struct kill_info ki;
+			ssize_t w, mess_cols = 0, mess_octs = 0;
+			int j = ksh_NSIG;
+			struct kill_info ki = { 0, 0 };
 
-			for (j = NSIG, ki.num_width = 1; j >= 10; j /= 10)
+			do {
 				ki.num_width++;
-			ki.name_width = mess_cols = mess_octs = 0;
-			for (j = 0; j < NSIG; j++) {
+			} while ((j /= 10));
+
+			for (j = 1; j < ksh_NSIG; j++) {
 				w = strlen(sigtraps[j].name);
 				if (w > ki.name_width)
 					ki.name_width = w;
@@ -1396,7 +1404,7 @@
 					mess_cols = w;
 			}
 
-			print_columns(shl_stdout, (unsigned int)(NSIG - 1),
+			print_columns(shl_stdout, (unsigned int)(ksh_NSIG - 1),
 			    kill_fmt_entry, (void *)&ki,
 			    ki.num_width + 1 + ki.name_width + 1 + mess_octs,
 			    ki.num_width + 1 + ki.name_width + 1 + mess_cols,
@@ -1662,8 +1670,11 @@
 		mode_t new_umask;
 
 		if (ksh_isdigit(*cp)) {
-			for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
-				new_umask = new_umask * 8 + (*cp - '0');
+			new_umask = 0;
+			while (*cp >= ord('0') && *cp <= ord('7')) {
+				new_umask = new_umask * 8 + ksh_numdig(*cp);
+				++cp;
+			}
 			if (*cp) {
 				bi_errorf("bad number");
 				return (1);
@@ -1955,8 +1966,9 @@
 			break;
 		case 0:
 			/* timeout expired for this call */
-			rv = 1;
-			goto c_read_out;
+			bytesread = 0;
+			/* fake EOF read; all cases return 1 */
+			goto c_read_didread;
 		default:
 			bi_errorf("%s: %s", Tselect, cstrerror(errno));
 			rv = 2;
@@ -1981,6 +1993,7 @@
 		goto c_read_readloop;
 	}
 
+ c_read_didread:
 	switch (readmode) {
 	case READALL:
 		if (bytesread == 0) {
@@ -2003,7 +2016,7 @@
 		if (bytesread == 0) {
 			/* end of file reached */
 			rv = 1;
-			xp = Xstring(xs, xp);
+			/* may be partial read: $? = 1, but content */
 			goto c_read_readdone;
 		}
 		xp += bytesread;
@@ -2066,7 +2079,7 @@
 	}
 
 	if (savehist)
-		histsave(&source->line, Xstring(xs, xp), true, false);
+		histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
 
 	ccp = cp = Xclose(xs, xp);
 	expanding = false;
@@ -2279,41 +2292,44 @@
 int
 c_trap(const char **wp)
 {
-	int i;
+	Trap *p = sigtraps;
+	int i = ksh_NSIG + 1;
 	const char *s;
-	Trap *p;
 
 	if (ksh_getopt(wp, &builtin_opt, null) == '?')
 		return (1);
 	wp += builtin_opt.optind;
 
 	if (*wp == NULL) {
-		for (p = sigtraps, i = NSIG + 1; --i >= 0; p++)
-			if (p->trap != NULL) {
+		do {
+			if (p->trap) {
 				shf_puts("trap -- ", shl_stdout);
 				print_value_quoted(shl_stdout, p->trap);
 				shprintf(" %s\n", p->name);
 			}
+			++p;
+		} while (--i);
 		return (0);
 	}
 
-	/*
-	 * Use case sensitive lookup for first arg so the
-	 * command 'exit' isn't confused with the pseudo-signal
-	 * 'EXIT'.
-	 */
-	/* get command */
-	s = (gettrap(*wp, false) == NULL) ? *wp++ : NULL;
-	if (s != NULL && s[0] == '-' && s[1] == '\0')
+	if (getn(*wp, &i)) {
+		/* first argument is a signal number, reset them all */
 		s = NULL;
+	} else {
+		/* first argument must be a command, then */
+		s = *wp++;
+		/* reset traps? */
+		if (ksh_isdash(s))
+			s = NULL;
+	}
 
-	/* set/clear traps */
+	/* set/clear the traps */
 	i = 0;
-	while (*wp != NULL)
-		if ((p = gettrap(*wp++, true)) == NULL) {
+	while (*wp)
+		if (!(p = gettrap(*wp++, true, true))) {
 			warningf(true, "%s: %s '%s'", builtin_argv0,
 			    "bad signal", wp[-1]);
-			++i;
+			i = 1;
 		} else
 			settrap(p, s);
 	return (i);
@@ -3412,7 +3428,27 @@
 # error nonsensical v ulimit
 #endif
 
+struct limits {
+	/* limit resource */
+	int resource;
+	/* multiply by to get rlim_{cur,max} values */
+	unsigned int factor;
+	/* getopts char */
+	char optchar;
+	/* limit name */
+	char name[1];
+};
+
 #define RLIMITS_DEFNS
+#define FN(lname,lid,lfac,lopt)				\
+	static const struct {				\
+		int resource;				\
+		unsigned int factor;			\
+		char optchar;				\
+		char name[sizeof(lname)];		\
+	} rlimits_ ## lid = {				\
+		lid, lfac, lopt, lname			\
+	};
 #include "rlimits.gen"
 
 static void print_ulimit(const struct limits *, int);
@@ -3630,9 +3666,9 @@
 	do {
 		if (*wp) {
 			fn = *wp++;
-			if (fn[0] == '-' && fn[1] == '\0')
+			if (ksh_isdash(fn))
 				fd = STDIN_FILENO;
-			else if ((fd = open(fn, O_RDONLY | O_BINARY)) < 0) {
+			else if ((fd = binopen2(fn, O_RDONLY)) < 0) {
 				eno = errno;
 				bi_errorf("%s: %s", fn, cstrerror(eno));
 				rv = 1;
diff --git a/src/histrap.c b/src/histrap.c
index 0dfe1c2..7a96aa8 100644
--- a/src/histrap.c
+++ b/src/histrap.c
@@ -27,9 +27,9 @@
 #include <sys/file.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134.2.5 2015/04/19 19:18:18 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.149 2015/07/09 20:52:40 tg Exp $");
 
-Trap sigtraps[NSIG + 1];
+Trap sigtraps[ksh_NSIG + 1];
 static struct sigaction Sigact_ign;
 
 #if HAVE_PERSISTENT_HISTORY
@@ -38,7 +38,7 @@
 static void writehistfile(int, const char *);
 #endif
 
-static int hist_execute(char *);
+static int hist_execute(char *, Area *);
 static char **hist_get(const char *, bool, bool);
 static char **hist_get_oldest(void);
 
@@ -84,6 +84,9 @@
 /* maximum considered size of persistent history file */
 #define MKSH_MAXHISTFSIZE	((off_t)1048576 * 96)
 
+/* hidden option */
+#define HIST_DISCARD		5
+
 int
 c_fc(const char **wp)
 {
@@ -223,7 +226,7 @@
 			xp += len;
 			line = Xclose(xs, xp);
 		}
-		return (hist_execute(line));
+		return (hist_execute(line, ATEMP));
 	}
 
 	if (editor && (lflag || nflag)) {
@@ -360,18 +363,17 @@
 		shf_close(shf);
 		*xp = '\0';
 		strip_nuls(Xstring(xs, xp), Xlength(xs, xp));
-		return (hist_execute(Xstring(xs, xp)));
+		return (hist_execute(Xstring(xs, xp), hist_source->areap));
 	}
 }
 
-/* Save cmd in history, execute cmd (cmd gets trashed) */
+/* save cmd in history, execute cmd (cmd gets afree’d) */
 static int
-hist_execute(char *cmd)
+hist_execute(char *cmd, Area *areap)
 {
 	static int last_line = -1;
 	Source *sold;
 	int ret;
-	char *p, *q;
 
 	/* Back up over last histsave */
 	if (histptr >= history && last_line != hist_source->line) {
@@ -381,22 +383,12 @@
 		last_line = hist_source->line;
 	}
 
-	for (p = cmd; p; p = q) {
-		if ((q = strchr(p, '\n'))) {
-			/* kill the newline */
-			*q++ = '\0';
-			if (!*q)
-				/* ignore trailing newline */
-				q = NULL;
-		}
-		histsave(&hist_source->line, p, true, true);
-
-		/* POSIX doesn't say this is done... */
-		shellf("%s\n", p);
-		if (q)
-			/* restore \n (trailing \n not restored) */
-			q[-1] = '\n';
-	}
+	histsave(&hist_source->line, cmd, HIST_STORE, true);
+	/* now *histptr == cmd without all trailing newlines */
+	afree(cmd, areap);
+	cmd = *histptr;
+	/* pdksh says POSIX doesn’t say this is done, testsuite needs it */
+	shellf("%s\n", cmd);
 
 	/*-
 	 * Commands are executed here instead of pushing them onto the
@@ -578,6 +570,7 @@
 		afree(hname, APERM);
 		hname = NULL;
 		/* let's reset the history */
+		histsave(NULL, NULL, HIST_DISCARD, true);
 		histptr = history - 1;
 		hist_source->line = 0;
 	}
@@ -612,6 +605,8 @@
 {
 	bool changed = false;
 
+	/* called by histsave(), may not HIST_DISCARD, caller should flush */
+
 	if (histfd != -1) {
 		int lno = hist_source->line;
 
@@ -631,29 +626,73 @@
  * save command in history
  */
 void
-histsave(int *lnp, const char *cmd, bool dowrite MKSH_A_UNUSED, bool ignoredups)
+histsave(int *lnp, const char *cmd, int svmode, bool ignoredups)
 {
-	char **hp;
-	char *c, *cp;
+	static char *enqueued = NULL;
+	char **hp, *c;
+	const char *ccp;
 
-	strdupx(c, cmd, APERM);
-	if ((cp = strchr(c, '\n')) != NULL)
-		*cp = '\0';
+	if (svmode == HIST_DISCARD) {
+		afree(enqueued, APERM);
+		enqueued = NULL;
+		return;
+	}
 
-	if (ignoredups && !strcmp(c, *histptr)
+	if (svmode == HIST_APPEND) {
+		if (!enqueued)
+			svmode = HIST_STORE;
+	} else if (enqueued) {
+		c = enqueued;
+		enqueued = NULL;
+		--*lnp;
+		histsave(lnp, c, HIST_STORE, true);
+		afree(c, APERM);
+	}
+
+	if (svmode == HIST_FLUSH)
+		return;
+
+	ccp = cmd + strlen(cmd);
+	while (ccp > cmd && ccp[-1] == '\n')
+		--ccp;
+	strndupx(c, cmd, ccp - cmd, APERM);
+
+	if (svmode != HIST_APPEND) {
+		if (ignoredups && !strcmp(c, *histptr)
 #if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
-	    && !histsync()
+		    && !histsync()
 #endif
-	    ) {
+		    ) {
+			afree(c, APERM);
+			return;
+		}
+		++*lnp;
+	}
+
+#if HAVE_PERSISTENT_HISTORY
+	if (svmode == HIST_STORE && histfd != -1)
+		writehistfile(*lnp, c);
+#endif
+
+	if (svmode == HIST_QUEUE || svmode == HIST_APPEND) {
+		size_t nenq, ncmd;
+
+		if (!enqueued) {
+			if (*c)
+				enqueued = c;
+			else
+				afree(c, APERM);
+			return;
+		}
+
+		nenq = strlen(enqueued);
+		ncmd = strlen(c);
+		enqueued = aresize(enqueued, nenq + 1 + ncmd + 1, APERM);
+		enqueued[nenq] = '\n';
+		memcpy(enqueued + nenq + 1, c, ncmd + 1);
 		afree(c, APERM);
 		return;
 	}
-	++*lnp;
-
-#if HAVE_PERSISTENT_HISTORY
-	if (dowrite && histfd != -1)
-		writehistfile(*lnp, c);
-#endif
 
 	hp = histptr;
 
@@ -707,6 +746,8 @@
 	enum { hist_init_first, hist_init_retry, hist_init_restore } hs;
 #endif
 
+	histsave(NULL, NULL, HIST_DISCARD, true);
+
 	if (Flag(FTALKING) == 0)
 		return;
 
@@ -723,8 +764,7 @@
 
  retry:
 	/* we have a file and are interactive */
-	if ((fd = open(hname, O_RDWR | O_CREAT | O_APPEND | O_BINARY,
-	    0600)) < 0)
+	if ((fd = binopen3(hname, O_RDWR | O_CREAT | O_APPEND, 0600)) < 0)
 		return;
 
 	histfd = savefd(fd);
@@ -759,8 +799,8 @@
 
 			/* create temporary file */
 			nhname = shf_smprintf("%s.%d", hname, (int)procpid);
-			if ((fd = open(nhname, O_RDWR | O_CREAT | O_TRUNC |
-			    O_EXCL | O_BINARY, 0600)) < 0) {
+			if ((fd = binopen3(nhname, O_RDWR | O_CREAT | O_TRUNC |
+			    O_EXCL, 0600)) < 0) {
 				/* just don't truncate then, meh. */
 				goto hist_trunc_dont;
 			}
@@ -864,7 +904,7 @@
 		}
 	} else {
 		s->line = lno--;
-		histsave(&lno, (char *)(base + 4), false, false);
+		histsave(&lno, (char *)(base + 4), HIST_NOTE, false);
 	}
 	/* advance base pointer past NUL */
 	bytes -= ++cp - base;
@@ -980,55 +1020,53 @@
 	trap_exstat = -1;
 
 	/* Populate sigtraps based on sys_signame and sys_siglist. */
-	/*XXX this is idiotic, use a multi-key/value hashtable! */
-	for (i = 0; i <= NSIG; i++) {
+	for (i = 1; i < ksh_NSIG; i++) {
 		sigtraps[i].signal = i;
-		if (i == ksh_SIGERR) {
-			sigtraps[i].name = "ERR";
-			sigtraps[i].mess = "Error handler";
-		} else {
 #if HAVE_SYS_SIGNAME
-			cs = sys_signame[i];
+		cs = sys_signame[i];
 #else
-			const struct mksh_sigpair *pair = mksh_sigpairs;
-			while ((pair->nr != i) && (pair->name != NULL))
-				++pair;
-			cs = pair->name;
+		const struct mksh_sigpair *pair = mksh_sigpairs;
+		while ((pair->nr != i) && (pair->name != NULL))
+			++pair;
+		cs = pair->name;
 #endif
-			if ((cs == NULL) ||
-			    (cs[0] == '\0'))
-				sigtraps[i].name = shf_smprintf("%d", i);
-			else {
-				char *s;
+		if ((cs == NULL) ||
+		    (cs[0] == '\0'))
+			sigtraps[i].name = shf_smprintf("%d", i);
+		else {
+			char *s;
 
-				/* this is not optimal, what about SIGSIG1? */
-				if ((cs[0] & 0xDF) == 'S' &&
-				    (cs[1] & 0xDF) == 'I' &&
-				    (cs[2] & 0xDF) == 'G' &&
-				    cs[3] != '\0') {
-					/* skip leading "SIG" */
-					cs += 3;
-				}
-				strdupx(s, cs, APERM);
-				sigtraps[i].name = s;
-				while ((*s = ksh_toupper(*s)))
-					++s;
+			/* this is not optimal, what about SIGSIG1? */
+			if (ksh_eq(cs[0], 'S', 's') &&
+			    ksh_eq(cs[1], 'I', 'i') &&
+			    ksh_eq(cs[2], 'G', 'g') &&
+			    cs[3] != '\0') {
+				/* skip leading "SIG" */
+				cs += 3;
 			}
-#if HAVE_SYS_SIGLIST
-			sigtraps[i].mess = sys_siglist[i];
-#elif HAVE_STRSIGNAL
-			sigtraps[i].mess = strsignal(i);
-#else
-			sigtraps[i].mess = NULL;
-#endif
-			if ((sigtraps[i].mess == NULL) ||
-			    (sigtraps[i].mess[0] == '\0'))
-				sigtraps[i].mess = shf_smprintf("%s %d",
-				    "Signal", i);
+			strdupx(s, cs, APERM);
+			sigtraps[i].name = s;
+			while ((*s = ksh_toupper(*s)))
+				++s;
 		}
+#if HAVE_SYS_SIGLIST
+		sigtraps[i].mess = sys_siglist[i];
+#elif HAVE_STRSIGNAL
+		sigtraps[i].mess = strsignal(i);
+#else
+		sigtraps[i].mess = NULL;
+#endif
+		if ((sigtraps[i].mess == NULL) ||
+		    (sigtraps[i].mess[0] == '\0'))
+			sigtraps[i].mess = shf_smprintf("%s %d",
+			    "Signal", i);
 	}
-	/* our name for signal 0 */
+	sigtraps[ksh_SIGEXIT].signal = ksh_SIGEXIT;
 	sigtraps[ksh_SIGEXIT].name = "EXIT";
+	sigtraps[ksh_SIGEXIT].mess = "Exit trap";
+	sigtraps[ksh_SIGERR].signal = ksh_SIGERR;
+	sigtraps[ksh_SIGERR].name = "ERR";
+	sigtraps[ksh_SIGERR].mess = "Error handler";
 
 	(void)sigemptyset(&Sigact_ign.sa_mask);
 	Sigact_ign.sa_flags = 0; /* interruptible */
@@ -1076,21 +1114,24 @@
 }
 
 Trap *
-gettrap(const char *cs, bool igncase)
+gettrap(const char *cs, bool igncase, bool allsigs)
 {
 	int i;
 	Trap *p;
 	char *as;
 
-	if (ksh_isdigit(*cs)) {
-		return ((getn(cs, &i) && 0 <= i && i < NSIG) ?
+	/* signal number (1..ksh_NSIG) or 0? */
+
+	if (ksh_isdigit(*cs))
+		return ((getn(cs, &i) && 0 <= i && i < ksh_NSIG) ?
 		    (&sigtraps[i]) : NULL);
-	}
+
+	/* do a lookup by name then */
 
 	/* this breaks SIGSIG1, but we do that above anyway */
-	if ((cs[0] & 0xDF) == 'S' &&
-	    (cs[1] & 0xDF) == 'I' &&
-	    (cs[2] & 0xDF) == 'G' &&
+	if (ksh_eq(cs[0], 'S', 's') &&
+	    ksh_eq(cs[1], 'I', 'i') &&
+	    ksh_eq(cs[2], 'G', 'g') &&
 	    cs[3] != '\0') {
 		/* skip leading "SIG" */
 		cs += 3;
@@ -1105,14 +1146,24 @@
 	} else
 		as = NULL;
 
+	/* this is idiotic, we really want a hashtable here */
+
 	p = sigtraps;
-	for (i = 0; i <= NSIG; i++) {
+	i = ksh_NSIG + 1;
+	do {
 		if (!strcmp(p->name, cs))
 			goto found;
 		++p;
-	}
-	p = NULL;
+	} while (--i);
+	goto notfound;
+
  found:
+	if (!allsigs) {
+		if (p->signal == ksh_SIGEXIT || p->signal == ksh_SIGERR) {
+ notfound:
+			p = NULL;
+		}
+	}
 	afree(as, ATEMP);
 	return (p);
 }
@@ -1156,14 +1207,16 @@
 int
 fatal_trap_check(void)
 {
-	int i;
-	Trap *p;
+	Trap *p = sigtraps;
+	int i = ksh_NSIG + 1;
 
 	/* todo: should check if signal is fatal, not the TF_DFL_INTR flag */
-	for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
+	do {
 		if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL)))
 			/* return value is used as an exit code */
 			return (128 + p->signal);
+		++p;
+	} while (--i);
 	return (0);
 }
 
@@ -1175,13 +1228,15 @@
 int
 trap_pending(void)
 {
-	int i;
-	Trap *p;
+	Trap *p = sigtraps;
+	int i = ksh_NSIG + 1;
 
-	for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
+	do {
 		if (p->set && ((p->trap && p->trap[0]) ||
 		    ((p->flags & (TF_DFL_INTR|TF_FATAL)) && !p->trap)))
 			return (p->signal);
+		++p;
+	} while (--i);
 	return (0);
 }
 
@@ -1192,8 +1247,8 @@
 void
 runtraps(int flag)
 {
-	int i;
-	Trap *p;
+	Trap *p = sigtraps;
+	int i = ksh_NSIG + 1;
 
 	if (ksh_tmout_state == TMOUT_LEAVING) {
 		ksh_tmout_state = TMOUT_EXECUTING;
@@ -1212,10 +1267,12 @@
 	if (flag & TF_FATAL)
 		fatal_trap = 0;
 	++trap_nested;
-	for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
+	do {
 		if (p->set && (!flag ||
 		    ((p->flags & flag) && p->trap == NULL)))
 			runtrap(p, false);
+		++p;
+	} while (--i);
 	if (!--trap_nested)
 		runtrap(NULL, true);
 }
@@ -1234,16 +1291,17 @@
 	p->set = 0;
 	if (trapstr == NULL) {
 		/* SIG_DFL */
-		if (p->flags & TF_FATAL) {
-			/* eg, SIGHUP */
-			exstat = (int)ksh_min(128U + (unsigned)i, 255U);
+		if (p->flags & (TF_FATAL | TF_DFL_INTR)) {
+			exstat = (int)(128U + (unsigned)i);
+			if ((unsigned)exstat > 255U)
+				exstat = 255;
+		}
+		/* e.g. SIGHUP */
+		if (p->flags & TF_FATAL)
 			unwind(LLEAVE);
-		}
-		if (p->flags & TF_DFL_INTR) {
-			/* eg, SIGINT, SIGQUIT, SIGTERM, etc. */
-			exstat = (int)ksh_min(128U + (unsigned)i, 255U);
+		/* e.g. SIGINT, SIGQUIT, SIGTERM, etc. */
+		if (p->flags & TF_DFL_INTR)
 			unwind(LINTR);
-		}
 		goto donetrap;
 	}
 	if (trapstr[0] == '\0')
@@ -1283,30 +1341,34 @@
 void
 cleartraps(void)
 {
-	int i;
-	Trap *p;
+	Trap *p = sigtraps;
+	int i = ksh_NSIG + 1;
 
 	trap = 0;
 	intrsig = 0;
 	fatal_trap = 0;
-	for (i = NSIG+1, p = sigtraps; --i >= 0; p++) {
+
+	do {
 		p->set = 0;
 		if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0]))
 			settrap(p, NULL);
-	}
+		++p;
+	} while (--i);
 }
 
 /* restore signals just before an exec(2) */
 void
 restoresigs(void)
 {
-	int i;
-	Trap *p;
+	Trap *p = sigtraps;
+	int i = ksh_NSIG + 1;
 
-	for (i = NSIG+1, p = sigtraps; --i >= 0; p++)
+	do {
 		if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL))
 			setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL,
 			    SS_RESTORE_CURR|SS_FORCE);
+		++p;
+	} while (--i);
 }
 
 void
diff --git a/src/jobs.c b/src/jobs.c
index 7a5b270..8469f83 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.105.2.2 2015/04/19 19:18:18 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.112 2015/04/19 14:40:09 tg Exp $");
 
 #if HAVE_KILLPG
 #define mksh_killpg		killpg
@@ -1274,7 +1274,7 @@
 		}
 	} else if (Flag(FPIPEFAIL)) {
 		do {
-			int i = proc_errorlevel(p);
+			const int i = proc_errorlevel(p);
 
 			if (i)
 				rv = i;
diff --git a/src/lalloc.c b/src/lalloc.c
index 9c1dd6d..f943365 100644
--- a/src/lalloc.c
+++ b/src/lalloc.c
@@ -20,7 +20,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.20.2.1 2015/01/25 15:35:47 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.21 2014/11/25 20:00:39 tg Exp $");
 
 /* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */
 #if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0)
diff --git a/src/lex.c b/src/lex.c
index 305f5a4..fb80244 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.193.2.5 2015/04/19 19:18:19 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.204 2015/07/05 19:53:46 tg Exp $");
 
 /*
  * states while lexing word
@@ -920,7 +920,7 @@
 				goto no_iop;
 			if (!ksh_isdigit(dp[c2 + 1]))
 				goto no_iop;
-			iop->unit = (iop->unit * 10) + dp[c2 + 1] - '0';
+			iop->unit = iop->unit * 10 + ksh_numdig(dp[c2 + 1]);
 			if (iop->unit >= FDBASE)
 				goto no_iop;
 		}
@@ -1461,16 +1461,23 @@
 		if (s->type == SFILE)
 			shf_fdclose(s->u.shf);
 		s->str = NULL;
-	} else if (interactive && *s->str &&
-	    (cur_prompt != PS1 || !ctype(*s->str, C_IFS | C_IFSWS))) {
-		histsave(&s->line, s->str, true, true);
+	} else if (interactive && *s->str) {
+		if (cur_prompt != PS1)
+			histsave(&s->line, s->str, HIST_APPEND, true);
+		else if (!ctype(*s->str, C_IFS | C_IFSWS))
+			histsave(&s->line, s->str, HIST_QUEUE, true);
 #if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
+		else
+			goto check_for_sole_return;
 	} else if (interactive && cur_prompt == PS1) {
+ check_for_sole_return:
 		cp = Xstring(s->xs, xp);
 		while (*cp && ctype(*cp, C_IFSWS))
 			++cp;
-		if (!*cp)
+		if (!*cp) {
+			histsave(&s->line, NULL, HIST_FLUSH, true);
 			histsync();
+		}
 #endif
 	}
 	if (interactive)
@@ -1495,6 +1502,7 @@
 			struct shf *shf;
 			char * volatile ps1;
 			Area *saved_atemp;
+			int saved_lineno;
 
 			ps1 = str_val(global("PS1"));
 			shf = shf_sopen(NULL, strlen(ps1) * 2,
@@ -1506,6 +1514,9 @@
 					shf_fprintf(shf, "%lu", s ?
 					    (unsigned long)s->line + 1 : 0UL);
 			ps1 = shf_sclose(shf);
+			saved_lineno = current_lineno;
+			if (s)
+				current_lineno = s->line + 1;
 			saved_atemp = ATEMP;
 			newenv(E_ERRH);
 			if (kshsetjmp(e->jbuf)) {
@@ -1521,6 +1532,7 @@
 				char *cp = substitute(ps1, 0);
 				strdupx(prompt, cp, saved_atemp);
 			}
+			current_lineno = saved_lineno;
 			quitenv(NULL);
 		}
 		break;
diff --git a/src/lksh.1 b/src/lksh.1
index fe6d59d..a13d7a0 100644
--- a/src/lksh.1
+++ b/src/lksh.1
@@ -1,4 +1,4 @@
-.\" $MirOS: src/bin/mksh/lksh.1,v 1.5.2.1 2015/03/21 00:12:45 tg Exp $
+.\" $MirOS: src/bin/mksh/lksh.1,v 1.10 2015/04/12 22:32:12 tg Exp $
 .\"-
 .\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015
 .\"	Thorsten “mirabilos” Glaser <tg@mirbsd.org>
@@ -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: March 21 2015 $
+.Dd $Mdocdate: April 12 2015 $
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
@@ -261,6 +261,23 @@
 mode and
 .Nm lksh
 do not keep file descriptors \*(Gt 2 private from sub-processes.
+.It
+.Nm lksh
+undefines an alias when a
+.Tn POSIX
+function with the same name is defined,
+to make that function immediately callable.
+In
+.Nm mksh ,
+aliases have precedence; the name must be quoted or
+.Ic unalias Ns ed
+to access it.
+.It
+Functions defined with the
+.Ic function
+reserved word share the shell options
+.Pq Ic set -o
+instead of locally scoping them.
 .El
 .Sh SEE ALSO
 .Xr mksh 1
diff --git a/src/main.c b/src/main.c
index 047aad1..bca8471 100644
--- a/src/main.c
+++ b/src/main.c
@@ -34,7 +34,7 @@
 #include <locale.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.285.2.4 2015/04/19 19:18:20 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.300 2015/07/10 19:36:35 tg Exp $");
 
 extern char **environ;
 
@@ -43,7 +43,7 @@
 #endif
 
 #ifndef MKSH_DEFAULT_TMPDIR
-#define MKSH_DEFAULT_TMPDIR	"/tmp"
+#define MKSH_DEFAULT_TMPDIR	MKSH_UNIXROOT "/tmp"
 #endif
 
 static uint8_t isuc(const char *);
@@ -66,28 +66,28 @@
 	Ttypeset, "-x", "HOME", "PATH", "SHELL", NULL,
 	Ttypeset, "-i10", "COLUMNS", "LINES", "SECONDS", "TMOUT", NULL,
 	Talias,
-	"integer=typeset -i",
-	Tlocal_typeset,
+	"integer=\\typeset -i",
+	"local=\\typeset",
 	/* not "alias -t --": hash -r needs to work */
-	"hash=alias -t",
-	"type=whence -v",
+	"hash=\\builtin alias -t",
+	"type=\\builtin whence -v",
 #if !defined(ANDROID) && !defined(MKSH_UNEMPLOYED)
 	/* not in Android for political reasons */
 	/* not in ARGE mksh due to no job control */
-	"stop=kill -STOP",
+	"stop=\\kill -STOP",
 #endif
-	"autoload=typeset -fu",
-	"functions=typeset -f",
-	"history=fc -l",
-	"nameref=typeset -n",
+	"autoload=\\typeset -fu",
+	"functions=\\typeset -f",
+	"history=\\builtin fc -l",
+	"nameref=\\typeset -n",
 	"nohup=nohup ",
-	Tr_fc_e_dash,
-	"source=PATH=$PATH:. command .",
-	"login=exec login",
+	"r=\\builtin fc -e -",
+	"source=PATH=$PATH" MKSH_PATHSEPS ". \\command .",
+	"login=\\exec login",
 	NULL,
 	 /* this is what AT&T ksh seems to track, with the addition of emacs */
 	Talias, "-tU",
-	"cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
+	Tcat, "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls",
 	"make", "mv", "pr", "rm", "sed", "sh", "vi", "who", NULL,
 	NULL
 };
@@ -193,6 +193,12 @@
 	ssize_t k;
 #endif
 
+#ifdef __OS2__
+	for (i = 0; i < 3; ++i)
+		if (!isatty(i))
+			setmode(i, O_BINARY);
+#endif
+
 	/* do things like getpgrp() et al. */
 	chvt_reinit();
 
@@ -264,7 +270,7 @@
 
 #if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED)
 		/* are we called as -sh or /bin/sh or so? */
-		if (!strcmp(ccp, "sh")) {
+		if (!strcmp(ccp, "sh" MKSH_EXE_EXT)) {
 			/* either also turns off braceexpand */
 #ifdef MKSH_BINSHPOSIX
 			/* enable better POSIX conformance */
@@ -318,7 +324,10 @@
 		 * "keeping a regular /usr"; this is supposed
 		 * to be a sane 'basic' default PATH
 		 */
-		def_path = "/bin:/usr/bin:/sbin:/usr/sbin";
+		def_path = MKSH_UNIXROOT "/bin" MKSH_PATHSEPS
+		    MKSH_UNIXROOT "/usr/bin" MKSH_PATHSEPS
+		    MKSH_UNIXROOT "/sbin" MKSH_PATHSEPS
+		    MKSH_UNIXROOT "/usr/sbin";
 #endif
 
 	/*
@@ -361,7 +370,7 @@
 	vp = global("PWD");
 	cp = str_val(vp);
 	/* Try to use existing $PWD if it is valid */
-	set_current_wd((cp[0] == '/' && test_eval(NULL, TO_FILEQ, cp, ".",
+	set_current_wd((mksh_abspath(cp) && test_eval(NULL, TO_FILEQ, cp, ".",
 	    true)) ? cp : NULL);
 	if (current_wd[0])
 		simplify_path(current_wd);
@@ -454,7 +463,19 @@
 			kshname = argv[argi++];
 	} else if (argi < argc && !Flag(FSTDIN)) {
 		s = pushs(SFILE, ATEMP);
+#ifdef __OS2__
+		/*
+		 * A bug in OS/2 extproc (like shebang) handling makes
+		 * it not pass the full pathname of a script, so we need
+		 * to search for it. This changes the behaviour of a
+		 * simple "mksh foo", but can't be helped.
+		 */
+		s->file = search_path(argv[argi++], path, X_OK, NULL);
+		if (!s->file || !*s->file)
+			s->file = argv[argi - 1];
+#else
 		s->file = argv[argi++];
+#endif
 		s->u.shf = shf_open(s->file, O_RDONLY, 0,
 		    SHF_MAPHI | SHF_CLEXEC);
 		if (s->u.shf == NULL) {
@@ -803,6 +824,8 @@
 			set_prompt(PS1, s);
 		}
 		t = compile(s, sfirst);
+		if (interactive)
+			histsave(&s->line, NULL, HIST_FLUSH, true);
 		sfirst = false;
 		if (!t)
 			goto source_no_tree;
@@ -1352,7 +1375,7 @@
 	shf_fdopen(2, SHF_WR, shl_xtrace);
 #ifdef DF
 	if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
-		if ((lfp = getenv("HOME")) == NULL || *lfp != '/')
+		if ((lfp = getenv("HOME")) == NULL || !mksh_abspath(lfp))
 			errorf("cannot get home directory");
 		lfp = shf_smprintf("%s/mksh-dbg.txt", lfp);
 	}
@@ -1402,7 +1425,7 @@
 	int nfd = fd;
 
 	if (fd < FDBASE && (nfd = fcntl(fd, F_DUPFD, FDBASE)) < 0 &&
-	    errno == EBADF)
+	    (errno == EBADF || errno == EPERM))
 		return (-1);
 	if (nfd < 0 || nfd > SHRT_MAX)
 		errorf("too many files open in shell");
@@ -1459,7 +1482,7 @@
 	if (name[0] == 'p' && !name[1])
 		return (coproc_getfd(mode, emsgp));
 	while (ksh_isdigit(*name)) {
-		fd = (fd * 10) + *name - '0';
+		fd = fd * 10 + ksh_numdig(*name);
 		if (fd >= FDBASE) {
 			if (emsgp)
 				*emsgp = "file descriptor too large";
@@ -1613,28 +1636,20 @@
 	memcpy(cp, "/shXXXXXX.tmp", 14);
 	/* point to the first of six Xes */
 	cp += 3;
-	/* generate random part of filename */
-	len = -1;
-	do {
-		i = rndget() % 36;
-		cp[++len] = i < 26 ? 'a' + i : '0' + i - 26;
-	} while (len < 5);
 
 	/* cyclically attempt to open a temporary file */
-	while ((i = open(tp->tffn, O_CREAT | O_EXCL | O_RDWR | O_BINARY,
-	    0600)) < 0) {
-		if (errno != EEXIST)
+	do {
+		/* generate random part of filename */
+		len = 0;
+		do {
+			cp[len++] = digits_lc[rndget() % 36];
+		} while (len < 6);
+
+		/* check if this one works */
+		if ((i = binopen3(tp->tffn, O_CREAT | O_EXCL | O_RDWR,
+		    0600)) < 0 && errno != EEXIST)
 			goto maketemp_out;
-		/* count down from z to a then from 9 to 0 */
-		while (cp[len] == '0')
-			if (!len--)
-				goto maketemp_out;
-		if (cp[len] == 'a')
-			cp[len] = '9';
-		else
-			--cp[len];
-		/* do another cycle */
-	}
+	} while (i < 0);
 
 	if (type == TT_FUNSUB) {
 		/* map us high and mark as close-on-exec */
diff --git a/src/mirhash.h b/src/mirhash.h
index 05729bc..df4a9dc 100644
--- a/src/mirhash.h
+++ b/src/mirhash.h
@@ -1,6 +1,6 @@
 /*-
- * Copyright © 2011, 2014
- *	Thorsten Glaser <tg@mirbsd.org>
+ * Copyright © 2011, 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
@@ -44,7 +44,7 @@
 
 #include <sys/types.h>
 
-__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.3 2014/10/02 19:34:06 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.4 2015/05/30 22:14:06 tg Exp $");
 
 /*-
  * BAFH itself is defined by the following primitives:
@@ -61,7 +61,8 @@
  *   the context is (still) zero, adding a NUL byte is not ignored.
  *
  * • BAFHror(eax,cl) evaluates to the unsigned 32-bit integer “eax”,
- *   rotated right by “cl” ∈ [0;31]; no casting, be careful!
+ *   rotated right by “cl” ∈ [0; 31] (no casting, be careful!) where
+ *   “eax” must be uint32_t and “cl” an in-range integer.
  *
  * • BAFHFinish(ctx) avalanches the context around so every sub-byte
  *   depends on all input octets; afterwards, the context variable’s
@@ -88,7 +89,7 @@
  * • BAFHHostStr(ctx,buf) does the same for C strings.
  *
  * All macros may use ctx multiple times in their expansion, but all
- * other arguments are always evaluated at most once.
+ * other arguments are always evaluated at most once except BAFHror.
  *
  * To stay portable, never use the BAFHHost*() macros (these are for
  * host-local entropy shuffling), and encode numbers using ULEB128.
@@ -206,6 +207,7 @@
 	} BAFHHost_v;						\
 								\
 	BAFHUpdate_s = (const void *)(s);			\
+	BAFHHost_v.as_u32 = 0;					\
 	if ((BAFHHost_v.as_u8[0] = *BAFHUpdate_s) != 0)		\
 		++BAFHUpdate_s;					\
 	if ((BAFHHost_v.as_u8[1] = *BAFHUpdate_s) != 0)		\
diff --git a/src/misc.c b/src/misc.c
index 74bafbe..deb95c3 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -30,7 +30,7 @@
 #include <grp.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.219.2.3 2015/03/20 22:21:04 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.238 2015/07/10 19:36:36 tg Exp $");
 
 #define KSH_CHVT_FLAG
 #ifdef MKSH_SMALL
@@ -52,7 +52,7 @@
     const unsigned char *, bool) MKSH_A_PURE;
 static int do_gmatch(const unsigned char *, const unsigned char *,
     const unsigned char *, const unsigned char *) MKSH_A_PURE;
-static const unsigned char *cclass(const unsigned char *, unsigned char)
+static const unsigned char *gmatch_cclass(const unsigned char *, unsigned char)
     MKSH_A_PURE;
 #ifdef KSH_CHVT_CODE
 static void chvt(const Getopt *);
@@ -93,12 +93,8 @@
 void
 initctypes(void)
 {
-	int c;
-
-	for (c = 'a'; c <= 'z'; c++)
-		chtypes[c] |= C_ALPHA;
-	for (c = 'A'; c <= 'Z'; c++)
-		chtypes[c] |= C_ALPHA;
+	setctypes(letters_uc, C_ALPHA);
+	setctypes(letters_lc, C_ALPHA);
 	chtypes['_'] |= C_ALPHA;
 	setctypes("0123456789", C_DIGIT);
 	/* \0 added automatically */
@@ -126,6 +122,17 @@
 
 
 #define SHFLAGS_DEFNS
+#define FN(sname,cname,flags,ochar)		\
+	static const struct {			\
+		/* character flag (if any) */	\
+		char c;				\
+		/* OF_* */			\
+		unsigned char optflags;		\
+		/* long name of option */	\
+		char name[sizeof(sname)];	\
+	} shoptione_ ## cname = {		\
+		ochar, flags, sname		\
+	};
 #include "sh_flags.gen"
 
 #define OFC(i) (options[i][-2])
@@ -166,11 +173,11 @@
 	int opts[NELEM(options)];
 };
 
-static char *options_fmt_entry(char *, size_t, unsigned int, const void *);
+static void options_fmt_entry(char *, size_t, unsigned int, const void *);
 static void printoptions(bool);
 
 /* format a single select menu item */
-static char *
+static void
 options_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
 {
 	const struct options_info *oi = (const struct options_info *)arg;
@@ -178,7 +185,6 @@
 	shf_snprintf(buf, buflen, "%-*s %s",
 	    oi->opt_width, OFN(oi->opts[i]),
 	    Flag(oi->opts[i]) ? "on" : "off");
-	return (buf);
 }
 
 static void
@@ -545,7 +551,7 @@
 		if (num.u > 214748364U)
 			/* overflow on multiplication */
 			return (0);
-		num.u = num.u * 10U + (unsigned int)(c - '0');
+		num.u = num.u * 10U + (unsigned int)ksh_numdig(c);
 		/* now: num.u <= 2147483649U */
 	} while ((c = *s++));
 
@@ -776,7 +782,7 @@
 		}
 		switch (*p++) {
 		case '[':
-			if (sc == 0 || (p = cclass(p, sc)) == NULL)
+			if (sc == 0 || (p = gmatch_cclass(p, sc)) == NULL)
 				return (0);
 			break;
 
@@ -889,7 +895,7 @@
 }
 
 static const unsigned char *
-cclass(const unsigned char *p, unsigned char sub)
+gmatch_cclass(const unsigned char *p, unsigned char sub)
 {
 	unsigned char c, d;
 	bool notp, found = false;
@@ -1007,7 +1013,7 @@
 		const char *arg = argv[go->optind], flag = arg ? *arg : '\0';
 
 		go->p = 1;
-		if (flag == '-' && arg[1] == '-' && arg[2] == '\0') {
+		if (flag == '-' && ksh_isdash(arg + 1)) {
 			go->optind++;
 			go->p = 0;
 			go->info |= GI_MINUSMINUS;
@@ -1220,7 +1226,7 @@
  */
 void
 print_columns(struct shf *shf, unsigned int n,
-    char *(*func)(char *, size_t, unsigned int, const void *),
+    void (*func)(char *, size_t, unsigned int, const void *),
     const void *arg, size_t max_oct, size_t max_colz, bool prefcol)
 {
 	unsigned int i, r, c, rows, cols, nspace, max_col;
@@ -1249,17 +1255,20 @@
 	str = alloc(max_oct, ATEMP);
 
 	/*
-	 * We use (max_col + 1) to consider the space separator.
-	 * Note that no space is printed after the last column
-	 * to avoid problems with terminals that have auto-wrap.
+	 * We use (max_col + 2) to consider the separator space.
+	 * Note that no spaces are printed after the last column
+	 * to avoid problems with terminals that have auto-wrap,
+	 * but we need to also take this into account in x_cols.
 	 */
-	cols = x_cols / (max_col + 1);
+	cols = (x_cols + 1) / (max_col + 2);
 
 	/* if we can only print one column anyway, skip the goo */
 	if (cols < 2) {
-		for (i = 0; i < n; ++i)
-			shf_fprintf(shf, "%s\n",
-			    (*func)(str, max_oct, i, arg));
+		for (i = 0; i < n; ++i) {
+			(*func)(str, max_oct, i, arg);
+			shf_puts(str, shf);
+			shf_putc('\n', shf);
+		}
 		goto out;
 	}
 
@@ -1270,18 +1279,19 @@
 	}
 
 	nspace = (x_cols - max_col * cols) / cols;
+	if (nspace < 2)
+		nspace = 2;
 	max_col = -max_col;
-	if (nspace <= 0)
-		nspace = 1;
 	for (r = 0; r < rows; r++) {
 		for (c = 0; c < cols; c++) {
-			i = c * rows + r;
-			if (i < n) {
-				shf_fprintf(shf, "%*s", max_col,
-				    (*func)(str, max_oct, i, arg));
-				if (c + 1 < cols)
-					shf_fprintf(shf, "%*s", nspace, null);
-			}
+			if ((i = c * rows + r) >= n)
+				break;
+			(*func)(str, max_oct, i, arg);
+			if (i + rows >= n)
+				shf_puts(str, shf);
+			else
+				shf_fprintf(shf, "%*s%*s",
+				    max_col, str, nspace, null);
 		}
 		shf_putchar('\n', shf);
 	}
@@ -1402,12 +1412,12 @@
 	/* max. recursion depth */
 	int symlinks = 32;
 
-	if (upath[0] == '/') {
+	if (mksh_abspath(upath)) {
 		/* upath is an absolute pathname */
 		strdupx(ipath, upath, ATEMP);
 	} else {
 		/* upath is a relative pathname, prepend cwd */
-		if ((tp = ksh_get_wd()) == NULL || tp[0] != '/')
+		if ((tp = ksh_get_wd()) == NULL || !mksh_abspath(tp))
 			return (NULL);
 		ipath = shf_smprintf("%s%s%s", tp, "/", upath);
 		afree(tp, ATEMP);
@@ -1510,7 +1520,7 @@
 			tp = shf_smprintf("%s%s%s", ldest, *ip ? "/" : "", ip);
 			afree(ipath, ATEMP);
 			ip = ipath = tp;
-			if (ldest[0] != '/') {
+			if (!mksh_abspath(ldest)) {
 				/* symlink target is a relative path */
 				xp = Xrestpos(xs, xp, pos);
 			} else
@@ -1610,7 +1620,7 @@
 	if (!file)
 		file = null;
 
-	if (file[0] == '/') {
+	if (mksh_abspath(file)) {
 		*phys_pathp = 0;
 		use_cdpath = false;
 	} else {
@@ -1627,15 +1637,15 @@
 		if (!plist)
 			use_cdpath = false;
 		else if (use_cdpath) {
-			char *pend;
+			char *pend = plist;
 
-			for (pend = plist; *pend && *pend != ':'; pend++)
-				;
+			while (*pend && *pend != MKSH_PATHSEPC)
+				++pend;
 			plen = pend - plist;
 			*cdpathp = *pend ? pend + 1 : NULL;
 		}
 
-		if ((!use_cdpath || !plen || plist[0] != '/') &&
+		if ((!use_cdpath || !plen || !mksh_abspath(plist)) &&
 		    (cwd && *cwd)) {
 			len = strlen(cwd);
 			XcheckN(*xsp, xp, len);
@@ -1721,7 +1731,7 @@
 				continue;
 			else if (len == 2 && tp[1] == '.') {
 				/* parent level, but how? */
-				if (*p == '/')
+				if (mksh_abspath(p))
 					/* absolute path, only one way */
 					goto strip_last_component;
 				else if (dp > sp) {
@@ -1921,7 +1931,7 @@
 		/* Ignore failure (happens if readonly or integer) */
 		setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR);
 
-	if (Xstring(xs, xp)[0] != '/') {
+	if (!mksh_abspath(Xstring(xs, xp))) {
 		pwd = NULL;
 	} else if (!physical) {
 		goto norealpath_PWD;
@@ -1999,9 +2009,9 @@
 #endif
 	    }
 	}
-	if ((fd = open(dv, O_RDWR | O_BINARY)) < 0) {
+	if ((fd = binopen2(dv, O_RDWR)) < 0) {
 		sleep(1);
-		if ((fd = open(dv, O_RDWR | O_BINARY)) < 0) {
+		if ((fd = binopen2(dv, O_RDWR)) < 0) {
 			errorf("%s: %s %s", "chvt", "can't open", dv);
 		}
 	}
@@ -2194,8 +2204,8 @@
 		wc = 0;
 		i = 3;
 		while (i--)
-			if ((c = (*fg)()) >= '0' && c <= '7')
-				wc = (wc << 3) + (c - '0');
+			if ((c = (*fg)()) >= ord('0') && c <= ord('7'))
+				wc = (wc << 3) + ksh_numdig(c);
 			else {
 				(*fp)(c);
 				break;
@@ -2204,13 +2214,13 @@
 	case 'U':
 		i = 8;
 		if (/* CONSTCOND */ 0)
-		/* FALLTHROUGH */
+			/* FALLTHROUGH */
 	case 'u':
-		i = 4;
+		  i = 4;
 		if (/* CONSTCOND */ 0)
-		/* FALLTHROUGH */
+			/* FALLTHROUGH */
 	case 'x':
-		i = cstyle ? -1 : 2;
+		  i = cstyle ? -1 : 2;
 		/**
 		 * x:	look for a hexadecimal number with up to
 		 *	two (C style: arbitrary) digits; convert
@@ -2221,12 +2231,12 @@
 		wc = 0;
 		while (i--) {
 			wc <<= 4;
-			if ((c = (*fg)()) >= '0' && c <= '9')
-				wc += c - '0';
-			else if (c >= 'A' && c <= 'F')
-				wc += c - 'A' + 10;
-			else if (c >= 'a' && c <= 'f')
-				wc += c - 'a' + 10;
+			if ((c = (*fg)()) >= ord('0') && c <= ord('9'))
+				wc += ksh_numdig(c);
+			else if (c >= ord('A') && c <= ord('F'))
+				wc += ksh_numuc(c) + 10;
+			else if (c >= ord('a') && c <= ord('f'))
+				wc += ksh_numlc(c) + 10;
 			else {
 				wc >>= 4;
 				(*fp)(c);
diff --git a/src/mksh.1 b/src/mksh.1
index 5e41d13..c612c68 100644
--- a/src/mksh.1
+++ b/src/mksh.1
@@ -1,5 +1,5 @@
-.\" $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 $
+.\" $MirOS: src/bin/mksh/mksh.1,v 1.377 2015/07/10 19:35:39 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
@@ -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 12 2015 $
+.Dd $Mdocdate: July 10 2015 $
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
@@ -476,7 +476,7 @@
 .Ql }
 delimit
 .Xr csh 1 Ns -style
-alterations (see
+alternations (see
 .Sx Brace expansion
 below);
 and finally,
@@ -1120,19 +1120,19 @@
 .Pp
 The following command aliases are defined automatically by the shell:
 .Bd -literal -offset indent
-autoload=\*(aqtypeset \-fu\*(aq
-functions=\*(aqtypeset \-f\*(aq
-hash=\*(aqalias \-t\*(aq
-history=\*(aqfc \-l\*(aq
-integer=\*(aqtypeset \-i\*(aq
-local=typeset
-login=\*(aqexec login\*(aq
-nameref=\*(aqtypeset \-n\*(aq
+autoload=\*(aq\etypeset \-fu\*(aq
+functions=\*(aq\etypeset \-f\*(aq
+hash=\*(aq\ebuiltin alias \-t\*(aq
+history=\*(aq\ebuiltin fc \-l\*(aq
+integer=\*(aq\etypeset \-i\*(aq
+local=\*(aq\etypeset\*(aq
+login=\*(aq\eexec login\*(aq
+nameref=\*(aq\etypeset \-n\*(aq
 nohup=\*(aqnohup \*(aq
-r=\*(aqfc \-e \-\*(aq
-source=\*(aqPATH=$PATH:. command .\*(aq
-stop=\*(aqkill \-STOP\*(aq
-type=\*(aqwhence \-v\*(aq
+r=\*(aq\ebuiltin fc \-e \-\*(aq
+source=\*(aqPATH=$PATH:. \ecommand .\*(aq
+stop=\*(aq\ekill \-STOP\*(aq
+type=\*(aq\ebuiltin whence \-v\*(aq
 .Ed
 .Pp
 Tracked aliases allow the shell to remember where it found a particular
@@ -1143,16 +1143,16 @@
 time the command is executed, the shell checks the saved path to see that it
 is still valid, and if so, avoids repeating the path search.
 Tracked aliases can be listed and created using
-.Ic alias \-t .
+.Ic alias Fl t .
 Note that changing the
 .Ev PATH
 parameter clears the saved paths for all tracked aliases.
 If the
 .Ic trackall
 option is set (i.e.\&
-.Ic set \-o Ic trackall
+.Ic set Fl o Ic trackall
 or
-.Ic set \-h ) ,
+.Ic set Fl h ) ,
 the shell tracks all commands.
 This option is set automatically for non-interactive shells.
 For interactive shells, only the following commands are
@@ -1213,7 +1213,7 @@
 the, initially empty, expression-local variable
 .Ev REPLY
 is set to within the
-.Ar command Ns No s .
+.Ar command Ns s .
 .Pp
 If a substitution appears outside of double quotes, the results of the
 substitution are generally subject to word or field splitting according to
@@ -1426,7 +1426,7 @@
 .Ic getopts ,
 .Ic read ,
 and
-.Ic set \-A
+.Ic set Fl A
 commands.
 Lastly, parameters can be assigned values using assignment operators
 inside arithmetic expressions (see
@@ -1538,7 +1538,9 @@
 .Pp
 The following forms of parameter substitution can also be used (if
 .Ar name
-is an array, its element #0 will be substituted in a scalar context):
+is an array, the element with the key
+.Dq 0
+will be substituted in scalar context):
 .Pp
 .Bl -tag -width Ds -compact
 .It Pf ${# Ns Ar name Ns \&}
@@ -1628,7 +1630,7 @@
 .Pf // Ar pattern / Ar string No }
 .Xc
 .Sm on
-Like ${..#..} substitution, but it replaces the longest match of
+Similar to ${..##..} substitution, but it replaces the longest match of
 .Ar pattern ,
 anchored anywhere in the value, with
 .Ar string .
@@ -1639,17 +1641,17 @@
 it is anchored at the beginning of the value; if it begins with
 .Ql % ,
 it is anchored at the end.
-Patterns that are empty or consist only of wildcards are invalid.
-A single
+Empty patterns cause no replacement to happen.
+A single leading
 .Ql /
-replaces the first occurence of the search
-.Ar pattern ,
-and two of them replace all occurences.
-If
+or use of a pattern that matches the empty string causes the
+replacement to happen only once; two leading slashes cause
+all occurrences of matches in the value to be replaced.
+If the trailing
 .Pf / Ar string
-is omitted, the
+is omitted, any matches of
 .Ar pattern
-is replaced by the empty string, i.e. deleted.
+are replaced by the empty string, i.e. deleted.
 Cannot be applied to a vector.
 Inefficiently implemented, may be slow.
 .Pp
@@ -1817,9 +1819,9 @@
 .Ev LINES .
 This parameter is used by the interactive line editing modes, and by the
 .Ic select ,
-.Ic set \-o ,
+.Ic set Fl o ,
 and
-.Ic kill \-l
+.Ic kill Fl l
 commands to format information columns.
 Importing from the environment or unsetting this parameter removes the
 binding to the actual terminal size in favour of the provided value.
@@ -1857,7 +1859,8 @@
 .It Ev HISTFILE
 The name of the file used to store command history.
 When assigned to or unset, the file is opened, history is truncated
-then loaded from the file; subsequent new lines are appended.
+then loaded from the file; subsequent new commands (possibly consisting
+of several lines) are appended once they successfully compiled.
 Also, several invocations of the shell will share history if their
 .Ev HISTFILE
 parameters all point to the same file.
@@ -2010,7 +2013,7 @@
 sequences (such as escape codes) by prefixing your prompt with a
 character (such as Ctrl-A) followed by a carriage return and then delimiting
 the escape codes with this character.
-Any occurences of that character in the prompt are not printed.
+Any occurrences of that character in the prompt are not printed.
 By the way, don't blame me for
 this hack; it's derived from the original
 .Xr ksh88 1 ,
@@ -2140,10 +2143,10 @@
 .Pp
 The home directory of previously expanded login names are cached and re-used.
 The
-.Ic alias \-d
+.Ic alias Fl d
 command may be used to list, change, and add to this cache (e.g.\&
 .Ic alias \-d fac=/usr/local/facilities; cd \*(TIfac/bin ) .
-.Ss Brace expansion (alteration)
+.Ss Brace expansion (alternation)
 Brace expressions take the following form:
 .Bd -unfilled -offset indent
 .Sm off
@@ -2743,9 +2746,9 @@
 A co-process (which is a pipeline created with the
 .Sq \*(Ba&
 operator) is an asynchronous process that the shell can both write to (using
-.Ic print \-p )
+.Ic print Fl p )
 and read from (using
-.Ic read \-p ) .
+.Ic read Fl p ) .
 The input and output of the co-process can also be manipulated using
 .Ic \*(Gt&p
 and
@@ -2783,13 +2786,13 @@
 portion of the co-process output when the most recently started co-process
 (instead of when all sharing co-processes) exits.
 .It
-.Ic print \-p
+.Ic print Fl p
 will ignore
 .Dv SIGPIPE
 signals during writes if the signal is not being trapped or ignored; the same
 is true if the co-process input has been duplicated to another file descriptor
 and
-.Ic print \-u Ns Ar n
+.Ic print Fl u Ns Ar n
 is used.
 .El
 .Ss Functions
@@ -2818,11 +2821,11 @@
 A list of functions can be obtained using
 .Ic typeset +f
 and the function definitions can be listed using
-.Ic typeset \-f .
+.Ic typeset Fl f .
 The
 .Ic autoload
 command (which is an alias for
-.Ic typeset \-fu )
+.Ic typeset Fl fu )
 may be used to create undefined functions: when an undefined function is
 executed, the shell searches the path specified in the
 .Ev FPATH
@@ -2843,9 +2846,9 @@
 and
 .Dq export ,
 which can be set with
-.Ic typeset \-ft
+.Ic typeset Fl ft
 and
-.Ic typeset \-fx ,
+.Ic typeset Fl fx ,
 respectively.
 When a traced function is executed, the shell's
 .Ic xtrace
@@ -2904,9 +2907,9 @@
 .Ic getopts
 outside the function).
 .It
-Bourne-style function definitions take precedence over alias dereferences
-and remove alias definitions upon encounter, while aliases take precedence
-over Korn-style functions.
+Shell options
+.Pq Ic set Fl o
+have local scope, i.e. changes inside a function are reset upon its exit.
 .El
 .Pp
 In the future, the following differences may also be added:
@@ -2920,10 +2923,6 @@
 .It
 The EXIT trap, if set in a function, will be executed after the function
 returns.
-.It
-Shell options
-.Pq Ic set Fl o
-have local scope, i.e. changes inside a function are reset upon its exit.
 .El
 .Ss Command execution
 After evaluation of command-line arguments, redirections, and parameter
@@ -3162,15 +3161,13 @@
 is a single dash
 .Pq Sq -
 or absent, read from standard input.
-Unless compiled with
-.Dv MKSH_NO_EXTERNAL_CAT ,
-if any options are given, an external
-.Xr cat 1
-utility is invoked instead if called from the shell.
 For direct builtin calls, the
 .Tn POSIX
 .Fl u
 option is supported as a no-op.
+For calls from shell, if any options are given, an external
+.Xr cat 1
+utility is preferred over the builtin.
 .Pp
 .It Xo
 .Ic cd
@@ -3298,9 +3295,9 @@
 .Ar cmd ,
 information about what would be executed is given (and the same is done for
 .Ar arg ... ) .
-For special and regular built-in commands and functions, their names are simply
-printed; for aliases, a command that defines them is printed; and for commands
-found by searching the
+For builtins, functions and keywords, their names are simply printed;
+for aliases, a command that defines them is printed;
+for utilities found by searching the
 .Ev PATH
 parameter, the full path of the command is printed.
 If no command is found
@@ -3694,6 +3691,9 @@
 See
 .Xr mknod 8
 for further information.
+This is not normally part of
+.Nm mksh ;
+however, distributors may have added this as builtin as a speed hack.
 .Pp
 .It Xo
 .Ic print
@@ -3754,8 +3754,9 @@
 .Xr printf 1 ,
 utility, except it uses the same
 .Sx Backslash expansion
-and I/O code and does hot handle floating point as the rest of
+and I/O code and does not handle floating point as the rest of
 .Nm mksh .
+An external utility is preferred over the builtin.
 This is not normally part of
 .Nm mksh ;
 however, distributors may have added this as builtin as a speed hack.
@@ -3834,7 +3835,8 @@
 .It Fl N Ar z
 Instead of reading till end-of-line, read exactly
 .Ar z
-bytes; less if EOF or a timeout occurs.
+bytes.
+If EOF or a timeout occurs, a partial read is returned with exit status 1.
 .It Fl n Ar z
 Instead of reading till end-of-line, read up to
 .Ar z
@@ -3853,6 +3855,9 @@
 Interrupt reading after
 .Ar n
 seconds (specified as positive decimal value with an optional fractional part).
+The exit status of
+.Nm read
+is 1 if the timeout occurred, but partial reads may still be returned.
 .It Fl r
 Normally, the ASCII backslash character escapes the special
 meaning of the following character and is stripped from the input;
@@ -3899,8 +3904,8 @@
 .Fl r
 option might be prudent; the same applies for:
 .Bd -literal -offset indent
-find . \-type f \-print0 \*(Ba \e
-    while IFS= read \-d \*(aq\*(aq \-r filename; do
+find . \-type f \-print0 \*(Ba& \e
+    while IFS= read \-d \*(aq\*(aq \-pr filename; do
 	print \-r \-\- "found \*(Lt${filename#./}\*(Gt"
 done
 .Ed
@@ -4040,23 +4045,6 @@
 .Nm ksh93
 is:
 .Ic foo=(a b c); foo+=(d e)
-.Pp
-Another
-.At
-.Nm ksh93
-and
-.Tn GNU
-.Nm bash
-extension allows specifying the indices used for
-.Ar arg ...
-.Pq from the above example, Ic a b c
-like this:
-.Ic set \-A foo \-\- [0]=a [1]=b [2]=c
-or
-.Ic foo=([0]=a [1]=b [2]=c)
-which can also be written
-.Ic foo=([0]=a b c)
-because indices are incremented automatically.
 .It Fl a \*(Ba Fl o Ic allexport
 All new parameters are created with the export attribute.
 .It Fl b \*(Ba Fl o Ic notify
@@ -4652,54 +4640,60 @@
 0m0.00s 0m0.00s
 .Ed
 .Pp
+.It Ic trap Ar n Op Ar signal ...
+If the first operand is a decimal unsigned integer, this resets all
+specified signals to the default action, i.e. is the same as calling
+.Ic trap
+with a minus sign
+.Pq Sq \-
+as
+.Ar handler ,
+followed by the arguments
+.Pq Ar n Op Ar signal ... ,
+all of which are treated as signals.
+.Pp
 .It Ic trap Op Ar handler signal ...
-Sets a trap handler that is to be executed when any of the specified signals are
-received.
+Sets a trap handler that is to be executed when any of the specified
+.Ar signal Ns s
+are received.
 .Ar handler
-is either a
-.Dv NULL
-string, indicating the signals are to be ignored, a minus sign
+is either an empty string, indicating the signals are to be ignored,
+a minus sign
 .Pq Sq \- ,
-indicating that the default action is to be taken for the signals (see
-.Xr signal 3 ) ,
-or a string containing shell commands to be evaluated and executed at the first
-opportunity (i.e. when the current command completes, or before printing the
-next
+indicating that the default action is to be taken for the signals
+.Pq see Xr signal 3 ,
+or a string containing shell commands to be executed at the first opportunity
+(i.e. when the current command completes, or before printing the next
 .Ev PS1
 prompt) after receipt of one of the signals.
 .Ar signal
-is the name of a signal (e.g.\&
-.Dv PIPE
-or
-.Dv ALRM )
+is the name of a signal
+.Pq e.g.\& Dv PIPE or Dv ALRM
 or the number of the signal (see the
-.Ic kill \-l
+.Ic kill Fl l
 command above).
 .Pp
 There are two special signals:
 .Dv EXIT
-(also known as 0) which is executed when the shell is about to exit, and
+.Pq also known as 0 ,
+which is executed when the shell is about to exit, and
 .Dv ERR ,
-which is executed after an error occurs (an error is something that would cause
-the shell to exit if the
-.Fl e
+which is executed after an error occurs; an error is something
+that would cause the shell to exit if the
+.Ic set Fl e
 or
-.Ic errexit
-option were set \*(en see the
-.Ic set
-command above).
+.Ic set Fl o Ic errexit
+option were set.
 .Dv EXIT
 handlers are executed in the environment of the last executed command.
-Note
-that for non-interactive shells, the trap handler cannot be changed for signals
-that were ignored when the shell started.
 .Pp
-With no arguments,
+Note that, for non-interactive shells, the trap handler cannot be changed
+for signals that were ignored when the shell started.
+.Pp
+With no arguments, the current state of the traps that have been set since
+the shell started is shown as a series of
 .Ic trap
-lists, as a series of
-.Ic trap
-commands, the current state of the traps that have been set since the shell
-started.
+commands.
 Note that the output of
 .Ic trap
 cannot be usefully piped to another process (an artifact of the fact that
@@ -5109,7 +5103,7 @@
 .Ic wait
 is that of the last specified job; if the last job is killed by a signal, the
 exit status is 128 + the number of the signal (see
-.Ic kill \-l Ar exit-status
+.Ic kill Fl l Ar exit-status
 above); if the last specified job can't be found (because it never existed, or
 had already finished), the exit status of
 .Ic wait
@@ -5180,9 +5174,9 @@
 .Ic jobs
 commands.
 If job control is fully enabled (using
-.Ic set \-m
+.Ic set Fl m
 or
-.Ic set \-o monitor ) ,
+.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
@@ -5277,7 +5271,7 @@
 .Dv SIGTSTP ) .
 .It Ar signal-description Op Dq core dumped
 The job was killed by a signal (e.g. memory fault, hangup); use
-.Ic kill \-l
+.Ic kill Fl l
 for a list of signal descriptions.
 The
 .Dq core dumped
@@ -5404,7 +5398,7 @@
 Most ordinary characters are bound to this.
 .It Xo backward\-char:
 .Op Ar n
-.No \*(haB , \*(haXD , ANSI-CurLeft
+.No \*(haB , \*(haXD , ANSI-CurLeft , PC-CurLeft
 .Xc
 Moves the cursor backward
 .Ar n
@@ -5421,7 +5415,7 @@
 characters.
 .It beginning\-of\-history: \*(ha[\*(Lt
 Moves to the beginning of the history.
-.It beginning\-of\-line: \*(haA, ANSI-Home
+.It beginning\-of\-line: \*(haA, ANSI-Home, PC-Home
 Moves the cursor to the beginning of the edited input line.
 .It Xo capitalise\-word:
 .Op Ar n
@@ -5477,7 +5471,7 @@
 characters before the cursor.
 .It Xo delete\-char\-forward:
 .Op Ar n
-.No ANSI-Del
+.No ANSI-Del , PC-Del
 .Xc
 Deletes
 .Ar n
@@ -5498,7 +5492,7 @@
 words.
 .It Xo down\-history:
 .Op Ar n
-.No \*(haN , \*(haXB , ANSI-CurDown
+.No \*(haN , \*(haXB , ANSI-CurDown , PC-CurDown
 .Xc
 Scrolls the history buffer forward
 .Ar n
@@ -5530,7 +5524,7 @@
 .Ic fc \-e ${VISUAL:\-${EDITOR:\-vi}} Ar n .
 .It end\-of\-history: \*(ha[\*(Gt
 Moves to the end of the history.
-.It end\-of\-line: \*(haE, ANSI-End
+.It end\-of\-line: \*(haE, ANSI-End, PC-End
 Moves the cursor to the end of the input line.
 .It eot: \*(ha_
 Acts as an end-of-file; this is useful because edit-mode input disables
@@ -5555,7 +5549,7 @@
 If no files match the pattern, the bell is rung.
 .It Xo forward\-char:
 .Op Ar n
-.No \*(haF , \*(haXC , ANSI-CurRight
+.No \*(haF , \*(haXC , ANSI-CurRight , PC-CurRight
 .Xc
 Moves the cursor forward
 .Ar n
@@ -5669,12 +5663,12 @@
 pattern.
 The history buffer retains only a finite number of lines; the oldest
 are discarded as necessary.
-.It search\-history\-up: ANSI-PgUp
+.It search\-history\-up: ANSI-PgUp, PC-PgUp
 Search backwards through the history buffer for commands whose beginning match
 the portion of the input line before the cursor.
 When used on an empty line, this has the same effect as
 .Ic up\-history .
-.It search\-history\-down: ANSI-PgDn
+.It search\-history\-down: ANSI-PgDn, PC-PgDn
 Search forwards through the history buffer for commands whose beginning match
 the portion of the input line before the cursor.
 When used on an empty line, this has the same effect as
@@ -5694,7 +5688,7 @@
 character to the right.
 .It Xo up\-history:
 .Op Ar n
-.No \*(haP , \*(haXA , ANSI-CurUp
+.No \*(haP , \*(haXA , ANSI-CurUp , PC-CurUp
 .Xc
 Scrolls the history buffer backward
 .Ar n
@@ -5806,7 +5800,7 @@
 Optional file name and command completion (see
 .Ic \*(haF
 above), enabled with
-.Ic set \-o vi\-tabcomplete .
+.Ic set Fl o Ic vi\-tabcomplete .
 .El
 .Pp
 In command mode, each character is interpreted as a command.
@@ -5919,7 +5913,7 @@
 is only recognised if the
 .Ic vi\-esccomplete
 option is set (see
-.Ic set \-o ) .
+.Ic set Fl o ) .
 If
 .Ar n
 is specified, the
@@ -6122,7 +6116,7 @@
 .Ar n Ns th
 occurrence of the last search string;
 the direction of the search is the opposite of the last search.
-.It Ar ANSI-CurUp
+.It Ar ANSI-CurUp , PC-PgUp
 Take the characters from the beginning of the line to the current
 cursor position as search string and do a backwards history search
 for lines beginning with this string; keep the cursor position.
@@ -6273,6 +6267,8 @@
 Undo the last edit command.
 .It U
 Undo all changes that have been made to the current line.
+.It PC Home, End, Del, and cursor keys
+They move as expected, both in insert and command mode.
 .It Ar intr No and Ar quit
 The interrupt and quit terminal characters cause the current line to be
 deleted and a new prompt to be printed.
@@ -6445,9 +6441,6 @@
 .\"
 .Sh CAVEATS
 .Nm
-only supports the Unicode BMP (Basic Multilingual Plane).
-.Pp
-.Nm
 has a different scope model from
 .At
 .Nm ksh ,
@@ -6479,7 +6472,7 @@
 provides a consistent, clear interface normally.
 This may deviate from POSIX in optional or opinionated places, such
 as whether leading-digit-zero numbers should be interpreted as octal.
-.Ic set \-o posix
+.Ic set Fl o Ic posix
 will cause the shell (either
 .Nm mksh
 or
@@ -6492,8 +6485,20 @@
 supports only the
 .Dq C
 locale.
-For users of UTF-8 locales, the following sh code makes the shell
-match the locale:
+.Nm mksh Ns 's
+.Ic utf8\-mode
+only supports the Unicode BMP (Basic Multilingual Plane) and maps
+raw octets into the U+EF80..U+EFFF wide character range; compare
+.Sx Arithmetic expressions .
+The following
+.Tn POSIX
+.Nm sh
+code toggles the
+.Ic utf8\-mode
+option dependent on the current
+.Tn POSIX
+locale for mksh to allow using the UTF-8 mode, within the constraints
+outlined above, in code portable across various shell implementations:
 .Bd -literal -offset indent
 case ${KSH_VERSION:\-} in
 *MIRBSD\ KSH*\*(Ba*LEGACY\ KSH*)
@@ -6526,7 +6531,7 @@
 .Xr memmove 3 .
 .Pp
 This document attempts to describe
-.Nm mksh\ R50e
+.Nm mksh\ R51
 and up,
 .\" with vendor patches from insert-your-name-here,
 compiled without any options impacting functionality, such as
@@ -6534,9 +6539,9 @@
 when not called as
 .Pa /bin/sh
 which, on some systems only, enables
-.Ic set \-o posix
+.Ic set Fl o Ic posix
 or
-.Ic set \-o sh
+.Ic set Fl o Ic sh
 automatically (whose behaviour differs across targets),
 for an operating environment supporting all of its advanced needs.
 .Pp
diff --git a/src/rlimits.gen b/src/rlimits.gen
index ef71dab..ddb4cc8 100644
--- a/src/rlimits.gen
+++ b/src/rlimits.gen
@@ -1,19 +1,8 @@
 #ifndef RLIMITS_OPTCS
 #if defined(RLIMITS_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.1 2013/11/17 22:21:18 tg Exp $");
-struct limits {
-	/* limit resource */
-	int resource;
-	/* multiply by to get rlim_{cur,max} values */
-	unsigned int factor;
-	/* getopts char */
-	char optchar;
-	/* limit name */
-	char name[1];
-};
-#define FN(lname,lid,lfac,lopt)					static const struct {						int resource;						unsigned int factor;					char optchar;						char name[sizeof(lname)];			} rlimits_ ## lid = {						lid, lfac, lopt, lname				};
+__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.2 2015/05/01 23:16:31 tg Exp $");
 #elif defined(RLIMITS_ITEMS)
-#define FN(lname,lid,lfac,lopt)					(const struct limits *)(&rlimits_ ## lid),
+#define FN(lname,lid,lfac,lopt) (const struct limits *)(&rlimits_ ## lid),
 #endif
 #ifndef F0
 #define F0 FN
diff --git a/src/rlimits.opt b/src/rlimits.opt
index 6c3908b..3759da8 100644
--- a/src/rlimits.opt
+++ b/src/rlimits.opt
@@ -1,18 +1,7 @@
 @RLIMITS_DEFNS
-__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.1 2013/11/17 22:21:18 tg Exp $");
-struct limits {
-	/* limit resource */
-	int resource;
-	/* multiply by to get rlim_{cur,max} values */
-	unsigned int factor;
-	/* getopts char */
-	char optchar;
-	/* limit name */
-	char name[1];
-};
-#define FN(lname,lid,lfac,lopt)					static const struct {						int resource;						unsigned int factor;					char optchar;						char name[sizeof(lname)];			} rlimits_ ## lid = {						lid, lfac, lopt, lname				};
+__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.2 2015/05/01 23:16:31 tg Exp $");
 @RLIMITS_ITEMS
-#define FN(lname,lid,lfac,lopt)					(const struct limits *)(&rlimits_ ## lid),
+#define FN(lname,lid,lfac,lopt) (const struct limits *)(&rlimits_ ## lid),
 @@
 
 /* generic options for the ulimit builtin */
diff --git a/src/sh.h b/src/sh.h
index 91f8961..c3109e5 100644
--- a/src/sh.h
+++ b/src/sh.h
@@ -64,6 +64,9 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#if HAVE_IO_H
+#include <io.h>
+#endif
 #if HAVE_LIBGEN_H
 #include <libgen.h>
 #endif
@@ -169,9 +172,9 @@
 #endif
 
 #ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.701.2.7 2015/04/19 19:18:21 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.739 2015/07/10 19:36:37 tg Exp $");
 #endif
-#define MKSH_VERSION "R50 2015/04/19"
+#define MKSH_VERSION "R51 2015/07/10"
 
 /* arithmetic types: C implementation */
 #if !HAVE_CAN_INTTYPES
@@ -253,7 +256,8 @@
 
 /* extra types */
 
-#if !HAVE_GETRUSAGE
+/* getrusage does not exist on OS/2 kLIBC */
+#if !HAVE_GETRUSAGE && !defined(__OS2__)
 #undef rusage
 #undef RUSAGE_SELF
 #undef RUSAGE_CHILDREN
@@ -298,16 +302,6 @@
 	} while (/* CONSTCOND */ 0)
 #endif
 
-#define ksh_isdigit(c)	(((c) >= '0') && ((c) <= '9'))
-#define ksh_islower(c)	(((c) >= 'a') && ((c) <= 'z'))
-#define ksh_isupper(c)	(((c) >= 'A') && ((c) <= 'Z'))
-#define ksh_tolower(c)	(((c) >= 'A') && ((c) <= 'Z') ? (c) - 'A' + 'a' : (c))
-#define ksh_toupper(c)	(((c) >= 'a') && ((c) <= 'z') ? (c) - 'a' + 'A' : (c))
-#define ksh_isdash(s)	(((s)[0] == '-') && ((s)[1] == '\0'))
-#define ksh_isspace(c)	((((c) >= 0x09) && ((c) <= 0x0D)) || ((c) == 0x20))
-#define ksh_min(x,y)	((x) < (y) ? (x) : (y))
-#define ksh_max(x,y)	((x) > (y) ? (x) : (y))
-
 #ifdef MKSH__NO_PATH_MAX
 #undef PATH_MAX
 #else
@@ -339,29 +333,69 @@
 #define DEFFILEMODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
 #endif
 
-#ifndef NSIG
-#if defined(_NSIG)
-#define NSIG		_NSIG
+
+/* determine ksh_NSIG: first, use the traditional definitions */
+#undef ksh_NSIG
+#if defined(NSIG)
+#define ksh_NSIG NSIG
+#elif defined(_NSIG)
+#define ksh_NSIG _NSIG
 #elif defined(SIGMAX)
-#define NSIG		(SIGMAX+1)
+#define ksh_NSIG (SIGMAX + 1)
 #elif defined(_SIGMAX)
-#define NSIG		(_SIGMAX+1)
+#define ksh_NSIG (_SIGMAX + 1)
+#elif defined(NSIG_MAX)
+#define ksh_NSIG NSIG_MAX
 #else
 # error Please have your platform define NSIG.
-#define NSIG		64
 #endif
-#endif
-
-/* get rid of this (and awk/printf(1) in Build.sh) later */
-#if (NSIG < 1)
+/* range-check them */
+#if (ksh_NSIG < 1)
 # error Your NSIG value is not positive.
-#unset NSIG
-#define NSIG		64
+#undef ksh_NSIG
+#endif
+/* second, see if the new POSIX definition is available */
+#ifdef NSIG_MAX
+#if (NSIG_MAX < 2)
+/* and usable */
+# error Your NSIG_MAX value is too small.
+#undef NSIG_MAX
+#elif (ksh_NSIG > NSIG_MAX)
+/* and realistic */
+# error Your NSIG value is larger than your NSIG_MAX value.
+#undef NSIG_MAX
+#else
+/* since it’s usable, prefer it */
+#undef ksh_NSIG
+#define ksh_NSIG NSIG_MAX
+#endif
+/* if NSIG_MAX is now still defined, use sysconf(_SC_NSIG) at runtime */
+#endif
+/* third, for cpp without the error directive, default */
+#ifndef ksh_NSIG
+#define ksh_NSIG 64
 #endif
 
 
 /* OS-dependent additions (functions, variables, by OS) */
 
+#ifdef MKSH_EXE_EXT
+#undef MKSH_EXE_EXT
+#define MKSH_EXE_EXT	".exe"
+#else
+#define MKSH_EXE_EXT	""
+#endif
+
+#ifdef __OS2__
+#define MKSH_PATHSEPS	";"
+#define MKSH_PATHSEPC	';'
+#define MKSH_UNIXROOT	"/@unixroot"
+#else
+#define MKSH_PATHSEPS	":"
+#define MKSH_PATHSEPC	':'
+#define MKSH_UNIXROOT	""
+#endif
+
 #if !HAVE_FLOCK_DECL
 extern int flock(int, int);
 #endif
@@ -476,6 +510,8 @@
 
 EXTERN const char digits_uc[] E_INIT("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
 EXTERN const char digits_lc[] E_INIT("0123456789abcdefghijklmnopqrstuvwxyz");
+#define letters_uc (digits_uc + 10)
+#define letters_lc (digits_lc + 10)
 
 /*
  * Evil hack for const correctness due to API brokenness
@@ -537,7 +573,7 @@
 #define mkssert(e)	do { } while (/* CONSTCOND */ 0)
 #endif
 
-#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 506)
+#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 511)
 #error Must run Build.sh to compile this.
 extern void thiswillneverbedefinedIhope(void);
 int
@@ -802,18 +838,19 @@
 EXTERN const char Tsynerr[] E_INIT("syntax error");
 #endif
 EXTERN const char Tselect[] E_INIT("select");
-EXTERN const char Tr_fc_e_dash[] E_INIT("r=fc -e -");
-#define Tfc_e_dash	(Tr_fc_e_dash + 2)	/* "fc -e -" */
-#define Zfc_e_dash	7			/* strlen(Tfc_e_dash) */
-EXTERN const char Tlocal_typeset[] E_INIT("local=typeset");
-#define T_typeset	(Tlocal_typeset + 5)	/* "=typeset" */
-#define Ttypeset	(Tlocal_typeset + 6)	/* "typeset" */
+EXTERN const char T_typeset[] E_INIT("=typeset");
+#define Ttypeset	(T_typeset + 1)		/* "typeset" */
 EXTERN const char Talias[] E_INIT("alias");
 EXTERN const char Tunalias[] E_INIT("unalias");
+EXTERN const char Tcat[] E_INIT("cat");
+#ifdef __OS2__
+EXTERN const char Textproc[] E_INIT("extproc");
+#endif
+#ifdef MKSH_PRINTF_BUILTIN
+EXTERN const char Tprintf[] E_INIT("printf");
+#endif
 EXTERN const char Tsgset[] E_INIT("*=set");
 #define Tset		(Tsgset + 2)		/* "set" */
-EXTERN const char Tsgunset[] E_INIT("*=unset");
-#define Tunset		(Tsgunset + 2)		/* "unset" */
 EXTERN const char Tsgexport[] E_INIT("*=export");
 #define Texport		(Tsgexport + 2)		/* "export" */
 EXTERN const char Tsgreadonly[] E_INIT("*=readonly");
@@ -892,13 +929,13 @@
 #define SS_USER		BIT(4)	/* user is doing the set (ie, trap command) */
 #define SS_SHTRAP	BIT(5)	/* trap for internal use (ALRM, CHLD, WINCH) */
 
-#define ksh_SIGEXIT	0	/* for trap EXIT */
-#define ksh_SIGERR	NSIG	/* for trap ERR */
+#define ksh_SIGEXIT 0		/* for trap EXIT */
+#define ksh_SIGERR  ksh_NSIG	/* for trap ERR */
 
 EXTERN volatile sig_atomic_t trap;	/* traps pending? */
 EXTERN volatile sig_atomic_t intrsig;	/* pending trap interrupts command */
 EXTERN volatile sig_atomic_t fatal_trap; /* received a fatal signal */
-extern	Trap	sigtraps[NSIG+1];
+extern Trap sigtraps[ksh_NSIG + 1];
 
 /* got_winch = 1 when we need to re-adjust the window size */
 #ifdef SIGWINCH
@@ -940,8 +977,20 @@
 #define ctype(c, t)	tobool( ((t) == C_SUBOP2) ?			\
 			    (((c) == '#' || (c) == '%') ? 1 : 0) :	\
 			    (chtypes[(unsigned char)(c)] & (t)) )
+#define ord(c)		((int)(unsigned char)(c))
 #define ksh_isalphx(c)	ctype((c), C_ALPHA)
 #define ksh_isalnux(c)	ctype((c), C_ALPHA | C_DIGIT)
+#define ksh_isdigit(c)	(((c) >= '0') && ((c) <= '9'))
+#define ksh_islower(c)	(((c) >= 'a') && ((c) <= 'z'))
+#define ksh_isupper(c)	(((c) >= 'A') && ((c) <= 'Z'))
+#define ksh_tolower(c)	(ksh_isupper(c) ? (c) - 'A' + 'a' : (c))
+#define ksh_toupper(c)	(ksh_islower(c) ? (c) - 'a' + 'A' : (c))
+#define ksh_isdash(s)	(((s)[0] == '-') && ((s)[1] == '\0'))
+#define ksh_isspace(c)	((((c) >= 0x09) && ((c) <= 0x0D)) || ((c) == 0x20))
+#define ksh_eq(c,u,l)	(((c) | 0x20) == (l))
+#define ksh_numdig(c)	((c) - ord('0'))
+#define ksh_numuc(c)	((c) - ord('A'))
+#define ksh_numlc(c)	((c) - ord('a'))
 
 EXTERN int ifs0 E_INIT(' ');	/* for "$*" */
 
@@ -1604,6 +1653,13 @@
 EXTERN char **histptr;		/* last history item */
 EXTERN mksh_ari_t histsize;	/* history size */
 
+/* flags to histsave */
+#define HIST_FLUSH	0
+#define HIST_QUEUE	1
+#define HIST_APPEND	2
+#define HIST_STORE	3
+#define HIST_NOTE	4
+
 /* user and system time of last j_waitjed job */
 EXTERN struct timeval j_usrtime, j_systime;
 
@@ -1730,7 +1786,7 @@
 #if HAVE_PERSISTENT_HISTORY
 void hist_finish(void);
 #endif
-void histsave(int *, const char *, bool, bool);
+void histsave(int *, const char *, int, bool);
 #if !defined(MKSH_SMALL) && HAVE_PERSISTENT_HISTORY
 bool histsync(void);
 #endif
@@ -1747,7 +1803,7 @@
 char **hist_get_newest(bool);
 void inittraps(void);
 void alarm_init(void);
-Trap *gettrap(const char *, bool);
+Trap *gettrap(const char *, bool, bool);
 void trapsig(int);
 void intrcheck(void);
 int fatal_trap_check(void);
@@ -1873,7 +1929,7 @@
 void print_value_quoted(struct shf *, const char *);
 char *quote_value(const char *);
 void print_columns(struct shf *, unsigned int,
-    char *(*)(char *, size_t, unsigned int, const void *),
+    void (*)(char *, size_t, unsigned int, const void *),
     const void *, size_t, size_t, bool);
 void strip_nuls(char *, size_t)
     MKSH_A_BOUNDED(__string__, 1, 2);
@@ -2038,6 +2094,33 @@
 
 extern int tty_init_fd(void);	/* initialise tty_fd, tty_devtty */
 
+#ifdef __OS2__
+#ifndef __GNUC__
+# error oops?
+#endif
+#define binopen2(path,flags)		__extension__({			\
+	int binopen2_fd = open((path), (flags) | O_BINARY);		\
+	if (binopen2_fd >= 0)						\
+		setmode(binopen2_fd, O_BINARY);				\
+	(binopen2_fd);							\
+})
+#define binopen3(path,flags,mode)	__extension__({			\
+	int binopen3_fd = open((path), (flags) | O_BINARY, (mode));	\
+	if (binopen3_fd >= 0)						\
+		setmode(binopen3_fd, O_BINARY);				\
+	(binopen3_fd);							\
+})
+#define mksh_abspath(s)			__extension__({			\
+	const char *mksh_abspath_s = (s);				\
+	(mksh_abspath_s[0] == '/' || (ksh_isalphx(mksh_abspath_s[0]) &&	\
+	    mksh_abspath_s[1] == ':'));					\
+})
+#else
+#define binopen2(path,flags)		open((path), (flags) | O_BINARY)
+#define binopen3(path,flags,mode)	open((path), (flags) | O_BINARY, (mode))
+#define mksh_abspath(s)			((s)[0] == '/')
+#endif
+
 /* be sure not to interfere with anyone else's idea about EXTERN */
 #ifdef EXTERN_DEFINED
 # undef EXTERN_DEFINED
diff --git a/src/sh_flags.gen b/src/sh_flags.gen
index cff2e87..7cd0882 100644
--- a/src/sh_flags.gen
+++ b/src/sh_flags.gen
@@ -1,12 +1,11 @@
 #ifndef SHFLAGS_OPTCS
 #if defined(SHFLAGS_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.2 2014/06/09 12:28:19 tg Exp $");
-#define FN(sname,cname,flags,ochar)			static const struct {					/* character flag (if any) */			char c;						/* OF_* */					unsigned char optflags;				/* long name of option */			char name[sizeof(sname)];		} shoptione_ ## cname = {				ochar, flags, sname			};
+__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.3 2015/05/01 23:16:31 tg Exp $");
 #elif defined(SHFLAGS_ENUMS)
 #define FN(sname,cname,flags,ochar)	cname,
 #define F0(sname,cname,flags,ochar)	cname = 0,
 #elif defined(SHFLAGS_ITEMS)
-#define FN(sname,cname,flags,ochar)		((const char *)(&shoptione_ ## cname)) + 2,
+#define FN(sname,cname,flags,ochar)	((const char *)(&shoptione_ ## cname)) + 2,
 #endif
 #ifndef F0
 #define F0 FN
diff --git a/src/sh_flags.opt b/src/sh_flags.opt
index 99e4a22..1d592c5 100644
--- a/src/sh_flags.opt
+++ b/src/sh_flags.opt
@@ -1,11 +1,10 @@
 @SHFLAGS_DEFNS
-__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.2 2014/06/09 12:28:19 tg Exp $");
-#define FN(sname,cname,flags,ochar)			static const struct {					/* character flag (if any) */			char c;						/* OF_* */					unsigned char optflags;				/* long name of option */			char name[sizeof(sname)];		} shoptione_ ## cname = {				ochar, flags, sname			};
+__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.3 2015/05/01 23:16:31 tg Exp $");
 @SHFLAGS_ENUMS
 #define FN(sname,cname,flags,ochar)	cname,
 #define F0(sname,cname,flags,ochar)	cname = 0,
 @SHFLAGS_ITEMS
-#define FN(sname,cname,flags,ochar)		((const char *)(&shoptione_ ## cname)) + 2,
+#define FN(sname,cname,flags,ochar)	((const char *)(&shoptione_ ## cname)) + 2,
 @@
 
 /* special cases */
diff --git a/src/shf.c b/src/shf.c
index cc30442..1c9e3d5 100644
--- a/src/shf.c
+++ b/src/shf.c
@@ -25,7 +25,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.62.2.2 2015/03/01 15:43:07 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.66 2015/07/09 20:52:43 tg Exp $");
 
 /* flags to shf_emptybuf() */
 #define EB_READSW	0x01	/* about to switch to reading */
@@ -62,7 +62,7 @@
 	shf->flags = SHF_ALLOCS;
 	/* Rest filled in by reopen. */
 
-	fd = open(name, oflags | O_BINARY, mode);
+	fd = binopen3(name, oflags, mode);
 	if (fd < 0) {
 		eno = errno;
 		afree(shf, shf->areap);
@@ -847,11 +847,11 @@
 			if (ksh_isdigit(c)) {
 				bool overflowed = false;
 
-				tmp = c - '0';
+				tmp = ksh_numdig(c);
 				while (c = *fmt++, ksh_isdigit(c)) {
 					if (notok2mul(2147483647, tmp, 10))
 						overflowed = true;
-					tmp = tmp * 10 + c - '0';
+					tmp = tmp * 10 + ksh_numdig(c);
 				}
 				--fmt;
 				if (overflowed)
@@ -872,7 +872,7 @@
 			/* nasty format */
 			break;
 
-		if (c >= 'A' && c <= 'Z') {
+		if (ksh_isupper(c)) {
 			flags |= FL_UPPER;
 			c = ksh_tolower(c);
 		}
@@ -917,7 +917,7 @@
 				/* FALLTHROUGH */
 			case 'u':
 				do {
-					*--cp = lnum % 10 + '0';
+					*--cp = digits_lc[lnum % 10];
 					lnum /= 10;
 				} while (lnum);
 
@@ -933,7 +933,7 @@
 
 			case 'o':
 				do {
-					*--cp = (lnum & 0x7) + '0';
+					*--cp = digits_lc[lnum & 0x7];
 					lnum >>= 3;
 				} while (lnum);
 
@@ -945,7 +945,7 @@
 				const char *digits = (flags & FL_UPPER) ?
 				    digits_uc : digits_lc;
 				do {
-					*--cp = digits[lnum & 0xf];
+					*--cp = digits[lnum & 0xF];
 					lnum >>= 4;
 				} while (lnum);
 
@@ -1013,7 +1013,7 @@
 						s++;
 						nwritten++;
 						if (--precision > 0 &&
-						    (*s | 0x20) == 'x') {
+						    ksh_eq(*s, 'X', 'x')) {
 							shf_putc(*s, shf);
 							s++;
 							precision--;
@@ -1025,8 +1025,10 @@
 					c = flags & FL_ZERO ? '0' : ' ';
 				if (field < 0) {
 					nwritten += -field;
-					for ( ; field < 0 ; field++)
+					while (field < 0) {
 						shf_putc(c, shf);
+						++field;
+					}
 				}
 			} else
 				c = ' ';
diff --git a/src/syn.c b/src/syn.c
index 67a8ed7..dafeda9 100644
--- a/src/syn.c
+++ b/src/syn.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.94.2.3 2015/04/12 22:32:35 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.101 2015/04/29 20:07:35 tg Exp $");
 
 struct nesting_state {
 	int start_token;	/* token than began nesting (eg, FOR) */
@@ -214,10 +214,10 @@
 
 		if (iop->unit > 9) {
 			*cp++ = CHAR;
-			*cp++ = '0' + (iop->unit / 10);
+			*cp++ = digits_lc[iop->unit / 10];
 		}
 		*cp++ = CHAR;
-		*cp++ = '0' + (iop->unit % 10);
+		*cp++ = digits_lc[iop->unit % 10];
 		*cp = EOS;
 
 		iop->ioflag &= ~IOBASH;
@@ -243,10 +243,10 @@
 }
 
 static const char let_cmd[] = {
-	CHAR, 'l', CHAR, 'e', CHAR, 't', CHAR, ']', EOS
+	QCHAR, 'l', CHAR, 'e', CHAR, 't', CHAR, ']', EOS
 };
 static const char setA_cmd0[] = {
-	CHAR, 's', CHAR, 'e', CHAR, 't', EOS
+	QCHAR, 's', CHAR, 'e', CHAR, 't', EOS
 };
 static const char setA_cmd1[] = {
 	CHAR, '-', CHAR, 'A', EOS
@@ -712,7 +712,7 @@
 		/* (2 * sizeof(char *)) is small enough */
 		t->left->args = alloc(2 * sizeof(char *), ATEMP);
 		t->left->args[0] = tv = alloc(3, ATEMP);
-		tv[0] = CHAR;
+		tv[0] = QCHAR;
 		tv[1] = ':';
 		tv[2] = EOS;
 		t->left->args[1] = NULL;
@@ -1074,7 +1074,8 @@
 	tv->tv_sec = 0;
 	/* parse integral part */
 	while (ksh_isdigit(*s)) {
-		tt.tv_sec = tv->tv_sec * 10 + (*s++ - '0');
+		tt.tv_sec = tv->tv_sec * 10 + ksh_numdig(*s++);
+		/*XXX this overflow check maybe UB */
 		if (tt.tv_sec / 10 != tv->tv_sec) {
 			errno = EOVERFLOW;
 			return (true);
@@ -1095,7 +1096,7 @@
 	/* parse decimal fraction */
 	i = 100000;
 	while (ksh_isdigit(*s)) {
-		tv->tv_usec += i * (*s++ - '0');
+		tv->tv_usec += i * ksh_numdig(*s++);
 		if (i == 1)
 			break;
 		i /= 10;
diff --git a/src/tree.c b/src/tree.c
index 3a79c15..c057559 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.72.2.1 2015/04/12 22:32:35 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.73 2015/04/11 22:03:32 tg Exp $");
 
 #define INDENT	8
 
diff --git a/src/var.c b/src/var.c
index f4da69a..428192c 100644
--- a/src/var.c
+++ b/src/var.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: var.c,v 1.38 2013/12/20 17:53:09 zhuk Exp $	*/
+/*	$OpenBSD: var.c,v 1.41 2015/04/17 17:20:41 deraadt Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -28,7 +28,7 @@
 #include <sys/sysctl.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.183.2.4 2015/04/19 19:18:23 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.193 2015/07/10 19:36:38 tg Exp $");
 
 /*-
  * Variables
@@ -510,7 +510,7 @@
 	}
 
 	if (c == '0' && arith) {
-		if ((s[0] | 0x20) == 'x') {
+		if (ksh_eq(s[0], 'X', 'x')) {
 			/* interpret as hexadecimal */
 			base = 16;
 			++s;
@@ -547,19 +547,19 @@
 				nump->u = (mksh_uari_t)wc;
 				return (1);
 			} else if (base > 36)
-				return (-1);
+				base = 10;
 			num = 0;
 			have_base = true;
 			continue;
 		}
 		if (ksh_isdigit(c))
-			c -= '0';
-		else {
-			c |= 0x20;
-			if (!ksh_islower(c))
-				return (-1);
-			c -= 'a' - 10;
-		}
+			c = ksh_numdig(c);
+		else if (ksh_isupper(c))
+			c = ksh_numuc(c) + 10;
+		else if (ksh_islower(c))
+			c = ksh_numlc(c) + 10;
+		else
+			return (-1);
 		if (c >= base)
 			return (-1);
 		/* handle overflow as truncation */
@@ -1281,7 +1281,7 @@
 
 			s = str_val(vp);
 			/* LINTED use of access */
-			if (s[0] == '/' && access(s, W_OK|X_OK) == 0 &&
+			if (mksh_abspath(s) && access(s, W_OK|X_OK) == 0 &&
 			    stat(s, &statb) == 0 && S_ISDIR(statb.st_mode))
 				strdupx(tmpdir, s, APERM);
 		}