Merge tag android-5.1.0_r1 into AOSP_5.1_MERGE

Change-Id: I3452a6ecdfee2fffd53835a0259d58b762bc90a5
diff --git a/Android.mk b/Android.mk
index 9989f67..2d572bd 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,18 +1,18 @@
 # Copyright © 2010, 2013
-#	Thorsten Glaser <t.glaser@tarent.de>
+#    Thorsten Glaser <t.glaser@tarent.de>
 # This file is provided under the same terms as mksh.
 
-LOCAL_PATH:=		$(call my-dir)
+LOCAL_PATH := $(call my-dir)
 
 
 # /system/etc/mkshrc
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE:=		mkshrc
-LOCAL_MODULE_CLASS:=	ETC
-LOCAL_MODULE_PATH:=	$(TARGET_OUT)/etc
-LOCAL_SRC_FILES:=	$(LOCAL_MODULE)
+LOCAL_MODULE := mkshrc
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
 
@@ -20,49 +20,65 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE:=		sh
+LOCAL_MODULE := sh
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
 # mksh source files
-LOCAL_SRC_FILES:=	src/lalloc.c src/edit.c src/eval.c src/exec.c \
-			src/expr.c src/funcs.c src/histrap.c src/jobs.c \
-			src/lex.c src/main.c src/misc.c src/shf.c \
-			src/syn.c src/tree.c src/var.c
+LOCAL_SRC_FILES := \
+    src/lalloc.c src/edit.c src/eval.c src/exec.c \
+    src/expr.c src/funcs.c src/histrap.c src/jobs.c \
+    src/lex.c src/main.c src/misc.c src/shf.c \
+    src/syn.c src/tree.c src/var.c
 
-LOCAL_SYSTEM_SHARED_LIBRARIES:= libc
+LOCAL_SYSTEM_SHARED_LIBRARIES := libc
 
-LOCAL_C_INCLUDES:=	$(LOCAL_PATH)/src
-# additional flags first, then from Makefrag.inc: CFLAGS, CPPFLAGS
-LOCAL_CFLAGS:=		-DMKSHRC_PATH=\"/system/etc/mkshrc\" \
-			-DMKSH_DEFAULT_EXECSHELL=\"/system/bin/sh\" \
-			-DMKSH_DEFAULT_TMPDIR=\"/data/local\" \
-		-Wno-deprecated-declarations \
-		-fno-asynchronous-unwind-tables -fwrapv \
-		-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_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_GETTIMEOFDAY=1 -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=481
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/src
 
-# check_categories= shell:legacy-no int:32 android convfds no-histfile
+# Additional flags first...
+LOCAL_CFLAGS += \
+    -DMKSHRC_PATH=\"/system/etc/mkshrc\" \
+    -DMKSH_DEFAULT_EXECSHELL=\"/system/bin/sh\" \
+    -DMKSH_DEFAULT_TMPDIR=\"/data/local\" \
+
+# ...then from Makefrag.inc: CFLAGS...
+LOCAL_CFLAGS += \
+    -Wno-deprecated-declarations \
+    -fno-asynchronous-unwind-tables \
+    -fno-strict-aliasing \
+    -fstack-protector -fwrapv \
+
+# ...and CPPFLAGS.
+LOCAL_CFLAGS += \
+    -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=504
 
 include $(BUILD_EXECUTABLE)
diff --git a/Makefrag.inc b/Makefrag.inc
new file mode 100644
index 0000000..b7a35bd
--- /dev/null
+++ b/Makefrag.inc
@@ -0,0 +1,40 @@
+# Makefile fragment for building mksh R50 2014/10/03
+
+PROG=		mksh
+MAN=		mksh.1
+SRCS=		lalloc.c eval.c exec.c expr.c funcs.c histrap.c jobs.c lex.c main.c misc.c shf.c syn.c tree.c var.c edit.c
+SRCS_FP=	../src/lalloc.c ../src/eval.c ../src/exec.c ../src/expr.c ../src/funcs.c ../src/histrap.c ../src/jobs.c ../src/lex.c ../src/main.c ../src/misc.c ../src/shf.c ../src/syn.c ../src/tree.c ../src/var.c ../src/edit.c
+OBJS_BP=	 lalloc.o eval.o exec.o expr.o funcs.o histrap.o jobs.o lex.o main.o misc.o shf.o syn.o tree.o var.o edit.o
+INDSRCS=	emacsfn.h rlimits.opt sh.h sh_flags.opt var_spec.h
+NONSRCS_INST=	dot.mkshrc $(MAN)
+NONSRCS_NOINST=	Build.sh Makefile Rebuild.sh check.pl check.t test.sh
+CC=		/huge-ssd/aosp-x86_64/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8/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 -fwrapv
+CPPFLAGS=	-I. -I'../src'  -isystem /huge-ssd/aosp-x86_64/bionic/libc/arch-x86/include -isystem /huge-ssd/aosp-x86_64/bionic/libc/include -isystem /huge-ssd/aosp-x86_64/bionic/libc/kernel/uapi -isystem /huge-ssd/aosp-x86_64/bionic/libc/kernel/uapi/asm-x86 -isystem /huge-ssd/aosp-x86_64/bionic/libm/include -isystem /huge-ssd/aosp-x86_64/bionic/libm/include/x86 -D_FORTIFY_SOURCE=2 -I/huge-ssd/aosp-x86_64/build/core/combo/include/arch/linux-x86/ -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=503
+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-x86_64/out/target/product/generic_x86_64/obj/lib/crtbegin_dynamic.o
+LIBS=		 -L/huge-ssd/aosp-x86_64/out/target/product/generic_x86_64/obj/lib -Wl,-rpath-link=/huge-ssd/aosp-x86_64/out/target/product/generic_x86_64/obj/lib -Wl,--no-whole-archive /huge-ssd/aosp-x86_64/out/target/product/generic_x86_64/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a -lc /huge-ssd/aosp-x86_64/out/target/product/generic_x86_64/obj/lib/crtend_android.o
+
+.depend $(OBJS_BP): rlimits.gen sh_flags.gen
+rlimits.gen: ../src/Build.sh ../src/rlimits.opt
+			srcfile=../src/rlimits.opt; BUILDSH_RUN_GENOPT=1; . ../src/Build.sh
+sh_flags.gen: ../src/Build.sh ../src/sh_flags.opt
+			srcfile=../src/sh_flags.opt; BUILDSH_RUN_GENOPT=1; . ../src/Build.sh
+
+# not BSD make only:
+#VPATH=		../src
+#all: $(PROG)
+#$(PROG): $(OBJS_BP)
+#	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS_BP) $(LIBS)
+#$(OBJS_BP): $(SRCS_FP) $(NONSRCS)
+#.c.o:
+#	$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+
+# for all make variants:
+#REGRESS_FLAGS=	-f
+#regress:
+#	./test.sh $(REGRESS_FLAGS)
+check_categories= shell:legacy-no int:32 android convfds no-histfile
+
+# for BSD make only:
+#.PATH: ../src
+#.include <bsd.prog.mk>
diff --git a/mkmf.sh b/mkmf.sh
index f819e0d..fafa34b 100644
--- a/mkmf.sh
+++ b/mkmf.sh
@@ -49,39 +49,27 @@
 # possible to the values used later. (You also must example the
 # results gathered from Makefrag.inc to see they are the same
 # across all Android platforms, or add appropriate ifdefs.)
-# Since we no longer use the NDK, the AOSP has to have been
-# built before using this script (targetting generic/emulator).
+# Since we no longer use the NDK, AOSP has to have been
+# built before using this script.
 
-CC=$aospdir/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin/arm-linux-androideabi-gcc
+CC=$ANDROID_TOOLCHAIN/*-gcc
+
+target_arch=$(cd $ANDROID_BUILD_TOP; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core make --no-print-directory -f build/core/config.mk dumpvar-TARGET_ARCH)
+
 addvar CPPFLAGS \
-    -I$aospdir/libnativehelper/include/nativehelper \
-    -isystem $aospdir/system/core/include \
-    -isystem $aospdir/hardware/libhardware/include \
-    -isystem $aospdir/hardware/libhardware_legacy/include \
-    -isystem $aospdir/hardware/ril/include \
-    -isystem $aospdir/libnativehelper/include \
-    -isystem $aospdir/frameworks/native/include \
-    -isystem $aospdir/frameworks/native/opengl/include \
-    -isystem $aospdir/frameworks/av/include \
-    -isystem $aospdir/frameworks/base/include \
-    -isystem $aospdir/external/skia/include \
-    -isystem $aospdir/out/target/product/generic/obj/include \
-    -isystem $aospdir/bionic/libc/arch-arm/include \
+    -isystem $aospdir/bionic/libc/arch-$target_arch/include \
     -isystem $aospdir/bionic/libc/include \
-    -isystem $aospdir/bionic/libstdc++/include \
     -isystem $aospdir/bionic/libc/kernel/uapi \
-    -isystem $aospdir/bionic/libc/kernel/uapi/asm-arm \
+    -isystem $aospdir/bionic/libc/kernel/uapi/asm-$target_arch \
     -isystem $aospdir/bionic/libm/include \
-    -isystem $aospdir/bionic/libm/include/arm \
-    -isystem $aospdir/bionic/libthread_db/include \
+    -isystem $aospdir/bionic/libm/include/$target_arch \
     -D_FORTIFY_SOURCE=2 \
-    -include $aospdir/build/core/combo/include/arch/linux-arm/AndroidConfig.h \
-    -I$aospdir/build/core/combo/include/arch/linux-arm/ \
+    -include $aospdir/build/core/combo/include/arch/linux-$target_arch/AndroidConfig.h \
+    -I$aospdir/build/core/combo/include/arch/linux-$target_arch/ \
     -DANDROID -DNDEBUG -UDEBUG
 addvar CFLAGS \
     -fno-exceptions \
     -Wno-multichar \
-    -msoft-float \
     -fpic \
     -fPIE \
     -ffunction-sections \
@@ -91,14 +79,10 @@
     -Wa,--noexecstack \
     -Werror=format-security \
     -fno-short-enums \
-    -march=armv7-a \
-    -mfloat-abi=softfp \
-    -mfpu=vfpv3-d16 \
     -Wno-unused-but-set-variable \
     -fno-builtin-sin \
     -fno-strict-volatile-bitfields \
     -Wno-psabi \
-    -mthumb-interwork \
     -fmessage-length=0 \
     -W \
     -Wall \
@@ -114,7 +98,6 @@
     -fgcse-after-reload \
     -frerun-cse-after-loop \
     -frename-registers \
-    -mthumb \
     -Os \
     -fomit-frame-pointer \
     -fno-strict-aliasing
@@ -131,18 +114,15 @@
     -Wl,-z,now \
     -Wl,--warn-shared-textrel \
     -Wl,--fatal-warnings \
-    -Wl,--icf=safe \
-    -Wl,--fix-cortex-a8 \
     -Wl,--no-undefined \
-    $aospdir/out/target/product/generic/obj/lib/crtbegin_dynamic.o
+    $ANDROID_PRODUCT_OUT/obj/lib/crtbegin_dynamic.o
 addvar LIBS \
-    -L$aospdir/out/target/product/generic/obj/lib \
-    -Wl,-rpath-link=$aospdir/out/target/product/generic/obj/lib \
+    -L$ANDROID_PRODUCT_OUT/obj/lib \
+    -Wl,-rpath-link=$ANDROID_PRODUCT_OUT/obj/lib \
     -Wl,--no-whole-archive \
-    $aospdir/out/target/product/generic/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a \
+    $ANDROID_PRODUCT_OUT/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a \
     -lc \
-    $aospdir/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin/../lib/gcc/arm-linux-androideabi/4.7/armv7-a/libgcc.a \
-    $aospdir/out/target/product/generic/obj/lib/crtend_android.o
+    $ANDROID_PRODUCT_OUT/obj/lib/crtend_android.o
 
 
 ### Flags used by test builds
diff --git a/src/Build.sh b/src/Build.sh
index 45af9dd..c59163b 100644
--- a/src/Build.sh
+++ b/src/Build.sh
@@ -1,8 +1,8 @@
 #!/bin/sh
-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.645 2013/08/10 13:44:25 tg Exp $'
+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.669 2014/10/07 15:22:12 tg Exp $'
 #-
 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-#		2011, 2012, 2013
+#		2011, 2012, 2013, 2014
 #	Thorsten Glaser <tg@mirbsd.org>
 #
 # Provided that these terms and disclaimer and all copyright notices
@@ -28,9 +28,6 @@
 LC_ALL=C
 export LC_ALL
 
-echo "For the build logs, demonstrate that /dev/null and /dev/tty exist:"
-ls -l /dev/null /dev/tty
-
 case $ZSH_VERSION:$VERSION in
 :zsh*) ZSH_VERSION=2 ;;
 esac
@@ -46,6 +43,162 @@
 	export PATH
 fi
 
+nl='
+'
+safeIFS='	'
+safeIFS=" $safeIFS$nl"
+IFS=$safeIFS
+allu=QWERTYUIOPASDFGHJKLZXCVBNM
+alll=qwertyuiopasdfghjklzxcvbnm
+alln=0123456789
+alls=______________________________________________________________
+
+genopt_die() {
+	if test -n "$1"; then
+		echo >&2 "E: $*"
+		echo >&2 "E: in '$srcfile': '$line'"
+	else
+		echo >&2 "E: invalid input in '$srcfile': '$line'"
+	fi
+	rm -f "$bn.gen"
+	exit 1
+}
+
+genopt_soptc() {
+	optc=`echo "$line" | sed 's/^[<>]\(.\).*$/\1/'`
+	test x"$optc" = x'|' && return
+	optclo=`echo "$optc" | tr $allu $alll`
+	if test x"$optc" = x"$optclo"; then
+		islo=1
+	else
+		islo=0
+	fi
+	sym=`echo "$line" | sed 's/^[<>]/|/'`
+	o_str=$o_str$nl"<$optclo$islo$sym"
+}
+
+genopt_scond() {
+	case x$cond in
+	x)
+		cond=
+		;;
+	x*' '*)
+		cond=`echo "$cond" | sed 's/^ //'`
+		cond="#if $cond"
+		;;
+	x'!'*)
+		cond=`echo "$cond" | sed 's/^!//'`
+		cond="#ifndef $cond"
+		;;
+	x*)
+		cond="#ifdef $cond"
+		;;
+	esac
+}
+
+do_genopt() {
+	srcfile=$1
+	test -f "$srcfile" || genopt_die Source file \$srcfile not set.
+	bn=`basename "$srcfile" | sed 's/.opt$//'`
+	o_gen=
+	o_str=
+	o_sym=
+	ddefs=
+	state=0
+	exec <"$srcfile"
+	IFS=
+	while IFS= read line; do
+		IFS=$safeIFS
+		case $state:$line in
+		2:'|'*)
+			# end of input
+			o_sym=`echo "$line" | sed 's/^.//'`
+			o_gen=$o_gen$nl"#undef F0"
+			o_gen=$o_gen$nl"#undef FN"
+			o_gen=$o_gen$ddefs
+			state=3
+			;;
+		1:@@)
+			# begin of data block
+			o_gen=$o_gen$nl"#endif"
+			o_gen=$o_gen$nl"#ifndef F0"
+			o_gen=$o_gen$nl"#define F0 FN"
+			o_gen=$o_gen$nl"#endif"
+			state=2
+			;;
+		*:@@*)
+			genopt_die ;;
+		0:@*|1:@*)
+			# begin of a definition block
+			sym=`echo "$line" | sed 's/^@//'`
+			if test $state = 0; then
+				o_gen=$o_gen$nl"#if defined($sym)"
+			else
+				o_gen=$o_gen$nl"#elif defined($sym)"
+			fi
+			ddefs="$ddefs$nl#undef $sym"
+			state=1
+			;;
+		0:*|3:*)
+			genopt_die ;;
+		1:*)
+			# definition line
+			o_gen=$o_gen$nl$line
+			;;
+		2:'<'*'|'*)
+			genopt_soptc
+			;;
+		2:'>'*'|'*)
+			genopt_soptc
+			cond=`echo "$line" | sed 's/^[^|]*|//'`
+			genopt_scond
+			case $optc in
+			'|') optc=0 ;;
+			*) optc=\'$optc\' ;;
+			esac
+			IFS= read line || genopt_die Unexpected EOF
+			IFS=$safeIFS
+			test -n "$cond" && o_gen=$o_gen$nl"$cond"
+			o_gen=$o_gen$nl"$line, $optc)"
+			test -n "$cond" && o_gen=$o_gen$nl"#endif"
+			;;
+		esac
+	done
+	case $state:$o_sym in
+	3:) genopt_die Expected optc sym at EOF ;;
+	3:*) ;;
+	*) genopt_die Missing EOF marker ;;
+	esac
+	echo "$o_str" | sort | while IFS='|' read x opts cond; do
+		IFS=$safeIFS
+		test -n "$x" || continue
+		genopt_scond
+		test -n "$cond" && echo "$cond"
+		echo "\"$opts\""
+		test -n "$cond" && echo "#endif"
+	done | {
+		echo "#ifndef $o_sym$o_gen"
+		echo "#else"
+		cat
+		echo "#undef $o_sym"
+		echo "#endif"
+	} >"$bn.gen"
+	IFS=$safeIFS
+	return 0
+}
+
+if test x"$BUILDSH_RUN_GENOPT" = x"1"; then
+	set x -G "$srcfile"
+	shift
+fi
+if test x"$1" = x"-G"; then
+	do_genopt "$2"
+	exit $?
+fi
+
+echo "For the build logs, demonstrate that /dev/null and /dev/tty exist:"
+ls -l /dev/null /dev/tty
+
 v() {
 	$e "$*"
 	eval "$@"
@@ -66,18 +219,12 @@
 rmf() {
 	for _f in "$@"; do
 		case $_f in
-		Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|*.ico|*.1) ;;
+		Build.sh|check.pl|check.t|dot.mkshrc|*.1|*.c|*.h|*.ico|*.opt) ;;
 		*) rm -f "$_f" ;;
 		esac
 	done
 }
 
-allu=QWERTYUIOPASDFGHJKLZXCVBNM
-alll=qwertyuiopasdfghjklzxcvbnm
-alln=0123456789
-alls=______________________________________________________________
-nl='
-'
 tcfn=no
 bi=
 ui=
@@ -193,8 +340,9 @@
 ac_ifcpp() {
 	expr=$1; shift
 	ac_testn "$@" <<-EOF
+		#include <unistd.h>
 		extern int thiswillneverbedefinedIhope(void);
-		int main(void) { return (
+		int main(void) { return (isatty(0) +
 		#$expr
 		    0
 		#else
@@ -251,7 +399,8 @@
 	else
 		ac_testn can_$vn '' "$ft" <<-'EOF'
 			/* evil apo'stroph in comment test */
-			int main(void) { return (0); }
+			#include <unistd.h>
+			int main(void) { return (isatty(0)); }
 		EOF
 	fi
 	eval fv=\$HAVE_CAN_`upper $vn`
@@ -291,19 +440,14 @@
 		esac
 	done
 	echo "#include <$hf>" >>x
-	echo 'int main(void) { return (0); }' >>x
+	echo '#include <unistd.h>' >>x
+	echo 'int main(void) { return (isatty(0)); }' >>x
 	ac_testn "$hv" "" "<$hf>" <x
 	rmf x
 	test 1 = $na || ac_cppflags
 }
 
 addsrcs() {
-	addsrcs_s=0
-	if test x"$1" = x"-s"; then
-		# optstatic
-		addsrcs_s=1
-		shift
-	fi
 	if test x"$1" = x"!"; then
 		fr=0
 		shift
@@ -311,13 +455,6 @@
 		fr=1
 	fi
 	eval i=\$$1
-	if test $addsrcs_s = 1; then
-		if test -f "$2" || test -f "$srcdir/$2"; then
-			# always add $2, since it exists
-			fr=1
-			i=1
-		fi
-	fi
 	test $fr = "$i" && case " $SRCS " in
 	*\ $2\ *)	;;
 	*)		SRCS="$SRCS $2" ;;
@@ -325,9 +462,21 @@
 }
 
 
-curdir=`pwd` srcdir=`dirname "$0" 2>/dev/null` check_categories=
-test -n "$srcdir" || srcdir=. # in case dirname does not exist
-dstversion=`sed -n '/define MKSH_VERSION/s/^.*"\([^"]*\)".*$/\1/p' $srcdir/sh.h`
+curdir=`pwd` srcdir=`dirname "$0" 2>/dev/null`
+case x$srcdir in
+x)
+	srcdir=.
+	;;
+*\ *|*"	"*|*"$nl"*)
+	echo >&2 Source directory should not contain space or tab or newline.
+	echo >&2 Errors may occur.
+	;;
+*"'"*)
+	echo Source directory must not contain single quotes.
+	exit 1
+	;;
+esac
+dstversion=`sed -n '/define MKSH_VERSION/s/^.*"\([^"]*\)".*$/\1/p' "$srcdir/sh.h"`
 add_cppflags -DMKSH_BUILDSH
 
 e=echo
@@ -336,6 +485,7 @@
 pm=0
 cm=normal
 optflags=-std-compile-opts
+check_categories=
 last=
 tfn=
 legacy=0
@@ -362,6 +512,10 @@
 	:-c)
 		last=c
 		;;
+	:-G)
+		echo "$me: Do not call me with '-G'!" >&2
+		exit 1
+		;;
 	:-g)
 		# checker, debug, valgrind build
 		add_cppflags -DDEBUG
@@ -423,7 +577,7 @@
 	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 \
+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
 
 SRCS="lalloc.c eval.c exec.c expr.c funcs.c histrap.c jobs.c"
@@ -462,7 +616,7 @@
 ccpc=-Wc,
 ccpl=-Wl,
 tsts=
-ccpr='|| for _f in ${tcfn}*; do case $_f in Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|*.ico|*.1) ;; *) rm -f "$_f" ;; esac; done'
+ccpr='|| for _f in ${tcfn}*; do case $_f in Build.sh|check.pl|check.t|dot.mkshrc|*.1|*.c|*.h|*.ico|*.opt) ;; *) rm -f "$_f" ;; esac; done'
 
 # Evil hack
 if test x"$TARGET_OS" = x"Android"; then
@@ -786,7 +940,12 @@
 	;;
 Darwin)
 	vv '|' "hwprefs machine_type os_type os_class >&2"
+	vv '|' "sw_vers >&2"
+	vv '|' "system_profiler SPSoftwareDataType SPHardwareDataType >&2"
+	vv '|' "/bin/sh --version >&2"
+	vv '|' "xcodebuild -version >&2"
 	vv '|' "uname -a >&2"
+	vv '|' "sysctl kern.version hw.machine hw.model hw.memsize hw.availcpu hw.cpufrequency hw.byteorder hw.cpu64bit_capable >&2"
 	;;
 IRIX*)
 	vv '|' "uname -a >&2"
@@ -905,7 +1064,10 @@
 sed 's/^/[ /' x
 eval `cat x`
 rmf x vv.out
-echo 'int main(void) { return (0); }' >conftest.c
+cat >conftest.c <<'EOF'
+#include <unistd.h>
+int main(void) { return (isatty(0)); }
+EOF
 case $ct in
 ack)
 	# work around "the famous ACK const bug"
@@ -1091,13 +1253,15 @@
 	dec)
 		CFLAGS="$CFLAGS ${ccpl}-non_shared"
 		ac_testn can_delexe compiler_fails 0 'for the -non_shared linker option' <<-EOF
-			int main(void) { return (0); }
+			#include <unistd.h>
+			int main(void) { return (isatty(0)); }
 		EOF
 		;;
 	dmc)
 		CFLAGS="$CFLAGS ${ccpl}/DELEXECUTABLE"
 		ac_testn can_delexe compiler_fails 0 'for the /DELEXECUTABLE linker option' <<-EOF
-			int main(void) { return (0); }
+			#include <unistd.h>
+			int main(void) { return (isatty(0)); }
 		EOF
 		;;
 	*)
@@ -1193,7 +1357,8 @@
 	;;
 sunpro)
 	cat >x <<-'EOF'
-		int main(void) { return (0); }
+		#include <unistd.h>
+		int main(void) { return (isatty(0)); }
 		#define __IDSTRING_CONCAT(l,p)	__LINTED__ ## l ## _ ## p
 		#define __IDSTRING_EXPAND(l,p)	__IDSTRING_CONCAT(l,p)
 		#define pad			void __IDSTRING_EXPAND(__LINE__,x)(void) { }
@@ -1235,7 +1400,9 @@
 	# mksh is not written in CFrustFrust!
 	ac_flags 1 no_eh_frame -fno-asynchronous-unwind-tables
 	ac_flags 1 fnostrictaliasing -fno-strict-aliasing
-	ac_flags 1 fstackprotectorall -fstack-protector-all
+	ac_flags 1 fstackprotectorstrong -fstack-protector-strong
+	test 1 = $HAVE_CAN_FSTACKPROTECTORSTRONG || \
+	    ac_flags 1 fstackprotectorall -fstack-protector-all
 	test $cm = dragonegg && case " $CC $CFLAGS $LDFLAGS " in
 	*\ -fplugin=*dragonegg*) ;;
 	*) ac_flags 1 fplugin_dragonegg -fplugin=dragonegg ;;
@@ -1356,8 +1523,8 @@
 	#include <string.h>
 	#undef __attribute__
 	int xcopy(const void *, void *, size_t)
-	    __attribute__((__bounded__ (__buffer__, 1, 3)))
-	    __attribute__((__bounded__ (__buffer__, 2, 3)));
+	    __attribute__((__bounded__(__buffer__, 1, 3)))
+	    __attribute__((__bounded__(__buffer__, 2, 3)));
 	int main(int ac, char *av[]) { return (xcopy(av[0], av[--ac], 1)); }
 	int xcopy(const void *s, void *d, size_t n) {
 		/*
@@ -1379,7 +1546,7 @@
 	#undef __attribute__
 	#undef fprintf
 	extern int fprintf(FILE *, const char *format, ...)
-	    __attribute__((__format__ (__printf__, 2, 3)));
+	    __attribute__((__format__(__printf__, 2, 3)));
 	int main(int ac, char **av) { return (fprintf(stderr, "%s%d", *av, ac)); }
 	#endif
 EOF
@@ -1396,14 +1563,29 @@
 	void fnord(void) { exit(0); }
 	#endif
 EOF
+ac_test attribute_pure '' 'for __attribute__((__pure__))' <<-'EOF'
+	#if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
+	extern int thiswillneverbedefinedIhope(void);
+	/* force a failure: TenDRA and gcc 1.42 have false positive here */
+	int main(void) { return (thiswillneverbedefinedIhope()); }
+	#else
+	#include <unistd.h>
+	#undef __attribute__
+	int foo(const char *) __attribute__((__pure__));
+	int main(int ac, char **av) { return (foo(av[ac - 1]) + isatty(0)); }
+	int foo(const char *s) { return ((int)s[0]); }
+	#endif
+EOF
 ac_test attribute_unused '' 'for __attribute__((__unused__))' <<-'EOF'
 	#if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
 	extern int thiswillneverbedefinedIhope(void);
 	/* force a failure: TenDRA and gcc 1.42 have false positive here */
 	int main(void) { return (thiswillneverbedefinedIhope()); }
 	#else
+	#include <unistd.h>
+	#undef __attribute__
 	int main(int ac __attribute__((__unused__)), char **av
-	    __attribute__((__unused__))) { return (0); }
+	    __attribute__((__unused__))) { return (isatty(0)); }
 	#endif
 EOF
 ac_test attribute_used '' 'for __attribute__((__used__))' <<-'EOF'
@@ -1412,8 +1594,10 @@
 	/* force a failure: TenDRA and gcc 1.42 have false positive here */
 	int main(void) { return (thiswillneverbedefinedIhope()); }
 	#else
+	#include <unistd.h>
+	#undef __attribute__
 	static const char fnord[] __attribute__((__used__)) = "42";
-	int main(void) { return (0); }
+	int main(void) { return (isatty(0)); }
 	#endif
 EOF
 
@@ -1465,7 +1649,8 @@
 	#include <sys/types.h>
 	#include <sys/time.h>
 	#include <time.h>
-	int main(void) { struct tm tm; return ((int)sizeof(tm)); }
+	#include <unistd.h>
+	int main(void) { struct tm tm; return ((int)sizeof(tm) + isatty(0)); }
 EOF
 ac_header sys/bsdtypes.h
 ac_header sys/file.h sys/types.h
@@ -1491,11 +1676,12 @@
 # Environment: definitions
 #
 echo '#include <sys/types.h>
+#include <unistd.h>
 /* check that off_t can represent 2^63-1 correctly, thx FSF */
-#define LARGE_OFF_T (((off_t)1 << 62) - 1 + ((off_t)1 << 62))
+#define LARGE_OFF_T ((((off_t)1 << 31) << 31) - 1 + (((off_t)1 << 31) << 31))
 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 &&
     LARGE_OFF_T % 2147483647 == 1) ? 1 : -1];
-int main(void) { return (0); }' >lft.c
+int main(void) { return (isatty(0)); }' >lft.c
 ac_testn can_lfs '' "for large file support" <lft.c
 save_CPPFLAGS=$CPPFLAGS
 add_cppflags -D_FILE_OFFSET_BITS=64
@@ -1546,7 +1732,7 @@
 	#include <sys/resource.h>
 	#endif
 	#include <unistd.h>
-	int main(void) { return ((int)(rlim_t)0); }
+	int main(void) { return (((int)(rlim_t)0) + isatty(0)); }
 EOF
 
 # only testn: added later below
@@ -1598,8 +1784,8 @@
 		#define EXTERN
 		#define MKSH_INCLUDES_ONLY
 		#include "sh.h"
-		__RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.645 2013/08/10 13:44:25 tg Exp $");
-		int main(void) { printf("Hello, World!\n"); return (0); }
+		__RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.669 2014/10/07 15:22:12 tg Exp $");
+		int main(void) { printf("Hello, World!\n"); return (isatty(0)); }
 EOF
 	case $cm in
 	llvm)
@@ -1638,12 +1824,14 @@
 ac_testn sys_errlist '' "the sys_errlist[] array and sys_nerr" <<-'EOF'
 	extern const int sys_nerr;
 	extern const char * const sys_errlist[];
-	int main(void) { return (*sys_errlist[sys_nerr - 1]); }
+	extern int isatty(int);
+	int main(void) { return (*sys_errlist[sys_nerr - 1] + isatty(0)); }
 EOF
 ac_testn _sys_errlist '!' sys_errlist 0 "the _sys_errlist[] array and _sys_nerr" <<-'EOF'
 	extern const int _sys_nerr;
 	extern const char * const _sys_errlist[];
-	int main(void) { return (*_sys_errlist[_sys_nerr - 1]); }
+	extern int isatty(int);
+	int main(void) { return (*_sys_errlist[_sys_nerr - 1] + isatty(0)); }
 EOF
 if test 1 = "$HAVE__SYS_ERRLIST"; then
 	add_cppflags -Dsys_nerr=_sys_nerr
@@ -1656,11 +1844,13 @@
 	uwhat=`upper $what`
 	ac_testn sys_sig$what '' "the sys_sig${what}[] array" <<-EOF
 		extern const char * const sys_sig${what}[];
-		int main(void) { return (sys_sig${what}[0][0]); }
+		extern int isatty(int);
+		int main(void) { return (sys_sig${what}[0][0] + isatty(0)); }
 	EOF
 	ac_testn _sys_sig$what '!' sys_sig$what 0 "the _sys_sig${what}[] array" <<-EOF
 		extern const char * const _sys_sig${what}[];
-		int main(void) { return (_sys_sig${what}[0][0]); }
+		extern int isatty(int);
+		int main(void) { return (_sys_sig${what}[0][0] + isatty(0)); }
 	EOF
 	eval uwhat_v=\$HAVE__SYS_SIG$uwhat
 	if test 1 = "$uwhat_v"; then
@@ -1703,12 +1893,22 @@
 	}
 EOF
 
+ac_test getsid <<-'EOF'
+	#include <unistd.h>
+	int main(void) { return ((int)getsid(0)); }
+EOF
+
 ac_test gettimeofday <<-'EOF'
 	#define MKSH_INCLUDES_ONLY
 	#include "sh.h"
 	int main(void) { struct timeval tv; return (gettimeofday(&tv, NULL)); }
 EOF
 
+ac_test issetugid <<-'EOF'
+	#include <unistd.h>
+	int main(void) { return (issetugid()); }
+EOF
+
 ac_test killpg <<-'EOF'
 	#include <signal.h>
 	int main(int ac, char *av[]) { return (av[0][killpg(123, ac)]); }
@@ -1722,7 +1922,7 @@
 	#include <strings.h>
 	#endif
 	int main(int ac, char *av[]) {
-		return (*(int *)(void *)memmove(av[0], av[1], ac));
+		return (*(int *)(void *)memmove(av[0], av[1], (size_t)ac));
 	}
 EOF
 
@@ -1894,12 +2094,12 @@
 ac_test sys_errlist_decl sys_errlist 0 "for declaration of sys_errlist[] and sys_nerr" <<-'EOF'
 	#define MKSH_INCLUDES_ONLY
 	#include "sh.h"
-	int main(void) { return (*sys_errlist[sys_nerr - 1]); }
+	int main(void) { return (*sys_errlist[sys_nerr - 1] + isatty(0)); }
 EOF
 ac_test sys_siglist_decl sys_siglist 0 'for declaration of sys_siglist[]' <<-'EOF'
 	#define MKSH_INCLUDES_ONLY
 	#include "sh.h"
-	int main(void) { return (sys_siglist[0][0]); }
+	int main(void) { return (sys_siglist[0][0] + isatty(0)); }
 EOF
 
 #
@@ -1970,7 +2170,7 @@
 		char padding[64 - NUM];
 	};
 char ctasserts_dblcheck[sizeof(struct ctasserts) == 64 ? 1 : -1];
-	int main(void) { return (sizeof(ctasserts_dblcheck)); }
+	int main(void) { return (sizeof(ctasserts_dblcheck) + isatty(0)); }
 EOF
 CFLAGS=$save_CFLAGS
 eval test 1 = \$HAVE_COMPILE_TIME_ASSERTS_$$ || exit 1
@@ -2054,6 +2254,9 @@
 #define NSIG (SIGMAX+1)
 #elif defined(_SIGMAX)
 #define NSIG (_SIGMAX+1)
+#else
+/* XXX better error out, see sh.h */
+#define NSIG 64
 #endif
 #endif
 int
@@ -2072,9 +2275,10 @@
 	test $printf = echo || test "`printf %d 42`" = 42 || printf=echo
 	test $printf = echo || NSIG=`printf %d "$NSIG" 2>/dev/null`
 	$printf "NSIG=$NSIG ... "
-	sigs="INT SEGV ABRT KILL ALRM BUS CHLD CLD CONT DIL EMT FPE HUP ILL"
-	sigs="$sigs INFO IO IOT LOST PIPE PROF PWR QUIT RESV SAK STOP SYS TERM"
-	sigs="$sigs TRAP TSTP TTIN TTOU URG USR1 USR2 VTALRM WINCH XCPU XFSZ"
+	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"
 	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]*[	 ]' | \
@@ -2108,12 +2312,11 @@
 	$e done.
 fi
 
-addsrcs -s '!' HAVE_STRLCPY strlcpy.c
+addsrcs '!' HAVE_STRLCPY strlcpy.c
 addsrcs USE_PRINTF_BUILTIN printf.c
 test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
 test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
-test -n "$LDSTATIC" && add_cppflags -DMKSH_OPTSTATIC
-add_cppflags -DMKSH_BUILD_R=481
+add_cppflags -DMKSH_BUILD_R=504
 
 $e $bi$me: Finished configuration testing, now producing output.$ao
 
@@ -2175,6 +2378,10 @@
 	fi
 	(( vflag )) && args[\${#args[*]}]=-v
 	(( xflag )) && args[\${#args[*]}]=-x	# force usage by synerr
+	if [[ -n \$TMPDIR && -d \$TMPDIR/. ]]; then
+		args[\${#args[*]}]=-T
+		args[\${#args[*]}]=\$TMPDIR
+	fi
 	print Testing mksh for conformance:
 	fgrep -e MirOS: -e MIRBSD "\$sflag"
 	print "This shell is actually:\\n\\t\$KSH_VERSION"
@@ -2224,6 +2431,10 @@
 	;;
 esac
 echo ": # work around NeXTstep bug" >Rebuild.sh
+for file in "$srcdir"/*.opt; do
+	echo "echo + Running genopt on '$file'..."
+	echo "(srcfile='$file'; BUILDSH_RUN_GENOPT=1; . '$srcdir/Build.sh')"
+done >>Rebuild.sh
 echo set -x >>Rebuild.sh
 for file in $SRCS; do
 	op=`echo x"$file" | sed 's/^x\(.*\)\.c$/\1./'`
@@ -2253,8 +2464,15 @@
 echo "$CC $CFLAGS $LDFLAGS -o \$tcfn $lobjs $LIBS $ccpr" >>Rebuild.sh
 echo "test -f \$tcfn || exit 1; $SIZE \$tcfn" >>Rebuild.sh
 if test $cm = makefile; then
-	extras='emacsfn.h sh.h sh_flags.h var_spec.h'
+	extras='emacsfn.h rlimits.opt sh.h sh_flags.opt var_spec.h'
 	test 0 = $HAVE_SYS_SIGNAME && extras="$extras signames.inc"
+	gens= genq=
+	for file in "$srcdir"/*.opt; do
+		genf=`basename "$file" | sed 's/.opt$/.gen/'`
+		gens="$gens $genf"
+		genq="$genq$nl$genf: $srcdir/Build.sh $file
+			srcfile=$file; BUILDSH_RUN_GENOPT=1; . $srcdir/Build.sh"
+	done
 	cat >Makefrag.inc <<EOF
 # Makefile fragment for building mksh $dstversion
 
@@ -2272,6 +2490,8 @@
 LDFLAGS=	$LDFLAGS
 LIBS=		$LIBS
 
+.depend \$(OBJS_BP):$gens$genq
+
 # not BSD make only:
 #VPATH=		$srcdir
 #all: \$(PROG)
@@ -2295,6 +2515,10 @@
 	$e Generated Makefrag.inc successfully.
 	exit 0
 fi
+for file in "$srcdir"/*.opt; do
+	$e "+ Running genopt on '$file'..."
+	do_genopt "$file" || exit 1
+done
 if test $cm = combine; then
 	objs="-o $mkshexe"
 	for file in $SRCS; do
@@ -2402,7 +2626,7 @@
 MKSH_DONT_EMIT_IDSTRING		omit RCS IDs from binary
 MKSH_MIDNIGHTBSD01ASH_COMPAT	set -o sh: additional compatibility quirk
 MKSH_NOPROSPECTOFWORK		disable jobs, co-processes, etc. (do not use)
-MKSH_NOPWNAM			skip PAM calls, for -static on eglibc, Solaris
+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
@@ -2429,7 +2653,7 @@
 Copy dot.mkshrc to /etc/skel/.mkshrc; install mksh into $prefix/bin; or
 /bin; install the manpage, if omitting the -r flag a catmanpage is made
 using $NROFF. Consider using a forward script as /etc/skel/.mkshrc like
-https://www.mirbsd.org/cvs.cgi/contrib/hosted/tg/deb/mksh/debian/.mkshrc?rev=HEAD
+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.
 
 EOD
diff --git a/src/check.pl b/src/check.pl
index ecd8f8d..d688509 100644
--- a/src/check.pl
+++ b/src/check.pl
@@ -1,8 +1,8 @@
-# $MirOS: src/bin/mksh/check.pl,v 1.32 2013/07/21 18:35:56 tg Exp $
-# $OpenBSD: th,v 1.16 2013/06/14 20:52:08 millert Exp $
+# $MirOS: src/bin/mksh/check.pl,v 1.37 2014/08/19 07:43:32 tg Exp $
+# $OpenBSD: th,v 1.1 2013/12/02 20:39:44 millert Exp $
 #-
 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
-#		2012, 2013
+#		2012, 2013, 2014
 #	Thorsten Glaser <tg@mirbsd.org>
 #
 # Provided that these terms and disclaimer and all copyright notices
@@ -172,7 +172,6 @@
 
 use Getopt::Std;
 use Config;
-use File::Temp qw/ :mktemp /;
 
 $os = defined $^O ? $^O : 'unknown';
 
@@ -251,7 +250,7 @@
 $test_prog = $opt_p;
 $verbose = defined $opt_v && $opt_v;
 $test_set = $opt_s;
-$temp_dir = $opt_T || "/tmp";
+$temp_base = $opt_T || "/tmp";
 if (defined $opt_t) {
     die "$prog: bad -t argument (should be number > 0): $opt_t\n"
 	if $opt_t !~ /^\d+$/ || $opt_t <= 0;
@@ -300,6 +299,18 @@
 die "$prog: couldn't get current working directory\n" if $pwd eq '';
 die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd);
 
+die "$prog: couldn't cd to $temp_base - $!\n" if !chdir($temp_base);
+die "$prog: couldn't get temporary directory base\n" unless -d '.';
+$temps = sprintf("chk%d-%d.", $$, time());
+$tempi = 0;
+until (mkdir(($tempdir = sprintf("%s%03d", $temps, $tempi)), 0700)) {
+    die "$prog: couldn't get temporary directory\n" if $tempi++ >= 999;
+}
+die "$prog: couldn't cd to $tempdir - $!\n" if !chdir($tempdir);
+chop($temp_dir = `pwd 2>/dev/null`);
+die "$prog: couldn't get temporary directory\n" if $temp_dir eq '';
+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 '/';
     die "$prog: $test_prog is not executable - bye\n"
@@ -314,15 +325,12 @@
 $| = 1;
 
 # Create temp files
-($fh, $temps) = mkstemp("${temp_dir}/rts.XXXXXXXX");
-close($fh);
-($fh, $tempi) = mkstemp("${temp_dir}/rti.XXXXXXXX");
-close($fh);
-($fh, $tempo) = mkstemp("${temp_dir}/rto.XXXXXXXX");
-close($fh);
-($fh, $tempe) = mkstemp("${temp_dir}/rte.XXXXXXXX");
-close($fh);
-$tempdir = mkdtemp("${temp_dir}/rtd.XXXXXXXX");
+$temps = "${temp_dir}/rts";
+$tempi = "${temp_dir}/rti";
+$tempo = "${temp_dir}/rto";
+$tempe = "${temp_dir}/rte";
+$tempdir = "${temp_dir}/rtd";
+mkdir($tempdir, 0700) or die "$prog: couldn't mkdir $tempdir - $!\n";
 
 if (-d $test_set) {
     $file_prefix_skip = length($test_set) + 1;
@@ -340,6 +348,7 @@
     print " ($nifailed ignored)" if $nifailed;
     print " ($nxfailed unexpected)" if $nxfailed;
     print " (as expected)" if $nfailed && !$nxfailed && !$nifailed;
+    print " ($nfailed expected)" if $nfailed && ($nxfailed || $nifailed);
     print "\nTotal passed: $tot_passed";
     print " ($nxpassed unexpected)" if $nxpassed;
     print "\n";
@@ -365,6 +374,7 @@
     unlink($tempi, $tempo, $tempe, $temps);
     &scrub_dir($tempdir) if defined $tempdir;
     rmdir($tempdir) if defined $tempdir;
+    rmdir($temp_dir) if defined $temp_dir;
 
     if ($sig) {
 	$SIG{$sig} = 'DEFAULT';
@@ -903,7 +913,7 @@
     } else {
 	$expr = $expect;
 	$expr =~ s/\b([wse])\b/\$$1/g;
-	$expr =~ s/\b(SIG[A-Z0-9]+)\b/&$1/g;
+	$expr =~ s/\b(SIG[A-Z][A-Z0-9]*)\b/&$1/g;
     }
     $w = eval $expr;
     if ($@ ne '') {
@@ -923,12 +933,13 @@
     %test = ();
     %cnt = ();
     while (<$in>) {
+	chop;
 	next if /^\s*$/;
 	next if /^ *#/;
 	last if /^\s*---\s*$/;
 	$start_lineno = $. if !defined $start_lineno;
 	if (!/^([-\w]+):\s*(|\S|\S.*\S)\s*$/) {
-	    print STDERR "$prog:$file:$.: unrecognised line\n";
+	    print STDERR "$prog:$file:$.: unrecognised line \"$_\"\n";
 	    return undef;
 	}
 	($field, $val) = ($1, $2);
@@ -1154,7 +1165,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-Z0-9]+\b)+$/) {
+	} elsif ($val !~ /^([\s<>+-=*%\/&|!()]|\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 8df826f..2e1d032 100644
--- a/src/check.t
+++ b/src/check.t
Binary files differ
diff --git a/src/dot.mkshrc b/src/dot.mkshrc
index cbd13ed..233a10c 100644
--- a/src/dot.mkshrc
+++ b/src/dot.mkshrc
@@ -1,8 +1,8 @@
 # $Id$
-# $MirOS: src/bin/mksh/dot.mkshrc,v 1.84 2013/08/10 13:43:50 tg Exp $
+# $MirOS: src/bin/mksh/dot.mkshrc,v 1.89 2014/07/28 21:45:44 tg Exp $
 #-
 # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
-#		2011, 2012, 2013
+#		2011, 2012, 2013, 2014
 #	Thorsten Glaser <tg@mirbsd.org>
 #
 # Provided that these terms and disclaimer and all copyright notices
@@ -105,14 +105,14 @@
 }
 chpwd .
 function cd {
-	builtin cd "$@"
+	builtin cd "$@" || return $?
 	chpwd "$@"
 }
 function cd_csh {
 	local d t=${1/#~/$DIRSTACKBASE}
 
 	if ! d=$(builtin cd "$t" 2>&1); then
-		print -u2 "${1}: ${d##*$t - }."
+		print -u2 "${1}: ${d##*cd: $t: }."
 		return 1
 	fi
 	cd "$t"
@@ -242,20 +242,23 @@
 
 # pager (not control character safe)
 function smores {
-	local dummy line llen curlin=0
-
-	cat "$@" | while IFS= read -r 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 dummy
-			[[ $dummy = [Qq]* ]] && return 0
-			curlin=$llen
-		fi
-		print -r -- "$line"
-	done
+	(
+		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
+				curlin=$llen
+			fi
+			print -r -- "$line"
+		done
+	)
 }
 
 # base64 encoder and decoder, RFC compliant, NUL safe
@@ -333,9 +336,12 @@
 	(( u )) || set -U
 }
 
-# mksh NUL counting, never zero
-typeset -Z11 -Uui16 Lnzathash_v
-function Lnzathash_add {
+# Better Avalanche for the Jenkins Hash
+typeset -Z11 -Uui16 Lbafh_v
+function Lbafh_init {
+	Lbafh_v=0
+}
+function Lbafh_add {
 	[[ -o utf8-mode ]]; local u=$?
 	set +U
 	local s
@@ -348,37 +354,20 @@
 	local -i i=0 n=${#s[*]}
 
 	while (( i < n )); do
-		((# Lnzathash_v = (Lnzathash_v + s[i++] + 1) * 1025 ))
-		((# Lnzathash_v ^= Lnzathash_v >> 6 ))
+		((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 ))
+		((# Lbafh_v ^= Lbafh_v >> 6 ))
 	done
 
 	(( u )) || set -U
 }
-function Lnzaathash_end {
-	((# Lnzathash_v *= 1025 ))
-	((# Lnzathash_v ^= Lnzathash_v >> 6 ))
-	((# Lnzathash_v += Lnzathash_v << 3 ))
-	((# Lnzathash_v = (Lnzathash_v ^
-	    (Lnzathash_v >> 11)) * 32769 ))
-	print ${Lnzathash_v#16#}
-}
-function Lnzaathash {
-	Lnzathash_v=0
-	Lnzathash_add "$@"
-	Lnzaathash_end
-}
-function Lnzathash {
-	Lnzathash_v=0
-	Lnzathash_add "$@"
-	Lnzathash_end
-}
-function Lnzathash_end {
-	if (( Lnzathash_v )); then
-		Lnzaathash_end
-	else
-		Lnzathash_v=1
-		print ${Lnzathash_v#16#}
-	fi
+function Lbafh_finish {
+	local -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
diff --git a/src/edit.c b/src/edit.c
index 675e7ed..ee5ed5c 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -1,11 +1,11 @@
-/*	$OpenBSD: edit.c,v 1.38 2013/06/03 15:41:59 tedu Exp $	*/
+/*	$OpenBSD: edit.c,v 1.39 2013/12/17 16:37:05 deraadt Exp $	*/
 /*	$OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $	*/
-/*	$OpenBSD: emacs.c,v 1.44 2011/09/05 04:50:33 marco Exp $	*/
-/*	$OpenBSD: vi.c,v 1.26 2009/06/29 22:50:19 martynas Exp $	*/
+/*	$OpenBSD: emacs.c,v 1.48 2013/12/17 16:37:05 deraadt Exp $	*/
+/*	$OpenBSD: vi.c,v 1.28 2013/12/18 16:45:46 deraadt Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013
+ *		 2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -28,7 +28,7 @@
 
 #ifndef MKSH_NO_CMDLINE_EDITING
 
-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.270 2013/08/14 20:26:17 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.276 2014/07/13 11:34:28 tg Exp $");
 
 /*
  * in later versions we might use libtermcap for this, but since external
@@ -82,7 +82,7 @@
 static void x_free_words(int, char **);
 static int x_escape(const char *, size_t, int (*)(const char *, size_t));
 static int x_emacs(char *);
-static void x_init_prompt(void);
+static void x_init_prompt(bool);
 #if !MKSH_S_NOVI
 static int x_vi(char *);
 #endif
@@ -148,6 +148,7 @@
 				if (x_cols != xx_cols && editmode == 1) {
 					/* redraw line in Emacs mode */
 					xx_cols = x_cols;
+					x_init_prompt(false);
 					x_e_rebuildline(MKSH_CLRTOEOL_STRING);
 				}
 			}
@@ -960,12 +961,11 @@
 static size_t x_bword(void);
 static size_t x_fword(bool);
 static void x_goto(char *);
-static char *x_bs0(char *, char *);
+static char *x_bs0(char *, char *) MKSH_A_PURE;
 static void x_bs3(char **);
 static int x_size_str(char *);
 static int x_size2(char *, char **);
 static void x_zots(char *);
-static void x_zotc2(int);
 static void x_zotc3(char **);
 static void x_load_hist(char **);
 static int x_search(char *, int, int);
@@ -990,7 +990,7 @@
 #endif
 static char *x_lastcp(void);
 static void do_complete(int, Comp_type);
-static size_t x_nb2nc(size_t);
+static size_t x_nb2nc(size_t) MKSH_A_PURE;
 
 static int unget_char = -1;
 
@@ -1167,16 +1167,17 @@
 }
 
 static void
-x_init_prompt(void)
+x_init_prompt(bool doprint)
 {
-	prompt_trunc = pprompt(prompt, 0);
+	prompt_trunc = pprompt(prompt, doprint ? 0 : -1);
 	pwidth = prompt_trunc % x_cols;
 	prompt_trunc -= pwidth;
 	if ((mksh_uari_t)pwidth > ((mksh_uari_t)x_cols - 3 - MIN_EDIT_SPACE)) {
 		/* force newline after prompt */
 		prompt_trunc = -1;
 		pwidth = 0;
-		x_e_putc2('\n');
+		if (doprint)
+			x_e_putc2('\n');
 	}
 }
 
@@ -1196,7 +1197,7 @@
 	x_histp = histptr + 1;
 	x_last_command = XFUNC_error;
 
-	x_init_prompt();
+	x_init_prompt(true);
 	x_displen = (xx_cols = x_cols) - 2 - (x_col = pwidth);
 	x_adj_done = 0;
 	x_adj_ok = true;
@@ -1606,7 +1607,7 @@
 static int
 x_size2(char *cp, char **dcp)
 {
-	int c = *(unsigned char *)cp;
+	uint8_t c = *(unsigned char *)cp;
 
 	if (UTFMODE && (c > 0x7F))
 		return (utf_widthadj(cp, (const char **)dcp));
@@ -1615,7 +1616,7 @@
 	if (c == '\t')
 		/* Kludge, tabs are always four spaces. */
 		return (4);
-	if (c < ' ' || c == 0x7f)
+	if (ISCTRL(c) && /* but not C1 */ c < 0x80)
 		/* control unsigned char */
 		return (2);
 	return (1);
@@ -1627,24 +1628,11 @@
 	int adj = x_adj_done;
 
 	x_lastcp();
-	while (*str && str < xlp && adj == x_adj_done)
+	while (*str && str < xlp && x_col < xx_cols && adj == x_adj_done)
 		x_zotc3(&str);
 }
 
 static void
-x_zotc2(int c)
-{
-	if (c == '\t') {
-		/* Kludge, tabs are always four spaces. */
-		x_e_puts("    ");
-	} else if (c < ' ' || c == 0x7f) {
-		x_e_putc2('^');
-		x_e_putc2(UNCTRL(c));
-	} else
-		x_e_putc2(c);
-}
-
-static void
 x_zotc3(char **cp)
 {
 	unsigned char c = **(unsigned char **)cp;
@@ -1653,7 +1641,7 @@
 		/* Kludge, tabs are always four spaces. */
 		x_e_puts("    ");
 		(*cp)++;
-	} else if (c < ' ' || c == 0x7f) {
+	} else if (ISCTRL(c) && /* but not C1 */ c < 0x80) {
 		x_e_putc2('^');
 		x_e_putc2(UNCTRL(c));
 		(*cp)++;
@@ -1765,7 +1753,10 @@
 static int
 x_end_of_text(int c MKSH_A_UNUSED)
 {
-	x_zotc2(edchars.eof);
+	char tmp = edchars.eof;
+	char *cp = &tmp;
+
+	x_zotc3(&cp);
 	x_putc('\r');
 	x_putc('\n');
 	x_flush();
@@ -2377,6 +2368,7 @@
 		/* XXX -- should handle \^ escape? */
 		if (*cp == '^') {
 			cp++;
+			/*XXX or ^^ escape? this is ugly. */
 			if (*cp >= '?')
 				/* includes '?'; ASCII */
 				*op++ = CTRL(*cp);
@@ -2398,7 +2390,7 @@
 {
 	char *p = *buf;
 
-	if (c < ' ' || c == 0x7f) {
+	if (ISCTRL(c)) {
 		*p++ = '^';
 		*p++ = UNCTRL(c);
 	} else
@@ -3341,8 +3333,6 @@
 #if !MKSH_S_NOVI
 /* +++ vi editing mode +++ */
 
-#define Ctrl(c)		(c&0x1f)
-
 struct edstate {
 	char *cbuf;
 	ssize_t winleft;
@@ -3363,7 +3353,7 @@
 static void restore_cbuf(void);
 static int putbuf(const char *, ssize_t, bool);
 static void del_range(int, int);
-static int findch(int, int, bool, bool);
+static int findch(int, int, bool, bool) MKSH_A_PURE;
 static int forwword(int);
 static int backword(int);
 static int endword(int);
@@ -3376,13 +3366,14 @@
 static void refresh(int);
 static int outofwin(void);
 static void rewindow(void);
-static int newcol(int, int);
+static int newcol(unsigned char, int);
 static void display(char *, char *, int);
 static void ed_mov_opt(int, char *);
 static int expand_word(int);
 static int complete_word(int, int);
 static int print_expansions(struct edstate *, int);
-#define char_len(c)	((c) < ' ' || (c) == 0x7F ? 2 : 1)
+#define char_len(c)	((ISCTRL((unsigned char)c) && \
+			/* but not C1 */ (unsigned char)c < 0x80) ? 2 : 1)
 static void x_vi_zotc(int);
 static void vi_error(void);
 static void vi_macro_reset(void);
@@ -3535,7 +3526,7 @@
 	es = &ebuf;
 	undo = &undobuf;
 
-	x_init_prompt();
+	x_init_prompt(true);
 	x_col = pwidth;
 
 	if (wbuf_len != x_cols - 3 && ((wbuf_len = x_cols - 3))) {
@@ -3556,7 +3547,7 @@
 	x_flush();
 	while (/* CONSTCOND */ 1) {
 		if (macro.p) {
-			c = *macro.p++;
+			c = (unsigned char)*macro.p++;
 			/* end of current macro? */
 			if (!c) {
 				/* more macros left to finish? */
@@ -3618,7 +3609,7 @@
 
 	case VNORMAL:
 		if (insert != 0) {
-			if (ch == Ctrl('v')) {
+			if (ch == CTRL('v')) {
 				state = VLIT;
 				ch = '^';
 			}
@@ -3730,7 +3721,7 @@
 		break;
 
 	case VXCH:
-		if (ch == Ctrl('['))
+		if (ch == CTRL('['))
 			state = VNORMAL;
 		else {
 			curcmd[cmdlen++] = ch;
@@ -3739,7 +3730,7 @@
 		break;
 
 	case VSEARCH:
-		if (ch == '\r' || ch == '\n' /*|| ch == Ctrl('[')*/ ) {
+		if (ch == '\r' || ch == '\n' /*|| ch == CTRL('[')*/ ) {
 			restore_cbuf();
 			/* Repeat last search? */
 			if (srchlen == 0) {
@@ -3754,10 +3745,10 @@
 				memcpy(srchpat, locpat, srchlen + 1);
 			}
 			state = VCMD;
-		} else if (ch == edchars.erase || ch == Ctrl('h')) {
+		} else if (ch == edchars.erase || ch == CTRL('h')) {
 			if (srchlen != 0) {
 				srchlen--;
-				es->linelen -= char_len((unsigned char)locpat[srchlen]);
+				es->linelen -= char_len(locpat[srchlen]);
 				es->cursor = es->linelen;
 				refresh(0);
 				return (0);
@@ -3772,10 +3763,10 @@
 			refresh(0);
 			return (0);
 		} else if (ch == edchars.werase) {
-			int i, n = srchlen;
+			unsigned int i, n;
 			struct edstate new_es, *save_es;
 
-			new_es.cursor = n;
+			new_es.cursor = srchlen;
 			new_es.cbuf = locpat;
 
 			save_es = es;
@@ -3783,9 +3774,10 @@
 			n = backword(1);
 			es = save_es;
 
-			for (i = srchlen; --i >= n; )
-				es->linelen -= char_len((unsigned char)locpat[i]);
-			srchlen = n;
+			i = (unsigned)srchlen;
+			while (--i >= n)
+				es->linelen -= char_len(locpat[i]);
+			srchlen = (int)n;
 			es->cursor = es->linelen;
 			refresh(0);
 			return (0);
@@ -3794,12 +3786,12 @@
 				vi_error();
 			else {
 				locpat[srchlen++] = ch;
-				if (ch < ' ' || ch == 0x7f) {
+				if (ISCTRL(ch) && /* but not C1 */ ch < 0x80) {
 					if ((size_t)es->linelen + 2 >
 					    (size_t)es->cbufsize)
 						vi_error();
 					es->cbuf[es->linelen++] = '^';
-					es->cbuf[es->linelen++] = ch ^ '@';
+					es->cbuf[es->linelen++] = UNCTRL(ch);
 				} else {
 					if (es->linelen >= es->cbufsize)
 						vi_error();
@@ -3910,7 +3902,7 @@
 		return (VXCH);
 	else if (ch == '.')
 		return (VREDO);
-	else if (ch == Ctrl('v'))
+	else if (ch == CTRL('v'))
 		return (VVERSION);
 	else if (is_cmd(ch))
 		return (VCMD);
@@ -3923,7 +3915,7 @@
 {
 	int tcursor;
 
-	if (ch == edchars.erase || ch == Ctrl('h')) {
+	if (ch == edchars.erase || ch == CTRL('h')) {
 		if (insert == REPLACE) {
 			if (es->cursor == undo->cursor) {
 				vi_error();
@@ -3980,7 +3972,7 @@
 	 * buffer (if user inserts & deletes char, ibuf gets trashed and
 	 * we don't want to use it)
 	 */
-	if (first_insert && ch != Ctrl('['))
+	if (first_insert && ch != CTRL('['))
 		saved_inslen = 0;
 	switch (ch) {
 	case '\0':
@@ -3990,7 +3982,7 @@
 	case '\n':
 		return (1);
 
-	case Ctrl('['):
+	case CTRL('['):
 		expanded = NONE;
 		if (first_insert) {
 			first_insert = false;
@@ -4008,19 +4000,19 @@
 			return (redo_insert(lastac - 1));
 
 	/* { Begin nonstandard vi commands */
-	case Ctrl('x'):
+	case CTRL('x'):
 		expand_word(0);
 		break;
 
-	case Ctrl('f'):
+	case CTRL('f'):
 		complete_word(0, 0);
 		break;
 
-	case Ctrl('e'):
+	case CTRL('e'):
 		print_expansions(es, 0);
 		break;
 
-	case Ctrl('i'):
+	case CTRL('i'):
 		if (Flag(FVITABCOMPLETE)) {
 			complete_word(0, 0);
 			break;
@@ -4075,8 +4067,8 @@
 		}
 		switch (*cmd) {
 
-		case Ctrl('l'):
-		case Ctrl('r'):
+		case CTRL('l'):
+		case CTRL('r'):
 			redraw_line(true);
 			break;
 
@@ -4263,7 +4255,7 @@
 
 		case 'j':
 		case '+':
-		case Ctrl('n'):
+		case CTRL('n'):
 			if (grabhist(modified, hnum + argcnt) < 0)
 				return (-1);
 			else {
@@ -4274,7 +4266,7 @@
 
 		case 'k':
 		case '-':
-		case Ctrl('p'):
+		case CTRL('p'):
 			if (grabhist(modified, hnum - argcnt) < 0)
 				return (-1);
 			else {
@@ -4506,26 +4498,26 @@
 		/* AT&T ksh */
 		case '=':
 		/* Nonstandard vi/ksh */
-		case Ctrl('e'):
+		case CTRL('e'):
 			print_expansions(es, 1);
 			break;
 
 
 		/* Nonstandard vi/ksh */
-		case Ctrl('i'):
+		case CTRL('i'):
 			if (!Flag(FVITABCOMPLETE))
 				return (-1);
 			complete_word(1, argcnt);
 			break;
 
 		/* some annoying AT&T kshs */
-		case Ctrl('['):
+		case CTRL('['):
 			if (!Flag(FVIESCCOMPLETE))
 				return (-1);
 		/* AT&T ksh */
 		case '\\':
 		/* Nonstandard vi/ksh */
-		case Ctrl('f'):
+		case CTRL('f'):
 			complete_word(1, argcnt);
 			break;
 
@@ -4533,7 +4525,7 @@
 		/* AT&T ksh */
 		case '*':
 		/* Nonstandard vi/ksh */
-		case Ctrl('x'):
+		case CTRL('x'):
 			expand_word(1);
 			break;
 
@@ -4612,7 +4604,7 @@
 		break;
 
 	case 'h':
-	case Ctrl('h'):
+	case CTRL('h'):
 		if (!sub && es->cursor == 0)
 			return (-1);
 		ncursor = es->cursor - argcnt;
@@ -5028,7 +5020,7 @@
 {
 	char *hptr;
 	int hist;
-	int anchored;
+	bool anchored;
 
 	if ((start == 0 && fwd == 0) || (start >= hlast - 1 && fwd == 1))
 		return (-1);
@@ -5036,7 +5028,7 @@
 		start++;
 	else
 		start--;
-	anchored = *pat == '^' ? (++pat, 1) : 0;
+	anchored = *pat == '^' ? (++pat, true) : false;
 	if ((hist = findhist(start, fwd, pat, anchored)) < 0) {
 		/* (start != 0 && fwd && match(holdbufp, pat) >= 0) */
 		if (start != 0 && fwd && strcmp(holdbufp, pat) >= 0) {
@@ -5125,7 +5117,7 @@
 }
 
 static int
-newcol(int ch, int col)
+newcol(unsigned char ch, int col)
 {
 	if (ch == '\t')
 		return ((col | 7) + 1);
@@ -5153,10 +5145,10 @@
 				*twb1++ = ' ';
 			} while (++col < winwidth && (col & 7) != 0);
 		else if (col < winwidth) {
-			if (ch < ' ' || ch == 0x7f) {
+			if (ISCTRL(ch) && /* but not C1 */ ch < 0x80) {
 				*twb1++ = '^';
 				if (++col < winwidth) {
-					*twb1++ = ch ^ '@';
+					*twb1++ = UNCTRL(ch);
 					col++;
 				}
 			} else {
@@ -5433,9 +5425,9 @@
 static void
 x_vi_zotc(int c)
 {
-	if (c < ' ' || c == 0x7f) {
+	if (ISCTRL(c)) {
 		x_putc('^');
-		c ^= '@';
+		c = UNCTRL(c);
 	}
 	x_putc(c);
 }
diff --git a/src/eval.c b/src/eval.c
index b6ff1dc..49a4c33 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1,8 +1,8 @@
-/*	$OpenBSD: eval.c,v 1.39 2013/07/01 17:25:27 jca Exp $	*/
+/*	$OpenBSD: eval.c,v 1.40 2013/09/14 20:09:30 millert Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013
+ *		 2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.142 2013/07/24 18:03:57 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.153 2014/10/07 15:22:16 tg Exp $");
 
 /*
  * string expansion
@@ -62,6 +62,7 @@
 #define IFS_WORD	0	/* word has chars (or quotes) */
 #define IFS_WS		1	/* have seen IFS white-space */
 #define IFS_NWS		2	/* have seen IFS non-white-space */
+#define IFS_IWS		3	/* begin of word, ignore IFS WS */
 
 static int varsub(Expand *, const char *, const char *, int *, int *);
 static int comsub(Expand *, const char *, int);
@@ -74,7 +75,7 @@
 static char *homedir(char *);
 #endif
 static void alt_expand(XPtrV *, char *, char *, char *, int);
-static int utflen(const char *);
+static int utflen(const char *) MKSH_A_PURE;
 static void utfincptr(const char *, mksh_ari_t *);
 
 /* UTFMODE functions */
@@ -244,8 +245,8 @@
 		internal_errorf("expand(NULL)");
 	/* for alias, readonly, set, typeset commands */
 	if ((f & DOVACHECK) && is_wdvarassign(ccp)) {
-		f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE);
-		f |= DOASNTILDE;
+		f &= ~(DOVACHECK | DOBLANK | DOGLOB | DOTILDE);
+		f |= DOASNTILDE | DOASNFIELD;
 	}
 	if (Flag(FNOGLOB))
 		f &= ~DOGLOB;
@@ -261,7 +262,7 @@
 	fdo = 0;
 	saw_eq = false;
 	/* must be 1/0 */
-	tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
+	tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0;
 	doblank = 0;
 	make_magic = false;
 	word = (f&DOBLANK) ? IFS_WS : IFS_WORD;
@@ -324,9 +325,9 @@
 				}
 				continue;
 			case EXPRSUB:
-				word = IFS_WORD;
 				tilde_ok = 0;
 				if (f & DONTRUNCOMMAND) {
+					word = IFS_WORD;
 					*dp++ = '$'; *dp++ = '('; *dp++ = '(';
 					while (*sp != '\0') {
 						Xcheck(ds, dp);
@@ -343,11 +344,10 @@
 					v_evaluate(&v, substitute(sp, 0),
 					    KSH_UNWIND_ERROR, true);
 					sp = strnul(sp) + 1;
-					cp = str_val(&v);
-					while (*cp) {
-						Xcheck(ds, dp);
-						*dp++ = *cp++;
-					}
+					x.str = str_val(&v);
+					type = XSUB;
+					if (f & DOBLANK)
+						doblank++;
 				}
 				continue;
 			case OSUBST: {
@@ -412,27 +412,10 @@
 					if (stype)
 						sp += slen;
 					switch (stype & 0x17F) {
-					case 0x100 | '#': {
-						char *beg, *end;
-						mksh_ari_t seed;
-						register uint32_t h;
-
-						beg = wdcopy(sp, ATEMP);
-						end = beg + (wdscan(sp, CSUBST) - sp);
-						end[-2] = EOS;
-						end = wdstrip(beg, 0);
-						afree(beg, ATEMP);
-						evaluate(substitute(end, 0),
-						    &seed, KSH_UNWIND_ERROR, true);
-						/* hash with seed, for now */
-						h = seed;
-						NZATUpdateString(h,
-						    str_val(st->var));
-						NZAATFinish(h);
+					case 0x100 | '#':
 						x.str = shf_smprintf("%08X",
-						    (unsigned int)h);
+						    (unsigned int)hash(str_val(st->var)));
 						break;
-					}
 					case 0x100 | 'Q': {
 						struct shf shf;
 
@@ -440,7 +423,7 @@
 						print_value_quoted(&shf, str_val(st->var));
 						x.str = shf_sclose(&shf);
 						break;
-					}
+					    }
 					case '0': {
 						char *beg, *mid, *end, *stg;
 						mksh_ari_t from = 0, num = -1, flen, finc = 0;
@@ -490,7 +473,7 @@
 							utfincptr(beg, &num);
 						strndupx(x.str, beg, num, ATEMP);
 						goto do_CSUBST;
-					}
+					    }
 					case '/': {
 						char *s, *p, *d, *sbeg, *end;
 						char *pat, *rrep;
@@ -634,7 +617,7 @@
 						if (rrep != null)
 							afree(rrep, ATEMP);
 						goto do_CSUBST;
-					}
+					    }
 					case '#':
 					case '%':
 						/* ! DOBLANK,DOBRACE,DOTILDE */
@@ -667,7 +650,7 @@
 						 * a arithmetic operator.
 						 */
 						if (!(x.var->flag & INTEGER))
-							f |= DOASNTILDE|DOTILDE;
+							f |= DOASNTILDE | DOTILDE;
 						f |= DOTEMP;
 						/*
 						 * These will be done after the
@@ -681,6 +664,7 @@
 						f |= DOTEMP;
 						/* FALLTHROUGH */
 					default:
+						word = quote ? IFS_WORD : IFS_IWS;
 						/* Enable tilde expansion */
 						tilde_ok = 1;
 						f |= DOTILDE;
@@ -689,7 +673,7 @@
 					/* skip word */
 					sp += wdscan(sp, CSUBST) - sp;
 				continue;
-			}
+			    }
 			case CSUBST:
 				/* only get here if expanding word */
  do_CSUBST:
@@ -700,7 +684,7 @@
 				*dp = '\0';
 				quote = st->quotep;
 				f = st->f;
-				if (f&DOBLANK)
+				if (f & DOBLANK)
 					doblank--;
 				switch (st->stype & 0x17F) {
 				case '#':
@@ -719,11 +703,12 @@
 					 */
 					x.str = trimsub(str_val(st->var),
 						dp, st->stype);
-					if (x.str[0] != '\0' || st->quotep)
+					if (x.str[0] != '\0') {
+						word = IFS_WS;
 						type = XSUB;
-					else
-						type = XNULLSUB;
-					if (f&DOBLANK)
+					} else
+						type = quote ? XSUB : XNULLSUB;
+					if (f & DOBLANK)
 						doblank++;
 					st = st->prev;
 					continue;
@@ -755,9 +740,10 @@
 					    dp, len), KSH_UNWIND_ERROR);
 					x.str = str_val(st->var);
 					type = XSUB;
-					if (f&DOBLANK)
+					if (f & DOBLANK)
 						doblank++;
 					st = st->prev;
+					word = quote || (!*x.str && (f & DOASNFIELD)) ? IFS_WORD : IFS_WS;
 					continue;
 				case '?': {
 					char *s = Xrestpos(ds, dp, st->base);
@@ -766,14 +752,15 @@
 					    dp == s ?
 					    "parameter null or not set" :
 					    (debunk(s, s, strlen(s) + 1), s));
-				}
+				    }
 				case '0':
 				case '/':
 				case 0x100 | '#':
 				case 0x100 | 'Q':
 					dp = Xrestpos(ds, dp, st->base);
 					type = XSUB;
-					if (f&DOBLANK)
+					word = quote || (!*x.str && (f & DOASNFIELD)) ? IFS_WORD : IFS_WS;
+					if (f & DOBLANK)
 						doblank++;
 					st = st->prev;
 					continue;
@@ -810,13 +797,8 @@
 			 * other stuff inside the quotes).
 			 */
 			type = XBASE;
-			if (f&DOBLANK) {
+			if (f & DOBLANK) {
 				doblank--;
-				/*
-				 * not really correct: x=; "$x$@" should
-				 * generate a null argument and
-				 * set A; "${@:+}" shouldn't.
-				 */
 				if (dp == Xstring(ds, dp))
 					word = IFS_WS;
 			}
@@ -826,7 +808,7 @@
 		case XSUBMID:
 			if ((c = *x.str++) == 0) {
 				type = XBASE;
-				if (f&DOBLANK)
+				if (f & DOBLANK)
 					doblank--;
 				continue;
 			}
@@ -840,21 +822,33 @@
 			if ((c = *x.str++) == '\0') {
 				/*
 				 * force null words to be created so
-				 * set -- '' 2 ''; foo "$@" will do
+				 * set -- "" 2 ""; echo "$@" will do
 				 * the right thing
 				 */
 				if (quote && x.split)
 					word = IFS_WORD;
 				if ((x.str = *x.u.strv++) == NULL) {
 					type = XBASE;
-					if (f&DOBLANK)
+					if (f & DOBLANK)
 						doblank--;
 					continue;
 				}
 				c = ifs0;
+				if ((f & DOASNFIELD)) {
+					/* assignment, do not field-split */
+					if (x.split) {
+						c = ' ';
+						break;
+					}
+					if (c == 0) {
+						continue;
+					}
+				}
 				if (c == 0) {
 					if (quote && !x.split)
 						continue;
+					if (!quote && word == IFS_WS)
+						continue;
 					/* this is so we don't terminate */
 					c = ' ';
 					/* now force-emit a word */
@@ -896,7 +890,7 @@
 				if (x.split)
 					subst_exstat = waitlast();
 				type = XBASE;
-				if (f&DOBLANK)
+				if (f & DOBLANK)
 					doblank--;
 				continue;
 			}
@@ -912,14 +906,14 @@
 			 *	word		|	ws	nws	0
 			 *	-----------------------------------
 			 *	IFS_WORD		w/WS	w/NWS	w
-			 *	IFS_WS			-/WS	w/NWS	-
-			 *	IFS_NWS			-/NWS	w/NWS	w
+			 *	IFS_WS			-/WS	-/NWS	-
+			 *	IFS_NWS			-/NWS	w/NWS	-
+			 *	IFS_IWS			-/WS	w/NWS	-
 			 * (w means generate a word)
-			 * Note that IFS_NWS/0 generates a word (AT&T ksh
-			 * doesn't do this, but POSIX does).
 			 */
-			if (word == IFS_WORD ||
-			    (!ctype(c, C_IFSWS) && c && word == IFS_NWS)) {
+			if ((word == IFS_WORD) || (c &&
+			    (word == IFS_IWS || word == IFS_NWS) &&
+			    !ctype(c, C_IFSWS))) {
  emit_word:
 				*dp++ = '\0';
 				cp = Xclose(ds, dp);
@@ -937,7 +931,8 @@
 					    strlen(cp) + 1));
 				fdo = 0;
 				saw_eq = false;
-				tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
+				/* must be 1/0 */
+				tilde_ok = (f & (DOTILDE | DOASNTILDE)) ? 1 : 0;
 				if (c == 0)
 					return;
 				Xinit(ds, dp, 128, ATEMP);
@@ -1021,7 +1016,7 @@
 					 * through the sequence ${A=a=}~
 					 */
 					if (type == XBASE &&
-					    (f & (DOTILDE|DOASNTILDE)) &&
+					    (f & (DOTILDE | DOASNTILDE)) &&
 					    (tilde_ok & 2)) {
 						const char *tcp;
 						char *tdp = dp;
@@ -1269,17 +1264,12 @@
 			if (*sp == '!' && sp[1]) {
 				++sp;
 				xp->var = global(sp);
-				if (vstrchr(sp, '[')) {
-					if (xp->var->flag & ISSET)
-						xp->str = shf_smprintf("%lu",
-						    arrayindex(xp->var));
-					else
-						xp->str = null;
-				} else if (xp->var->flag & ISSET)
-					xp->str = xp->var->name;
+				if (vstrchr(sp, '['))
+					xp->str = shf_smprintf("%s[%lu]",
+					    xp->var->name,
+					    arrayindex(xp->var));
 				else
-					/* ksh93 compat */
-					xp->str = "0";
+					xp->str = xp->var->name;
 			} else {
 				xp->var = global(sp);
 				xp->str = str_val(xp->var);
diff --git a/src/exec.c b/src/exec.c
index 50ec9ca..b60511d 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -2,7 +2,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013
+ *		 2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.125 2013/07/21 20:44:44 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.133 2014/10/03 17:32:11 tg Exp $");
 
 #ifndef MKSH_DEFAULT_EXECSHELL
 #define MKSH_DEFAULT_EXECSHELL	"/bin/sh"
@@ -462,7 +462,7 @@
 	if (vp_pipest->flag & INT_L) {
 		unset(vp_pipest, 1);
 		vp_pipest->flag = DEFINED | ISSET | INTEGER | RDONLY |
-		    ARRAY | INT_U;
+		    ARRAY | INT_U | INT_L;
 		vp_pipest->val.i = rv;
 	}
 
@@ -604,19 +604,15 @@
 				/* go on, use the builtin */
 				break;
 #endif
-#if !defined(MKSH_SMALL)
 		} else if (tp->val.f == c_trap) {
 			t->u.evalflags &= ~DOTCOMEXEC;
 			break;
-#endif
 		} else
 			break;
 		tp = findcom(ap[0], fcflags & (FC_BI|FC_FUNC));
 	}
-#if !defined(MKSH_SMALL)
 	if (t->u.evalflags & DOTCOMEXEC)
 		flags |= XEXEC;
-#endif
 	l_expand = e->loc;
 	if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN))))
 		type_flags = 0;
@@ -639,7 +635,7 @@
 	for (i = 0; t->vars[i]; i++) {
 		/* do NOT lookup in the new var/fn block just created */
 		e->loc = l_expand;
-		cp = evalstr(t->vars[i], DOASNTILDE);
+		cp = evalstr(t->vars[i], DOASNTILDE | DOASNFIELD);
 		e->loc = l_assign;
 		if (Flag(FXTRACE)) {
 			const char *ccp;
@@ -656,7 +652,7 @@
 		/* but assign in there as usual */
 		typeset(cp, type_flags, 0, 0, 0);
 		if (bourne_function_call && !(type_flags & EXPORT))
-			typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
+			typeset(cp, LOCAL | LOCAL_COPY | EXPORT, 0, 0, 0);
 	}
 
 	if (Flag(FXTRACE)) {
@@ -816,7 +812,7 @@
 
 		/* set $_ to programme's full path */
 		/* setstr() can't fail here */
-		setstr(typeset("_", LOCAL|EXPORT, 0, INTEGER, 0),
+		setstr(typeset("_", LOCAL | EXPORT, 0, INTEGER, 0),
 		    tp->val.s, KSH_RETURN_ERROR);
 
 		if (flags&XEXEC) {
@@ -869,7 +865,7 @@
 	*tp->args-- = tp->str;
 
 #ifndef MKSH_SMALL
-	if ((fd = open(tp->str, O_RDONLY)) >= 0) {
+	if ((fd = open(tp->str, O_RDONLY | O_BINARY)) >= 0) {
 		/* read first MAXINTERP octets from file */
 		if (read(fd, buf, sizeof(buf)) <= 0)
 			/* read error -> no good */
@@ -884,14 +880,14 @@
 		fd = (char *)cp - buf;		/* either 0 or (if BOM) 3 */
 
 		/* scan for newline (or CR) or NUL _before_ end of buffer */
-		while ((char *)cp < (buf + sizeof(buf)))
+		while ((size_t)((char *)cp - buf) < sizeof(buf))
 			if (*cp == '\0' || *cp == '\n' || *cp == '\r') {
 				*cp = '\0';
 				break;
 			} else
 				++cp;
 		/* if the shebang line is longer than MAXINTERP, bail out */
-		if ((char *)cp >= (buf + sizeof(buf)))
+		if ((size_t)((char *)cp - buf) >= sizeof(buf))
 			goto noshebang;
 
 		/* restore begin of shebang position (buf+0 or buf+3) */
@@ -923,6 +919,10 @@
 				*tp->args-- = (char *)cp;
 		}
  noshebang:
+		if (buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' &&
+		    buf[3] == 'F')
+			errorf("%s: not executable: %d-bit ELF file", tp->str,
+			    32 * ((uint8_t)buf[4]));
 		fd = buf[0] << 8 | buf[1];
 		if ((fd == /* OMAGIC */ 0407) ||
 		    (fd == /* NMAGIC */ 0410) ||
@@ -931,7 +931,6 @@
 		    (fd == /* ECOFF_I386 */ 0x4C01) ||
 		    (fd == /* ECOFF_M68K */ 0x0150 || fd == 0x5001) ||
 		    (fd == /* ECOFF_SH */   0x0500 || fd == 0x0005) ||
-		    (fd == 0x7F45 && buf[2] == 'L' && buf[3] == 'F') ||
 		    (fd == /* "MZ" */ 0x4D5A) ||
 		    (fd == /* gzip */ 0x1F8B))
 			errorf("%s: not executable: magic %04X", tp->str, fd);
@@ -1374,7 +1373,7 @@
 			warningf(true, "%s: %s", cp, "restricted");
 			return (-1);
 		}
-		u = open(cp, flags, 0666);
+		u = open(cp, flags | O_BINARY, 0666);
 	}
 	if (u < 0) {
 		/* herein() may already have printed message */
@@ -1507,7 +1506,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, 0)) < 0) {
+	if (!(shf = h->shf) || (fd = open(h->tffn, O_RDONLY | O_BINARY, 0)) < 0) {
 		i = errno;
 		warningf(true, "can't %s temporary file %s: %s",
 		    !shf ? "create" : "open", h->tffn, cstrerror(i));
@@ -1669,7 +1668,7 @@
 dbteste_isa(Test_env *te, Test_meta meta)
 {
 	Test_op ret = TO_NONOP;
-	int uqword;
+	bool uqword;
 	const char *p;
 
 	if (!*te->pos.wp)
diff --git a/src/expr.c b/src/expr.c
index e91c0da..057666e 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -1,8 +1,8 @@
-/*	$OpenBSD: expr.c,v 1.22 2013/03/28 08:39:28 nicm Exp $	*/
+/*	$OpenBSD: expr.c,v 1.23 2013/12/17 16:37:06 deraadt Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013
+ *		 2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.72 2013/07/21 18:38:56 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.76 2014/06/24 19:53:19 tg Exp $");
 
 /* the order of these enums is constrained by the order of opinfo[] */
 enum token {
@@ -916,8 +916,7 @@
 	return (rv);
 }
 
-#ifndef MKSH_mirbsd_wcwidth
-/* From: X11/xc/programs/xterm/wcwidth.c,v 1.6 2013/05/31 23:27:09 tg Exp $ */
+/* From: X11/xc/programs/xterm/wcwidth.c,v 1.8 2014/06/24 19:53:53 tg Exp $ */
 
 struct mb_ucsrange {
 	unsigned short beg;
@@ -925,11 +924,11 @@
 };
 
 static int mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems,
-    unsigned int val);
+    unsigned int val) MKSH_A_PURE;
 
 /*
- * Generated by MirOS: contrib/code/Snippets/eawparse,v 1.1 2013/05/31 23:27:16 tg Exp $
- * from Unicode 6.2.0
+ * Generated by MirOS: contrib/code/Snippets/eawparse,v 1.2 2013/11/30 13:45:17 tg Exp $
+ * from the Unicode Character Database, Version 7.0.0
  */
 
 static const struct mb_ucsrange mb_ucs_combining[] = {
@@ -940,8 +939,9 @@
 	{ 0x05C1, 0x05C2 },
 	{ 0x05C4, 0x05C5 },
 	{ 0x05C7, 0x05C7 },
-	{ 0x0600, 0x0604 },
+	{ 0x0600, 0x0605 },
 	{ 0x0610, 0x061A },
+	{ 0x061C, 0x061C },
 	{ 0x064B, 0x065F },
 	{ 0x0670, 0x0670 },
 	{ 0x06D6, 0x06DD },
@@ -958,8 +958,7 @@
 	{ 0x0825, 0x0827 },
 	{ 0x0829, 0x082D },
 	{ 0x0859, 0x085B },
-	{ 0x08E4, 0x08FE },
-	{ 0x0900, 0x0902 },
+	{ 0x08E4, 0x0902 },
 	{ 0x093A, 0x093A },
 	{ 0x093C, 0x093C },
 	{ 0x0941, 0x0948 },
@@ -995,16 +994,19 @@
 	{ 0x0B82, 0x0B82 },
 	{ 0x0BC0, 0x0BC0 },
 	{ 0x0BCD, 0x0BCD },
+	{ 0x0C00, 0x0C00 },
 	{ 0x0C3E, 0x0C40 },
 	{ 0x0C46, 0x0C48 },
 	{ 0x0C4A, 0x0C4D },
 	{ 0x0C55, 0x0C56 },
 	{ 0x0C62, 0x0C63 },
+	{ 0x0C81, 0x0C81 },
 	{ 0x0CBC, 0x0CBC },
 	{ 0x0CBF, 0x0CBF },
 	{ 0x0CC6, 0x0CC6 },
 	{ 0x0CCC, 0x0CCD },
 	{ 0x0CE2, 0x0CE3 },
+	{ 0x0D01, 0x0D01 },
 	{ 0x0D41, 0x0D44 },
 	{ 0x0D4D, 0x0D4D },
 	{ 0x0D62, 0x0D63 },
@@ -1050,13 +1052,14 @@
 	{ 0x17C6, 0x17C6 },
 	{ 0x17C9, 0x17D3 },
 	{ 0x17DD, 0x17DD },
-	{ 0x180B, 0x180D },
+	{ 0x180B, 0x180E },
 	{ 0x18A9, 0x18A9 },
 	{ 0x1920, 0x1922 },
 	{ 0x1927, 0x1928 },
 	{ 0x1932, 0x1932 },
 	{ 0x1939, 0x193B },
 	{ 0x1A17, 0x1A18 },
+	{ 0x1A1B, 0x1A1B },
 	{ 0x1A56, 0x1A56 },
 	{ 0x1A58, 0x1A5E },
 	{ 0x1A60, 0x1A60 },
@@ -1064,6 +1067,7 @@
 	{ 0x1A65, 0x1A6C },
 	{ 0x1A73, 0x1A7C },
 	{ 0x1A7F, 0x1A7F },
+	{ 0x1AB0, 0x1ABE },
 	{ 0x1B00, 0x1B03 },
 	{ 0x1B34, 0x1B34 },
 	{ 0x1B36, 0x1B3A },
@@ -1073,7 +1077,7 @@
 	{ 0x1B80, 0x1B81 },
 	{ 0x1BA2, 0x1BA5 },
 	{ 0x1BA8, 0x1BA9 },
-	{ 0x1BAB, 0x1BAB },
+	{ 0x1BAB, 0x1BAD },
 	{ 0x1BE6, 0x1BE6 },
 	{ 0x1BE8, 0x1BE9 },
 	{ 0x1BED, 0x1BED },
@@ -1085,12 +1089,13 @@
 	{ 0x1CE2, 0x1CE8 },
 	{ 0x1CED, 0x1CED },
 	{ 0x1CF4, 0x1CF4 },
-	{ 0x1DC0, 0x1DE6 },
+	{ 0x1CF8, 0x1CF9 },
+	{ 0x1DC0, 0x1DF5 },
 	{ 0x1DFC, 0x1DFF },
 	{ 0x200B, 0x200F },
 	{ 0x202A, 0x202E },
 	{ 0x2060, 0x2064 },
-	{ 0x206A, 0x206F },
+	{ 0x2066, 0x206F },
 	{ 0x20D0, 0x20F0 },
 	{ 0x2CEF, 0x2CF1 },
 	{ 0x2D7F, 0x2D7F },
@@ -1113,11 +1118,13 @@
 	{ 0xA9B3, 0xA9B3 },
 	{ 0xA9B6, 0xA9B9 },
 	{ 0xA9BC, 0xA9BC },
+	{ 0xA9E5, 0xA9E5 },
 	{ 0xAA29, 0xAA2E },
 	{ 0xAA31, 0xAA32 },
 	{ 0xAA35, 0xAA36 },
 	{ 0xAA43, 0xAA43 },
 	{ 0xAA4C, 0xAA4C },
+	{ 0xAA7C, 0xAA7C },
 	{ 0xAAB0, 0xAAB0 },
 	{ 0xAAB2, 0xAAB4 },
 	{ 0xAAB7, 0xAAB8 },
@@ -1130,7 +1137,7 @@
 	{ 0xABED, 0xABED },
 	{ 0xFB1E, 0xFB1E },
 	{ 0xFE00, 0xFE0F },
-	{ 0xFE20, 0xFE26 },
+	{ 0xFE20, 0xFE2D },
 	{ 0xFEFF, 0xFEFF },
 	{ 0xFFF9, 0xFFFB }
 };
@@ -1188,4 +1195,3 @@
 		return (2);
 	return (1);
 }
-#endif
diff --git a/src/funcs.c b/src/funcs.c
index 53ab789..bb7971e 100644
--- a/src/funcs.c
+++ b/src/funcs.c
@@ -1,11 +1,11 @@
-/*	$OpenBSD: c_ksh.c,v 1.33 2009/02/07 14:03:24 kili Exp $	*/
-/*	$OpenBSD: c_sh.c,v 1.43 2013/04/19 17:39:45 deraadt Exp $	*/
+/*	$OpenBSD: c_ksh.c,v 1.34 2013/12/17 16:37:05 deraadt Exp $	*/
+/*	$OpenBSD: c_sh.c,v 1.45 2014/08/27 08:26:04 jmc Exp $	*/
 /*	$OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $	*/
-/*	$OpenBSD: c_ulimit.c,v 1.17 2008/03/21 12:51:19 millert Exp $	*/
+/*	$OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- *		 2010, 2011, 2012, 2013
+ *		 2010, 2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -38,7 +38,7 @@
 #endif
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.244 2013/06/03 22:28:32 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.258 2014/09/03 19:55:51 tg Exp $");
 
 #if HAVE_KILLPG
 /*
@@ -60,6 +60,10 @@
 #define c_ulimit	c_true
 #endif
 
+#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
+static int c_suspend(const char **);
+#endif
+
 /* getn() that prints error */
 static int
 bi_getn(const char *as, int *ai)
@@ -123,6 +127,9 @@
 	{"*=return", c_exitreturn},
 	{Tsgset, c_set},
 	{"*=shift", c_shift},
+#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
+	{"suspend", c_suspend},
+#endif
 	{"test", c_test},
 	{"*=times", c_times},
 	{"*=trap", c_trap},
@@ -641,6 +648,7 @@
 	const char *opts;
 	const char *fieldstr = NULL, *basestr = NULL;
 	bool localv = false, func = false, pflag = false, istset = true;
+	enum namerefflag new_refflag = SRF_NOP;
 
 	switch (**wp) {
 
@@ -721,7 +729,7 @@
 			flag = LCASEV;
 			break;
 		case 'n':
-			set_refflag = (builtin_opt.info & GI_PLUS) ?
+			new_refflag = (builtin_opt.info & GI_PLUS) ?
 			    SRF_DISABLE : SRF_ENABLE;
 			break;
 		/* export, readonly: POSIX -p flag */
@@ -745,8 +753,6 @@
 			flag = EXPORT;
 			break;
 		case '?':
- errout:
-			set_refflag = SRF_NOP;
 			return (1);
 		}
 		if (builtin_opt.info & GI_PLUS) {
@@ -761,10 +767,10 @@
 	}
 
 	if (fieldstr && !bi_getn(fieldstr, &field))
-		goto errout;
+		return (1);
 	if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) {
 		bi_errorf("%s: %s", "bad integer base", basestr);
-		goto errout;
+		return (1);
 	}
 
 	if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] &&
@@ -776,9 +782,9 @@
 	}
 
 	if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) ||
-	    set_refflag != SRF_NOP)) {
+	    new_refflag != SRF_NOP)) {
 		bi_errorf("only -t, -u and -x options may be used with -f");
-		goto errout;
+		return (1);
 	}
 	if (wp[builtin_opt.optind]) {
 		/*
@@ -802,10 +808,18 @@
 		 * are also set in this command
 		 */
 		if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV |
-		    INTEGER | INT_U | INT_L)) || set_refflag != SRF_NOP)
+		    INTEGER | INT_U | INT_L)) || new_refflag != SRF_NOP)
 			fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL |
 			    LCASEV | INTEGER | INT_U | INT_L);
 	}
+	if (new_refflag != SRF_NOP) {
+		fclr &= ~(ARRAY | ASSOC);
+		fset &= ~(ARRAY | ASSOC);
+		fclr |= EXPORT;
+		fset |= ASSOC;
+		if (new_refflag == SRF_DISABLE)
+			fclr |= ASSOC;
+	}
 
 	/* set variables and attributes */
 	if (wp[builtin_opt.optind] &&
@@ -836,14 +850,12 @@
 				}
 			} else if (!typeset(wp[i], fset, fclr, field, base)) {
 				bi_errorf("%s: %s", wp[i], "is not an identifier");
-				goto errout;
+				return (1);
 			}
 		}
-		set_refflag = SRF_NOP;
 		return (rv);
 	}
 
-	set_refflag = SRF_NOP;
 	/* list variables and attributes */
 
 	/* no difference at this point.. */
@@ -1345,8 +1357,10 @@
 			for (; wp[i]; i++) {
 				if (!bi_getn(wp[i], &n))
 					return (1);
+#if (NSIG < 128)
 				if (n > 128 && n < 128 + NSIG)
 					n -= 128;
+#endif
 				if (n > 0 && n < NSIG)
 					shprintf("%s\n", sigtraps[n].name);
 				else
@@ -3333,16 +3347,6 @@
 #define SOFT	0x1
 #define HARD	0x2
 
-struct limits {
-	const char *name;
-	int resource;		/* resource to get/set */
-	unsigned int factor;	/* multiply by to get rlim_{cur,max} values */
-	char option;
-};
-
-static void print_ulimit(const struct limits *, int);
-static int set_ulimit(const struct limits *, const char *, int);
-
 /* Magic to divine the 'm' and 'v' limits */
 
 #ifdef RLIMIT_AS
@@ -3385,165 +3389,38 @@
 #undef ULIMIT_M_IS_VMEM
 #endif
 
+#if defined(ULIMIT_M_IS_RSS) && defined(ULIMIT_M_IS_VMEM)
+# error nonsensical m ulimit
+#endif
+
+#if defined(ULIMIT_V_IS_VMEM) && defined(ULIMIT_V_IS_AS)
+# error nonsensical v ulimit
+#endif
+
+#define RLIMITS_DEFNS
+#include "rlimits.gen"
+
+static void print_ulimit(const struct limits *, int);
+static int set_ulimit(const struct limits *, const char *, int);
+
+static const struct limits * const rlimits[] = {
+#define RLIMITS_ITEMS
+#include "rlimits.gen"
+};
+
+static const char rlimits_opts[] =
+#define RLIMITS_OPTCS
+#include "rlimits.gen"
+    ;
 
 int
 c_ulimit(const char **wp)
 {
-	static const struct limits limits[] = {
-		/* do not use options -H, -S or -a or change the order */
-#ifdef RLIMIT_CPU
-		{ "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
-#endif
-#ifdef RLIMIT_FSIZE
-		{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
-#endif
-#ifdef RLIMIT_CORE
-		{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
-#endif
-#ifdef RLIMIT_DATA
-		{ "data(KiB)", RLIMIT_DATA, 1024, 'd' },
-#endif
-#ifdef RLIMIT_STACK
-		{ "stack(KiB)", RLIMIT_STACK, 1024, 's' },
-#endif
-#ifdef RLIMIT_MEMLOCK
-		{ "lockedmem(KiB)", RLIMIT_MEMLOCK, 1024, 'l' },
-#endif
-#ifdef RLIMIT_NOFILE
-		{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
-#endif
-#ifdef RLIMIT_NPROC
-		{ "processes", RLIMIT_NPROC, 1, 'p' },
-#endif
-#ifdef RLIMIT_SWAP
-		{ "swap(KiB)", RLIMIT_SWAP, 1024, 'w' },
-#endif
-#ifdef RLIMIT_LOCKS
-		{ "flocks", RLIMIT_LOCKS, -1, 'L' },
-#endif
-#ifdef RLIMIT_TIME
-		{ "humantime(seconds)", RLIMIT_TIME, 1, 'T' },
-#endif
-#ifdef RLIMIT_NOVMON
-		{ "vnodemonitors", RLIMIT_NOVMON, 1, 'V' },
-#endif
-#ifdef RLIMIT_SIGPENDING
-		{ "sigpending", RLIMIT_SIGPENDING, 1, 'i' },
-#endif
-#ifdef RLIMIT_MSGQUEUE
-		{ "msgqueue(bytes)", RLIMIT_MSGQUEUE, 1, 'q' },
-#endif
-#ifdef RLIMIT_AIO_MEM
-		{ "AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024, 'M' },
-#endif
-#ifdef RLIMIT_AIO_OPS
-		{ "AIOoperations", RLIMIT_AIO_OPS, 1, 'O' },
-#endif
-#ifdef RLIMIT_TCACHE
-		{ "cachedthreads", RLIMIT_TCACHE, 1, 'C' },
-#endif
-#ifdef RLIMIT_SBSIZE
-		{ "sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024, 'B' },
-#endif
-#ifdef RLIMIT_PTHREAD
-		{ "threadsperprocess", RLIMIT_PTHREAD, 1, 'P' },
-#endif
-#ifdef RLIMIT_NICE
-		{ "maxnice", RLIMIT_NICE, 1, 'e' },
-#endif
-#ifdef RLIMIT_RTPRIO
-		{ "maxrtprio", RLIMIT_RTPRIO, 1, 'r' },
-#endif
-#if defined(ULIMIT_M_IS_RSS)
-		{ "resident-set(KiB)", RLIMIT_RSS, 1024, 'm' },
-#elif defined(ULIMIT_M_IS_VMEM)
-		{ "memory(KiB)", RLIMIT_VMEM, 1024, 'm' },
-#endif
-#if defined(ULIMIT_V_IS_VMEM)
-		{ "virtual-memory(KiB)", RLIMIT_VMEM, 1024, 'v' },
-#elif defined(ULIMIT_V_IS_AS)
-		{ "address-space(KiB)", RLIMIT_AS, 1024, 'v' },
-#endif
-		{ NULL, 0, 0, 0 }
-	};
-	static const char opts[] = "a"
-#ifdef RLIMIT_SBSIZE
-	    "B"
-#endif
-#ifdef RLIMIT_TCACHE
-	    "C"
-#endif
-#ifdef RLIMIT_CORE
-	    "c"
-#endif
-#ifdef RLIMIT_DATA
-	    "d"
-#endif
-#ifdef RLIMIT_NICE
-	    "e"
-#endif
-#ifdef RLIMIT_FSIZE
-	    "f"
-#endif
-	    "H"
-#ifdef RLIMIT_SIGPENDING
-	    "i"
-#endif
-#ifdef RLIMIT_LOCKS
-	    "L"
-#endif
-#ifdef RLIMIT_MEMLOCK
-	    "l"
-#endif
-#ifdef RLIMIT_AIO_MEM
-	    "M"
-#endif
-#if defined(ULIMIT_M_IS_RSS) || defined(ULIMIT_M_IS_VMEM)
-	    "m"
-#endif
-#ifdef RLIMIT_NOFILE
-	    "n"
-#endif
-#ifdef RLIMIT_AIO_OPS
-	    "O"
-#endif
-#ifdef RLIMIT_PTHREAD
-	    "P"
-#endif
-#ifdef RLIMIT_NPROC
-	    "p"
-#endif
-#ifdef RLIMIT_MSGQUEUE
-	    "q"
-#endif
-#ifdef RLIMIT_RTPRIO
-	    "r"
-#endif
-	    "S"
-#ifdef RLIMIT_STACK
-	    "s"
-#endif
-#ifdef RLIMIT_TIME
-	    "T"
-#endif
-#ifdef RLIMIT_CPU
-	    "t"
-#endif
-#ifdef RLIMIT_NOVMON
-	    "V"
-#endif
-#if defined(ULIMIT_V_IS_VMEM) || defined(ULIMIT_V_IS_AS)
-	    "v"
-#endif
-#ifdef RLIMIT_SWAP
-	    "w"
-#endif
-	    ;
+	size_t i = 0;
 	int how = SOFT | HARD, optc, what = 'f';
 	bool all = false;
-	const struct limits *l;
 
-	while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
+	while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1)
 		switch (optc) {
 		case 'H':
 			how = HARD;
@@ -3555,31 +3432,32 @@
 			all = true;
 			break;
 		case '?':
-			bi_errorf("usage: ulimit [-%s] [value]", opts);
+			bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts);
 			return (1);
 		default:
 			what = optc;
 		}
 
-	for (l = limits; l->name && l->option != what; l++)
-		;
-	if (!l->name) {
-		internal_warningf("ulimit: %c", what);
-		return (1);
+	while (i < NELEM(rlimits)) {
+		if (rlimits[i]->optchar == what)
+			goto found;
+		++i;
 	}
-
+	internal_warningf("ulimit: %c", what);
+	return (1);
+ found:
 	if (wp[builtin_opt.optind]) {
 		if (all || wp[builtin_opt.optind + 1]) {
 			bi_errorf("too many arguments");
 			return (1);
 		}
-		return (set_ulimit(l, wp[builtin_opt.optind], how));
+		return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how));
 	}
 	if (!all)
-		print_ulimit(l, how);
-	else for (l = limits; l->name; l++) {
-		shprintf("%-20s ", l->name);
-		print_ulimit(l, how);
+		print_ulimit(rlimits[i], how);
+	else for (i = 0; i < NELEM(rlimits); ++i) {
+		shprintf("%-20s ", rlimits[i]->name);
+		print_ulimit(rlimits[i], how);
 	}
 	return (0);
 }
@@ -3611,7 +3489,11 @@
 	}
 
 	if (getrlimit(l->resource, &limit) < 0) {
-		/* some can't be read, e.g. Linux RLIMIT_LOCKS */
+#ifndef MKSH_SMALL
+		bi_errorf("limit %s could not be read, contact the mksh developers: %s",
+		    l->name, cstrerror(errno));
+#endif
+		/* some can't be read */
 		limit.rlim_cur = RLIM_INFINITY;
 		limit.rlim_max = RLIM_INFINITY;
 	}
@@ -3735,7 +3617,7 @@
 			fn = *wp++;
 			if (fn[0] == '-' && fn[1] == '\0')
 				fd = STDIN_FILENO;
-			else if ((fd = open(fn, O_RDONLY)) < 0) {
+			else if ((fd = open(fn, O_RDONLY | O_BINARY)) < 0) {
 				eno = errno;
 				bi_errorf("%s: %s", fn, cstrerror(eno));
 				rv = 1;
@@ -3844,3 +3726,24 @@
 	return (rv);
 }
 #endif
+
+#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
+static int
+c_suspend(const char **wp)
+{
+	if (wp[1] != NULL) {
+		bi_errorf("too many arguments");
+		return (1);
+	}
+	if (Flag(FLOGIN)) {
+		/* Can't suspend an orphaned process group. */
+		if (getpgid(kshppid) == getpgid(0) ||
+		    getsid(kshppid) != getsid(0)) {
+			bi_errorf("can't suspend a login shell");
+			return (1);
+		}
+	}
+	j_suspend();
+	return (0);
+}
+#endif
diff --git a/src/histrap.c b/src/histrap.c
index 3b28f23..d15cc8d 100644
--- a/src/histrap.c
+++ b/src/histrap.c
@@ -3,7 +3,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012
+ *		 2011, 2012, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -27,7 +27,7 @@
 #include <sys/file.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.131 2012/12/28 02:28:35 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134 2014/06/09 13:25:53 tg Exp $");
 
 Trap sigtraps[NSIG + 1];
 static struct sigaction Sigact_ign;
@@ -442,7 +442,7 @@
 			hp = NULL;
 		}
 	} else {
-		int anchored = *str == '?' ? (++str, 0) : 1;
+		bool anchored = *str == '?' ? (++str, false) : true;
 
 		/* the -1 is to avoid the current fc command */
 		if ((n = findhist(histptr - history - 1, 0, str, anchored)) < 0)
@@ -509,7 +509,7 @@
  * direction.
  */
 int
-findhist(int start, int fwd, const char *str, int anchored)
+findhist(int start, int fwd, const char *str, bool anchored)
 {
 	char **hp;
 	int maxhist = histptr - history;
@@ -720,7 +720,8 @@
 
  retry:
 	/* we have a file and are interactive */
-	if ((fd = open(hname, O_RDWR | O_CREAT | O_APPEND, 0600)) < 0)
+	if ((fd = open(hname, O_RDWR | O_CREAT | O_APPEND | O_BINARY,
+	    0600)) < 0)
 		return;
 
 	histfd = savefd(fd);
@@ -756,7 +757,7 @@
 			/* create temporary file */
 			nhname = shf_smprintf("%s.%d", hname, (int)procpid);
 			if ((fd = open(nhname, O_RDWR | O_CREAT | O_TRUNC |
-			    O_EXCL, 0600)) < 0) {
+			    O_EXCL | O_BINARY, 0600)) < 0) {
 				/* just don't truncate then, meh. */
 				goto hist_trunc_dont;
 			}
@@ -976,6 +977,7 @@
 	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++) {
 		sigtraps[i].signal = i;
 		if (i == ksh_SIGERR) {
diff --git a/src/jobs.c b/src/jobs.c
index 3277c78..18179c1 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -1,8 +1,8 @@
-/*	$OpenBSD: jobs.c,v 1.39 2009/12/13 04:36:48 deraadt Exp $	*/
+/*	$OpenBSD: jobs.c,v 1.40 2013/09/04 15:49:18 millert Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
- *		 2012, 2013
+ *		 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.100 2013/07/26 20:33:23 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.105 2014/10/03 12:32:48 tg Exp $");
 
 #if HAVE_KILLPG
 #define mksh_killpg		killpg
@@ -225,6 +225,54 @@
 	}
 }
 
+#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
+/* suspend the shell */
+void
+j_suspend(void)
+{
+	struct sigaction sa, osa;
+
+	/* Restore tty and pgrp. */
+	if (ttypgrp_ok) {
+		if (tty_hasstate)
+			mksh_tcset(tty_fd, &tty_state);
+		if (restore_ttypgrp >= 0) {
+			if (tcsetpgrp(tty_fd, restore_ttypgrp) < 0) {
+				warningf(false, "%s: %s %s: %s", "j_suspend",
+				    "tcsetpgrp", "failed", cstrerror(errno));
+			} else if (setpgid(0, restore_ttypgrp) < 0) {
+				warningf(false, "%s: %s %s: %s", "j_suspend",
+				    "setpgid", "failed", cstrerror(errno));
+			}
+		}
+	}
+
+	/* Suspend the shell. */
+	memset(&sa, 0, sizeof(sa));
+	sigemptyset(&sa.sa_mask);
+	sa.sa_handler = SIG_DFL;
+	sigaction(SIGTSTP, &sa, &osa);
+	kill(0, SIGTSTP);
+
+	/* Back from suspend, reset signals, pgrp and tty. */
+	sigaction(SIGTSTP, &osa, NULL);
+	if (ttypgrp_ok) {
+		if (restore_ttypgrp >= 0) {
+			if (setpgid(0, kshpid) < 0) {
+				warningf(false, "%s: %s %s: %s", "j_suspend",
+				    "setpgid", "failed", cstrerror(errno));
+				ttypgrp_ok = false;
+			} else if (tcsetpgrp(tty_fd, kshpid) < 0) {
+				warningf(false, "%s: %s %s: %s", "j_suspend",
+				    "tcsetpgrp", "failed", cstrerror(errno));
+				ttypgrp_ok = false;
+			}
+		}
+		tty_init_state();
+	}
+}
+#endif
+
 /* job cleanup before shell exit */
 void
 j_exit(void)
@@ -1222,6 +1270,15 @@
 				rv = vp->val.i;
 			p = p->next;
 		}
+	} else if (Flag(FPIPEFAIL) && (j->proc_list != NULL)) {
+		Proc *p = j->proc_list;
+		int i;
+
+		while (p != NULL) {
+			if ((i = proc_errorlevel(p)))
+				rv = i;
+			p = p->next;
+		}
 	}
 
 	if (!(flags & JW_ASYNCNOTIFY)
@@ -1281,7 +1338,11 @@
 	getrusage(RUSAGE_CHILDREN, &ru0);
 	do {
 #ifndef MKSH_NOPROSPECTOFWORK
-		pid = waitpid(-1, &status, (WNOHANG|WUNTRACED));
+		pid = waitpid(-1, &status, (WNOHANG |
+#if defined(WCONTINUED) && defined(WIFCONTINUED)
+		    WCONTINUED |
+#endif
+		    WUNTRACED));
 #else
 		pid = wait(&status);
 #endif
@@ -1320,6 +1381,13 @@
 		if (WIFSTOPPED(status))
 			p->state = PSTOPPED;
 		else
+#if defined(WCONTINUED) && defined(WIFCONTINUED)
+		  if (WIFCONTINUED(status)) {
+			p->state = j->state = PRUNNING;
+			/* skip check_job(), no-op in this case */
+			continue;
+		} else
+#endif
 #endif
 		  if (WIFSIGNALED(status))
 			p->state = PSIGNALLED;
diff --git a/src/lex.c b/src/lex.c
index e58d8b8..9d39998 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -1,8 +1,8 @@
-/*	$OpenBSD: lex.c,v 1.47 2013/03/03 19:11:34 guenther Exp $	*/
+/*	$OpenBSD: lex.c,v 1.49 2013/12/17 16:37:06 deraadt Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013
+ *		 2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.188 2013/08/10 13:44:31 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.193 2014/06/29 11:28:28 tg Exp $");
 
 /*
  * states while lexing word
@@ -159,9 +159,10 @@
 	state = statep->type;					\
 } while (/* CONSTCOND */ 0)
 
-#define PUSH_SRETRACE()	do {					\
+#define PUSH_SRETRACE(s) do {					\
 	struct sretrace_info *ri;				\
 								\
+	PUSH_STATE(s);						\
 	statep->ls_start = Xsavepos(ws, wp);			\
 	ri = alloc(sizeof(struct sretrace_info), ATEMP);	\
 	Xinit(ri->xs, ri->xp, 64, ATEMP);			\
@@ -176,6 +177,7 @@
 	dp = (void *)retrace_info;				\
 	retrace_info = retrace_info->next;			\
 	afree(dp, ATEMP);					\
+	POP_STATE();						\
 } while (/* CONSTCOND */ 0)
 
 /**
@@ -404,9 +406,8 @@
 					c = getsc();
 					if (c == '(') /*)*/ {
 						*wp++ = EXPRSUB;
-						PUSH_STATE(SASPAREN);
+						PUSH_SRETRACE(SASPAREN);
 						statep->nparen = 2;
-						PUSH_SRETRACE();
 						*retrace_info->xp++ = '(';
 					} else {
 						ungetsc(c);
@@ -650,7 +651,6 @@
 				if (statep->nparen == 1) {
 					/* end of EXPRSUB */
 					POP_SRETRACE();
-					POP_STATE();
 
 					if ((c2 = getsc()) == /*(*/ ')') {
 						cz = strlen(sp) - 2;
@@ -833,8 +833,7 @@
 				} else if (c2 == '"') {
 					/* FALLTHROUGH */
 			case '"':
-					state = statep->type = SHEREDQUOTE;
-					PUSH_SRETRACE();
+					PUSH_SRETRACE(SHEREDQUOTE);
 					break;
 				}
 				ungetsc(c2);
@@ -1440,6 +1439,7 @@
 		alarm(0);
 	}
 	cp = Xstring(s->xs, xp);
+	rndpush(cp);
 	s->start = s->str = cp;
 	strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
 	/* Note: if input is all nulls, this is not eof */
@@ -1521,9 +1521,10 @@
 int
 pprompt(const char *cp, int ntruncate)
 {
-	int columns = 0, lines = 0;
-	bool indelimit = false;
 	char delimiter = 0;
+	bool doprint = (ntruncate != -1);
+	bool indelimit = false;
+	int columns = 0, lines = 0;
 
 	/*
 	 * Undocumented AT&T ksh feature:
@@ -1552,18 +1553,19 @@
 		else if (UTFMODE && ((unsigned char)*cp > 0x7F)) {
 			const char *cp2;
 			columns += utf_widthadj(cp, &cp2);
-			if (indelimit ||
-			    (ntruncate < (x_cols * lines + columns)))
+			if (doprint && (indelimit ||
+			    (ntruncate < (x_cols * lines + columns))))
 				shf_write(cp, cp2 - cp, shl_out);
 			cp = cp2 - /* loop increment */ 1;
 			continue;
 		} else
 			columns++;
-		if ((*cp != delimiter) &&
+		if (doprint && (*cp != delimiter) &&
 		    (indelimit || (ntruncate < (x_cols * lines + columns))))
 			shf_putc(*cp, shl_out);
 	}
-	shf_flush(shl_out);
+	if (doprint)
+		shf_flush(shl_out);
 	return (x_cols * lines + columns);
 }
 
diff --git a/src/main.c b/src/main.c
index 291ab40..f12d9b9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,11 +1,11 @@
-/*	$OpenBSD: main.c,v 1.52 2013/06/15 17:25:19 millert Exp $	*/
-/*	$OpenBSD: tty.c,v 1.9 2006/03/14 22:08:01 deraadt Exp $	*/
-/*	$OpenBSD: io.c,v 1.22 2006/03/17 16:30:13 millert Exp $	*/
+/*	$OpenBSD: main.c,v 1.54 2013/11/28 10:33:37 sobrado Exp $	*/
+/*	$OpenBSD: tty.c,v 1.10 2014/08/10 02:44:26 guenther Exp $	*/
+/*	$OpenBSD: io.c,v 1.25 2014/08/11 20:28:47 guenther Exp $	*/
 /*	$OpenBSD: table.c,v 1.15 2012/02/19 07:52:30 otto Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013
+ *		 2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -34,7 +34,7 @@
 #include <locale.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.269 2013/07/25 18:07:46 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.284 2014/10/03 17:19:27 tg Exp $");
 
 extern char **environ;
 
@@ -48,7 +48,6 @@
 
 static uint8_t isuc(const char *);
 static int main_init(int, const char *[], Source **, struct block **);
-uint32_t chvt_rndsetup(const void *, size_t);
 void chvt_reinit(void);
 static void reclaim(void);
 static void remove_temps(struct temp *);
@@ -64,7 +63,7 @@
 
 static const char *initcoms[] = {
 	Ttypeset, "-r", initvsn, NULL,
-	Ttypeset, "-x", "HOME", "PATH", "RANDOM", "SHELL", NULL,
+	Ttypeset, "-x", "HOME", "PATH", "SHELL", NULL,
 	Ttypeset, "-i10", "COLUMNS", "LINES", "SECONDS", "TMOUT", NULL,
 	Talias,
 	"integer=typeset -i",
@@ -76,7 +75,6 @@
 	/* not in Android for political reasons */
 	/* not in ARGE mksh due to no job control */
 	"stop=kill -STOP",
-	"suspend=kill -STOP $$",
 #endif
 	"autoload=typeset -fu",
 	"functions=typeset -f",
@@ -144,21 +142,6 @@
 	return ((mksh_uari_t)h);
 }
 
-uint32_t
-chvt_rndsetup(const void *bp, size_t sz)
-{
-	register uint32_t h;
-
-	NZATInit(h);
-	/* variation through pid, ppid, and the works */
-	NZATUpdateMem(h, &rndsetupstate, sizeof(rndsetupstate));
-	/* some variation, some possibly entropy, depending on OE */
-	NZATUpdateMem(h, bp, sz);
-	NZAATFinish(h);
-
-	return (h);
-}
-
 void
 chvt_reinit(void)
 {
@@ -201,7 +184,7 @@
 	int argi, i;
 	Source *s = NULL;
 	struct block *l;
-	unsigned char restricted, errexit, utf_flag;
+	unsigned char restricted_shell, errexit, utf_flag;
 	char *cp;
 	const char *ccp, **wp;
 	struct tbl *vp;
@@ -247,6 +230,23 @@
 	if (!*ccp)
 		ccp = empty_argv[0];
 
+	/*
+	 * Turn on nohup by default. (AT&T ksh does not have a nohup
+	 * option - it always sends the hup).
+	 */
+	Flag(FNOHUP) = 1;
+
+	/*
+	 * Turn on brace expansion by default. AT&T kshs that have
+	 * alternation always have it on.
+	 */
+	Flag(FBRACEEXPAND) = 1;
+
+	/*
+	 * Turn on "set -x" inheritance by default.
+	 */
+	Flag(FXTRACEREC) = 1;
+
 	/* define built-in commands and see if we were called as one */
 	ktinit(APERM, &builtins,
 	    /* currently up to 51 builtins: 75% of 128 = 2^7 */
@@ -329,25 +329,6 @@
 	/* setstr can't fail here */
 	setstr(vp, def_path, KSH_RETURN_ERROR);
 
-	/*
-	 * Turn on nohup by default for now - will change to off
-	 * by default once people are aware of its existence
-	 * (AT&T ksh does not have a nohup option - it always sends
-	 * the hup).
-	 */
-	Flag(FNOHUP) = 1;
-
-	/*
-	 * Turn on brace expansion by default. AT&T kshs that have
-	 * alternation always have it on.
-	 */
-	Flag(FBRACEEXPAND) = 1;
-
-	/*
-	 * Turn on "set -x" inheritance by default.
-	 */
-	Flag(FXTRACEREC) = 1;
-
 #ifndef MKSH_NO_CMDLINE_EDITING
 	/*
 	 * Set edit mode to emacs by default, may be overridden
@@ -361,9 +342,14 @@
 #endif
 
 	/* import environment */
-	if (environ != NULL)
-		for (wp = (const char **)environ; *wp != NULL; wp++)
+	if (environ != NULL) {
+		wp = (const char **)environ;
+		while (*wp != NULL) {
+			rndpush(*wp);
 			typeset(*wp, IMPORT | EXPORT, 0, 0, 0);
+			++wp;
+		}
+	}
 
 	/* for security */
 	typeset(initifs, 0, 0, 0, 0);
@@ -421,7 +407,11 @@
 	setint_n((vp_pipest = global("PIPESTATUS")), 0, 10);
 
 	/* Set this before parsing arguments */
-	Flag(FPRIVILEGED) = kshuid != ksheuid || kshgid != kshegid;
+	Flag(FPRIVILEGED) = (
+#if HAVE_ISSETUGID
+	    issetugid() ||
+#endif
+	    kshuid != ksheuid || kshgid != kshegid) ? 2 : 0;
 
 	/* this to note if monitor is set on command line (see below) */
 #ifndef MKSH_UNEMPLOYED
@@ -436,44 +426,6 @@
 			return (1);
 	}
 
-#if defined(DEBUG) && !defined(MKSH_LEGACY_MODE)
-	/* test wraparound of arithmetic types */
-	{
-		volatile long xl;
-		volatile unsigned long xul;
-		volatile int xi;
-		volatile unsigned int xui;
-		volatile mksh_ari_t xa;
-		volatile mksh_uari_t xua, xua2;
-		volatile uint8_t xc;
-
-		xa = 2147483647;
-		xua = 2147483647;
-		++xa;
-		++xua;
-		xua2 = xa;
-		xl = xa;
-		xul = xua;
-		xa = 0;
-		xua = 0;
-		--xa;
-		--xua;
-		xi = xa;
-		xui = xua;
-		xa = -1;
-		xua = xa;
-		++xa;
-		++xua;
-		xc = 0;
-		--xc;
-		if ((xua2 != 2147483648UL) ||
-		    (xl != (-2147483647L-1)) || (xul != 2147483648UL) ||
-		    (xi != -1) || (xui != 4294967295U) ||
-		    (xa != 0) || (xua != 0) || (xc != 255))
-			errorf("integer wraparound test failed");
-	}
-#endif
-
 	/* process this later only, default to off (hysterical raisins) */
 	utf_flag = UTFMODE;
 	UTFMODE = 0;
@@ -485,7 +437,6 @@
 		s = pushs(SSTRINGCMDLINE, ATEMP);
 		if (!(s->start = s->str = argv[argi++]))
 			errorf("%s %s", "-c", "requires an argument");
-#if !defined(MKSH_SMALL)
 		while (*s->str) {
 			if (*s->str != ' ' && ctype(*s->str, C_QUOTE))
 				break;
@@ -494,7 +445,6 @@
 		if (!*s->str)
 			s->flags |= SF_MAYEXEC;
 		s->str = s->start;
-#endif
 #ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
 		/* compatibility to MidnightBSD 0.1 /bin/sh (kludge) */
 		if (Flag(FSH) && argv[argi] && !strcmp(argv[argi], "--"))
@@ -543,12 +493,14 @@
 #ifndef MKSH_ASSUME_UTF8
 			/* auto-detect from locale or environment */
 			utf_flag = 4;
-#elif MKSH_ASSUME_UTF8
+#else /* this may not be an #elif */
+#if MKSH_ASSUME_UTF8
 			utf_flag = 1;
 #else
 			/* always disable UTF-8 (for interactive) */
 			utf_flag = 0;
 #endif
+#endif
 		}
 #ifndef MKSH_NO_CMDLINE_EDITING
 		x_init();
@@ -625,7 +577,7 @@
 	}
 
 	/* Disable during .profile/ENV reading */
-	restricted = Flag(FRESTRICTED);
+	restricted_shell = Flag(FRESTRICTED);
 	Flag(FRESTRICTED) = 0;
 	errexit = Flag(FERREXIT);
 	Flag(FERREXIT) = 0;
@@ -637,25 +589,25 @@
 	if (!current_wd[0] && Flag(FTALKING))
 		warningf(false, "can't determine current directory");
 
-	if (Flag(FLOGIN)) {
+	if (Flag(FLOGIN))
 		include(MKSH_SYSTEM_PROFILE, 0, NULL, true);
-		if (!Flag(FPRIVILEGED))
-			include(substitute("$HOME/.profile", 0), 0,
-			    NULL, true);
-	}
-	if (Flag(FPRIVILEGED))
+	if (!Flag(FPRIVILEGED)) {
+		if (Flag(FLOGIN))
+			include(substitute("$HOME/.profile", 0), 0, NULL, true);
+		if (Flag(FTALKING)) {
+			cp = substitute(substitute("${ENV:-" MKSHRC_PATH "}",
+			    0), DOTILDE);
+			if (cp[0] != '\0')
+				include(cp, 0, NULL, true);
+		}
+	} else {
 		include(MKSH_SUID_PROFILE, 0, NULL, true);
-	else if (Flag(FTALKING)) {
-		char *env_file;
-
-		/* include $ENV */
-		env_file = substitute(substitute("${ENV:-" MKSHRC_PATH "}", 0),
-		    DOTILDE);
-		if (*env_file != '\0')
-			include(env_file, 0, NULL, true);
+		/* turn off -p if not set explicitly */
+		if (Flag(FPRIVILEGED) != 1)
+			change_flag(FPRIVILEGED, OF_INTERNAL, false);
 	}
 
-	if (restricted) {
+	if (restricted_shell) {
 		shcomexec(restr_com);
 		/* After typeset command... */
 		Flag(FRESTRICTED) = 1;
@@ -873,11 +825,8 @@
 					unwind(LEXIT);
 				break;
 			}
-		}
-#if !defined(MKSH_SMALL)
-		  else if ((s->flags & SF_MAYEXEC) && t->type == TCOM)
+		} else if ((s->flags & SF_MAYEXEC) && t->type == TCOM)
 			t->u.evalflags |= DOTCOMEXEC;
-#endif
 		if (!Flag(FNOEXEC) || (s->flags & SF_TTY))
 			exstat = execute(t, 0, NULL) & 0xFF;
 
@@ -1659,7 +1608,8 @@
 	} while (len < 5);
 
 	/* cyclically attempt to open a temporary file */
-	while ((i = open(tp->tffn, O_CREAT | O_EXCL | O_RDWR, 0600)) < 0) {
+	while ((i = open(tp->tffn, O_CREAT | O_EXCL | O_RDWR | O_BINARY,
+	    0600)) < 0) {
 		if (errno != EEXIST)
 			goto maketemp_out;
 		/* count down from z to a then from 9 to 0 */
@@ -1921,9 +1871,10 @@
 
 	cb = *ocb;
 	if (forread) {
+		cb.c_iflag &= ~(ISTRIP);
 		cb.c_lflag &= ~(ICANON) | ECHO;
 	} else {
-		cb.c_iflag &= ~(INLCR | ICRNL);
+		cb.c_iflag &= ~(INLCR | ICRNL | ISTRIP);
 		cb.c_lflag &= ~(ISIG | ICANON | ECHO);
 	}
 #if defined(VLNEXT) && defined(_POSIX_VDISABLE)
diff --git a/src/mirhash.h b/src/mirhash.h
new file mode 100644
index 0000000..05729bc
--- /dev/null
+++ b/src/mirhash.h
@@ -0,0 +1,224 @@
+/*-
+ * Copyright © 2011, 2014
+ *	Thorsten Glaser <tg@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un‐
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person’s immediate fault when using the work as intended.
+ *-
+ * This file provides BAFH (Better Avalanche for the Jenkins Hash) as
+ * inline macro bodies that operate on “register uint32_t” variables,
+ * with variants that use their local intermediate registers.
+ *
+ * Usage note for BAFH with entropy distribution: input up to 4 bytes
+ * is best combined into a 32-bit unsigned integer, which is then run
+ * through BAFHFinish_reg for mixing and then used as context instead
+ * of 0. Longer input should be handled the same: take the first four
+ * bytes as IV after mixing then add subsequent bytes the same way.
+ * This needs counting input bytes and is endian-dependent, thus not,
+ * for speed reasons, specified for the regular stable hash, but very
+ * much recommended if the actual output value may differ across runs
+ * (so is using a random value instead of 0 for the IV).
+ *-
+ * Little quote gem:
+ *	We are looking into it. Changing the core
+ *	hash function in PHP isn't a trivial change
+ *	and will take us some time.
+ * -- Rasmus Lerdorf
+ */
+
+#ifndef SYSKERN_MIRHASH_H
+#define SYSKERN_MIRHASH_H 1
+#define SYSKERN_MIRHASH_BAFH
+
+#include <sys/types.h>
+
+__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.3 2014/10/02 19:34:06 tg Exp $");
+
+/*-
+ * BAFH itself is defined by the following primitives:
+ *
+ * • BAFHInit(ctx) initialises the hash context, which consists of a
+ *   sole 32-bit unsigned integer (ideally in a register), to 0.
+ *   It is possible to use any initial value out of [0; 2³²[ – which
+ *   is, in fact, recommended if using BAFH for entropy distribution
+ *   – but for a regular stable hash, the IV 0 is needed.
+ *
+ * • BAFHUpdateOctet(ctx,val) compresses the unsigned 8-bit quantity
+ *   into the hash context. The algorithm used is Jenkins’ one-at-a-
+ *   time, except that an additional constant 1 is added so that, if
+ *   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!
+ *
+ * • BAFHFinish(ctx) avalanches the context around so every sub-byte
+ *   depends on all input octets; afterwards, the context variable’s
+ *   value is the hash output. BAFH does not use any padding, nor is
+ *   the input length added; this is due to the common use case (for
+ *   quick entropy distribution and use with a hashtable).
+ *   Warning: BAFHFinish uses the MixColumn algorithm of AES – which
+ *   is reversible (to avoid introducing funnels and reducing entro‐
+ *   py), so blinding may need to be employed for some uses, e.g. in
+ *   mksh, after a fork.
+ *
+ * The BAFHUpdateOctet and BAFHFinish are available in two flavours:
+ * suffixed with _reg (assumes the context is in a register) or _mem
+ * (which doesn’t).
+ *
+ * The following high-level macros (with _reg and _mem variants) are
+ * available:
+ *
+ * • BAFHUpdateMem(ctx,buf,len) adds a memory block to a context.
+ * • BAFHUpdateStr(ctx,buf) is equivalent to using len=strlen(buf).
+ * • BAFHHostMem(ctx,buf,len) calculates the hash of the memory buf‐
+ *   fer using the first 4 octets (mixed) for IV, as outlined above;
+ *   the result is endian-dependent; “ctx” assumed to be a register.
+ * • 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.
+ *
+ * To stay portable, never use the BAFHHost*() macros (these are for
+ * host-local entropy shuffling), and encode numbers using ULEB128.
+ */
+
+#define BAFHInit(h) do {					\
+	(h) = 0;						\
+} while (/* CONSTCOND */ 0)
+
+#define BAFHUpdateOctet_reg(h,b) do {				\
+	(h) += (uint8_t)(b);					\
+	++(h);							\
+	(h) += (h) << 10;					\
+	(h) ^= (h) >> 6;					\
+} while (/* CONSTCOND */ 0)
+
+#define BAFHUpdateOctet_mem(m,b) do {				\
+	register uint32_t BAFH_h = (m);				\
+								\
+	BAFHUpdateOctet_reg(BAFH_h, (b));			\
+	(m) = BAFH_h;						\
+} while (/* CONSTCOND */ 0)
+
+#define BAFHror(eax,cl) (((eax) >> (cl)) | ((eax) << (32 - (cl))))
+
+#define BAFHFinish_reg(h) do {					\
+	register uint32_t BAFHFinish_v;				\
+								\
+	BAFHFinish_v = ((h) >> 7) & 0x01010101U;		\
+	BAFHFinish_v += BAFHFinish_v << 1;			\
+	BAFHFinish_v += BAFHFinish_v << 3;			\
+	BAFHFinish_v ^= ((h) << 1) & 0xFEFEFEFEU;		\
+								\
+	BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8);		\
+	BAFHFinish_v ^= ((h) = BAFHror((h), 8));		\
+	BAFHFinish_v ^= ((h) = BAFHror((h), 8));		\
+	(h) = BAFHror((h), 8) ^ BAFHFinish_v;			\
+} while (/* CONSTCOND */ 0)
+
+#define BAFHFinish_mem(m) do {					\
+	register uint32_t BAFHFinish_v, BAFH_h = (m);		\
+								\
+	BAFHFinish_v = (BAFH_h >> 7) & 0x01010101U;		\
+	BAFHFinish_v += BAFHFinish_v << 1;			\
+	BAFHFinish_v += BAFHFinish_v << 3;			\
+	BAFHFinish_v ^= (BAFH_h << 1) & 0xFEFEFEFEU;		\
+								\
+	BAFHFinish_v ^= BAFHror(BAFHFinish_v, 8);		\
+	BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8));		\
+	BAFHFinish_v ^= (BAFH_h = BAFHror(BAFH_h, 8));		\
+	(m) = BAFHror(BAFH_h, 8) ^ BAFHFinish_v;		\
+} while (/* CONSTCOND */ 0)
+
+#define BAFHUpdateMem_reg(h,p,z) do {				\
+	register const uint8_t *BAFHUpdate_p;			\
+	register size_t BAFHUpdate_z = (z);			\
+								\
+	BAFHUpdate_p = (const void *)(p);			\
+	while (BAFHUpdate_z--)					\
+		BAFHUpdateOctet_reg((h), *BAFHUpdate_p++);	\
+} while (/* CONSTCOND */ 0)
+
+/* meh should have named them _r/m but that’s not valid C */
+#define BAFHUpdateMem_mem(m,p,z) do {				\
+	register uint32_t BAFH_h = (m);				\
+								\
+	BAFHUpdateMem_reg(BAFH_h, (p), (z));			\
+	(m) = BAFH_h;						\
+} while (/* CONSTCOND */ 0)
+
+#define BAFHUpdateStr_reg(h,s) do {				\
+	register const uint8_t *BAFHUpdate_s;			\
+	register uint8_t BAFHUpdate_c;				\
+								\
+	BAFHUpdate_s = (const void *)(s);			\
+	while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0)		\
+		BAFHUpdateOctet_reg((h), BAFHUpdate_c);		\
+} while (/* CONSTCOND */ 0)
+
+#define BAFHUpdateStr_mem(m,s) do {				\
+	register uint32_t BAFH_h = (m);				\
+								\
+	BAFHUpdateStr_reg(BAFH_h, (s));				\
+	(m) = BAFH_h;						\
+} while (/* CONSTCOND */ 0)
+
+#define BAFHHostMem(h,p,z) do {					\
+	register const uint8_t *BAFHUpdate_p;			\
+	register size_t BAFHUpdate_z = (z);			\
+	size_t BAFHHost_z;					\
+	union {							\
+		uint8_t as_u8[4];				\
+		uint32_t as_u32;				\
+	} BAFHHost_v;						\
+								\
+	BAFHUpdate_p = (const void *)(p);			\
+	BAFHHost_v.as_u32 = 0;					\
+	BAFHHost_z = BAFHUpdate_z < 4 ? BAFHUpdate_z : 4;	\
+	memcpy(BAFHHost_v.as_u8, BAFHUpdate_p, BAFHHost_z);	\
+	BAFHUpdate_p += BAFHHost_z;				\
+	BAFHUpdate_z -= BAFHHost_z;				\
+	(h) = BAFHHost_v.as_u32;				\
+	BAFHFinish_reg(h);					\
+	while (BAFHUpdate_z--)					\
+		BAFHUpdateOctet_reg((h), *BAFHUpdate_p++);	\
+	BAFHFinish_reg(h);					\
+} while (/* CONSTCOND */ 0)
+
+#define BAFHHostStr(h,s) do {					\
+	register const uint8_t *BAFHUpdate_s;			\
+	register uint8_t BAFHUpdate_c;				\
+	union {							\
+		uint8_t as_u8[4];				\
+		uint32_t as_u32;				\
+	} BAFHHost_v;						\
+								\
+	BAFHUpdate_s = (const void *)(s);			\
+	if ((BAFHHost_v.as_u8[0] = *BAFHUpdate_s) != 0)		\
+		++BAFHUpdate_s;					\
+	if ((BAFHHost_v.as_u8[1] = *BAFHUpdate_s) != 0)		\
+		++BAFHUpdate_s;					\
+	if ((BAFHHost_v.as_u8[2] = *BAFHUpdate_s) != 0)		\
+		++BAFHUpdate_s;					\
+	if ((BAFHHost_v.as_u8[3] = *BAFHUpdate_s) != 0)		\
+		++BAFHUpdate_s;					\
+	(h) = BAFHHost_v.as_u32;				\
+	BAFHFinish_reg(h);					\
+	while ((BAFHUpdate_c = *BAFHUpdate_s++) != 0)		\
+		BAFHUpdateOctet_reg((h), BAFHUpdate_c);		\
+	BAFHFinish_reg(h);					\
+} while (/* CONSTCOND */ 0)
+
+#endif
diff --git a/src/misc.c b/src/misc.c
index adf4bc4..82d47d6 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1,9 +1,9 @@
-/*	$OpenBSD: misc.c,v 1.37 2009/04/19 20:34:05 sthen Exp $	*/
+/*	$OpenBSD: misc.c,v 1.38 2013/11/28 10:33:37 sobrado Exp $	*/
 /*	$OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013
+ *		 2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -30,7 +30,7 @@
 #include <grp.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.214 2013/08/11 14:57:09 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.219 2014/01/05 21:57:27 tg Exp $");
 
 #define KSH_CHVT_FLAG
 #ifdef MKSH_SMALL
@@ -49,10 +49,11 @@
 unsigned char chtypes[UCHAR_MAX + 1];
 
 static const unsigned char *pat_scan(const unsigned char *,
-    const unsigned char *, bool);
+    const unsigned char *, bool) MKSH_A_PURE;
 static int do_gmatch(const unsigned char *, const unsigned char *,
-    const unsigned char *, const unsigned char *);
-static const unsigned char *cclass(const unsigned char *, unsigned char);
+    const unsigned char *, const unsigned char *) MKSH_A_PURE;
+static const unsigned char *cclass(const unsigned char *, unsigned char)
+    MKSH_A_PURE;
 #ifdef KSH_CHVT_CODE
 static void chvt(const Getopt *);
 #endif
@@ -125,7 +126,7 @@
 
 
 #define SHFLAGS_DEFNS
-#include "sh_flags.h"
+#include "sh_flags.gen"
 
 #define OFC(i) (options[i][-2])
 #define OFF(i) (((const unsigned char *)options[i])[-1])
@@ -133,7 +134,7 @@
 
 const char * const options[] = {
 #define SHFLAGS_ITEMS
-#include "sh_flags.h"
+#include "sh_flags.gen"
 };
 
 /*
@@ -271,6 +272,7 @@
 
 		/*XXX this can probably be optimised */
 		kshegid = kshgid = getgid();
+		ksheuid = kshuid = getuid();
 #if HAVE_SETRESUGID
 		DO_SETUID(setresgid, (kshegid, kshegid, kshegid));
 #if HAVE_SETGROUPS
@@ -278,9 +280,8 @@
 		setgroups(1, &kshegid);
 #endif
 		DO_SETUID(setresuid, (ksheuid, ksheuid, ksheuid));
-#else
+#else /* !HAVE_SETRESUGID */
 		/* seteuid, setegid, setgid don't EAGAIN on Linux */
-		ksheuid = kshuid = getuid();
 #ifndef MKSH__NO_SETEUGID
 		seteuid(ksheuid);
 #endif
@@ -289,7 +290,7 @@
 		setegid(kshegid);
 #endif
 		setgid(kshegid);
-#endif
+#endif /* !HAVE_SETRESUGID */
 	} else if ((f == FPOSIX || f == FSH) && newval) {
 		/* Turning on -o posix or -o sh? */
 		Flag(FBRACEEXPAND) = 0;
@@ -341,10 +342,20 @@
     int what,
     bool *setargsp)
 {
-	static char cmd_opts[NELEM(options) + 5]; /* o:T:\0 */
-	static char set_opts[NELEM(options) + 6]; /* A:o;s\0 */
+	static const char cmd_opts[] =
+#define SHFLAGS_NOT_SET
+#define SHFLAGS_OPTCS
+#include "sh_flags.gen"
+#undef SHFLAGS_NOT_SET
+	    ;
+	static const char set_opts[] =
+#define SHFLAGS_NOT_CMD
+#define SHFLAGS_OPTCS
+#include "sh_flags.gen"
+#undef SHFLAGS_NOT_CMD
+	    ;
 	bool set;
-	char *opts;
+	const char *opts;
 	const char *array = NULL;
 	Getopt go;
 	size_t i;
@@ -352,36 +363,6 @@
 	bool sortargs = false;
 	bool fcompatseen = false;
 
-	/* First call? Build option strings... */
-	if (cmd_opts[0] == '\0') {
-		char ch, *p = cmd_opts, *q = set_opts;
-
-		/* see cmd_opts[] declaration */
-		*p++ = 'o';
-		*p++ = ':';
-#ifdef KSH_CHVT_FLAG
-		*p++ = 'T';
-		*p++ = ':';
-#endif
-		/* see set_opts[] declaration */
-		*q++ = 'A';
-		*q++ = ':';
-		*q++ = 'o';
-		*q++ = ';';
-		*q++ = 's';
-
-		for (i = 0; i < NELEM(options); i++) {
-			if ((ch = OFC(i))) {
-				if (OFF(i) & OF_CMDLINE)
-					*p++ = ch;
-				if (OFF(i) & OF_SET)
-					*q++ = ch;
-			}
-		}
-		*p = '\0';
-		*q = '\0';
-	}
-
 	if (what == OF_CMDLINE) {
 		const char *p = argv[0], *q;
 		/*
@@ -1972,7 +1953,6 @@
 
 
 #ifdef KSH_CHVT_CODE
-extern uint32_t chvt_rndsetup(const void *, size_t);
 extern void chvt_reinit(void);
 
 static void
@@ -2016,9 +1996,9 @@
 #endif
 	    }
 	}
-	if ((fd = open(dv, O_RDWR)) < 0) {
+	if ((fd = open(dv, O_RDWR | O_BINARY)) < 0) {
 		sleep(1);
-		if ((fd = open(dv, O_RDWR)) < 0) {
+		if ((fd = open(dv, O_RDWR | O_BINARY)) < 0) {
 			errorf("%s: %s %s", "chvt", "can't open", dv);
 		}
 	}
diff --git a/src/mksh.1 b/src/mksh.1
index 621aa97..480184e 100644
--- a/src/mksh.1
+++ b/src/mksh.1
@@ -1,8 +1,8 @@
-.\" $MirOS: src/bin/mksh/mksh.1,v 1.320 2013/08/10 14:11:39 tg Exp $
-.\" $OpenBSD: ksh.1,v 1.147 2013/06/13 19:43:09 millert Exp $
+.\" $MirOS: src/bin/mksh/mksh.1,v 1.344 2014/10/07 15:30:12 tg Exp $
+.\" $OpenBSD: ksh.1,v 1.153 2014/08/17 07:15:41 jmc Exp $
 .\"-
 .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-.\"		2010, 2011, 2012, 2013
+.\"		2010, 2011, 2012, 2013, 2014
 .\"	Thorsten Glaser <tg@mirbsd.org>
 .\"
 .\" Provided that these terms and disclaimer and all copyright notices
@@ -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: August 10 2013 $
+.Dd $Mdocdate: October 7 2014 $
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
@@ -208,7 +208,7 @@
 .Ar string .
 .It Fl i
 Interactive shell.
-A shell is
+A shell that reads commands from standard input is
 .Dq interactive
 if this
 option is used or if both standard input and standard error are attached
@@ -247,8 +247,7 @@
 Privileged shell.
 A shell is
 .Dq privileged
-if this option is used
-or if the real user ID or group ID does not match the
+if the real user ID or group ID does not match the
 effective user ID or group ID (see
 .Xr getuid 2
 and
@@ -257,6 +256,9 @@
 its effective user ID (group ID) to its real user ID (group ID).
 For further implications, see
 .Sx Startup files .
+If the shell is privileged and this flag is not explicitly set, the
+.Dq privileged
+option is cleared automatically after processing the startup files.
 .It Fl r
 Restricted shell.
 A shell is
@@ -366,6 +368,9 @@
 substitution; if unset or empty, the user mkshrc profile is processed;
 otherwise, if a file whose name is the substitution result exists,
 it is processed; non-existence is silently ignored.
+A privileged shell then drops privileges if neither was the
+.Fl p
+option given on the command line nor set during execution of the startup files.
 .Ss Command syntax
 The shell begins parsing its input by removing any backslash-newline
 combinations, then breaking it into
@@ -955,7 +960,7 @@
 .Sq !=
 and
 .Sq =
-expressions are patterns (e.g. the comparison
+expressions are a subset of patterns (e.g. the comparison
 .Ic \&[[ foobar = f*r ]]
 succeeds).
 This even works indirectly:
@@ -967,6 +972,7 @@
 .Pp
 Perhaps surprisingly, the first comparison succeeds,
 whereas the second doesn't.
+This does not apply to all extglob metacharacters, currently.
 .El
 .El
 .Ss Quoting
@@ -1123,7 +1129,6 @@
 nohup=\*(aqnohup \*(aq
 r=\*(aqfc \-e \-\*(aq
 stop=\*(aqkill \-STOP\*(aq
-suspend=\*(aqkill \-STOP $$\*(aq
 type=\*(aqwhence \-v\*(aq
 .Ed
 .Pp
@@ -1227,10 +1232,8 @@
 whitespace octets, delimit a field.
 As a special case, leading and trailing
 .Ev IFS
-whitespace and trailing
-.Ev IFS
-non-whitespace are stripped (i.e. no leading or trailing empty field
-is created by it); leading
+whitespace is stripped (i.e. no leading or trailing empty field
+is created by it); leading or trailing
 .Pf non- Ev IFS
 whitespace does create an empty field.
 .Pp
@@ -1685,17 +1688,10 @@
 must start with a space, opening parenthesis or digit to be recognised.
 Cannot be applied to a vector.
 .Pp
-.It Xo
-.Pf ${ Ar name
-.Pf @# Ns Oo Ar seed Oc Ns }
-.Xc
-The internal hash of the expansion of
-.Ar name ,
-with an optional (defaulting to zero)
-.Op Ar seed .
-At the moment, this is NZAAT (a 32-bit hash based on
-Bob Jenkins' one-at-a-time hash), but this is not set.
-This is the hash the shell uses internally for its associative arrays.
+.It Pf ${ Ns Ar name Ns @#}
+The hash (using the BAFH algorithm) of the expansion of
+.Ar name .
+This is also used internally for the shell's hashtables.
 .Pp
 .It Pf ${ Ns Ar name Ns @Q}
 A quoted expression safe for re-entry, whose value is the value of the
@@ -1879,6 +1875,9 @@
 .It Ev HISTSIZE
 The number of commands normally stored for history.
 The default is 2047.
+Do not set this value to insanely high values such as 1000000000 because
+.Nm
+can then not allocate enough memory for the history and will not start.
 .It Ev HOME
 The default directory for the
 .Ic cd
@@ -2037,7 +2036,7 @@
 in the prompt string:
 .Bd -literal -offset indent
 x=$(print \e\e001)
-PS1="$x$(print \e\er)$x$(tput smso)$x\e$PWD$x$(tput rmso)$x\*(Gt "
+PS1="$x$(print \e\er)$x$(tput so)$x\e$PWD$x$(tput se)$x\*(Gt "
 .Ed
 .Pp
 Due to a strong suggestion from David G. Korn,
@@ -2531,6 +2530,12 @@
 as numeric arguments to the
 .Ic test
 command, and as the value of an assignment to an integer parameter.
+.Em Warning :
+This also affects implicit conversion to integer, for example as done by the
+.Ic let
+command.
+.Em Never
+use unchecked user input, e.g. from the environment, in arithmetics!
 .Pp
 Expressions are calculated using signed arithmetic and the
 .Vt mksh_ari_t
@@ -2592,7 +2597,7 @@
 built-in command.
 Prefixing numbers with a sole digit zero
 .Pq Sq 0
-leads to the shell interpreting it as base-8 integer in
+leads to the shell interpreting it as base-8 (octal) integer in
 .Ic posix
 mode
 .Em only ;
@@ -2699,7 +2704,7 @@
 Less than; the result is 1 if the left argument is less than the right, 0 if
 not.
 .It \*(Lt= \*(Gt \*(Gt=
-Less than or equal, greater than or equal, greater than.
+Less than or equal, greater than, greater than or equal.
 See
 .Ic \*(Lt .
 .It \*(Lt\*(Lt\*(Lt \*(Gt\*(Gt\*(Gt
@@ -2713,8 +2718,15 @@
 .It + \- * /
 Addition, subtraction, multiplication, and division.
 .It %
-Remainder; the result is the remainder of the division of the left argument by
-the right.
+Remainder; the result is the symmetric remainder of the division of the left
+argument by the right.
+To get the mathematical modulus of
+.Dq a Ic mod No b ,
+use the formula
+.Do
+.Pq a % b + b
+.No % b
+.Dc .
 .It Xo
 .Sm off
 .Aq Ar arg1 ?
@@ -2953,8 +2965,9 @@
 .Ic false , fc , fg , getopts ,
 .Ic jobs , kill , let , mknod ,
 .Ic print , pwd , read , realpath ,
-.Ic rename , sleep , test , true ,
-.Ic ulimit , umask , unalias , whence
+.Ic rename , sleep , suspend , test ,
+.Ic true , ulimit , umask , unalias ,
+.Ic whence
 .Pp
 Once the type of command has been determined, any command-line parameter
 assignments are performed and exported for the duration of the command.
@@ -3411,6 +3424,7 @@
 .Ar last
 select commands from the history.
 Commands can be selected by history number
+(negative numbers go backwards from the current, most recent, line)
 or a string specifying the most recent command starting with that string.
 The
 .Fl l
@@ -3623,7 +3637,7 @@
 is syntactic sugar for
 .No let \&" Ns Ar expr Ns \&" .
 .Pp
-.It let]
+.It Ic let]
 Internally used alias for
 .Ic let .
 .Pp
@@ -4036,6 +4050,12 @@
 .It Fl C \*(Ba Fl o Ic noclobber
 Prevent \*(Gt redirection from overwriting existing files.
 Instead, \*(Gt\*(Ba must be used to force an overwrite.
+Note that this is not safe to use for creation of temporary files or
+lockfiles due to a TOCTOU in a check allowing one to redirect output to
+.Pa /dev/null
+or other device files even in
+.Ic noclobber
+mode.
 .It Fl e \*(Ba Fl o Ic errexit
 Exit (after executing the
 .Dv ERR
@@ -4242,6 +4262,9 @@
 Enable
 .Xr vi 1 Ns -like
 command-line editing (interactive shells only).
+See
+.Sx Vi editing mode
+for documentation and limitations.
 .It Fl o Ic vi\-esccomplete
 In vi command-line editing, do command and file name completion when escape
 (\*(ha[) is entered in command mode.
@@ -4315,6 +4338,16 @@
 .Nm mksh ,
 this is implemented as a shell alias instead of a builtin.
 .Pp
+.It Ic suspend
+Stops the shell as if it had received the suspend character from
+the terminal.
+It is not possible to suspend a login shell unless the parent process
+is a member of the same terminal session but is a member of a different
+process group.
+As a general rule, if the shell was started by another shell or via
+.Xr su 1 ,
+it can be suspended.
+.Pp
 .It Ic test Ar expression
 .It Ic \&[ Ar expression Ic \&]
 .Ic test
@@ -4878,7 +4911,7 @@
 .Pp
 .It Xo
 .Ic ulimit
-.Op Fl aBCcdefHiLlMmnOPpqrSsTtVvw
+.Op Fl aBCcdefHilMmnOPpqrSsTtVvw
 .Op Ar value
 .Xc
 Display or set process limits.
@@ -4929,8 +4962,6 @@
 .It Fl i Ar n
 Set the number of pending signals to
 .Ar n .
-.It Fl L Ar n
-Control flocks; documentation is missing.
 .It Fl l Ar n
 Impose a limit of
 .Ar n
@@ -5673,6 +5704,7 @@
 .Ss Vi editing mode
 .Em Note:
 The vi command-line editing mode is orphaned, yet still functional.
+It is 8-bit clean but specifically does not support UTF-8 or MBCS.
 .Pp
 The vi command-line editor in
 .Nm
@@ -6307,15 +6339,15 @@
 .%A Stephen G. Kochan
 .%A Patrick H. Wood
 .%B "\\*(tNUNIX\\*(sP Shell Programming"
-.%V "Revised Edition"
-.%D 1990
-.%I "Hayden"
-.%P "xi\ +\ 490 pages"
-.%O "ISBN 978\-0\-672\-48448\-3 (0\-672\-48448\-X)"
+.%V "3rd Edition"
+.%D 2003
+.%I "Sams"
+.%P "xiii\ +\ 437 pages"
+.%O "ISBN 978\-0\-672\-32490\-1 (0\-672\-32490\-3)"
 .Re
 .Rs
 .%A "IEEE Inc."
-.%B "\\*(tNIEEE\\*(sP Standard for Information Technology \*(en Portable Operating System Interface (POSIX)"
+.%T "\\*(tNIEEE\\*(sP Standard for Information Technology \*(en Portable Operating System Interface (POSIX)"
 .%V "Part 2: Shell and Utilities"
 .%D 1993
 .%I "IEEE Press"
@@ -6348,24 +6380,35 @@
 .%O "ISBN 978\-0\-201\-56324\-5 (0\-201\-56324\-X)"
 .Re
 .Sh AUTHORS
+.An -nosplit
 .Nm "The MirBSD Korn Shell"
 is developed by
 .An Thorsten Glaser Aq tg@mirbsd.org
 and currently maintained as part of The MirOS Project.
-This shell is based upon the Public Domain Korn SHell.
-The developer of mksh recognises the efforts of the pdksh authors,
-who had dedicated their work into Public Domain, our users, and
-all contributors, such as the Debian and OpenBSD projects.
-.\"
-.\" Charles Forsyth, author of the (Public Domain) Bourne Shell clone,
-.\" which mksh is derived from, agreed to the following:
-.\"
-.\" In countries where the Public Domain status of the work may not be
-.\" valid, its primary author hereby grants a copyright licence to the
-.\" general public to deal in the work without restriction and permis-
-.\" sion to sublicence derivates under the terms of any (OSI approved)
-.\" Open Source licence.
-.\"
+This shell is based on the public domain 7th edition Bourne shell clone by
+.An Charles Forsyth ,
+who kindly agreed to, in countries where the Public Domain status of the work
+may not be valid, grant a copyright licence to the general public to deal in
+the work without restriction and permission to sublicence derivates under the
+terms of any (OSI approved) Open Source licence,
+and parts of the BRL shell by
+.An Doug A. Gwyn ,
+.An Doug Kingston ,
+.An Ron Natalie ,
+.An Arnold Robbins ,
+.An Lou Salkind ,
+and others.
+The first release of
+.Nm pdksh
+was created by
+.An Eric Gisin ,
+and it was subsequently maintained by
+.An John R. MacMillan Aq Mt change!john@sq.sq.com ,
+.An Simon J. Gerraty Aq Mt sjg@zen.void.oz.au ,
+and
+.An Michael Rendell Aq Mt michael@cs.mun.ca .
+The effort of several projects, such as Debian and OpenBSD, and other
+contributors including our users, to improve the shell is appreciated.
 See the documentation, CVS, and web site for details.
 .Pp
 The BSD daemon is Copyright \(co Marshall Kirk McKusick.
@@ -6407,8 +6450,8 @@
 .Pp
 .Nm mksh
 provides a consistent set of 32-bit integer arithmetics, both signed
-and unsigned, with defined wraparound and sign of the result of a modulo
-operation, even (defying POSIX) on 64-bit systems.
+and unsigned, with defined wraparound and sign of the result of a
+remainder operation, even (defying POSIX) on 64-bit systems.
 If you require 64-bit integer arithmetics, use
 .Nm lksh Pq legacy mksh
 instead, but be aware that, in POSIX, it's legal for the OS to make
@@ -6425,7 +6468,7 @@
 .Ed
 .Pp
 This document attempts to describe
-.Nm mksh\ R48
+.Nm mksh\ R50
 and up,
 compiled without any options impacting functionality, such as
 .Dv MKSH_SMALL ,
diff --git a/src/rlimits.gen b/src/rlimits.gen
new file mode 100644
index 0000000..ef71dab
--- /dev/null
+++ b/src/rlimits.gen
@@ -0,0 +1,174 @@
+#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				};
+#elif defined(RLIMITS_ITEMS)
+#define FN(lname,lid,lfac,lopt)					(const struct limits *)(&rlimits_ ## lid),
+#endif
+#ifndef F0
+#define F0 FN
+#endif
+#ifdef RLIMIT_CPU
+FN("time(cpu-seconds)", RLIMIT_CPU, 1, 't')
+#endif
+#ifdef RLIMIT_FSIZE
+FN("file(blocks)", RLIMIT_FSIZE, 512, 'f')
+#endif
+#ifdef RLIMIT_CORE
+FN("coredump(blocks)", RLIMIT_CORE, 512, 'c')
+#endif
+#ifdef RLIMIT_DATA
+FN("data(KiB)", RLIMIT_DATA, 1024, 'd')
+#endif
+#ifdef RLIMIT_STACK
+FN("stack(KiB)", RLIMIT_STACK, 1024, 's')
+#endif
+#ifdef RLIMIT_MEMLOCK
+FN("lockedmem(KiB)", RLIMIT_MEMLOCK, 1024, 'l')
+#endif
+#ifdef RLIMIT_NOFILE
+FN("nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n')
+#endif
+#ifdef RLIMIT_NPROC
+FN("processes", RLIMIT_NPROC, 1, 'p')
+#endif
+#ifdef RLIMIT_SWAP
+FN("swap(KiB)", RLIMIT_SWAP, 1024, 'w')
+#endif
+#ifdef RLIMIT_TIME
+FN("humantime(seconds)", RLIMIT_TIME, 1, 'T')
+#endif
+#ifdef RLIMIT_NOVMON
+FN("vnodemonitors", RLIMIT_NOVMON, 1, 'V')
+#endif
+#ifdef RLIMIT_SIGPENDING
+FN("sigpending", RLIMIT_SIGPENDING, 1, 'i')
+#endif
+#ifdef RLIMIT_MSGQUEUE
+FN("msgqueue(bytes)", RLIMIT_MSGQUEUE, 1, 'q')
+#endif
+#ifdef RLIMIT_AIO_MEM
+FN("AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024, 'M')
+#endif
+#ifdef RLIMIT_AIO_OPS
+FN("AIOoperations", RLIMIT_AIO_OPS, 1, 'O')
+#endif
+#ifdef RLIMIT_TCACHE
+FN("cachedthreads", RLIMIT_TCACHE, 1, 'C')
+#endif
+#ifdef RLIMIT_SBSIZE
+FN("sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024, 'B')
+#endif
+#ifdef RLIMIT_PTHREAD
+FN("threadsperprocess", RLIMIT_PTHREAD, 1, 'P')
+#endif
+#ifdef RLIMIT_NICE
+FN("maxnice", RLIMIT_NICE, 1, 'e')
+#endif
+#ifdef RLIMIT_RTPRIO
+FN("maxrtprio", RLIMIT_RTPRIO, 1, 'r')
+#endif
+#ifdef ULIMIT_M_IS_RSS
+FN("resident-set(KiB)", RLIMIT_RSS, 1024, 'm')
+#endif
+#ifdef ULIMIT_M_IS_VMEM
+FN("memory(KiB)", RLIMIT_VMEM, 1024, 'm')
+#endif
+#ifdef ULIMIT_V_IS_VMEM
+FN("virtual-memory(KiB)", RLIMIT_VMEM, 1024, 'v')
+#endif
+#ifdef ULIMIT_V_IS_AS
+FN("address-space(KiB)", RLIMIT_AS, 1024, 'v')
+#endif
+#undef F0
+#undef FN
+#undef RLIMITS_DEFNS
+#undef RLIMITS_ITEMS
+#else
+"a"
+#ifdef RLIMIT_SBSIZE
+"B"
+#endif
+#ifdef RLIMIT_TCACHE
+"C"
+#endif
+#ifdef RLIMIT_CORE
+"c"
+#endif
+#ifdef RLIMIT_DATA
+"d"
+#endif
+#ifdef RLIMIT_NICE
+"e"
+#endif
+#ifdef RLIMIT_FSIZE
+"f"
+#endif
+"H"
+#ifdef RLIMIT_SIGPENDING
+"i"
+#endif
+#ifdef RLIMIT_MEMLOCK
+"l"
+#endif
+#ifdef RLIMIT_AIO_MEM
+"M"
+#endif
+#ifdef ULIMIT_M_IS_RSS
+"m"
+#endif
+#ifdef ULIMIT_M_IS_VMEM
+"m"
+#endif
+#ifdef RLIMIT_NOFILE
+"n"
+#endif
+#ifdef RLIMIT_AIO_OPS
+"O"
+#endif
+#ifdef RLIMIT_PTHREAD
+"P"
+#endif
+#ifdef RLIMIT_NPROC
+"p"
+#endif
+#ifdef RLIMIT_MSGQUEUE
+"q"
+#endif
+#ifdef RLIMIT_RTPRIO
+"r"
+#endif
+"S"
+#ifdef RLIMIT_STACK
+"s"
+#endif
+#ifdef RLIMIT_TIME
+"T"
+#endif
+#ifdef RLIMIT_CPU
+"t"
+#endif
+#ifdef RLIMIT_NOVMON
+"V"
+#endif
+#ifdef ULIMIT_V_IS_AS
+"v"
+#endif
+#ifdef ULIMIT_V_IS_VMEM
+"v"
+#endif
+#ifdef RLIMIT_SWAP
+"w"
+#endif
+#undef RLIMITS_OPTCS
+#endif
diff --git a/src/rlimits.opt b/src/rlimits.opt
new file mode 100644
index 0000000..6c3908b
--- /dev/null
+++ b/src/rlimits.opt
@@ -0,0 +1,96 @@
+@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				};
+@RLIMITS_ITEMS
+#define FN(lname,lid,lfac,lopt)					(const struct limits *)(&rlimits_ ## lid),
+@@
+
+/* generic options for the ulimit builtin */
+
+<a|
+<H|
+<S|
+
+/* do not use options -H, -S or -a or change the order */
+
+>t|RLIMIT_CPU
+FN("time(cpu-seconds)", RLIMIT_CPU, 1
+
+>f|RLIMIT_FSIZE
+FN("file(blocks)", RLIMIT_FSIZE, 512
+
+>c|RLIMIT_CORE
+FN("coredump(blocks)", RLIMIT_CORE, 512
+
+>d|RLIMIT_DATA
+FN("data(KiB)", RLIMIT_DATA, 1024
+
+>s|RLIMIT_STACK
+FN("stack(KiB)", RLIMIT_STACK, 1024
+
+>l|RLIMIT_MEMLOCK
+FN("lockedmem(KiB)", RLIMIT_MEMLOCK, 1024
+
+>n|RLIMIT_NOFILE
+FN("nofiles(descriptors)", RLIMIT_NOFILE, 1
+
+>p|RLIMIT_NPROC
+FN("processes", RLIMIT_NPROC, 1
+
+>w|RLIMIT_SWAP
+FN("swap(KiB)", RLIMIT_SWAP, 1024
+
+>T|RLIMIT_TIME
+FN("humantime(seconds)", RLIMIT_TIME, 1
+
+>V|RLIMIT_NOVMON
+FN("vnodemonitors", RLIMIT_NOVMON, 1
+
+>i|RLIMIT_SIGPENDING
+FN("sigpending", RLIMIT_SIGPENDING, 1
+
+>q|RLIMIT_MSGQUEUE
+FN("msgqueue(bytes)", RLIMIT_MSGQUEUE, 1
+
+>M|RLIMIT_AIO_MEM
+FN("AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024
+
+>O|RLIMIT_AIO_OPS
+FN("AIOoperations", RLIMIT_AIO_OPS, 1
+
+>C|RLIMIT_TCACHE
+FN("cachedthreads", RLIMIT_TCACHE, 1
+
+>B|RLIMIT_SBSIZE
+FN("sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024
+
+>P|RLIMIT_PTHREAD
+FN("threadsperprocess", RLIMIT_PTHREAD, 1
+
+>e|RLIMIT_NICE
+FN("maxnice", RLIMIT_NICE, 1
+
+>r|RLIMIT_RTPRIO
+FN("maxrtprio", RLIMIT_RTPRIO, 1
+
+>m|ULIMIT_M_IS_RSS
+FN("resident-set(KiB)", RLIMIT_RSS, 1024
+>m|ULIMIT_M_IS_VMEM
+FN("memory(KiB)", RLIMIT_VMEM, 1024
+
+>v|ULIMIT_V_IS_VMEM
+FN("virtual-memory(KiB)", RLIMIT_VMEM, 1024
+>v|ULIMIT_V_IS_AS
+FN("address-space(KiB)", RLIMIT_AS, 1024
+
+|RLIMITS_OPTCS
diff --git a/src/sh.h b/src/sh.h
index 5a95190..b3d1c0b 100644
--- a/src/sh.h
+++ b/src/sh.h
@@ -1,16 +1,16 @@
-/*	$OpenBSD: sh.h,v 1.31 2012/09/10 01:25:30 tedu Exp $	*/
+/*	$OpenBSD: sh.h,v 1.33 2013/12/18 13:53:12 millert Exp $	*/
 /*	$OpenBSD: shf.h,v 1.6 2005/12/11 18:53:51 deraadt Exp $	*/
 /*	$OpenBSD: table.h,v 1.8 2012/02/19 07:52:30 otto Exp $	*/
 /*	$OpenBSD: tree.h,v 1.10 2005/03/28 21:28:22 deraadt Exp $	*/
 /*	$OpenBSD: expand.h,v 1.6 2005/03/30 17:16:37 deraadt Exp $	*/
 /*	$OpenBSD: lex.h,v 1.13 2013/03/03 19:11:34 guenther Exp $	*/
-/*	$OpenBSD: proto.h,v 1.34 2012/06/27 07:17:19 otto Exp $	*/
+/*	$OpenBSD: proto.h,v 1.35 2013/09/04 15:49:19 millert Exp $	*/
 /*	$OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $	*/
 /*	$OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $	*/
 
 /*-
  * Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *	       2011, 2012, 2013
+ *	       2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -108,12 +108,12 @@
 
 #undef __attribute__
 #if HAVE_ATTRIBUTE_BOUNDED
-#define MKSH_A_BOUNDED(x,y,z)	__attribute__((__bounded__ (x, y, z)))
+#define MKSH_A_BOUNDED(x,y,z)	__attribute__((__bounded__(x, y, z)))
 #else
 #define MKSH_A_BOUNDED(x,y,z)	/* nothing */
 #endif
 #if HAVE_ATTRIBUTE_FORMAT
-#define MKSH_A_FORMAT(x,y,z)	__attribute__((__format__ (x, y, z)))
+#define MKSH_A_FORMAT(x,y,z)	__attribute__((__format__(x, y, z)))
 #else
 #define MKSH_A_FORMAT(x,y,z)	/* nothing */
 #endif
@@ -122,6 +122,11 @@
 #else
 #define MKSH_A_NORETURN		/* nothing */
 #endif
+#if HAVE_ATTRIBUTE_PURE
+#define MKSH_A_PURE		__attribute__((__pure__))
+#else
+#define MKSH_A_PURE		/* nothing */
+#endif
 #if HAVE_ATTRIBUTE_UNUSED
 #define MKSH_A_UNUSED		__attribute__((__unused__))
 #else
@@ -164,9 +169,9 @@
 #endif
 
 #ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.667 2013/08/14 20:26:19 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.697 2014/10/07 15:22:17 tg Exp $");
 #endif
-#define MKSH_VERSION "R48 2013/08/14"
+#define MKSH_VERSION "R50 2014/10/07"
 
 /* arithmetic types: C implementation */
 #if !HAVE_CAN_INTTYPES
@@ -298,7 +303,7 @@
 #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) != NULL) && ((s)[0] == '-') && ((s)[1] == '\0'))
+#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))
@@ -337,9 +342,19 @@
 #define NSIG		(SIGMAX+1)
 #elif defined(_SIGMAX)
 #define NSIG		(_SIGMAX+1)
+#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)
+# error Your NSIG value is not positive.
+#unset NSIG
+#define NSIG		64
+#endif
+
 
 /* OS-dependent additions (functions, variables, by OS) */
 
@@ -396,6 +411,10 @@
 #endif
 #endif
 
+#ifndef O_BINARY
+#define O_BINARY	0
+#endif
+
 #ifdef MKSH__NO_SYMLINK
 #undef S_ISLNK
 #define S_ISLNK(m)	(/* CONSTCOND */ 0)
@@ -414,12 +433,8 @@
 #define mksh_tcset(fd,st) ioctl((fd), TCSETAW, (st))
 #endif
 
-/* remove redundancies */
-
-#if defined(MirBSD) && (MirBSD >= 0x0AB3) && !defined(MKSH_OPTSTATIC)
-#define MKSH_mirbsd_wcwidth
-#define utf_wcwidth(i) wcwidth((__WCHAR_TYPE__)i)
-extern int wcwidth(__WCHAR_TYPE__);
+#ifndef ISTRIP
+#define ISTRIP		0
 #endif
 
 
@@ -518,7 +533,7 @@
 #define mkssert(e)	do { } while (/* CONSTCOND */ 0)
 #endif
 
-#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 481)
+#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 504)
 #error Must run Build.sh to compile this.
 extern void thiswillneverbedefinedIhope(void);
 int
@@ -660,7 +675,7 @@
  */
 enum sh_flag {
 #define SHFLAGS_ENUMS
-#include "sh_flags.h"
+#include "sh_flags.gen"
 	FNFLAGS		/* (place holder: how many flags are there) */
 };
 
@@ -1163,11 +1178,11 @@
 #define arrayindex(vp)	((unsigned long)((vp)->flag & AINDEX ? \
 			    (vp)->ua.index : 0))
 
-EXTERN enum {
+enum namerefflag {
 	SRF_NOP,
 	SRF_ENABLE,
 	SRF_DISABLE
-} set_refflag E_INIT(SRF_NOP);
+};
 
 /* command types */
 #define CNONE		0	/* undefined */
@@ -1380,22 +1395,8 @@
 #define DOTEMP	BIT(8)		/* dito: in word part of ${..[%#=?]..} */
 #define DOVACHECK BIT(9)	/* var assign check (for typeset, set, etc) */
 #define DOMARKDIRS BIT(10)	/* force markdirs behaviour */
-#if !defined(MKSH_SMALL)
 #define DOTCOMEXEC BIT(11)	/* not an eval flag, used by sh -c hack */
-#endif
-
-/*
- * The arguments of [[ .. ]] expressions are kept in t->args[] and flags
- * indicating how the arguments have been munged are kept in t->vars[].
- * The contents of t->vars[] are stuffed strings (so they can be treated
- * like all other t->vars[]) in which the second character is the one that
- * is examined. The DB_* defines are the values for these second characters.
- */
-#define DB_NORM	1	/* normal argument */
-#define DB_OR	2	/* || -> -o conversion */
-#define DB_AND	3	/* && -> -a conversion */
-#define DB_BE	4	/* an inserted -BE */
-#define DB_PAT	5	/* a pattern argument */
+#define DOASNFIELD BIT(12)	/* is assignment, change field handling */
 
 #define X_EXTRA	20	/* this many extra bytes in X string */
 
@@ -1426,7 +1427,7 @@
 #define XcheckN(xs, xp, n) do {					\
 	ssize_t more = ((xp) + (n)) - (xs).end;			\
 	if (more > 0)						\
-		(xp) = Xcheck_grow(&(xs), (xp), more);		\
+		(xp) = Xcheck_grow(&(xs), (xp), (size_t)more);	\
 } while (/* CONSTCOND */ 0)
 
 /* check for overflow, expand string */
@@ -1526,9 +1527,7 @@
 #define SF_ALIASEND	BIT(2)	/* faking space at end of alias */
 #define SF_TTY		BIT(3)	/* type == SSTDIN & it is a tty */
 #define SF_HASALIAS	BIT(4)	/* u.tblp valid (SALIAS, SEOF) */
-#if !defined(MKSH_SMALL)
 #define SF_MAYEXEC	BIT(5)	/* special sh -c optimisation hack */
-#endif
 
 typedef union {
 	int i;
@@ -1587,6 +1586,7 @@
 #undef CTRL
 #define	CTRL(x)		((x) == '?' ? 0x7F : (x) & 0x1F)	/* ASCII */
 #define	UNCTRL(x)	((x) ^ 0x40)				/* ASCII */
+#define	ISCTRL(x)	(((signed char)((uint8_t)(x) + 1)) < 33)
 
 #define IDENT		64
 
@@ -1614,48 +1614,6 @@
 } while (/* CONSTCOND */ 0)
 
 
-/* NZAAT hash based on Bob Jenkins' one-at-a-time hash */
-
-/* From: src/kern/include/nzat.h,v 1.2 2011/07/18 00:35:40 tg Exp $ */
-
-#define NZATInit(h) do {					\
-	(h) = 0;						\
-} while (/* CONSTCOND */ 0)
-
-#define NZATUpdateByte(h,b) do {				\
-	(h) += (uint8_t)(b);					\
-	++(h);							\
-	(h) += (h) << 10;					\
-	(h) ^= (h) >> 6;					\
-} while (/* CONSTCOND */ 0)
-
-#define NZATUpdateMem(h,p,z) do {				\
-	register const uint8_t *NZATUpdateMem_p;		\
-	register size_t NZATUpdateMem_z = (z);			\
-								\
-	NZATUpdateMem_p = (const void *)(p);			\
-	while (NZATUpdateMem_z--)				\
-		NZATUpdateByte((h), *NZATUpdateMem_p++);	\
-} while (/* CONSTCOND */ 0)
-
-#define NZATUpdateString(h,s) do {				\
-	register const char *NZATUpdateString_s;		\
-	register uint8_t NZATUpdateString_c;			\
-								\
-	NZATUpdateString_s = (const void *)(s);			\
-	while ((NZATUpdateString_c = *NZATUpdateString_s++))	\
-		NZATUpdateByte((h), NZATUpdateString_c);	\
-} while (/* CONSTCOND */ 0)
-
-#define NZAATFinish(h) do {					\
-	(h) += (h) << 10;					\
-	(h) ^= (h) >> 6;					\
-	(h) += (h) << 3;					\
-	(h) ^= (h) >> 11;					\
-	(h) += (h) << 15;					\
-} while (/* CONSTCOND */ 0)
-
-
 /* lalloc.c */
 void ainit(Area *);
 void afreeall(Area *);
@@ -1706,12 +1664,10 @@
 size_t utf_mbtowc(unsigned int *, const char *);
 size_t utf_wctomb(char *, unsigned int);
 int utf_widthadj(const char *, const char **);
-size_t utf_mbswidth(const char *);
-const char *utf_skipcols(const char *, int);
-size_t utf_ptradj(const char *);
-#ifndef MKSH_mirbsd_wcwidth
-int utf_wcwidth(unsigned int);
-#endif
+size_t utf_mbswidth(const char *) MKSH_A_PURE;
+const char *utf_skipcols(const char *, int) MKSH_A_PURE;
+size_t utf_ptradj(const char *) MKSH_A_PURE;
+int utf_wcwidth(unsigned int) MKSH_A_PURE;
 int ksh_access(const char *, int);
 struct tbl *tempvar(void);
 /* funcs.c */
@@ -1779,10 +1735,10 @@
 void sethistfile(const char *);
 #endif
 #if !defined(MKSH_NO_CMDLINE_EDITING) && !MKSH_S_NOVI
-char **histpos(void);
+char **histpos(void) MKSH_A_PURE;
 int histnum(int);
 #endif
-int findhist(int, int, const char *, int);
+int findhist(int, int, const char *, bool) MKSH_A_PURE;
 char **hist_get_newest(bool);
 void inittraps(void);
 void alarm_init(void);
@@ -1818,6 +1774,9 @@
 #ifndef MKSH_UNEMPLOYED
 int j_resume(const char *, int);
 #endif
+#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
+void j_suspend(void);
+#endif
 int j_jobs(const char *, int, int);
 void j_notify(void);
 pid_t j_async(void);
@@ -1895,15 +1854,15 @@
 /* misc.c */
 void setctypes(const char *, int);
 void initctypes(void);
-size_t option(const char *);
+size_t option(const char *) MKSH_A_PURE;
 char *getoptions(void);
 void change_flag(enum sh_flag, int, bool);
 void change_xtrace(unsigned char, bool);
 int parse_args(const char **, int, bool *);
 int getn(const char *, int *);
 int gmatchx(const char *, const char *, bool);
-int has_globbing(const char *, const char *);
-int xstrcmp(const void *, const void *);
+int has_globbing(const char *, const char *) MKSH_A_PURE;
+int xstrcmp(const void *, const void *) MKSH_A_PURE;
 void ksh_getopt_reset(Getopt *, int);
 int ksh_getopt(const char **, Getopt *, const char *);
 void print_value_quoted(struct shf *, const char *);
@@ -1995,19 +1954,21 @@
 void setint_n(struct tbl *, mksh_ari_t, int);
 struct tbl *typeset(const char *, uint32_t, uint32_t, int, int);
 void unset(struct tbl *, int);
-const char *skip_varname(const char *, int);
-const char *skip_wdvarname(const char *, bool);
-int is_wdvarname(const char *, bool);
-int is_wdvarassign(const char *);
+const char *skip_varname(const char *, bool) MKSH_A_PURE;
+const char *skip_wdvarname(const char *, bool) MKSH_A_PURE;
+int is_wdvarname(const char *, bool) MKSH_A_PURE;
+int is_wdvarassign(const char *) MKSH_A_PURE;
 struct tbl *arraysearch(struct tbl *, uint32_t);
 char **makenv(void);
 void change_winsz(void);
-size_t array_ref_len(const char *);
+size_t array_ref_len(const char *) MKSH_A_PURE;
 char *arrayname(const char *);
 mksh_uari_t set_array(const char *, bool, const char **);
-uint32_t hash(const void *);
+uint32_t hash(const void *) MKSH_A_PURE;
+uint32_t chvt_rndsetup(const void *, size_t) MKSH_A_PURE;
 mksh_ari_t rndget(void);
 void rndset(unsigned long);
+void rndpush(const void *);
 
 enum Test_op {
 	/* non-operator */
@@ -2058,10 +2019,11 @@
 
 extern const char * const dbtest_tokens[];
 
-Test_op	test_isop(Test_meta, const char *);
+Test_op	test_isop(Test_meta, const char *) MKSH_A_PURE;
 int test_eval(Test_env *, Test_op, const char *, const char *, bool);
 int test_parse(Test_env *);
 
+/* tty_fd is not opened O_BINARY, it's thus never read/written */
 EXTERN int tty_fd E_INIT(-1);	/* dup'd tty file descriptor */
 EXTERN bool tty_devtty;		/* true if tty_fd is from /dev/tty */
 EXTERN mksh_ttyst tty_state;	/* saved tty state */
diff --git a/src/sh_flags.gen b/src/sh_flags.gen
new file mode 100644
index 0000000..cff2e87
--- /dev/null
+++ b/src/sh_flags.gen
@@ -0,0 +1,136 @@
+#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			};
+#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,
+#endif
+#ifndef F0
+#define F0 FN
+#endif
+F0("allexport", FEXPORT, OF_ANY, 'a')
+#if HAVE_NICE
+FN("bgnice", FBGNICE, OF_ANY, 0)
+#endif
+FN("braceexpand", FBRACEEXPAND, OF_ANY, 0)
+#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("emacs", FEMACS, OF_ANY, 0)
+#endif
+FN("errexit", FERREXIT, OF_ANY, 'e')
+#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("gmacs", FGMACS, OF_ANY, 0)
+#endif
+FN("ignoreeof", FIGNOREEOF, OF_ANY, 0)
+FN("inherit-xtrace", FXTRACEREC, OF_ANY, 0)
+#ifndef SHFLAGS_NOT_CMD
+FN("interactive", FTALKING, OF_CMDLINE, 'i')
+#endif
+FN("keyword", FKEYWORD, OF_ANY, 'k')
+#ifndef SHFLAGS_NOT_CMD
+FN("login", FLOGIN, OF_CMDLINE, 'l')
+#endif
+FN("markdirs", FMARKDIRS, OF_ANY, 'X')
+#ifndef MKSH_UNEMPLOYED
+FN("monitor", FMONITOR, OF_ANY, 'm')
+#endif
+FN("noclobber", FNOCLOBBER, OF_ANY, 'C')
+FN("noexec", FNOEXEC, OF_ANY, 'n')
+FN("noglob", FNOGLOB, OF_ANY, 'f')
+FN("nohup", FNOHUP, OF_ANY, 0)
+FN("nolog", FNOLOG, OF_ANY, 0)
+#ifndef MKSH_UNEMPLOYED
+FN("notify", FNOTIFY, OF_ANY, 'b')
+#endif
+FN("nounset", FNOUNSET, OF_ANY, 'u')
+FN("physical", FPHYSICAL, OF_ANY, 0)
+FN("pipefail", FPIPEFAIL, OF_ANY, 0)
+FN("posix", FPOSIX, OF_ANY, 0)
+FN("privileged", FPRIVILEGED, OF_ANY, 'p')
+#ifndef SHFLAGS_NOT_CMD
+FN("restricted", FRESTRICTED, OF_CMDLINE, 'r')
+#endif
+FN("sh", FSH, OF_ANY, 0)
+#ifndef SHFLAGS_NOT_CMD
+FN("stdin", FSTDIN, OF_CMDLINE, 's')
+#endif
+FN("trackall", FTRACKALL, OF_ANY, 'h')
+FN("utf8-mode", FUNICODE, OF_ANY, 'U')
+FN("verbose", FVERBOSE, OF_ANY, 'v')
+#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("vi", FVI, OF_ANY, 0)
+#endif
+#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("vi-esccomplete", FVIESCCOMPLETE, OF_ANY, 0)
+#endif
+#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("vi-tabcomplete", FVITABCOMPLETE, OF_ANY, 0)
+#endif
+#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("viraw", FVIRAW, OF_ANY, 0)
+#endif
+FN("xtrace", FXTRACE, OF_ANY, 'x')
+#ifndef SHFLAGS_NOT_CMD
+FN("", FCOMMAND, OF_CMDLINE, 'c')
+#endif
+FN("", FAS_BUILTIN, OF_INTERNAL, 0)
+FN("", FTALKING_I, OF_INTERNAL, 0)
+#undef F0
+#undef FN
+#undef SHFLAGS_DEFNS
+#undef SHFLAGS_ENUMS
+#undef SHFLAGS_ITEMS
+#else
+#ifndef SHFLAGS_NOT_SET
+"A:"
+#endif
+"a"
+#ifndef MKSH_UNEMPLOYED
+"b"
+#endif
+"C"
+#ifndef SHFLAGS_NOT_CMD
+"c"
+#endif
+"e"
+"f"
+"h"
+#ifndef SHFLAGS_NOT_CMD
+"i"
+#endif
+"k"
+#ifndef SHFLAGS_NOT_CMD
+"l"
+#endif
+#ifndef MKSH_UNEMPLOYED
+"m"
+#endif
+"n"
+#ifndef SHFLAGS_NOT_CMD
+"o:"
+#endif
+#ifndef SHFLAGS_NOT_SET
+"o;"
+#endif
+"p"
+#ifndef SHFLAGS_NOT_CMD
+"r"
+#endif
+#ifndef SHFLAGS_NOT_CMD
+"s"
+#endif
+#ifndef SHFLAGS_NOT_SET
+"s"
+#endif
+#ifndef SHFLAGS_NOT_CMD
+"T:"
+#endif
+"U"
+"u"
+"v"
+"X"
+"x"
+#undef SHFLAGS_OPTCS
+#endif
diff --git a/src/sh_flags.h b/src/sh_flags.h
deleted file mode 100644
index 3e4cf56..0000000
--- a/src/sh_flags.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#if defined(SHFLAGS_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.16 2013/08/11 14:57:11 tg Exp $");
-#define FN(sname,cname,ochar,flags)		\
-	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		\
-	};
-#elif defined(SHFLAGS_ENUMS)
-#define FN(sname,cname,ochar,flags)	cname,
-#define F0(sname,cname,ochar,flags)	cname = 0,
-#elif defined(SHFLAGS_ITEMS)
-#define FN(sname,cname,ochar,flags)	\
-	((const char *)(&shoptione_ ## cname)) + 2,
-#endif
-
-#ifndef F0
-#define F0 FN
-#endif
-
-/*
- * special cases (see parse_args()): -A, -o, -s
- *
- * options are sorted by their longnames
- */
-
-/* -a	all new parameters are created with the export attribute */
-F0("allexport", FEXPORT, 'a', OF_ANY)
-
-#if HAVE_NICE
-/* ./.	bgnice */
-FN("bgnice", FBGNICE, 0, OF_ANY)
-#endif
-
-/* ./.	enable {} globbing (non-standard) */
-FN("braceexpand", FBRACEEXPAND, 0, OF_ANY)
-
-#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
-/* ./.	Emacs command line editing mode */
-FN("emacs", FEMACS, 0, OF_ANY)
-#endif
-
-/* -e	quit on error */
-FN("errexit", FERREXIT, 'e', OF_ANY)
-
-#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
-/* ./.	Emacs command line editing mode, gmacs variant */
-FN("gmacs", FGMACS, 0, OF_ANY)
-#endif
-
-/* ./.	reading EOF does not exit */
-FN("ignoreeof", FIGNOREEOF, 0, OF_ANY)
-
-/* ./.	inherit -x flag */
-FN("inherit-xtrace", FXTRACEREC, 0, OF_ANY)
-
-/* -i	interactive shell */
-FN("interactive", FTALKING, 'i', OF_CMDLINE)
-
-/* -k	name=value are recognised anywhere */
-FN("keyword", FKEYWORD, 'k', OF_ANY)
-
-/* -l	login shell */
-FN("login", FLOGIN, 'l', OF_CMDLINE)
-
-/* -X	mark dirs with / in file name completion */
-FN("markdirs", FMARKDIRS, 'X', OF_ANY)
-
-#ifndef MKSH_UNEMPLOYED
-/* -m	job control monitoring */
-FN("monitor", FMONITOR, 'm', OF_ANY)
-#endif
-
-/* -C	don't overwrite existing files */
-FN("noclobber", FNOCLOBBER, 'C', OF_ANY)
-
-/* -n	don't execute any commands */
-FN("noexec", FNOEXEC, 'n', OF_ANY)
-
-/* -f	don't do file globbing */
-FN("noglob", FNOGLOB, 'f', OF_ANY)
-
-/* ./.	don't kill running jobs when login shell exits */
-FN("nohup", FNOHUP, 0, OF_ANY)
-
-/* ./.	don't save functions in history (no effect) */
-FN("nolog", FNOLOG, 0, OF_ANY)
-
-#ifndef MKSH_UNEMPLOYED
-/* -b	asynchronous job completion notification */
-FN("notify", FNOTIFY, 'b', OF_ANY)
-#endif
-
-/* -u	using an unset variable is an error */
-FN("nounset", FNOUNSET, 'u', OF_ANY)
-
-/* ./.	don't do logical cds/pwds (non-standard) */
-FN("physical", FPHYSICAL, 0, OF_ANY)
-
-/* ./.	errorlevel of a pipeline is the rightmost nonzero value */
-FN("pipefail", FPIPEFAIL, 0, OF_ANY)
-
-/* ./.	adhere more closely to POSIX even when undesirable */
-FN("posix", FPOSIX, 0, OF_ANY)
-
-/* -p	use suid_profile; privileged shell */
-FN("privileged", FPRIVILEGED, 'p', OF_ANY)
-
-/* -r	restricted shell */
-FN("restricted", FRESTRICTED, 'r', OF_CMDLINE)
-
-/* ./.	kludge mode for better compat with traditional sh (OS-specific) */
-FN("sh", FSH, 0, OF_ANY)
-
-/* -s	(invocation) parse stdin (pseudo non-standard) */
-FN("stdin", FSTDIN, 's', OF_CMDLINE)
-
-/* -h	create tracked aliases for all commands */
-FN("trackall", FTRACKALL, 'h', OF_ANY)
-
-/* -U	enable UTF-8 processing (non-standard) */
-FN("utf8-mode", FUNICODE, 'U', OF_ANY)
-
-/* -v	echo input */
-FN("verbose", FVERBOSE, 'v', OF_ANY)
-
-#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
-/* ./.	Vi command line editing mode */
-FN("vi", FVI, 0, OF_ANY)
-
-/* ./.	enable ESC as file name completion character (non-standard) */
-FN("vi-esccomplete", FVIESCCOMPLETE, 0, OF_ANY)
-
-/* ./.	enable Tab as file name completion character (non-standard) */
-FN("vi-tabcomplete", FVITABCOMPLETE, 0, OF_ANY)
-
-/* ./.	always read in raw mode (no effect) */
-FN("viraw", FVIRAW, 0, OF_ANY)
-#endif
-
-/* -x	execution trace (display commands as they are run) */
-FN("xtrace", FXTRACE, 'x', OF_ANY)
-
-/* -c	(invocation) execute specified command */
-FN("", FCOMMAND, 'c', OF_CMDLINE)
-
-/*
- * anonymous flags: used internally by shell only (not visible to user)
- */
-
-/* ./.	direct builtin call (divined from argv[0] multi-call binary) */
-FN("", FAS_BUILTIN, 0, OF_INTERNAL)
-
-/* ./.	(internal) initial shell was interactive */
-FN("", FTALKING_I, 0, OF_INTERNAL)
-
-#undef FN
-#undef F0
-#undef SHFLAGS_DEFNS
-#undef SHFLAGS_ENUMS
-#undef SHFLAGS_ITEMS
diff --git a/src/sh_flags.opt b/src/sh_flags.opt
new file mode 100644
index 0000000..99e4a22
--- /dev/null
+++ b/src/sh_flags.opt
@@ -0,0 +1,179 @@
+@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			};
+@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,
+@@
+
+/* special cases */
+
+<o:|!SHFLAGS_NOT_CMD
+<T:|!SHFLAGS_NOT_CMD
+<A:|!SHFLAGS_NOT_SET
+<o;|!SHFLAGS_NOT_SET
+<s|!SHFLAGS_NOT_SET
+
+/*
+ * options are sorted by their longnames
+ */
+
+/* -a	all new parameters are created with the export attribute */
+>a|
+F0("allexport", FEXPORT, OF_ANY
+
+/* ./.	bgnice */
+>| HAVE_NICE
+FN("bgnice", FBGNICE, OF_ANY
+
+/* ./.	enable {} globbing (non-standard) */
+>|
+FN("braceexpand", FBRACEEXPAND, OF_ANY
+
+/* ./.	Emacs command line editing mode */
+>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("emacs", FEMACS, OF_ANY
+
+/* -e	quit on error */
+>e|
+FN("errexit", FERREXIT, OF_ANY
+
+/* ./.	Emacs command line editing mode, gmacs variant */
+>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("gmacs", FGMACS, OF_ANY
+
+/* ./.	reading EOF does not exit */
+>|
+FN("ignoreeof", FIGNOREEOF, OF_ANY
+
+/* ./.	inherit -x flag */
+>|
+FN("inherit-xtrace", FXTRACEREC, OF_ANY
+
+/* -i	interactive shell */
+>i|!SHFLAGS_NOT_CMD
+FN("interactive", FTALKING, OF_CMDLINE
+
+/* -k	name=value are recognised anywhere */
+>k|
+FN("keyword", FKEYWORD, OF_ANY
+
+/* -l	login shell */
+>l|!SHFLAGS_NOT_CMD
+FN("login", FLOGIN, OF_CMDLINE
+
+/* -X	mark dirs with / in file name completion */
+>X|
+FN("markdirs", FMARKDIRS, OF_ANY
+
+/* -m	job control monitoring */
+>m|!MKSH_UNEMPLOYED
+FN("monitor", FMONITOR, OF_ANY
+
+/* -C	don't overwrite existing files */
+>C|
+FN("noclobber", FNOCLOBBER, OF_ANY
+
+/* -n	don't execute any commands */
+>n|
+FN("noexec", FNOEXEC, OF_ANY
+
+/* -f	don't do file globbing */
+>f|
+FN("noglob", FNOGLOB, OF_ANY
+
+/* ./.	don't kill running jobs when login shell exits */
+>|
+FN("nohup", FNOHUP, OF_ANY
+
+/* ./.	don't save functions in history (no effect) */
+>|
+FN("nolog", FNOLOG, OF_ANY
+
+/* -b	asynchronous job completion notification */
+>b|!MKSH_UNEMPLOYED
+FN("notify", FNOTIFY, OF_ANY
+
+/* -u	using an unset variable is an error */
+>u|
+FN("nounset", FNOUNSET, OF_ANY
+
+/* ./.	don't do logical cds/pwds (non-standard) */
+>|
+FN("physical", FPHYSICAL, OF_ANY
+
+/* ./.	errorlevel of a pipeline is the rightmost nonzero value */
+>|
+FN("pipefail", FPIPEFAIL, OF_ANY
+
+/* ./.	adhere more closely to POSIX even when undesirable */
+>|
+FN("posix", FPOSIX, OF_ANY
+
+/* -p	privileged shell (suid) */
+>p|
+FN("privileged", FPRIVILEGED, OF_ANY
+
+/* -r	restricted shell */
+>r|!SHFLAGS_NOT_CMD
+FN("restricted", FRESTRICTED, OF_CMDLINE
+
+/* ./.	kludge mode for better compat with traditional sh (OS-specific) */
+>|
+FN("sh", FSH, OF_ANY
+
+/* -s	(invocation) parse stdin (pseudo non-standard) */
+>s|!SHFLAGS_NOT_CMD
+FN("stdin", FSTDIN, OF_CMDLINE
+
+/* -h	create tracked aliases for all commands */
+>h|
+FN("trackall", FTRACKALL, OF_ANY
+
+/* -U	enable UTF-8 processing (non-standard) */
+>U|
+FN("utf8-mode", FUNICODE, OF_ANY
+
+/* -v	echo input */
+>v|
+FN("verbose", FVERBOSE, OF_ANY
+
+/* ./.	Vi command line editing mode */
+>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("vi", FVI, OF_ANY
+
+/* ./.	enable ESC as file name completion character (non-standard) */
+>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("vi-esccomplete", FVIESCCOMPLETE, OF_ANY
+
+/* ./.	enable Tab as file name completion character (non-standard) */
+>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("vi-tabcomplete", FVITABCOMPLETE, OF_ANY
+
+/* ./.	always read in raw mode (no effect) */
+>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+FN("viraw", FVIRAW, OF_ANY
+
+/* -x	execution trace (display commands as they are run) */
+>x|
+FN("xtrace", FXTRACE, OF_ANY
+
+/* -c	(invocation) execute specified command */
+>c|!SHFLAGS_NOT_CMD
+FN("", FCOMMAND, OF_CMDLINE
+
+/*
+ * anonymous flags: used internally by shell only (not visible to user
+ */
+
+/* ./.	direct builtin call (divined from argv[0] multi-call binary) */
+>|
+FN("", FAS_BUILTIN, OF_INTERNAL
+
+/* ./.	(internal) initial shell was interactive */
+>|
+FN("", FTALKING_I, OF_INTERNAL
+
+|SHFLAGS_OPTCS
diff --git a/src/shf.c b/src/shf.c
index e8ec14a..33e89bd 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.61 2013/07/21 18:36:03 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.62 2013/10/09 11:59:30 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, mode);
+	fd = open(name, oflags | O_BINARY, mode);
 	if (fd < 0) {
 		eno = errno;
 		afree(shf, shf->areap);
diff --git a/src/signames.inc b/src/signames.inc
new file mode 100644
index 0000000..07811fd
--- /dev/null
+++ b/src/signames.inc
@@ -0,0 +1,31 @@
+		{ "ABRT", 6 },
+		{ "FPE", 8 },
+		{ "ILL", 4 },
+		{ "INT", 2 },
+		{ "SEGV", 11 },
+		{ "TERM", 15 },
+		{ "ALRM", 14 },
+		{ "BUS", 7 },
+		{ "CHLD", 17 },
+		{ "CONT", 18 },
+		{ "HUP", 1 },
+		{ "KILL", 9 },
+		{ "PIPE", 13 },
+		{ "QUIT", 3 },
+		{ "STOP", 19 },
+		{ "TSTP", 20 },
+		{ "TTIN", 21 },
+		{ "TTOU", 22 },
+		{ "USR1", 10 },
+		{ "USR2", 12 },
+		{ "POLL", 29 },
+		{ "PROF", 27 },
+		{ "SYS", 31 },
+		{ "TRAP", 5 },
+		{ "URG", 23 },
+		{ "VTALRM", 26 },
+		{ "XCPU", 24 },
+		{ "XFSZ", 25 },
+		{ "WINCH", 28 },
+		{ "PWR", 30 },
+		{ "STKFLT", 16 },
diff --git a/src/strlcpy.c b/src/strlcpy.c
index 53f9130..c0ebfd5 100644
--- a/src/strlcpy.c
+++ b/src/strlcpy.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2006, 2008, 2009
+ * Copyright (c) 2006, 2008, 2009, 2013
  *	Thorsten Glaser <tg@mirbsd.org>
  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
  *
@@ -18,13 +18,14 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/strlcpy.c,v 1.7 2009/06/10 18:12:50 tg Rel $");
+__RCSID("$MirOS: src/bin/mksh/strlcpy.c,v 1.8 2013/11/05 22:10:15 tg Exp $");
 
 /*
  * Copy src to string dst of size siz. At most siz-1 characters
  * will be copied. Always NUL terminates (unless siz == 0).
  * Returns strlen(src); if retval >= siz, truncation occurred.
  */
+#undef strlcpy
 size_t
 strlcpy(char *dst, const char *src, size_t siz)
 {
diff --git a/src/syn.c b/src/syn.c
index 5c07d51..6a544df 100644
--- a/src/syn.c
+++ b/src/syn.c
@@ -2,7 +2,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- *		 2011, 2012, 2013
+ *		 2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.92 2013/06/03 22:28:17 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.94 2014/01/05 21:57:29 tg Exp $");
 
 struct nesting_state {
 	int start_token;	/* token than began nesting (eg, FOR) */
@@ -59,7 +59,7 @@
 static void nesting_push(struct nesting_state *, int);
 static void nesting_pop(struct nesting_state *);
 static int assign_command(const char *);
-static int inalias(struct source *);
+static int inalias(struct source *) MKSH_A_PURE;
 static Test_op dbtestp_isa(Test_env *, Test_meta);
 static const char *dbtestp_getopnd(Test_env *, Test_op, bool);
 static int dbtestp_eval(Test_env *, Test_op, const char *,
@@ -976,7 +976,7 @@
 dbtestp_isa(Test_env *te, Test_meta meta)
 {
 	int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
-	int uqword;
+	bool uqword;
 	char *save = NULL;
 	Test_op ret = TO_NONOP;
 
diff --git a/src/tree.c b/src/tree.c
index dcbd7a1..8026f8b 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.71 2013/07/26 20:33:24 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.72 2013/09/24 20:19:45 tg Exp $");
 
 #define INDENT	8
 
@@ -778,15 +778,16 @@
 	if (--sz == 0 || (c = (unsigned char)(*cp++)) == 0)
 		/* NUL or not enough free space */
 		goto vist_out;
-	if ((c & 0x60) == 0 || (c & 0x7F) == 0x7F) {
+	if (ISCTRL(c & 0x7F)) {
 		/* C0 or C1 control character or DEL */
 		if (--sz == 0)
 			/* not enough free space for two chars */
 			goto vist_out;
 		*dst++ = (c & 0x80) ? '$' : '^';
-		c = (c & 0x7F) ^ 0x40;
+		c = UNCTRL(c & 0x7F);
 	} else if (UTFMODE && c > 0x7F) {
 		/* better not try to display broken multibyte chars */
+		/* also go easy on the Unicode: no U+FFFD here */
 		c = '?';
 	}
 	*dst++ = c;
@@ -801,10 +802,10 @@
 void
 dumpchar(struct shf *shf, int c)
 {
-	if (((c & 0x60) == 0) || ((c & 0x7F) == 0x7F)) {
+	if (ISCTRL(c & 0x7F)) {
 		/* C0 or C1 control character or DEL */
 		shf_putc((c & 0x80) ? '$' : '^', shf);
-		c = (c & 0x7F) ^ 0x40;
+		c = UNCTRL(c & 0x7F);
 	}
 	shf_putc(c, shf);
 }
diff --git a/src/var.c b/src/var.c
index ba8fd82..9f05ec1 100644
--- a/src/var.c
+++ b/src/var.c
@@ -1,8 +1,8 @@
-/*	$OpenBSD: var.c,v 1.35 2013/04/05 01:31:30 tedu Exp $	*/
+/*	$OpenBSD: var.c,v 1.38 2013/12/20 17:53:09 zhuk Exp $	*/
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *		 2011, 2012, 2013
+ *		 2011, 2012, 2013, 2014
  *	Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -22,12 +22,13 @@
  */
 
 #include "sh.h"
+#include "mirhash.h"
 
 #if defined(__OpenBSD__)
 #include <sys/sysctl.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.173 2013/05/31 22:47:14 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.183 2014/10/04 11:47:19 tg Exp $");
 
 /*-
  * Variables
@@ -40,7 +41,9 @@
  */
 
 static struct table specials;
-static uint32_t lcg_state = 5381;
+static uint32_t lcg_state = 5381, qh_state = 4711;
+/* may only be set by typeset() just before call to array_index_calc() */
+static enum namerefflag innermost_refflag = SRF_NOP;
 
 static char *formatstr(struct tbl *, const char *);
 static void exportprep(struct tbl *, const char *);
@@ -164,7 +167,8 @@
 /*
  * Used to calculate an array index for global()/local(). Sets *arrayp
  * to true if this is an array, sets *valp to the array index, returns
- * the basename of the array.
+ * the basename of the array. May only be called from global()/local()
+ * and must be their first callee.
  */
 static const char *
 array_index_calc(const char *n, bool *arrayp, uint32_t *valp)
@@ -176,7 +180,7 @@
 	*arrayp = false;
  redo_from_ref:
 	p = skip_varname(n, false);
-	if (set_refflag == SRF_NOP && (p != n) && ksh_isalphx(n[0])) {
+	if (innermost_refflag == SRF_NOP && (p != n) && ksh_isalphx(n[0])) {
 		struct tbl *vp;
 		char *vn;
 
@@ -184,8 +188,8 @@
 		/* check if this is a reference */
 		varsearch(e->loc, &vp, vn, hash(vn));
 		afree(vn, ATEMP);
-		if (vp && (vp->flag & (DEFINED|ASSOC|ARRAY)) ==
-		    (DEFINED|ASSOC)) {
+		if (vp && (vp->flag & (DEFINED | ASSOC | ARRAY)) ==
+		    (DEFINED | ASSOC)) {
 			char *cp;
 
 			/* gotcha! */
@@ -195,6 +199,7 @@
 			goto redo_from_ref;
 		}
 	}
+	innermost_refflag = SRF_NOP;
 
 	if (p != n && *p == '[' && (len = array_ref_len(p))) {
 		char *sub, *tmp;
@@ -225,10 +230,13 @@
 	bool array;
 	uint32_t h, val;
 
-	/* Check to see if this is an array */
+	/*
+	 * check to see if this is an array;
+	 * dereference namerefs; must come first
+	 */
 	n = array_index_calc(n, &array, &val);
 	h = hash(n);
-	c = n[0];
+	c = (unsigned char)n[0];
 	if (!ksh_isalphx(c)) {
 		if (array)
 			errorf("bad substitution");
@@ -238,9 +246,7 @@
 		vp->areap = ATEMP;
 		*vp->name = c;
 		if (ksh_isdigit(c)) {
-			for (c = 0; ksh_isdigit(*n); n++)
-				c = c*10 + *n-'0';
-			if (c <= l->argc)
+			if (getn(n, &c) && (c <= l->argc))
 				/* setstr can't fail here */
 				setstr(vp, l->argv[c], KSH_RETURN_ERROR);
 			vp->flag |= RDONLY;
@@ -297,7 +303,10 @@
 	bool array;
 	uint32_t h, val;
 
-	/* check to see if this is an array */
+	/*
+	 * check to see if this is an array;
+	 * dereference namerefs; must come first
+	 */
 	n = array_index_calc(n, &array, &val);
 	mkssert(n != NULL);
 	h = hash(n);
@@ -500,7 +509,7 @@
 		base = 8;
 		have_base = true;
 	}
-	while ((c = *s++)) {
+	while ((c = (unsigned char)*s++)) {
 		if (c == '-') {
 			neg = true;
 			continue;
@@ -702,6 +711,16 @@
 	const char *val;
 	size_t len;
 	bool vappend = false;
+	enum namerefflag new_refflag = SRF_NOP;
+
+	if ((set & (ARRAY | ASSOC)) == ASSOC) {
+		new_refflag = SRF_ENABLE;
+		set &= ~(ARRAY | ASSOC);
+	}
+	if ((clr & (ARRAY | ASSOC)) == ASSOC) {
+		new_refflag = SRF_DISABLE;
+		clr &= ~(ARRAY | ASSOC);
+	}
 
 	/* check for valid variable name, search for value */
 	val = skip_varname(var, false);
@@ -710,7 +729,7 @@
 		return (NULL);
 	}
 	if (*val == '[') {
-		if (set_refflag != SRF_NOP)
+		if (new_refflag != SRF_NOP)
 			errorf("%s: %s", var,
 			    "reference variable can't be an array");
 		len = array_ref_len(val);
@@ -732,18 +751,18 @@
 		}
 		val += len;
 	}
-	if (val[0] == '=' || (val[0] == '+' && val[1] == '=')) {
+	if (val[0] == '=') {
 		strndupx(tvar, var, val - var, ATEMP);
-		if (*val++ == '+') {
-			++val;
-			vappend = true;
-		}
-	} else if ((val[0] != '\0') || (set & IMPORT)) {
-		/*
-		 * must have a = when setting a variable by importing
-		 * the original environment, otherwise be empty; we
-		 * also end up here when a variable name was invalid
-		 */
+		++val;
+	} else if (set & IMPORT) {
+		/* environment invalid variable name or no assignment */
+		return (NULL);
+	} else if (val[0] == '+' && val[1] == '=') {
+		strndupx(tvar, var, val - var, ATEMP);
+		val += 2;
+		vappend = true;
+	} else if (val[0] != '\0') {
+		/* other invalid variable names (not from environment) */
 		return (NULL);
 	} else {
 		/* just varname with no value part nor equals sign */
@@ -756,18 +775,49 @@
 			tvar[len - 3] = '\0';
 	}
 
-	if (set_refflag == SRF_ENABLE) {
-		const char *qval;
+	if (new_refflag == SRF_ENABLE) {
+		const char *qval, *ccp;
 
 		/* bail out on 'nameref foo+=bar' */
 		if (vappend)
-			errorfz();
+			errorf("appending not allowed for nameref");
 		/* find value if variable already exists */
 		if ((qval = val) == NULL) {
 			varsearch(e->loc, &vp, tvar, hash(tvar));
-			if (vp != NULL)
-				qval = str_val(vp);
+			if (vp == NULL)
+				goto nameref_empty;
+			qval = str_val(vp);
 		}
+		/* check target value for being a valid variable name */
+		ccp = skip_varname(qval, false);
+		if (ccp == qval) {
+			if (ksh_isdigit(qval[0])) {
+				int c;
+
+				if (getn(qval, &c))
+					goto nameref_rhs_checked;
+			} else if (qval[1] == '\0') switch (qval[0]) {
+			case '$':
+			case '!':
+			case '?':
+			case '#':
+			case '-':
+				goto nameref_rhs_checked;
+			}
+ nameref_empty:
+			errorf("%s: %s", var, "empty nameref target");
+		}
+		len = (*ccp == '[') ? array_ref_len(ccp) : 0;
+		if (ccp[len]) {
+			/*
+			 * works for cases "no array", "valid array with
+			 * junk after it" and "invalid array"; in the
+			 * latter case, len is also 0 and points to '['
+			 */
+			errorf("%s: %s", qval,
+			    "nameref target not a valid parameter name");
+		}
+ nameref_rhs_checked:
 		/* prevent nameref loops */
 		while (qval) {
 			if (!strcmp(qval, tvar))
@@ -775,7 +825,7 @@
 				    "expression recurses on parameter");
 			varsearch(e->loc, &vp, qval, hash(qval));
 			qval = NULL;
-			if (vp && ((vp->flag & (ARRAY|ASSOC)) == ASSOC))
+			if (vp && ((vp->flag & (ARRAY | ASSOC)) == ASSOC))
 				qval = str_val(vp);
 		}
 	}
@@ -785,11 +835,12 @@
 	    strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0))
 		errorf("%s: %s", tvar, "restricted");
 
-	vp = (set&LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) :
+	innermost_refflag = new_refflag;
+	vp = (set & LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) :
 	    global(tvar);
-	if (set_refflag == SRF_DISABLE && (vp->flag & (ARRAY|ASSOC)) == ASSOC)
+	if (new_refflag == SRF_DISABLE && (vp->flag & (ARRAY|ASSOC)) == ASSOC)
 		vp->flag &= ~ASSOC;
-	else if (set_refflag == SRF_ENABLE) {
+	else if (new_refflag == SRF_ENABLE) {
 		if (vp->flag & ARRAY) {
 			struct tbl *a, *tmp;
 
@@ -809,14 +860,14 @@
 
 	set &= ~(LOCAL|LOCAL_COPY);
 
-	vpbase = (vp->flag & ARRAY) ? global(arrayname(var)) : vp;
+	vpbase = (vp->flag & ARRAY) ? global(arrayname(tvar)) : vp;
 
 	/*
 	 * only allow export flag to be set; AT&T ksh allows any
 	 * attribute to be changed which means it can be truncated or
 	 * modified (-L/-R/-Z/-i)
 	 */
-	if ((vpbase->flag&RDONLY) &&
+	if ((vpbase->flag & RDONLY) &&
 	    (val || clr || (set & ~EXPORT)))
 		/* XXX check calls - is error here ok by POSIX? */
 		errorfx(2, "read-only: %s", tvar);
@@ -960,7 +1011,7 @@
  * the terminating NUL if whole string is legal).
  */
 const char *
-skip_varname(const char *s, int aok)
+skip_varname(const char *s, bool aok)
 {
 	size_t alen;
 
@@ -1338,7 +1389,7 @@
 	struct tbl *prev, *curr, *news;
 	size_t len;
 
-	vp->flag = (vp->flag | (ARRAY|DEFINED)) & ~ASSOC;
+	vp->flag = (vp->flag | (ARRAY | DEFINED)) & ~ASSOC;
 	/* the table entry is always [0] */
 	if (val == 0)
 		return (vp);
@@ -1378,6 +1429,8 @@
  * Return the length of an array reference (eg, [1+2]) - cp is assumed
  * to point to the open bracket. Returns 0 if there is no matching
  * closing bracket.
+ *
+ * XXX this should parse the actual arithmetic syntax
  */
 size_t
 array_ref_len(const char *cp)
@@ -1458,6 +1511,7 @@
 		afree(cp, ATEMP);
 	}
 	while ((ccp = vals[i])) {
+#if 0 /* temporarily taken out due to regression */
 		if (*ccp == '[') {
 			int level = 0;
 
@@ -1478,6 +1532,7 @@
 			} else
 				ccp = vals[i];
 		}
+#endif
 
 		vq = arraysearch(vp, j);
 		/* would be nice to deal with errors here... (see above) */
@@ -1492,6 +1547,11 @@
 void
 change_winsz(void)
 {
+	struct timeval tv;
+
+	mksh_TIME(tv);
+	BAFHUpdateMem_mem(qh_state, &tv, sizeof(tv));
+
 #ifdef TIOCGWINSZ
 	/* check if window size has changed */
 	if (tty_init_fd() < 2) {
@@ -1522,9 +1582,28 @@
 {
 	register uint32_t h;
 
-	NZATInit(h);
-	NZATUpdateString(h, s);
-	NZAATFinish(h);
+	BAFHInit(h);
+	BAFHUpdateStr_reg(h, s);
+	BAFHFinish_reg(h);
+	return (h);
+}
+
+uint32_t
+chvt_rndsetup(const void *bp, size_t sz)
+{
+	register uint32_t h;
+
+	/* use LCG as seed but try to get them to deviate immediately */
+	h = lcg_state;
+	(void)rndget();
+	BAFHFinish_reg(h);
+	/* variation through pid, ppid, and the works */
+	BAFHUpdateMem_reg(h, &rndsetupstate, sizeof(rndsetupstate));
+	/* some variation, some possibly entropy, depending on OE */
+	BAFHUpdateMem_reg(h, bp, sz);
+	/* mix them all up */
+	BAFHFinish_reg(h);
+
 	return (h);
 }
 
@@ -1542,28 +1621,67 @@
 rndset(unsigned long v)
 {
 	register uint32_t h;
+#if defined(arc4random_pushb_fast) || defined(MKSH_A4PB)
+	register uint32_t t;
+#endif
+	struct {
+		struct timeval tv;
+		void *sp;
+		uint32_t qh;
+		pid_t pp;
+		short r;
+	} z;
 
-	NZATInit(h);
-	NZATUpdateMem(h, &lcg_state, sizeof(lcg_state));
-	NZATUpdateMem(h, &v, sizeof(v));
+#ifdef DEBUG
+	/* clear the allocated space, for valgrind */
+	memset(&z, 0, sizeof(z));
+#endif
+
+	h = lcg_state;
+	BAFHFinish_reg(h);
+	BAFHUpdateMem_reg(h, &v, sizeof(v));
+
+	mksh_TIME(z.tv);
+	z.sp = &lcg_state;
+	z.pp = procpid;
+	z.r = (short)rndget();
 
 #if defined(arc4random_pushb_fast) || defined(MKSH_A4PB)
+	t = qh_state;
+	BAFHFinish_reg(t);
+	z.qh = (t & 0xFFFF8000) | rndget();
+	lcg_state = (t << 15) | rndget();
 	/*
 	 * either we have very chap entropy get and push available,
 	 * with malloc() pulling in this code already anyway, or the
 	 * user requested us to use the old functions
 	 */
-	lcg_state = h;
-	NZAATFinish(lcg_state);
+	t = h;
+	BAFHUpdateMem_reg(t, &lcg_state, sizeof(lcg_state));
+	BAFHFinish_reg(t);
+	lcg_state = t;
 #if defined(arc4random_pushb_fast)
 	arc4random_pushb_fast(&lcg_state, sizeof(lcg_state));
 	lcg_state = arc4random();
 #else
 	lcg_state = arc4random_pushb(&lcg_state, sizeof(lcg_state));
 #endif
-	NZATUpdateMem(h, &lcg_state, sizeof(lcg_state));
+	BAFHUpdateMem_reg(h, &lcg_state, sizeof(lcg_state));
+#else
+	z.qh = qh_state;
 #endif
 
-	NZAATFinish(h);
+	BAFHUpdateMem_reg(h, &z, sizeof(z));
+	BAFHFinish_reg(h);
 	lcg_state = h;
 }
+
+void
+rndpush(const void *s)
+{
+	register uint32_t h = qh_state;
+
+	BAFHUpdateStr_reg(h, s);
+	BAFHUpdateOctet_reg(h, 0);
+	qh_state = h;
+}