OSDN Git Service

Update to mksh R48 jb-x86
authorThorsten Glaser <tg@mirbsd.org>
Thu, 25 Jul 2013 14:24:45 +0000 (14:24 +0000)
committerThorsten Glaser <tg@mirbsd.org>
Wed, 14 Aug 2013 21:33:39 +0000 (21:33 +0000)
Change-Id: I4d1bef9bf8ddc7899cfb32a6f2fa9e6f632bc53f

26 files changed:
Android.mk
mkmf.sh
mkshrc
src/Build.sh
src/check.pl
src/check.t
src/dot.mkshrc
src/edit.c
src/eval.c
src/exec.c
src/expr.c
src/funcs.c
src/jobs.c
src/lalloc.c
src/lex.c
src/lksh.1 [new file with mode: 0644]
src/main.c
src/misc.c
src/mksh.1
src/mksh.ico [new file with mode: 0644]
src/sh.h
src/sh_flags.h
src/shf.c
src/syn.c
src/tree.c
src/var.c

index 0d8807e..3b1c9fd 100644 (file)
@@ -37,6 +37,7 @@ LOCAL_C_INCLUDES:=    $(LOCAL_PATH)/src
 LOCAL_CFLAGS:=         -DMKSHRC_PATH=\"/system/etc/mkshrc\" \
                        -DMKSH_DEFAULT_EXECSHELL=\"/system/bin/sh\" \
                        -DMKSH_DEFAULT_TMPDIR=\"/data/local\" \
 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 \
                -fno-asynchronous-unwind-tables -fwrapv \
                -DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_CONSERVATIVE_FDS \
                -DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH \
@@ -62,9 +63,8 @@ LOCAL_CFLAGS:=                -DMKSHRC_PATH=\"/system/etc/mkshrc\" \
                -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_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 -DHAVE_SILENT_IDIVWRAPV=0 \
-               -DMKSH_BUILD_R=431
+               -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=481
 
 
-# check categories: shell:legacy-no int:32 android convfds no-histfile
+# check_categories= shell:legacy-no int:32 android convfds no-histfile
 
 include $(BUILD_EXECUTABLE)
 
 include $(BUILD_EXECUTABLE)
diff --git a/mkmf.sh b/mkmf.sh
index 6e2517c..f48db92 100644 (file)
--- a/mkmf.sh
+++ b/mkmf.sh
@@ -64,7 +64,6 @@ addvar CPPFLAGS \
     -isystem $aospdir/frameworks/native/opengl/include \
     -isystem $aospdir/frameworks/av/include \
     -isystem $aospdir/frameworks/base/include \
     -isystem $aospdir/frameworks/native/opengl/include \
     -isystem $aospdir/frameworks/av/include \
     -isystem $aospdir/frameworks/base/include \
-    -isystem $aospdir/frameworks/base/opengl/include \
     -isystem $aospdir/external/skia/include \
     -isystem $aospdir/out/target/product/generic/obj/include \
     -isystem $aospdir/bionic/libc/arch-arm/include \
     -isystem $aospdir/external/skia/include \
     -isystem $aospdir/out/target/product/generic/obj/include \
     -isystem $aospdir/bionic/libc/arch-arm/include \
@@ -75,11 +74,10 @@ addvar CPPFLAGS \
     -isystem $aospdir/bionic/libm/include \
     -isystem $aospdir/bionic/libm/include/arm \
     -isystem $aospdir/bionic/libthread_db/include \
     -isystem $aospdir/bionic/libm/include \
     -isystem $aospdir/bionic/libm/include/arm \
     -isystem $aospdir/bionic/libthread_db/include \
-    -D_FORTIFY_SOURCE=1 \
+    -D_FORTIFY_SOURCE=2 \
     -include $aospdir/build/core/combo/include/arch/linux-arm/AndroidConfig.h \
     -I$aospdir/build/core/combo/include/arch/linux-arm/ \
     -DANDROID -DNDEBUG -UDEBUG
     -include $aospdir/build/core/combo/include/arch/linux-arm/AndroidConfig.h \
     -I$aospdir/build/core/combo/include/arch/linux-arm/ \
     -DANDROID -DNDEBUG -UDEBUG
-# who would have thought the AOSP devs are funny? -fno-builtin-sin
 addvar CFLAGS \
     -fno-exceptions \
     -Wno-multichar \
 addvar CFLAGS \
     -fno-exceptions \
     -Wno-multichar \
@@ -123,6 +121,7 @@ addvar CFLAGS \
 addvar LDFLAGS \
     -nostdlib \
     -Bdynamic \
 addvar LDFLAGS \
     -nostdlib \
     -Bdynamic \
+    -fPIE \
     -pie \
     -Wl,-dynamic-linker,/system/bin/linker \
     -Wl,--gc-sections \
     -pie \
     -Wl,-dynamic-linker,/system/bin/linker \
     -Wl,--gc-sections \
@@ -131,6 +130,7 @@ addvar LDFLAGS \
     -Wl,-z,relro \
     -Wl,-z,now \
     -Wl,--warn-shared-textrel \
     -Wl,-z,relro \
     -Wl,-z,now \
     -Wl,--warn-shared-textrel \
+    -Wl,--fatal-warnings \
     -Wl,--icf=safe \
     -Wl,--fix-cortex-a8 \
     -Wl,--no-undefined \
     -Wl,--icf=safe \
     -Wl,--fix-cortex-a8 \
     -Wl,--no-undefined \
@@ -138,9 +138,9 @@ addvar LDFLAGS \
 addvar LIBS \
     -L$aospdir/out/target/product/generic/obj/lib \
     -Wl,-rpath-link=$aospdir/out/target/product/generic/obj/lib \
 addvar LIBS \
     -L$aospdir/out/target/product/generic/obj/lib \
     -Wl,-rpath-link=$aospdir/out/target/product/generic/obj/lib \
-    -lc \
     -Wl,--no-whole-archive \
     -Wl,--no-whole-archive \
-    $aospdir/out/target/product/generic/obj/STATIC_LIBRARIES/libcompiler-rt-extras_intermediates/libcompiler-rt-extras.a \
+    $aospdir/out/target/product/generic/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
 
     $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
 
@@ -181,11 +181,6 @@ export HAVE_CAN_FNOSTRICTALIASING HAVE_CAN_FSTACKPROTECTORALL HAVE_CAN_WALL
 # even the idea of persistent history on a phone is funny
 HAVE_PERSISTENT_HISTORY=0; export HAVE_PERSISTENT_HISTORY
 
 # even the idea of persistent history on a phone is funny
 HAVE_PERSISTENT_HISTORY=0; export HAVE_PERSISTENT_HISTORY
 
-# this is a run-time check and dependent on the target CPU
-# architecture (at _least_!) and cannot be auto-detected,
-# so always include the safety check even if unnecessary
-HAVE_SILENT_IDIVWRAPV=0; export HAVE_SILENT_IDIVWRAPV
-
 # ... and run it!
 export CC CPPFLAGS CFLAGS LDFLAGS LIBS TARGET_OS
 sh ../src/Build.sh $args
 # ... and run it!
 export CC CPPFLAGS CFLAGS LDFLAGS LIBS TARGET_OS
 sh ../src/Build.sh $args
diff --git a/mkshrc b/mkshrc
index 2951595..6d135a3 100644 (file)
--- a/mkshrc
+++ b/mkshrc
@@ -9,12 +9,13 @@
 : ${TERM:=vt100} ${HOME:=/data} ${MKSH:=/system/bin/sh} ${HOSTNAME:=$(getprop ro.product.device)}
 : ${SHELL:=$MKSH} ${USER:=$(typeset x=$(id); x=${x#*\(}; print -r -- ${x%%\)*})} ${HOSTNAME:=android}
 if (( USER_ID )); then PS1='$'; else PS1='#'; fi
 : ${TERM:=vt100} ${HOME:=/data} ${MKSH:=/system/bin/sh} ${HOSTNAME:=$(getprop ro.product.device)}
 : ${SHELL:=$MKSH} ${USER:=$(typeset x=$(id); x=${x#*\(}; print -r -- ${x%%\)*})} ${HOSTNAME:=android}
 if (( USER_ID )); then PS1='$'; else PS1='#'; fi
-function precmd {
-       typeset e=$?
+PS4='[$EPOCHREALTIME] '; PS1='${|
+       local e=$?
 
 
-       (( e )) && print -n "$e|"
-}
-PS1='$(precmd)$USER@$HOSTNAME:${PWD:-?} '"$PS1 "
+       (( e )) && REPLY+="$e|"
+
+       return $e
+}$USER@$HOSTNAME:${PWD:-?} '"$PS1 "
 export HOME HOSTNAME MKSH SHELL TERM USER
 alias l='ls'
 alias la='l -a'
 export HOME HOSTNAME MKSH SHELL TERM USER
 alias l='ls'
 alias la='l -a'
@@ -22,7 +23,34 @@ alias ll='l -l'
 alias lo='l -a -l'
 
 function hd {
 alias lo='l -a -l'
 
 function hd {
-       cat "$@" | command hd /proc/self/fd/0
+       local -Uui16 -Z11 pos=0
+       local -Uui16 -Z5 hv=2147483647
+       local dasc line i
+
+       cat "$@" | { set +U; if read -arN -1 line; then
+               typeset -i1 line
+               i=0
+               while (( i < ${#line[*]} )); do
+                       hv=${line[i++]}
+                       if (( (pos & 15) == 0 )); then
+                               (( pos )) && print -r -- "$dasc|"
+                               print -n "${pos#16#}  "
+                               dasc=' |'
+                       fi
+                       print -n "${hv#16#} "
+                       if (( (hv < 32) || (hv > 126) )); then
+                               dasc+=.
+                       else
+                               dasc+=${line[i-1]#1#}
+                       fi
+                       (( (pos++ & 15) == 7 )) && print -n -- '- '
+               done
+               while (( pos & 15 )); do
+                       print -n '   '
+                       (( (pos++ & 15) == 7 )) && print -n -- '- '
+               done
+               (( hv == 2147483647 )) || print -r -- "$dasc|"
+       fi; }
 }
 
 function more {
 }
 
 function more {
index 31c559d..45af9dd 100644 (file)
@@ -1,5 +1,5 @@
 #!/bin/sh
 #!/bin/sh
-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.622 2013/02/19 18:45:15 tg Exp $'
+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.645 2013/08/10 13:44:25 tg Exp $'
 #-
 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #              2011, 2012, 2013
 #-
 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #              2011, 2012, 2013
@@ -28,6 +28,9 @@ srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.622 2013/02/19 18:45:15 tg Exp $'
 LC_ALL=C
 export LC_ALL
 
 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
 case $ZSH_VERSION:$VERSION in
 :zsh*) ZSH_VERSION=2 ;;
 esac
@@ -63,7 +66,7 @@ vq() {
 rmf() {
        for _f in "$@"; do
                case $_f in
 rmf() {
        for _f in "$@"; do
                case $_f in
-               Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|mksh.1) ;;
+               Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|*.ico|*.1) ;;
                *) rm -f "$_f" ;;
                esac
        done
                *) rm -f "$_f" ;;
                esac
        done
@@ -190,6 +193,7 @@ ac_testn() {
 ac_ifcpp() {
        expr=$1; shift
        ac_testn "$@" <<-EOF
 ac_ifcpp() {
        expr=$1; shift
        ac_testn "$@" <<-EOF
+               extern int thiswillneverbedefinedIhope(void);
                int main(void) { return (
                #$expr
                    0
                int main(void) { return (
                #$expr
                    0
@@ -458,7 +462,7 @@ oswarn=
 ccpc=-Wc,
 ccpl=-Wl,
 tsts=
 ccpc=-Wc,
 ccpl=-Wl,
 tsts=
-ccpr='|| for _f in ${tcfn}*; do case $_f in Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|mksh.1) ;; *) rm -f "$_f" ;; esac; done'
+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'
 
 # Evil hack
 if test x"$TARGET_OS" = x"Android"; then
 
 # Evil hack
 if test x"$TARGET_OS" = x"Android"; then
@@ -686,8 +690,11 @@ Plan9)
        add_cppflags -D_SUSV2_SOURCE
        add_cppflags -DMKSH_ASSUME_UTF8; HAVE_ISSET_MKSH_ASSUME_UTF8=1
        add_cppflags -DMKSH_NO_CMDLINE_EDITING
        add_cppflags -D_SUSV2_SOURCE
        add_cppflags -DMKSH_ASSUME_UTF8; HAVE_ISSET_MKSH_ASSUME_UTF8=1
        add_cppflags -DMKSH_NO_CMDLINE_EDITING
+       add_cppflags -DMKSH__NO_SETEUGID
        oswarn=' and will currently not work'
        add_cppflags -DMKSH_UNEMPLOYED
        oswarn=' and will currently not work'
        add_cppflags -DMKSH_UNEMPLOYED
+       # this is for detecting kencc
+       add_cppflags -DMKSH_MAYBE_KENCC
        ;;
 PW32*)
        HAVE_SIG_T=0    # incompatible
        ;;
 PW32*)
        HAVE_SIG_T=0    # incompatible
@@ -766,7 +773,7 @@ esac
 
 : ${HAVE_MKNOD=0}
 
 
 : ${HAVE_MKNOD=0}
 
-: ${AWK=awk} ${CC=cc} ${NROFF=nroff}
+: ${AWK=awk} ${CC=cc} ${NROFF=nroff} ${SIZE=size}
 test 0 = $r && echo | $NROFF -v 2>&1 | grep GNU >/dev/null 2>&1 && \
     NROFF="$NROFF -c"
 
 test 0 = $r && echo | $NROFF -v 2>&1 | grep GNU >/dev/null 2>&1 && \
     NROFF="$NROFF -c"
 
@@ -876,6 +883,9 @@ ct="ucode"
 ct="uslc"
 #elif defined(__LCC__)
 ct="lcc"
 ct="uslc"
 #elif defined(__LCC__)
 ct="lcc"
+#elif defined(MKSH_MAYBE_KENCC)
+/* and none of the above matches */
+ct="kencc"
 #else
 ct="unknown"
 #endif
 #else
 ct="unknown"
 #endif
@@ -952,6 +962,9 @@ iar)
 icc)
        vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN $LIBS -V"
        ;;
 icc)
        vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN $LIBS -V"
        ;;
+kencc)
+       vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN -v conftest.c $LIBS"
+       ;;
 lcc)
        vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN -v conftest.c $LIBS"
        add_cppflags -D__inline__=__inline
 lcc)
        vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN -v conftest.c $LIBS"
        add_cppflags -D__inline__=__inline
@@ -1074,19 +1087,23 @@ if ac_ifcpp 'if 0' compiler_fails '' \
     'if the compiler does not fail correctly'; then
        save_CFLAGS=$CFLAGS
        : ${HAVE_CAN_DELEXE=x}
     'if the compiler does not fail correctly'; then
        save_CFLAGS=$CFLAGS
        : ${HAVE_CAN_DELEXE=x}
-       if test $ct = dmc; then
-               CFLAGS="$CFLAGS ${ccpl}/DELEXECUTABLE"
-               ac_testn can_delexe compiler_fails 0 'for the /DELEXECUTABLE linker option' <<-EOF
-                       int main(void) { return (0); }
-               EOF
-       elif test $ct = dec; then
+       case $ct in
+       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); }
                EOF
                CFLAGS="$CFLAGS ${ccpl}-non_shared"
                ac_testn can_delexe compiler_fails 0 'for the -non_shared linker option' <<-EOF
                        int main(void) { return (0); }
                EOF
-       else
+               ;;
+       dmc)
+               CFLAGS="$CFLAGS ${ccpl}/DELEXECUTABLE"
+               ac_testn can_delexe compiler_fails 0 'for the /DELEXECUTABLE linker option' <<-EOF
+                       int main(void) { return (0); }
+               EOF
+               ;;
+       *)
                exit 1
                exit 1
-       fi
+               ;;
+       esac
        test 1 = $HAVE_CAN_DELEXE || CFLAGS=$save_CFLAGS
        ac_testn compiler_still_fails '' 'if the compiler still does not fail correctly' <<-EOF
        EOF
        test 1 = $HAVE_CAN_DELEXE || CFLAGS=$save_CFLAGS
        ac_testn compiler_still_fails '' 'if the compiler still does not fail correctly' <<-EOF
        EOF
@@ -1099,49 +1116,65 @@ if ac_ifcpp 'ifdef __TINYC__' couldbe_tcc '!' compiler_known 0 \
        HAVE_COMPILER_KNOWN=1
 fi
 
        HAVE_COMPILER_KNOWN=1
 fi
 
-if test $ct = sunpro; then
-       test x"$save_NOWARN" = x"" && save_NOWARN='-errwarn=%none'
-       ac_flags 0 errwarnnone "$save_NOWARN"
-       test 1 = $HAVE_CAN_ERRWARNNONE || save_NOWARN=
-       ac_flags 0 errwarnall "-errwarn=%all"
-       test 1 = $HAVE_CAN_ERRWARNALL && DOWARN="-errwarn=%all"
-elif test $ct = hpcc; then
+case $ct in
+bcc)
+       save_NOWARN="${ccpc}-w"
+       DOWARN="${ccpc}-w!"
+       ;;
+dec)
+       # -msg_* flags not used yet, or is -w2 correct?
+       ;;
+dmc)
+       save_NOWARN="${ccpc}-w"
+       DOWARN="${ccpc}-wx"
+       ;;
+hpcc)
        save_NOWARN=
        DOWARN=+We
        save_NOWARN=
        DOWARN=+We
-elif test $ct = mipspro; then
+       ;;
+kencc)
+       save_NOWARN=
+       DOWARN=
+       ;;
+mipspro)
        save_NOWARN=
        DOWARN="-diag_error 1-10000"
        save_NOWARN=
        DOWARN="-diag_error 1-10000"
-elif test $ct = msc; then
+       ;;
+msc)
        save_NOWARN="${ccpc}/w"
        DOWARN="${ccpc}/WX"
        save_NOWARN="${ccpc}/w"
        DOWARN="${ccpc}/WX"
-elif test $ct = dmc; then
-       save_NOWARN="${ccpc}-w"
-       DOWARN="${ccpc}-wx"
-elif test $ct = bcc; then
-       save_NOWARN="${ccpc}-w"
-       DOWARN="${ccpc}-w!"
-elif test $ct = dec; then
-       : -msg_* flags not used yet, or is -w2 correct?
-elif test $ct = xlc; then
-       save_NOWARN=-qflag=i:e
-       DOWARN=-qflag=i:i
-elif test $ct = tendra; then
+       ;;
+sunpro)
+       test x"$save_NOWARN" = x"" && save_NOWARN='-errwarn=%none'
+       ac_flags 0 errwarnnone "$save_NOWARN"
+       test 1 = $HAVE_CAN_ERRWARNNONE || save_NOWARN=
+       ac_flags 0 errwarnall "-errwarn=%all"
+       test 1 = $HAVE_CAN_ERRWARNALL && DOWARN="-errwarn=%all"
+       ;;
+tendra)
        save_NOWARN=-w
        save_NOWARN=-w
-elif test $ct = ucode; then
+       ;;
+ucode)
        save_NOWARN=
        DOWARN=-w2
        save_NOWARN=
        DOWARN=-w2
-elif test $ct = watcom; then
+       ;;
+watcom)
        save_NOWARN=
        DOWARN=-Wc,-we
        save_NOWARN=
        DOWARN=-Wc,-we
-else
+       ;;
+xlc)
+       save_NOWARN=-qflag=i:e
+       DOWARN=-qflag=i:i
+       ;;
+*)
        test x"$save_NOWARN" = x"" && save_NOWARN=-Wno-error
        ac_flags 0 wnoerror "$save_NOWARN"
        test 1 = $HAVE_CAN_WNOERROR || save_NOWARN=
        ac_flags 0 werror -Werror
        test 1 = $HAVE_CAN_WERROR && DOWARN=-Werror
        test x"$save_NOWARN" = x"" && save_NOWARN=-Wno-error
        ac_flags 0 wnoerror "$save_NOWARN"
        test 1 = $HAVE_CAN_WNOERROR || save_NOWARN=
        ac_flags 0 werror -Werror
        test 1 = $HAVE_CAN_WERROR && DOWARN=-Werror
-fi
-
-test $ct = icc && DOWARN="$DOWARN -wd1419"
+       test $ct = icc && DOWARN="$DOWARN -wd1419"
+       ;;
+esac
 NOWARN=$save_NOWARN
 
 #
 NOWARN=$save_NOWARN
 
 #
@@ -1149,7 +1182,16 @@ NOWARN=$save_NOWARN
 #
 i=`echo :"$orig_CFLAGS" | sed 's/^://' | tr -c -d $alll$allu$alln`
 # optimisation: only if orig_CFLAGS is empty
 #
 i=`echo :"$orig_CFLAGS" | sed 's/^://' | tr -c -d $alll$allu$alln`
 # optimisation: only if orig_CFLAGS is empty
-test x"$i" = x"" && if test $ct = sunpro; then
+test x"$i" = x"" && case $ct in
+hpcc)
+       phase=u
+       ac_flags 1 otwo +O2
+       phase=x
+       ;;
+kencc|tcc|tendra)
+       # no special optimisation
+       ;;
+sunpro)
        cat >x <<-'EOF'
                int main(void) { return (0); }
                #define __IDSTRING_CONCAT(l,p)  __LINTED__ ## l ## _ ## p
        cat >x <<-'EOF'
                int main(void) { return (0); }
                #define __IDSTRING_CONCAT(l,p)  __LINTED__ ## l ## _ ## p
@@ -1159,25 +1201,37 @@ test x"$i" = x"" && if test $ct = sunpro; then
        yes pad | head -n 256 >>x
        ac_flags - 1 otwo -xO2 <x
        rmf x
        yes pad | head -n 256 >>x
        ac_flags - 1 otwo -xO2 <x
        rmf x
-elif test $ct = hpcc; then
-       phase=u
-       ac_flags 1 otwo +O2
-       phase=x
-elif test $ct = xlc; then
+       ;;
+xlc)
        ac_flags 1 othree "-O3 -qstrict"
        test 1 = $HAVE_CAN_OTHREE || ac_flags 1 otwo -O2
        ac_flags 1 othree "-O3 -qstrict"
        test 1 = $HAVE_CAN_OTHREE || ac_flags 1 otwo -O2
-elif test $ct = tcc || test $ct = tendra; then
-       : no special optimisation
-else
+       ;;
+*)
        ac_flags 1 otwo -O2
        test 1 = $HAVE_CAN_OTWO || ac_flags 1 optimise -O
        ac_flags 1 otwo -O2
        test 1 = $HAVE_CAN_OTWO || ac_flags 1 optimise -O
-fi
+       ;;
+esac
 # other flags: just add them if they are supported
 i=0
 # other flags: just add them if they are supported
 i=0
-if test $ct = gcc; then
+case $ct in
+bcc)
+       ac_flags 1 strpool "${ccpc}-d" 'if string pooling can be enabled'
+       ;;
+clang)
+       i=1
+       ;;
+dec)
+       ac_flags 0 verb -verbose
+       ac_flags 1 rodata -readonly_strings
+       ;;
+dmc)
+       ac_flags 1 decl "${ccpc}-r" 'for strict prototype checks'
+       ac_flags 1 schk "${ccpc}-s" 'for stack overflow checking'
+       ;;
+gcc)
        # The following tests run with -Werror (gcc only) if possible
        NOWARN=$DOWARN; phase=u
        # The following tests run with -Werror (gcc only) if possible
        NOWARN=$DOWARN; phase=u
-       ac_flags 0 wnooverflow -Wno-overflow
+       ac_flags 1 wnodeprecateddecls -Wno-deprecated-declarations
        # mksh is not written in CFrustFrust!
        ac_flags 1 no_eh_frame -fno-asynchronous-unwind-tables
        ac_flags 1 fnostrictaliasing -fno-strict-aliasing
        # mksh is not written in CFrustFrust!
        ac_flags 1 no_eh_frame -fno-asynchronous-unwind-tables
        ac_flags 1 fnostrictaliasing -fno-strict-aliasing
@@ -1186,15 +1240,19 @@ if test $ct = gcc; then
        *\ -fplugin=*dragonegg*) ;;
        *) ac_flags 1 fplugin_dragonegg -fplugin=dragonegg ;;
        esac
        *\ -fplugin=*dragonegg*) ;;
        *) ac_flags 1 fplugin_dragonegg -fplugin=dragonegg ;;
        esac
-       if test $cm = lto; then
-               fv=0
-               checks='1 2 3 4 5 6 7 8'
-       elif test $cm = combine; then
+       case $cm in
+       combine)
                fv=0
                checks='7 8'
                fv=0
                checks='7 8'
-       else
+               ;;
+       lto)
+               fv=0
+               checks='1 2 3 4 5 6 7 8'
+               ;;
+       *)
                fv=1
                fv=1
-       fi
+               ;;
+       esac
        test $fv = 1 || for what in $checks; do
                test $fv = 1 && break
                case $what in
        test $fv = 1 || for what in $checks; do
                test $fv = 1 && break
                case $what in
@@ -1223,32 +1281,23 @@ if test $ct = gcc; then
                    "if gcc supports $t_cflags $t_ldflags" "$t_ldflags"
        done
        i=1
                    "if gcc supports $t_cflags $t_ldflags" "$t_ldflags"
        done
        i=1
-elif test $ct = icc; then
-       ac_flags 1 fnobuiltinsetmode -fno-builtin-setmode
-       ac_flags 1 fnostrictaliasing -fno-strict-aliasing
-       ac_flags 1 fstacksecuritycheck -fstack-security-check
-       i=1
-elif test $ct = sunpro; then
-       phase=u
-       ac_flags 1 v -v
-       ac_flags 1 ipo -xipo 'for cross-module optimisation'
-       phase=x
-elif test $ct = hpcc; then
+       ;;
+hpcc)
        phase=u
        # probably not needed
        #ac_flags 1 agcc -Agcc 'for support of GCC extensions'
        phase=x
        phase=u
        # probably not needed
        #ac_flags 1 agcc -Agcc 'for support of GCC extensions'
        phase=x
-elif test $ct = dec; then
-       ac_flags 0 verb -verbose
-       ac_flags 1 rodata -readonly_strings
-elif test $ct = dmc; then
-       ac_flags 1 decl "${ccpc}-r" 'for strict prototype checks'
-       ac_flags 1 schk "${ccpc}-s" 'for stack overflow checking'
-elif test $ct = bcc; then
-       ac_flags 1 strpool "${ccpc}-d" 'if string pooling can be enabled'
-elif test $ct = mipspro; then
+       ;;
+icc)
+       ac_flags 1 fnobuiltinsetmode -fno-builtin-setmode
+       ac_flags 1 fnostrictaliasing -fno-strict-aliasing
+       ac_flags 1 fstacksecuritycheck -fstack-security-check
+       i=1
+       ;;
+mipspro)
        ac_flags 1 fullwarn -fullwarn 'for remark output support'
        ac_flags 1 fullwarn -fullwarn 'for remark output support'
-elif test $ct = msc; then
+       ;;
+msc)
        ac_flags 1 strpool "${ccpc}/GF" 'if string pooling can be enabled'
        echo 'int main(void) { char test[64] = ""; return (*test); }' >x
        ac_flags - 1 stackon "${ccpc}/GZ" 'if stack checks can be enabled' <x
        ac_flags 1 strpool "${ccpc}/GF" 'if string pooling can be enabled'
        echo 'int main(void) { char test[64] = ""; return (*test); }' >x
        ac_flags - 1 stackon "${ccpc}/GZ" 'if stack checks can be enabled' <x
@@ -1257,24 +1306,33 @@ elif test $ct = msc; then
        rmf x
        ac_flags 1 wall "${ccpc}/Wall" 'to enable all warnings'
        ac_flags 1 wp64 "${ccpc}/Wp64" 'to enable 64-bit warnings'
        rmf x
        ac_flags 1 wall "${ccpc}/Wall" 'to enable all warnings'
        ac_flags 1 wp64 "${ccpc}/Wp64" 'to enable 64-bit warnings'
-elif test $ct = xlc; then
+       ;;
+nwcc)
+       i=1
+       #broken# ac_flags 1 ssp -stackprotect
+       ;;
+sunpro)
+       phase=u
+       ac_flags 1 v -v
+       ac_flags 1 ipo -xipo 'for cross-module optimisation'
+       phase=x
+       ;;
+tcc)
+       : #broken# ac_flags 1 boundschk -b
+       ;;
+tendra)
+       ac_flags 0 ysystem -Ysystem
+       test 1 = $HAVE_CAN_YSYSTEM && CPPFLAGS="-Ysystem $CPPFLAGS"
+       ac_flags 1 extansi -Xa
+       ;;
+xlc)
        ac_flags 1 rodata "-qro -qroconst -qroptr"
        ac_flags 1 rtcheck -qcheck=all
        #ac_flags 1 rtchkc -qextchk     # reported broken
        ac_flags 1 wformat "-qformat=all -qformat=nozln"
        #ac_flags 1 wp64 -qwarn64       # too verbose for now
        ac_flags 1 rodata "-qro -qroconst -qroptr"
        ac_flags 1 rtcheck -qcheck=all
        #ac_flags 1 rtchkc -qextchk     # reported broken
        ac_flags 1 wformat "-qformat=all -qformat=nozln"
        #ac_flags 1 wp64 -qwarn64       # too verbose for now
-elif test $ct = tendra; then
-       ac_flags 0 ysystem -Ysystem
-       test 1 = $HAVE_CAN_YSYSTEM && CPPFLAGS="-Ysystem $CPPFLAGS"
-       ac_flags 1 extansi -Xa
-elif test $ct = tcc; then
-       : #broken# ac_flags 1 boundschk -b
-elif test $ct = clang; then
-       i=1
-elif test $ct = nwcc; then
-       i=1
-       : #broken# ac_flags 1 ssp -stackprotect
-fi
+       ;;
+esac
 # flags common to a subset of compilers (run with -Werror on gcc)
 if test 1 = $i; then
        ac_flags 1 wall -Wall
 # flags common to a subset of compilers (run with -Werror on gcc)
 if test 1 = $i; then
        ac_flags 1 wall -Wall
@@ -1291,6 +1349,7 @@ test $ct = pcc && phase=u
 #
 ac_test attribute_bounded '' 'for __attribute__((__bounded__))' <<-'EOF'
        #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
 #
 ac_test attribute_bounded '' 'for __attribute__((__bounded__))' <<-'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
        /* force a failure: TenDRA and gcc 1.42 have false positive here */
        int main(void) { return (thiswillneverbedefinedIhope()); }
        #else
@@ -1311,6 +1370,7 @@ ac_test attribute_bounded '' 'for __attribute__((__bounded__))' <<-'EOF'
 EOF
 ac_test attribute_format '' 'for __attribute__((__format__))' <<-'EOF'
        #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
 EOF
 ac_test attribute_format '' 'for __attribute__((__format__))' <<-'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
        /* force a failure: TenDRA and gcc 1.42 have false positive here */
        int main(void) { return (thiswillneverbedefinedIhope()); }
        #else
@@ -1325,6 +1385,7 @@ ac_test attribute_format '' 'for __attribute__((__format__))' <<-'EOF'
 EOF
 ac_test attribute_noreturn '' 'for __attribute__((__noreturn__))' <<-'EOF'
        #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
 EOF
 ac_test attribute_noreturn '' 'for __attribute__((__noreturn__))' <<-'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
        /* force a failure: TenDRA and gcc 1.42 have false positive here */
        int main(void) { return (thiswillneverbedefinedIhope()); }
        #else
@@ -1337,6 +1398,7 @@ ac_test attribute_noreturn '' 'for __attribute__((__noreturn__))' <<-'EOF'
 EOF
 ac_test attribute_unused '' 'for __attribute__((__unused__))' <<-'EOF'
        #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
 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
        /* force a failure: TenDRA and gcc 1.42 have false positive here */
        int main(void) { return (thiswillneverbedefinedIhope()); }
        #else
@@ -1346,6 +1408,7 @@ ac_test attribute_unused '' 'for __attribute__((__unused__))' <<-'EOF'
 EOF
 ac_test attribute_used '' 'for __attribute__((__used__))' <<-'EOF'
        #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
 EOF
 ac_test attribute_used '' 'for __attribute__((__used__))' <<-'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
        /* force a failure: TenDRA and gcc 1.42 have false positive here */
        int main(void) { return (thiswillneverbedefinedIhope()); }
        #else
@@ -1368,8 +1431,8 @@ if ac_ifcpp 'ifdef MKSH_SMALL' isset_MKSH_SMALL '' \
        check_categories="$check_categories smksh"
        HAVE_ISSET_MKSH_CONSERVATIVE_FDS=1      # from sh.h
 fi
        check_categories="$check_categories smksh"
        HAVE_ISSET_MKSH_CONSERVATIVE_FDS=1      # from sh.h
 fi
-ac_ifcpp 'ifdef MKSH_BINSHREDUCED' isset_MKSH_BINSHREDUCED '' \
-    "if a reduced-feature sh is requested" && \
+ac_ifcpp 'if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED)' \
+    isset_MKSH_BINSH '' 'if invoking as sh should be handled specially' && \
     check_categories="$check_categories binsh"
 ac_ifcpp 'ifdef MKSH_UNEMPLOYED' isset_MKSH_UNEMPLOYED '' \
     "if mksh will be built without job control" && \
     check_categories="$check_categories binsh"
 ac_ifcpp 'ifdef MKSH_UNEMPLOYED' isset_MKSH_UNEMPLOYED '' \
     "if mksh will be built without job control" && \
@@ -1491,14 +1554,16 @@ ac_testn sig_t <<-'EOF'
        #include <sys/types.h>
        #include <signal.h>
        #include <stddef.h>
        #include <sys/types.h>
        #include <signal.h>
        #include <stddef.h>
-       int main(void) { return ((int)(ptrdiff_t)(sig_t)(ptrdiff_t)kill(0,0)); }
+       volatile sig_t foo = (sig_t)0;
+       int main(void) { return (foo == (sig_t)0); }
 EOF
 
 ac_testn sighandler_t '!' sig_t 0 <<-'EOF'
        #include <sys/types.h>
        #include <signal.h>
        #include <stddef.h>
 EOF
 
 ac_testn sighandler_t '!' sig_t 0 <<-'EOF'
        #include <sys/types.h>
        #include <signal.h>
        #include <stddef.h>
-       int main(void) { return ((int)(ptrdiff_t)(sighandler_t)(ptrdiff_t)kill(0,0)); }
+       volatile sighandler_t foo = (sighandler_t)0;
+       int main(void) { return (foo == (sighandler_t)0); }
 EOF
 if test 1 = $HAVE_SIGHANDLER_T; then
        add_cppflags -Dsig_t=sighandler_t
 EOF
 if test 1 = $HAVE_SIGHANDLER_T; then
        add_cppflags -Dsig_t=sighandler_t
@@ -1509,7 +1574,8 @@ ac_testn __sighandler_t '!' sig_t 0 <<-'EOF'
        #include <sys/types.h>
        #include <signal.h>
        #include <stddef.h>
        #include <sys/types.h>
        #include <signal.h>
        #include <stddef.h>
-       int main(void) { return ((int)(ptrdiff_t)(__sighandler_t)(ptrdiff_t)kill(0,0)); }
+       volatile __sighandler_t foo = (__sighandler_t)0;
+       int main(void) { return (foo == (__sighandler_t)0); }
 EOF
 if test 1 = $HAVE___SIGHANDLER_T; then
        add_cppflags -Dsig_t=__sighandler_t
 EOF
 if test 1 = $HAVE___SIGHANDLER_T; then
        add_cppflags -Dsig_t=__sighandler_t
@@ -1532,7 +1598,7 @@ else
                #define EXTERN
                #define MKSH_INCLUDES_ONLY
                #include "sh.h"
                #define EXTERN
                #define MKSH_INCLUDES_ONLY
                #include "sh.h"
-               __RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.622 2013/02/19 18:45:15 tg Exp $");
+               __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); }
 EOF
        case $cm in
                int main(void) { printf("Hello, World!\n"); return (0); }
 EOF
        case $cm in
@@ -1748,7 +1814,7 @@ EOF
 ac_test setresugid <<-'EOF'
        #include <sys/types.h>
        #include <unistd.h>
 ac_test setresugid <<-'EOF'
        #include <sys/types.h>
        #include <unistd.h>
-       int main(void) { setresuid(0,0,0); return (setresgid(0,0,0)); }
+       int main(void) { return (setresuid(0,0,0) + setresgid(0,0,0)); }
 EOF
 
 ac_test setgroups setresugid 0 <<-'EOF'
 EOF
 
 ac_test setgroups setresugid 0 <<-'EOF'
@@ -1848,7 +1914,6 @@ ac_testdone
 ac_cppflags
 
 save_CFLAGS=$CFLAGS
 ac_cppflags
 
 save_CFLAGS=$CFLAGS
-test x1 = x$HAVE_CAN_WNOOVERFLOW && CFLAGS="$CFLAGS -Wno-overflow"
 ac_testn compile_time_asserts_$$ '' 'whether compile-time assertions pass' <<-'EOF'
        #define MKSH_INCLUDES_ONLY
        #include "sh.h"
 ac_testn compile_time_asserts_$$ '' 'whether compile-time assertions pass' <<-'EOF'
        #define MKSH_INCLUDES_ONLY
        #include "sh.h"
@@ -1875,13 +1940,8 @@ cta(long_size_no_matter_of_signedness, sizeof(long) == sizeof(unsigned long));
 #ifndef MKSH_LEGACY_MODE
 /* the next assertion is probably not really needed */
 cta(ari_is_4_char, sizeof(mksh_ari_t) == 4);
 #ifndef MKSH_LEGACY_MODE
 /* the next assertion is probably not really needed */
 cta(ari_is_4_char, sizeof(mksh_ari_t) == 4);
-/* but the next two are; we REQUIRE signed integer wraparound */
+/* but this is */
 cta(ari_has_31_bit, 0 < (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1));
 cta(ari_has_31_bit, 0 < (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1));
-#ifndef MKSH_GCC55009
-cta(ari_sign_32_bit_and_wrap,
-    (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1) >
-    (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 2));
-#endif
 /* the next assertion is probably not really needed */
 cta(uari_is_4_char, sizeof(mksh_uari_t) == 4);
 /* but the next three are; we REQUIRE unsigned integer wraparound */
 /* the next assertion is probably not really needed */
 cta(uari_is_4_char, sizeof(mksh_uari_t) == 4);
 /* but the next three are; we REQUIRE unsigned integer wraparound */
@@ -1890,10 +1950,15 @@ cta(uari_has_32_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4
 cta(uari_wrap_32_bit,
     (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) >
     (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4));
 cta(uari_wrap_32_bit,
     (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) >
     (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4));
+#define NUM 22
+#else
+#define NUM 16
 #endif
 /* these are always required */
 cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0);
 cta(uari_is_unsigned, (mksh_uari_t)-1 > (mksh_uari_t)0);
 #endif
 /* these are always required */
 cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0);
 cta(uari_is_unsigned, (mksh_uari_t)-1 > (mksh_uari_t)0);
+/* we require these to have the precisely same size and assume 2s complement */
+cta(ari_size_no_matter_of_signedness, sizeof(mksh_ari_t) == sizeof(mksh_uari_t));
 
 cta(sizet_size_no_matter_of_signedness, sizeof(ssize_t) == sizeof(size_t));
 cta(ptrdifft_sizet_same_size, sizeof(ptrdiff_t) == sizeof(size_t));
 
 cta(sizet_size_no_matter_of_signedness, sizeof(ssize_t) == sizeof(size_t));
 cta(ptrdifft_sizet_same_size, sizeof(ptrdiff_t) == sizeof(size_t));
@@ -1901,17 +1966,10 @@ cta(ptrdifft_voidptr_same_size, sizeof(ptrdiff_t) == sizeof(void *));
 cta(ptrdifft_funcptr_same_size, sizeof(ptrdiff_t) == sizeof(void (*)(void)));
 /* our formatting routines assume this */
 cta(ptr_fits_in_long, sizeof(ptrdiff_t) <= sizeof(long));
 cta(ptrdifft_funcptr_same_size, sizeof(ptrdiff_t) == sizeof(void (*)(void)));
 /* our formatting routines assume this */
 cta(ptr_fits_in_long, sizeof(ptrdiff_t) <= sizeof(long));
+/* for struct alignment people */
+               char padding[64 - NUM];
        };
        };
-#ifndef MKSH_LEGACY_MODE
-#ifndef MKSH_GCC55009
-#define NUM 22
-#else
-#define NUM 21
-#endif
-#else
-#define NUM 15
-#endif
-char ctasserts_dblcheck[sizeof(struct ctasserts) == NUM ? 1 : -1];
+char ctasserts_dblcheck[sizeof(struct ctasserts) == 64 ? 1 : -1];
        int main(void) { return (sizeof(ctasserts_dblcheck)); }
 EOF
 CFLAGS=$save_CFLAGS
        int main(void) { return (sizeof(ctasserts_dblcheck)); }
 EOF
 CFLAGS=$save_CFLAGS
@@ -1957,71 +2015,6 @@ EOF
 fi
 
 #
 fi
 
 #
-# runtime checks
-# once this is more than one, check if we can do runtime
-# checks (not cross-compiling) first to save on warnings
-#
-$e "${bi}run-time checks follow$ao, please ignore any weird errors"
-
-if ac_testnnd silent_idivwrapv '' '(run-time) whether signed integer division overflows wrap silently' <<-'EOF'
-       #define MKSH_INCLUDES_ONLY
-       #include "sh.h"
-       #if !defined(MKSH_LEGACY_MODE) || HAVE_LONG_32BIT
-       #define IDIVWRAPV_VL    (mksh_uari_t)0x80000000UL
-       #elif HAVE_LONG_64BIT
-       #define IDIVWRAPV_VL    (mksh_uari_t)0x8000000000000000UL
-       #else
-       # error "cannot check this"
-       #endif
-       #ifdef SIGFPE
-       static void fpe_catcher(int) MKSH_A_NORETURN;
-       #endif
-       int main(int ac, char **av) {
-               mksh_ari_t o1, o2, r1, r2;
-
-       #ifdef SIGFPE
-               signal(SIGFPE, fpe_catcher);
-       #endif
-               o1 = (mksh_ari_t)IDIVWRAPV_VL;
-               o2 = -ac;
-               r1 = o1 / o2;
-               r2 = o1 % o2;
-               if (r1 == o1 && r2 == 0) {
-                       printf("si");
-                       return (0);
-               }
-               printf("no %d %d %d %d %s", (int)o1, (int)o2, (int)r1,
-                   (int)r2, av[0]);
-               return (1);
-       }
-       #ifdef SIGFPE
-       static const char fpe_msg[] = "no, got SIGFPE, what were they smoking?";
-       #define fpe_msglen (sizeof(fpe_msg) - 1)
-       static void fpe_catcher(int sig MKSH_A_UNUSED) {
-               _exit(write(1, fpe_msg, fpe_msglen) == fpe_msglen ? 2 : 3);
-       }
-       #endif
-EOF
-then
-       if test $fv = 0; then
-               echo "| hrm, compiling this failed, but we will just failback"
-       else
-               echo "| running test programme; this will fail if cross-compiling"
-               echo "| in which case we will gracefully degrade to the default"
-               ./$tcfn >vv.out 2>&1
-               rv=$?
-               echo "| result: `cat vv.out`"
-               fv=0
-               test $rv = 0 && test x"`cat vv.out`" = x"si" && fv=1
-       fi
-       rmf conftest.c conftest.o ${tcfn}* vv.out
-       ac_testdone
-fi
-ac_cppflags
-
-$e "${bi}end of run-time checks$ao"
-
-#
 # Compiler: Praeprocessor (only if needed)
 #
 test 0 = $HAVE_SYS_SIGNAME && if ac_testinit cpp_dd '' \
 # Compiler: Praeprocessor (only if needed)
 #
 test 0 = $HAVE_SYS_SIGNAME && if ac_testinit cpp_dd '' \
@@ -2120,7 +2113,7 @@ addsrcs USE_PRINTF_BUILTIN printf.c
 test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
 test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
 test -n "$LDSTATIC" && add_cppflags -DMKSH_OPTSTATIC
 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=431
+add_cppflags -DMKSH_BUILD_R=481
 
 $e $bi$me: Finished configuration testing, now producing output.$ao
 
 
 $e $bi$me: Finished configuration testing, now producing output.$ao
 
@@ -2219,13 +2212,17 @@ cat >test.sh <<-EOF
        exit \$rv
 EOF
 chmod 755 test.sh
        exit \$rv
 EOF
 chmod 755 test.sh
-if test $cm = llvm; then
-       emitbc="-emit-llvm -c"
-elif test $cm = dragonegg; then
+case $cm in
+dragonegg)
        emitbc="-S -flto"
        emitbc="-S -flto"
-else
+       ;;
+llvm)
+       emitbc="-emit-llvm -c"
+       ;;
+*)
        emitbc=-c
        emitbc=-c
-fi
+       ;;
+esac
 echo ": # work around NeXTstep bug" >Rebuild.sh
 echo set -x >>Rebuild.sh
 for file in $SRCS; do
 echo ": # work around NeXTstep bug" >Rebuild.sh
 echo set -x >>Rebuild.sh
 for file in $SRCS; do
@@ -2254,7 +2251,7 @@ dragonegg|llvm)
 esac
 echo tcfn=$mkshexe >>Rebuild.sh
 echo "$CC $CFLAGS $LDFLAGS -o \$tcfn $lobjs $LIBS $ccpr" >>Rebuild.sh
 esac
 echo tcfn=$mkshexe >>Rebuild.sh
 echo "$CC $CFLAGS $LDFLAGS -o \$tcfn $lobjs $LIBS $ccpr" >>Rebuild.sh
-echo 'test -f $tcfn || exit 1; size $tcfn' >>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'
        test 0 = $HAVE_SYS_SIGNAME && extras="$extras signames.inc"
 if test $cm = makefile; then
        extras='emacsfn.h sh.h sh_flags.h var_spec.h'
        test 0 = $HAVE_SYS_SIGNAME && extras="$extras signames.inc"
@@ -2335,15 +2332,17 @@ test $cm = combine || v "$CC $CFLAGS $LDFLAGS -o $tcfn $lobjs $LIBS $ccpr"
 test -f $tcfn || exit 1
 test 1 = $r || v "$NROFF -mdoc <'$srcdir/mksh.1' >$tfn.cat1" || \
     rmf $tfn.cat1
 test -f $tcfn || exit 1
 test 1 = $r || v "$NROFF -mdoc <'$srcdir/mksh.1' >$tfn.cat1" || \
     rmf $tfn.cat1
-test 0 = $eq && v size $tcfn
+test 0 = $eq && v $SIZE $tcfn
 i=install
 test -f /usr/ucb/$i && i=/usr/ucb/$i
 test 1 = $eq && e=:
 $e
 $e Installing the shell:
 $e "# $i -c -s -o root -g bin -m 555 $tfn /bin/$tfn"
 i=install
 test -f /usr/ucb/$i && i=/usr/ucb/$i
 test 1 = $eq && e=:
 $e
 $e Installing the shell:
 $e "# $i -c -s -o root -g bin -m 555 $tfn /bin/$tfn"
-$e "# grep -x /bin/$tfn /etc/shells >/dev/null || echo /bin/$tfn >>/etc/shells"
-$e "# $i -c -o root -g bin -m 444 dot.mkshrc /usr/share/doc/mksh/examples/"
+if test $legacy = 0; then
+       $e "# grep -x /bin/$tfn /etc/shells >/dev/null || echo /bin/$tfn >>/etc/shells"
+       $e "# $i -c -o root -g bin -m 444 dot.mkshrc /usr/share/doc/mksh/examples/"
+fi
 $e
 $e Installing the manual:
 if test -f $tfn.cat1; then
 $e
 $e Installing the manual:
 if test -f $tfn.cat1; then
@@ -2351,7 +2350,7 @@ if test -f $tfn.cat1; then
            "/usr/share/man/cat1/$tfn.0"
        $e or
 fi
            "/usr/share/man/cat1/$tfn.0"
        $e or
 fi
-$e "# $i -c -o root -g bin -m 444 mksh.1 /usr/share/man/man1/$tfn.1"
+$e "# $i -c -o root -g bin -m 444 $tfn.1 /usr/share/man/man1/$tfn.1"
 $e
 $e Run the regression test suite: ./test.sh
 $e Please also read the sample file dot.mkshrc and the fine manual.
 $e
 $e Run the regression test suite: ./test.sh
 $e Please also read the sample file dot.mkshrc and the fine manual.
@@ -2389,6 +2388,7 @@ DEBUG_LEAKS                       enable freeing resources before exiting
 MKSHRC_PATH                    "~/.mkshrc" (do not change)
 MKSH_A4PB                      force use of arc4random_pushb
 MKSH_ASSUME_UTF8               (0=disabled, 1=enabled; default: unset)
 MKSHRC_PATH                    "~/.mkshrc" (do not change)
 MKSH_A4PB                      force use of arc4random_pushb
 MKSH_ASSUME_UTF8               (0=disabled, 1=enabled; default: unset)
+MKSH_BINSHPOSIX                        if */sh or */-sh, enable set -o posix
 MKSH_BINSHREDUCED              if */sh or */-sh, enable set -o sh
 MKSH_CLRTOEOL_STRING           "\033[K"
 MKSH_CLS_STRING                        "\033[;H\033[J"
 MKSH_BINSHREDUCED              if */sh or */-sh, enable set -o sh
 MKSH_CLRTOEOL_STRING           "\033[K"
 MKSH_CLS_STRING                        "\033[;H\033[J"
@@ -2400,7 +2400,6 @@ MKSH_DISABLE_DEPRECATED           disable code paths scheduled for later removal
 MKSH_DISABLE_EXPERIMENTAL      disable code not yet comfy for (LTS) snapshots
 MKSH_DISABLE_TTY_WARNING       shut up warning about ctty if OS cant be fixed
 MKSH_DONT_EMIT_IDSTRING                omit RCS IDs from binary
 MKSH_DISABLE_EXPERIMENTAL      disable code not yet comfy for (LTS) snapshots
 MKSH_DISABLE_TTY_WARNING       shut up warning about ctty if OS cant be fixed
 MKSH_DONT_EMIT_IDSTRING                omit RCS IDs from binary
-MKSH_GCC55009                  DANGER! see http://www.mirbsd.org/mksh.htm#p41
 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_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
index 5e55cd4..ecd8f8d 100644 (file)
@@ -1,7 +1,8 @@
-# $MirOS: src/bin/mksh/check.pl,v 1.31 2012/04/06 12:22:14 tg Exp $
-# $OpenBSD: th,v 1.13 2006/05/18 21:27:23 miod Exp $
+# $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 $
 #-
 #-
-# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012
+# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
+#              2012, 2013
 #      Thorsten Glaser <tg@mirbsd.org>
 #
 # Provided that these terms and disclaimer and all copyright notices
 #      Thorsten Glaser <tg@mirbsd.org>
 #
 # Provided that these terms and disclaimer and all copyright notices
@@ -171,13 +172,15 @@ BEGIN {
 
 use Getopt::Std;
 use Config;
 
 use Getopt::Std;
 use Config;
+use File::Temp qw/ :mktemp /;
 
 $os = defined $^O ? $^O : 'unknown';
 
 ($prog = $0) =~ s#.*/##;
 
 $Usage = <<EOF ;
 
 $os = defined $^O ? $^O : 'unknown';
 
 ($prog = $0) =~ s#.*/##;
 
 $Usage = <<EOF ;
-Usage: $prog [-Pv] [-C cat] [-e e=v] [-p prog] [-s fn] [-t tmo] name ...
+Usage: $prog [-Pv] [-C cat] [-e e=v] [-p prog] [-s fn] [-T dir] \
+       [-t tmo] name ...
        -C c    Specify the comma separated list of categories the program
                belongs to (see category field).
        -e e=v  Set the environment variable e to v for all tests
        -C c    Specify the comma separated list of categories the program
                belongs to (see category field).
        -e e=v  Set the environment variable e to v for all tests
@@ -188,6 +191,7 @@ Usage: $prog [-Pv] [-C cat] [-e e=v] [-p prog] [-s fn] [-t tmo] name ...
        -p p    Use p as the program to test
        -s s    Read tests from file s; if s is a directory, it is recursively
                scaned for test files (which end in .t).
        -p p    Use p as the program to test
        -s s    Read tests from file s; if s is a directory, it is recursively
                scaned for test files (which end in .t).
+       -T dir  Use dir instead of /tmp to hold temporary files
        -t t    Use t as default time limit for tests (default is unlimited)
        -v      Verbose mode: print reason test failed.
        name    specifies the name of the test(s) to run; if none are
        -t t    Use t as default time limit for tests (default is unlimited)
        -v      Verbose mode: print reason test failed.
        name    specifies the name of the test(s) to run; if none are
@@ -229,12 +233,6 @@ EOF
        "os:$os", '1'
        );
 
        "os:$os", '1'
        );
 
-$temps = "/tmp/rts$$";
-$tempi = "/tmp/rti$$";
-$tempo = "/tmp/rto$$";
-$tempe = "/tmp/rte$$";
-$tempdir = "/tmp/rtd$$";
-
 $nfailed = 0;
 $nifailed = 0;
 $nxfailed = 0;
 $nfailed = 0;
 $nifailed = 0;
 $nxfailed = 0;
@@ -243,7 +241,7 @@ $nxpassed = 0;
 
 %known_tests = ();
 
 
 %known_tests = ();
 
-if (!getopts('C:e:Pp:s:t:v')) {
+if (!getopts('C:e:Pp:s:T:t:v')) {
     print STDERR $Usage;
     exit 1;
 }
     print STDERR $Usage;
     exit 1;
 }
@@ -253,6 +251,7 @@ die "$prog: no test set specified (use -s)\n" if !defined $opt_s;
 $test_prog = $opt_p;
 $verbose = defined $opt_v && $opt_v;
 $test_set = $opt_s;
 $test_prog = $opt_p;
 $verbose = defined $opt_v && $opt_v;
 $test_set = $opt_s;
+$temp_dir = $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;
 if (defined $opt_t) {
     die "$prog: bad -t argument (should be number > 0): $opt_t\n"
        if $opt_t !~ /^\d+$/ || $opt_t <= 0;
@@ -297,8 +296,6 @@ if (defined $opt_e) {
 }
 %old_env = %ENV;
 
 }
 %old_env = %ENV;
 
-die "$prog: couldn't make directory $tempdir - $!\n" if !mkdir($tempdir, 0777);
-
 chop($pwd = `pwd 2>/dev/null`);
 die "$prog: couldn't get current working directory\n" if $pwd eq '';
 die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd);
 chop($pwd = `pwd 2>/dev/null`);
 die "$prog: couldn't get current working directory\n" if $pwd eq '';
 die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd);
@@ -316,6 +313,17 @@ $SIG{'ALRM'} = 'catch_sigalrm';
 
 $| = 1;
 
 
 $| = 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");
+
 if (-d $test_set) {
     $file_prefix_skip = length($test_set) + 1;
     $ret = &process_test_dir($test_set);
 if (-d $test_set) {
     $file_prefix_skip = length($test_set) + 1;
     $ret = &process_test_dir($test_set);
@@ -433,6 +441,8 @@ run_test
     local(*test) = @_;
     local($name) = $test{':full-name'};
 
     local(*test) = @_;
     local($name) = $test{':full-name'};
 
+    return undef if !&scrub_dir($tempdir);
+
     if (defined $test{'stdin'}) {
        return undef if !&write_file($tempi, $test{'stdin'});
        $ifile = $tempi;
     if (defined $test{'stdin'}) {
        return undef if !&write_file($tempi, $test{'stdin'});
        $ifile = $tempi;
@@ -444,8 +454,6 @@ run_test
        return undef if !&write_file($temps, $test{'script'});
     }
 
        return undef if !&write_file($temps, $test{'script'});
     }
 
-    return undef if !&scrub_dir($tempdir);
-
     if (!chdir($tempdir)) {
        print STDERR "$prog: couldn't cd to $tempdir - $!\n";
        return undef;
     if (!chdir($tempdir)) {
        print STDERR "$prog: couldn't cd to $tempdir - $!\n";
        return undef;
index d33febd..8df826f 100644 (file)
@@ -1,7 +1,9 @@
-# $MirOS: src/bin/mksh/check.t,v 1.597 2013/02/19 18:45:17 tg Exp $
+# $MirOS: src/bin/mksh/check.t,v 1.629 2013/08/14 20:26:15 tg Exp $
 # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
 # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
 # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
 # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
 # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
 # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
+# $OpenBSD: regress.t,v 1.15 2013/07/01 17:25:27 jca Exp $
+# $OpenBSD: obsd-regress.t,v 1.5 2013/07/01 17:25:27 jca Exp $
 #-
 # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #            2011, 2012, 2013
 #-
 # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #            2011, 2012, 2013
@@ -29,7 +31,7 @@
 # http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD
 
 expected-stdout:
 # http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD
 
 expected-stdout:
-       @(#)MIRBSD KSH R43 2013/02/19
+       @(#)MIRBSD KSH R48 2013/08/14
 description:
        Check version of shell.
 stdin:
 description:
        Check version of shell.
 stdin:
@@ -38,7 +40,7 @@ name: KSH_VERSION
 category: shell:legacy-no
 ---
 expected-stdout:
 category: shell:legacy-no
 ---
 expected-stdout:
-       @(#)LEGACY KSH R43 2013/02/19
+       @(#)LEGACY KSH R48 2013/08/14
 description:
        Check version of legacy shell.
 stdin:
 description:
        Check version of legacy shell.
 stdin:
@@ -290,6 +292,22 @@ stdin:
 expected-stdout:
        = 4 2 =
 ---
 expected-stdout:
        = 4 2 =
 ---
+name: arith-lazy-4
+description:
+       Check that preun/postun not done on non-evaluated side of ternary
+       operator
+stdin:
+       (( m = n = 0, 1 ? n++ : m++ ? 2 : 3 ))
+       echo "($n, $m)"
+       m=0; echo $(( 0 ? ++m : 2 )); echo $m
+       m=0; echo $(( 0 ? m++ : 2 )); echo $m
+expected-stdout:
+       (1, 0)
+       2
+       0
+       2
+       0
+---
 name: arith-ternary-prec-1
 description:
        Check precedence of ternary operator vs assignment
 name: arith-ternary-prec-1
 description:
        Check precedence of ternary operator vs assignment
@@ -363,30 +381,35 @@ expected-stdout:
 ---
 name: arith-mandatory
 description:
 ---
 name: arith-mandatory
 description:
-       If MKSH_GCC55009 is set when compiling, passing of
-       this test is *mandatory* for a valid mksh executable!
+       Passing of this test is *mandatory* for a valid mksh executable!
 category: shell:legacy-no
 stdin:
        typeset -i sari=0
        typeset -Ui uari=0
        typeset -i x=0
 category: shell:legacy-no
 stdin:
        typeset -i sari=0
        typeset -Ui uari=0
        typeset -i x=0
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #0
        let --sari --uari
        let --sari --uari
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #1
        sari=2147483647 uari=2147483647
        sari=2147483647 uari=2147483647
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #2
        let ++sari ++uari
        let ++sari ++uari
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #3
        let --sari --uari
        let 'sari *= 2' 'uari *= 2'
        let ++sari ++uari
        let --sari --uari
        let 'sari *= 2' 'uari *= 2'
        let ++sari ++uari
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #4
        let ++sari ++uari
        let ++sari ++uari
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #5
        sari=-2147483648 uari=-2147483648
        sari=-2147483648 uari=-2147483648
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #6
        let --sari --uari
        let --sari --uari
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #7
+       (( sari = -5 >> 1 ))
+       ((# uari = -5 >> 1 ))
+       print -r -- $((x++)):$sari=$uari. #8
+       (( sari = -2 ))
+       ((# uari = sari ))
+       print -r -- $((x++)):$sari=$uari. #9
 expected-stdout:
        0:0=0.
        1:-1=4294967295.
 expected-stdout:
        0:0=0.
        1:-1=4294967295.
@@ -396,6 +419,8 @@ expected-stdout:
        5:0=0.
        6:-2147483648=2147483648.
        7:2147483647=2147483647.
        5:0=0.
        6:-2147483648=2147483648.
        7:2147483647=2147483647.
+       8:-3=2147483645.
+       9:-2=4294967294.
 ---
 name: arith-unsigned-1
 description:
 ---
 name: arith-unsigned-1
 description:
@@ -2530,30 +2555,6 @@ expected-stdout:
        \END
        end
 ---
        \END
        end
 ---
-name: heredoc-quoting-unsubst
-description:
-       Check for correct handling of quoted characters in
-       here documents without substitution (marker is quoted).
-stdin:
-       foo=bar
-       cat <<-'EOF'
-               x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
-       EOF
-expected-stdout:
-       x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
----
-name: heredoc-quoting-subst
-description:
-       Check for correct handling of quoted characters in
-       here documents with substitution (marker is not quoted).
-stdin:
-       foo=bar
-       cat <<-EOF
-               x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
-       EOF
-expected-stdout:
-       x " \" \ \ $ $ baz `echo baz` bar $foo x
----
 name: heredoc-tmpfile-1
 description:
        Check that heredoc temp files aren't removed too soon or too late.
 name: heredoc-tmpfile-1
 description:
        Check that heredoc temp files aren't removed too soon or too late.
@@ -2736,6 +2737,131 @@ expected-stdout:
        hi
        Left overs: *
 ---
        hi
        Left overs: *
 ---
+name: heredoc-quoting-unsubst
+description:
+       Check for correct handling of quoted characters in
+       here documents without substitution (marker is quoted).
+stdin:
+       foo=bar
+       cat <<-'EOF'
+               x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
+       EOF
+expected-stdout:
+       x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
+---
+name: heredoc-quoting-subst
+description:
+       Check for correct handling of quoted characters in
+       here documents with substitution (marker is not quoted).
+stdin:
+       foo=bar
+       cat <<-EOF
+               x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
+       EOF
+expected-stdout:
+       x " \" \ \ $ $ baz `echo baz` bar $foo x
+---
+name: single-quotes-in-braces
+description:
+       Check that single quotes inside unquoted {} are treated as quotes
+stdin:
+       foo=1
+       echo ${foo:+'blah  $foo'}
+expected-stdout:
+       blah  $foo
+---
+name: single-quotes-in-quoted-braces
+description:
+       Check that single quotes inside quoted {} are treated as
+       normal char
+stdin:
+       foo=1
+       echo "${foo:+'blah  $foo'}"
+expected-stdout:
+       'blah  1'
+---
+name: single-quotes-in-braces-nested
+description:
+       Check that single quotes inside unquoted {} are treated as quotes,
+       even if that's inside a double-quoted command expansion
+stdin:
+       foo=1
+       echo "$( echo ${foo:+'blah  $foo'})"
+expected-stdout:
+       blah  $foo
+---
+name: single-quotes-in-brace-pattern
+description:
+       Check that single quotes inside {} pattern are treated as quotes
+stdin:
+       foo=1234
+       echo ${foo%'2'*} "${foo%'2'*}" ${foo%2'*'} "${foo%2'*'}"
+expected-stdout:
+       1 1 1234 1234
+---
+name: single-quotes-in-heredoc-braces
+description:
+       Check that single quotes inside {} in heredoc are treated
+       as normal char
+stdin:
+       foo=1
+       cat <<EOM
+       ${foo:+'blah  $foo'}
+       EOM
+expected-stdout:
+       'blah  1'
+---
+name: single-quotes-in-nested-braces
+description:
+       Check that single quotes inside nested unquoted {} are
+       treated as quotes
+stdin:
+       foo=1
+       echo ${foo:+${foo:+'blah  $foo'}}
+expected-stdout:
+       blah  $foo
+---
+name: single-quotes-in-nested-quoted-braces
+description:
+       Check that single quotes inside nested quoted {} are treated
+       as normal char
+stdin:
+       foo=1
+       echo "${foo:+${foo:+'blah  $foo'}}"
+expected-stdout:
+       'blah  1'
+---
+name: single-quotes-in-nested-braces-nested
+description:
+       Check that single quotes inside nested unquoted {} are treated
+       as quotes, even if that's inside a double-quoted command expansion
+stdin:
+       foo=1
+       echo "$( echo ${foo:+${foo:+'blah  $foo'}})"
+expected-stdout:
+       blah  $foo
+---
+name: single-quotes-in-nested-brace-pattern
+description:
+       Check that single quotes inside nested {} pattern are treated as quotes
+stdin:
+       foo=1234
+       echo ${foo:+${foo%'2'*}} "${foo:+${foo%'2'*}}" ${foo:+${foo%2'*'}} "${foo:+${foo%2'*'}}"
+expected-stdout:
+       1 1 1234 1234
+---
+name: single-quotes-in-heredoc-nested-braces
+description:
+       Check that single quotes inside nested {} in heredoc are treated
+       as normal char
+stdin:
+       foo=1
+       cat <<EOM
+       ${foo:+${foo:+'blah  $foo'}}
+       EOM
+expected-stdout:
+       'blah  1'
+---
 name: history-basic
 description:
        See if we can test history at all
 name: history-basic
 description:
        See if we can test history at all
@@ -3466,10 +3592,10 @@ stdin:
        showargs 3 $@
        showargs 4 "$@"
 expected-stdout:
        showargs 3 $@
        showargs 4 "$@"
 expected-stdout:
-        <1> <A B C>
+        <1> <A> <B> <C>
         <2> <ABC>
         <2> <ABC>
-        <3> <A B C>
-        <4> <A B C>
+        <3> <A> <B> <C>
+        <4> <A> <B> <C>
 ---
 name: IFS-space-colon-1
 description:
 ---
 name: IFS-space-colon-1
 description:
@@ -3772,22 +3898,17 @@ expected-stdout:
 ---
 name: integer-base-check-flat
 description:
 ---
 name: integer-base-check-flat
 description:
-       Check behaviour does not match POSuX, because a not type-safe
-       scripting language has *no* business interpreting "010" as octal
-category: shell:legacy-no
+       Check behaviour does not match POSuX (except if set -o posix),
+       because a not type-safe scripting language has *no* business
+       interpreting the string "010" as octal numer eight (dangerous).
 stdin:
 stdin:
-       echo :$((10)).$((010)).$((0x10)).
+       echo 1 "$("$__progname" -c 'echo :$((10))/$((010)),$((0x10)):')" .
+       echo 2 "$("$__progname" -o posix -c 'echo :$((10))/$((010)),$((0x10)):')" .
+       echo 3 "$("$__progname" -o sh -c 'echo :$((10))/$((010)),$((0x10)):')" .
 expected-stdout:
 expected-stdout:
-       :10.10.16.
----
-name: integer-base-check-flat-legacy
-description:
-       Check behaviour matches POSuX for LEGACY KSH
-category: shell:legacy-yes
-stdin:
-       echo :$((10)).$((010)).$((0x10)).
-expected-stdout:
-       :10.8.16.
+       1 :10/10,16: .
+       2 :10/8,16: .
+       3 :10/10,16: .
 ---
 name: integer-base-check-numeric-from
 description:
 ---
 name: integer-base-check-numeric-from
 description:
@@ -3913,6 +4034,13 @@ expected-stdout:
        s:-9223372036854775808.-1.0.
        u:9223372036854775808.18446744073709551615.0.
 ---
        s:-9223372036854775808.-1.0.
        u:9223372036854775808.18446744073709551615.0.
 ---
+name: integer-size-FAIL-to-detect
+description:
+       Notify the user that their ints are not 32 or 64 bit
+category: int:u
+stdin:
+       :
+---
 name: lineno-stdin
 description:
        See if $LINENO is updated and can be modified.
 name: lineno-stdin
 description:
        See if $LINENO is updated and can be modified.
@@ -4245,7 +4373,7 @@ description:
        should print 0 according to POSIX (dash, bash, ksh93, posh)
        but not 0 according to the getopt(1) manual page, ksh88, and
        Bourne sh (such as /bin/sh on Solaris).
        should print 0 according to POSIX (dash, bash, ksh93, posh)
        but not 0 according to the getopt(1) manual page, ksh88, and
        Bourne sh (such as /bin/sh on Solaris).
-       In mksh R39b, we honour POSIX except when -o sh is set.
+       We honour POSIX except when -o sh is set.
 category: shell:legacy-no
 stdin:
        showf() {
 category: shell:legacy-no
 stdin:
        showf() {
@@ -4265,10 +4393,15 @@ stdin:
        showf
        set -- `false`
        echo rv=$?
        showf
        set -- `false`
        echo rv=$?
+       set -o posix -o sh
+       showf
+       set -- `false`
+       echo rv=$?
 expected-stdout:
        FPOSIX=0 FSH=0 rv=0
        FPOSIX=0 FSH=1 rv=1
        FPOSIX=1 FSH=0 rv=0
 expected-stdout:
        FPOSIX=0 FSH=0 rv=0
        FPOSIX=0 FSH=1 rv=1
        FPOSIX=1 FSH=0 rv=0
+       FPOSIX=1 FSH=1 rv=0
 ---
 name: regression-10-legacy
 description:
 ---
 name: regression-10-legacy
 description:
@@ -4297,10 +4430,15 @@ stdin:
        showf
        set -- `false`
        echo rv=$?
        showf
        set -- `false`
        echo rv=$?
+       set -o posix -o sh
+       showf
+       set -- `false`
+       echo rv=$?
 expected-stdout:
        FPOSIX=0 FSH=0 rv=1
        FPOSIX=0 FSH=1 rv=1
 expected-stdout:
        FPOSIX=0 FSH=0 rv=1
        FPOSIX=0 FSH=1 rv=1
-       FPOSIX=1 FSH=0 rv=1
+       FPOSIX=1 FSH=0 rv=0
+       FPOSIX=1 FSH=1 rv=0
 ---
 name: regression-11
 description:
 ---
 name: regression-11
 description:
@@ -4663,18 +4801,16 @@ expected-stdout:
 ---
 name: regression-39
 description:
 ---
 name: regression-39
 description:
-       set -e: errors in command substitutions aren't ignored
-       Not clear if they should be or not... bash passes here
-       this may actually be required for make, so changed the
-       test to make this an mksh feature, not a bug
-arguments: !-e!
+       Only posh and oksh(2013-07) say “hi” below; FreeBSD sh,
+       GNU bash in POSIX mode, dash, ksh93, mksh don’t. All of
+       them exit 0. The POSIX behaviour is needed by BSD make.
 stdin:
 stdin:
+       set -e
        echo `false; echo hi`
        echo `false; echo hi`
-#expected-fail: yes
-#expected-stdout:
-#      hi
+       echo $?
 expected-stdout:
        
 expected-stdout:
        
+       0
 ---
 name: regression-40
 description:
 ---
 name: regression-40
 description:
@@ -5984,6 +6120,27 @@ expected-stdout:
        EXtrap
        = noeval-undef 1 .
 ---
        EXtrap
        = noeval-undef 1 .
 ---
+name: exit-trap-interactive
+description:
+       Check that interactive shell doesn't exit via EXIT trap on syntax error
+arguments: !-i!
+stdin:
+       trap -- EXIT
+       echo Syntax error <
+       echo 'After error 1'
+       trap 'echo Exit trap' EXIT
+       echo Syntax error <
+       echo 'After error 2'
+       trap 'echo Exit trap' EXIT
+       exit
+       echo 'After exit'
+expected-stdout:
+       After error 1
+       After error 2
+       Exit trap
+expected-stderr-pattern:
+       /syntax error: 'newline' unexpected/
+---
 name: test-stlt-1
 description:
        Check that test also can handle string1 < string2 etc.
 name: test-stlt-1
 description:
        Check that test also can handle string1 < string2 etc.
@@ -6178,7 +6335,7 @@ expected-stdout:
 ---
 name: sh-mode-2a
 description:
 ---
 name: sh-mode-2a
 description:
-       Check that sh mode is *not* automatically turned on
+       Check that posix or sh mode is *not* automatically turned on
 category: !binsh
 stdin:
        ln -s "$__progname" ksh || cp "$__progname" ksh
 category: !binsh
 stdin:
        ln -s "$__progname" ksh || cp "$__progname" ksh
@@ -6187,7 +6344,7 @@ stdin:
        ln -s "$__progname" ./-sh || cp "$__progname" ./-sh
        for shell in {,-}{,k}sh; do
                print -- $shell $(./$shell +l -c \
        ln -s "$__progname" ./-sh || cp "$__progname" ./-sh
        for shell in {,-}{,k}sh; do
                print -- $shell $(./$shell +l -c \
-                   '[[ $(set +o) == *@(-o sh)@(| *) ]] && echo sh || echo nosh')
+                   '[[ $(set +o) == *"-o "@(sh|posix)@(| *) ]] && echo sh || echo nosh')
        done
 expected-stdout:
        sh nosh
        done
 expected-stdout:
        sh nosh
@@ -6197,7 +6354,7 @@ expected-stdout:
 ---
 name: sh-mode-2b
 description:
 ---
 name: sh-mode-2b
 description:
-       Check that sh mode *is* automatically turned on
+       Check that posix or sh mode *is* automatically turned on
 category: binsh
 stdin:
        ln -s "$__progname" ksh || cp "$__progname" ksh
 category: binsh
 stdin:
        ln -s "$__progname" ksh || cp "$__progname" ksh
@@ -6206,7 +6363,7 @@ stdin:
        ln -s "$__progname" ./-sh || cp "$__progname" ./-sh
        for shell in {,-}{,k}sh; do
                print -- $shell $(./$shell +l -c \
        ln -s "$__progname" ./-sh || cp "$__progname" ./-sh
        for shell in {,-}{,k}sh; do
                print -- $shell $(./$shell +l -c \
-                   '[[ $(set +o) == *@(-o sh)@(| *) ]] && echo sh || echo nosh')
+                   '[[ $(set +o) == *"-o "@(sh|posix)@(| *) ]] && echo sh || echo nosh')
        done
 expected-stdout:
        sh sh
        done
 expected-stdout:
        sh sh
@@ -6275,6 +6432,28 @@ expected-stdout:
        PIPESTATUS[0]=0
        8 PIPESTATUS[0]=0 PIPESTATUS[1]=0 .
 ---
        PIPESTATUS[0]=0
        8 PIPESTATUS[0]=0 PIPESTATUS[1]=0 .
 ---
+name: pipeline-4
+description:
+       Check that "set -o pipefail" does what it's supposed to
+stdin:
+       echo 1 "$("$__progname" -c '(exit 12) | (exit 23) | (exit 42); echo $?')" .
+       echo 2 "$("$__progname" -c '! (exit 12) | (exit 23) | (exit 42); echo $?')" .
+       echo 3 "$("$__progname" -o pipefail -c '(exit 12) | (exit 23) | (exit 42); echo $?')" .
+       echo 4 "$("$__progname" -o pipefail -c '! (exit 12) | (exit 23) | (exit 42); echo $?')" .
+       echo 5 "$("$__progname" -c '(exit 23) | (exit 42) | :; echo $?')" .
+       echo 6 "$("$__progname" -c '! (exit 23) | (exit 42) | :; echo $?')" .
+       echo 7 "$("$__progname" -o pipefail -c '(exit 23) | (exit 42) | :; echo $?')" .
+       echo 8 "$("$__progname" -o pipefail -c '! (exit 23) | (exit 42) | :; echo $?')" .
+expected-stdout:
+       1 42 .
+       2 0 .
+       3 42 .
+       4 0 .
+       5 0 .
+       6 1 .
+       7 42 .
+       8 0 .
+---
 name: persist-history-1
 description:
        Check if persistent history saving works
 name: persist-history-1
 description:
        Check if persistent history saving works
@@ -7551,6 +7730,28 @@ stdin:
 expected-stdout:
        ab
 ---
 expected-stdout:
        ab
 ---
+name: print-cr
+description:
+       Check that CR+LF is not collapsed into LF as some MSYS shells wrongly do
+stdin:
+       echo '#!'"$__progname" >foo
+       cat >>foo <<-'EOF'
+               print -n -- '220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT\r\n220->> Bitte keine Werbung einwerfen! <<\r\r\n220 Who do you wanna pretend to be today'
+               print \?\r
+       EOF
+       chmod +x foo
+       echo "[$(./foo)]"
+       ./foo | while IFS= read -r line; do
+               print -r -- "{$line}"
+       done
+expected-stdout:
+       [220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT\r
+       220->> Bitte keine Werbung einwerfen! <<\r\r
+       220 Who do you wanna pretend to be today?\r]
+       {220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT\r}
+       {220->> Bitte keine Werbung einwerfen! <<\r\r}
+       {220 Who do you wanna pretend to be today?\r}
+---
 name: print-nul-chars
 description:
        Check handling of NUL characters for print and COMSUB
 name: print-nul-chars
 description:
        Check handling of NUL characters for print and COMSUB
@@ -8363,6 +8564,7 @@ name: bashiop-1
 description:
        Check if GNU bash-like I/O redirection works
        Part 1: this is also supported by GNU bash
 description:
        Check if GNU bash-like I/O redirection works
        Part 1: this is also supported by GNU bash
+category: shell:legacy-no
 stdin:
        exec 3>&1
        function threeout {
 stdin:
        exec 3>&1
        function threeout {
@@ -8383,6 +8585,7 @@ name: bashiop-2a
 description:
        Check if GNU bash-like I/O redirection works
        Part 2: this is *not* supported by GNU bash
 description:
        Check if GNU bash-like I/O redirection works
        Part 2: this is *not* supported by GNU bash
+category: shell:legacy-no
 stdin:
        exec 3>&1
        function threeout {
 stdin:
        exec 3>&1
        function threeout {
@@ -8403,6 +8606,7 @@ name: bashiop-2b
 description:
        Check if GNU bash-like I/O redirection works
        Part 2: this is *not* supported by GNU bash
 description:
        Check if GNU bash-like I/O redirection works
        Part 2: this is *not* supported by GNU bash
+category: shell:legacy-no
 stdin:
        exec 3>&1
        function threeout {
 stdin:
        exec 3>&1
        function threeout {
@@ -8423,6 +8627,7 @@ name: bashiop-2c
 description:
        Check if GNU bash-like I/O redirection works
        Part 2: this is supported by GNU bash 4 only
 description:
        Check if GNU bash-like I/O redirection works
        Part 2: this is supported by GNU bash 4 only
+category: shell:legacy-no
 stdin:
        echo mir >foo
        set -o noclobber
 stdin:
        echo mir >foo
        set -o noclobber
@@ -8446,6 +8651,7 @@ name: bashiop-3a
 description:
        Check if GNU bash-like I/O redirection fails correctly
        Part 1: this is also supported by GNU bash
 description:
        Check if GNU bash-like I/O redirection fails correctly
        Part 1: this is also supported by GNU bash
+category: shell:legacy-no
 stdin:
        echo mir >foo
        set -o noclobber
 stdin:
        echo mir >foo
        set -o noclobber
@@ -8467,6 +8673,7 @@ name: bashiop-3b
 description:
        Check if GNU bash-like I/O redirection fails correctly
        Part 2: this is *not* supported by GNU bash
 description:
        Check if GNU bash-like I/O redirection fails correctly
        Part 2: this is *not* supported by GNU bash
+category: shell:legacy-no
 stdin:
        echo mir >foo
        set -o noclobber
 stdin:
        echo mir >foo
        set -o noclobber
@@ -8490,6 +8697,7 @@ description:
        Check if GNU bash-like I/O redirection works
        Part 4: this is also supported by GNU bash,
        but failed in some mksh versions
        Check if GNU bash-like I/O redirection works
        Part 4: this is also supported by GNU bash,
        but failed in some mksh versions
+category: shell:legacy-no
 stdin:
        exec 3>&1
        function threeout {
 stdin:
        exec 3>&1
        function threeout {
@@ -8511,6 +8719,34 @@ expected-stdout:
        ras
        dwa
 ---
        ras
        dwa
 ---
+name: bashiop-5-normal
+description:
+       Check if GNU bash-like I/O redirection is only supported
+       in !POSIX !sh mode as it breaks existing scripts' syntax
+category: shell:legacy-no
+stdin:
+       :>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
+       :>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
+       :>x; echo 3 "$("$__progname" -o sh -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
+expected-stdout:
+       1  = foo echo bar .
+       2  = bar .
+       3  = bar .
+---
+name: bashiop-5-legacy
+description:
+       Check if GNU bash-like I/O redirection is not parsed
+       in lksh as it breaks existing scripts' syntax
+category: shell:legacy-yes
+stdin:
+       :>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
+       :>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
+       :>x; echo 3 "$("$__progname" -o sh -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
+expected-stdout:
+       1  = bar .
+       2  = bar .
+       3  = bar .
+---
 name: mkshiop-1
 description:
        Check for support of more than 9 file descriptors
 name: mkshiop-1
 description:
        Check for support of more than 9 file descriptors
@@ -8534,10 +8770,57 @@ expected-stdout:
        bar
        baz
 ---
        bar
        baz
 ---
-name: oksh-shcrash
+name: oksh-eval
 description:
 description:
-       src/regress/bin/ksh/shcrash.sh,v 1.1
+       $OpenBSD: eval.sh,v 1.1 2010/03/24 08:29:44 fgsch Exp $
 stdin:
 stdin:
+       a=
+       for n in ${a#*=}; do echo 1hu ${n} .; done
+       for n in "${a#*=}"; do echo 1hq ${n} .; done
+       for n in ${a##*=}; do echo 2hu ${n} .; done
+       for n in "${a##*=}"; do echo 2hq ${n} .; done
+       for n in ${a%=*}; do echo 1pu ${n} .; done
+       for n in "${a%=*}"; do echo 1pq ${n} .; done
+       for n in ${a%%=*}; do echo 2pu ${n} .; done
+       for n in "${a%%=*}"; do echo 2pq ${n} .; done
+expected-stdout:
+       1hq .
+       2hq .
+       1pq .
+       2pq .
+---
+name: oksh-and-list-error-1
+description:
+       Test exit status of rightmost element in 2 element && list in -e mode
+stdin:
+       true && false
+       echo "should not print"
+arguments: !-e!
+expected-exit: e != 0
+---
+name: oksh-and-list-error-2
+description:
+       Test exit status of rightmost element in 3 element && list in -e mode
+stdin:
+       true && true && false
+       echo "should not print"
+arguments: !-e!
+expected-exit: e != 0
+---
+name: oksh-or-list-error-1
+description:
+       Test exit status of || list in -e mode
+stdin:
+       false || false
+       echo "should not print"
+arguments: !-e!
+expected-exit: e != 0
+---
+name: oksh-longline-crash
+description:
+       This used to cause a core dump
+stdin:
+       ulimit -c 0
        deplibs="-lz -lpng /usr/local/lib/libjpeg.la -ltiff -lm -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libglib.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgtk.la -ltiff -ljpeg -lz -lpng -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk_pixbuf.la -lz -lpng /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libglib.la -lm -lm /usr/local/lib/libaudiofile.la -lm -lm -laudiofile -L/usr/local/lib /usr/local/lib/libesd.la -lm -lz -L/usr/local/lib /usr/local/lib/libgnomesupport.la -lm -lz -lm -lglib -L/usr/local/lib /usr/local/lib/libgnome.la -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgtk.la -lICE -lSM -lz -lpng /usr/local/lib/libungif.la /usr/local/lib/libjpeg.la -ltiff -lm -lz -lpng /usr/local/lib/libungif.la -lz /usr/local/lib/libjpeg.la -ltiff -L/usr/local/lib -L/usr/X11R6/lib /usr/local/lib/libgdk_imlib.la -lm -L/usr/local/lib /usr/local/lib/libart_lgpl.la -lm -lz -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lICE -lSM -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -L/usr/X11R6/lib -lm -lz -lpng -lungif -lz -ljpeg -ltiff -ljpeg -lgdk_imlib -lglib -lm -laudiofile -lm -laudiofile -lesd -L/usr/local/lib /usr/local/lib/libgnomeui.la -lz -lz /usr/local/lib/libxml.la -lz -lz -lz /usr/local/lib/libxml.la -lm -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libglib.la /usr/local/lib/libgmodule.la -lintl -lglib -lgmodule /usr/local/lib/libgdk.la /usr/local/lib/libgtk.la -L/usr/X11R6/lib -L/usr/local/lib /usr/local/lib/libglade.la -lz -lz -lz /usr/local/lib/libxml.la /usr/local/lib/libglib.la -lm -lm /usr/local/lib/libaudiofile.la -lm -lm -laudiofile /usr/local/lib/libesd.la -lm -lz /usr/local/lib/libgnomesupport.la -lm -lz -lm -lglib /usr/local/lib/libgnome.la -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -lglib -lgmodule /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -lglib -lgmodule /usr/local/lib/libgtk.la -lICE -lSM -lz -lpng /usr/local/lib/libungif.la /usr/local/lib/libjpeg.la -ltiff -lm -lz -lz /usr/local/lib/libgdk_imlib.la /usr/local/lib/libart_lgpl.la -lm -lz -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lm -lz -lungif -lz -ljpeg -ljpeg -lgdk_imlib -lglib -lm -laudiofile -lm -laudiofile -lesd /usr/local/lib/libgnomeui.la -L/usr/X11R6/lib -L/usr/local/lib /usr/local/lib/libglade-gnome.la /usr/local/lib/libglib.la -lm -lm /usr/local/lib/libaudiofile.la -lm -lm -laudiofile -L/usr/local/lib /usr/local/lib/libesd.la -lm -lz -L/usr/local/lib /usr/local/lib/libgnomesupport.la -lm -lz -lm -lglib -L/usr/local/lib /usr/local/lib/libgnome.la -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgtk.la -lICE -lSM -lz -lpng /usr/local/lib/libungif.la /usr/local/lib/libjpeg.la -ltiff -lm -lz -lpng /usr/local/lib/libungif.la -lz /usr/local/lib/libjpeg.la -ltiff -L/usr/local/lib -L/usr/X11R6/lib /usr/local/lib/libgdk_imlib.la -lm -L/usr/local/lib /usr/local/lib/libart_lgpl.la -lm -lz -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lICE -lSM -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -L/usr/X11R6/lib -lm -lz -lpng -lungif -lz -ljpeg -ltiff -ljpeg -lgdk_imlib -lglib -lm -laudiofile -lm -laudiofile -lesd -L/usr/local/lib /usr/local/lib/libgnomeui.la -L/usr/X11R6/lib -L/usr/local/lib"
        specialdeplibs="-lgnomeui -lart_lgpl -lgdk_imlib -ltiff -ljpeg -lungif -lpng -lz -lSM -lICE -lgtk -lgdk -lgmodule -lintl -lXext -lX11 -lgnome -lgnomesupport -lesd -laudiofile -lm -lglib"
        for deplib in $deplibs; do
        deplibs="-lz -lpng /usr/local/lib/libjpeg.la -ltiff -lm -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libglib.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgtk.la -ltiff -ljpeg -lz -lpng -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk_pixbuf.la -lz -lpng /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libglib.la -lm -lm /usr/local/lib/libaudiofile.la -lm -lm -laudiofile -L/usr/local/lib /usr/local/lib/libesd.la -lm -lz -L/usr/local/lib /usr/local/lib/libgnomesupport.la -lm -lz -lm -lglib -L/usr/local/lib /usr/local/lib/libgnome.la -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgtk.la -lICE -lSM -lz -lpng /usr/local/lib/libungif.la /usr/local/lib/libjpeg.la -ltiff -lm -lz -lpng /usr/local/lib/libungif.la -lz /usr/local/lib/libjpeg.la -ltiff -L/usr/local/lib -L/usr/X11R6/lib /usr/local/lib/libgdk_imlib.la -lm -L/usr/local/lib /usr/local/lib/libart_lgpl.la -lm -lz -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lICE -lSM -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -L/usr/X11R6/lib -lm -lz -lpng -lungif -lz -ljpeg -ltiff -ljpeg -lgdk_imlib -lglib -lm -laudiofile -lm -laudiofile -lesd -L/usr/local/lib /usr/local/lib/libgnomeui.la -lz -lz /usr/local/lib/libxml.la -lz -lz -lz /usr/local/lib/libxml.la -lm -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libglib.la /usr/local/lib/libgmodule.la -lintl -lglib -lgmodule /usr/local/lib/libgdk.la /usr/local/lib/libgtk.la -L/usr/X11R6/lib -L/usr/local/lib /usr/local/lib/libglade.la -lz -lz -lz /usr/local/lib/libxml.la /usr/local/lib/libglib.la -lm -lm /usr/local/lib/libaudiofile.la -lm -lm -laudiofile /usr/local/lib/libesd.la -lm -lz /usr/local/lib/libgnomesupport.la -lm -lz -lm -lglib /usr/local/lib/libgnome.la -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -lglib -lgmodule /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -lglib -lgmodule /usr/local/lib/libgtk.la -lICE -lSM -lz -lpng /usr/local/lib/libungif.la /usr/local/lib/libjpeg.la -ltiff -lm -lz -lz /usr/local/lib/libgdk_imlib.la /usr/local/lib/libart_lgpl.la -lm -lz -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lm -lz -lungif -lz -ljpeg -ljpeg -lgdk_imlib -lglib -lm -laudiofile -lm -laudiofile -lesd /usr/local/lib/libgnomeui.la -L/usr/X11R6/lib -L/usr/local/lib /usr/local/lib/libglade-gnome.la /usr/local/lib/libglib.la -lm -lm /usr/local/lib/libaudiofile.la -lm -lm -laudiofile -L/usr/local/lib /usr/local/lib/libesd.la -lm -lz -L/usr/local/lib /usr/local/lib/libgnomesupport.la -lm -lz -lm -lglib -L/usr/local/lib /usr/local/lib/libgnome.la -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgtk.la -lICE -lSM -lz -lpng /usr/local/lib/libungif.la /usr/local/lib/libjpeg.la -ltiff -lm -lz -lpng /usr/local/lib/libungif.la -lz /usr/local/lib/libjpeg.la -ltiff -L/usr/local/lib -L/usr/X11R6/lib /usr/local/lib/libgdk_imlib.la -lm -L/usr/local/lib /usr/local/lib/libart_lgpl.la -lm -lz -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lICE -lSM -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -L/usr/X11R6/lib -lm -lz -lpng -lungif -lz -ljpeg -ltiff -ljpeg -lgdk_imlib -lglib -lm -laudiofile -lm -laudiofile -lesd -L/usr/local/lib /usr/local/lib/libgnomeui.la -L/usr/X11R6/lib -L/usr/local/lib"
        specialdeplibs="-lgnomeui -lart_lgpl -lgdk_imlib -ltiff -ljpeg -lungif -lpng -lz -lSM -lICE -lgtk -lgdk -lgmodule -lintl -lXext -lX11 -lgnome -lgnomesupport -lesd -laudiofile -lm -lglib"
        for deplib in $deplibs; do
@@ -8554,6 +8837,99 @@ stdin:
                esac
        done
 ---
                esac
        done
 ---
+name: oksh-seterror-1
+description:
+       The -e flag should be ignored when executing a compound list
+       followed by an if statement.
+stdin:
+       if true; then false && false; fi
+       true
+arguments: !-e!
+expected-exit: e == 0
+---
+name: oksh-seterror-2
+description:
+       The -e flag should be ignored when executing a compound list
+       followed by an if statement.
+stdin:
+       if true; then if true; then false && false; fi; fi
+       true
+arguments: !-e!
+expected-exit: e == 0
+---
+name: oksh-seterror-3
+description:
+       The -e flag should be ignored when executing a compound list
+       followed by an elif statement.
+stdin:
+       if true; then :; elif true; then false && false; fi
+arguments: !-e!
+expected-exit: e == 0
+---
+name: oksh-seterror-4
+description:
+       The -e flag should be ignored when executing a pipeline
+       beginning with '!'
+stdin:
+       for i in 1 2 3
+       do
+               false && false
+               true || false
+       done
+arguments: !-e!
+expected-exit: e == 0
+---
+name: oksh-seterror-5
+description:
+       The -e flag should be ignored when executing a pipeline
+       beginning with '!'
+stdin:
+       ! true | false
+       true
+arguments: !-e!
+expected-exit: e == 0
+---
+name: oksh-seterror-6
+description:
+       When trapping ERR and EXIT, both traps should run in -e mode
+       when an error occurs.
+stdin:
+       trap 'echo EXIT' EXIT
+       trap 'echo ERR' ERR
+       set -e
+       false
+       echo DONE
+       exit 0
+arguments: !-e!
+expected-exit: e != 0
+expected-stdout:
+       ERR
+       EXIT
+---
+name: oksh-seterror-7
+description:
+       The -e flag within a command substitution should be honored
+stdin:
+       echo $( set -e; false; echo foo )
+arguments: !-e!
+expected-stdout:
+       
+---
+name: oksh-input-comsub
+description:
+       A command substitution using input redirection should exit with
+       failure if the input file does not exist.
+stdin:
+       var=$(< non-existent)
+expected-exit: e != 0
+expected-stderr-pattern: /non-existent/
+---
+name: oksh-empty-for-list
+description:
+       A for list which expands to zero items should not execute the body.
+stdin:
+       set foo bar baz ; for out in ; do echo $out ; done
+---
 name: oksh-varfunction-mod1
 description:
        $OpenBSD: varfunction.sh,v 1.1 2003/12/15 05:28:40 otto Exp $
 name: oksh-varfunction-mod1
 description:
        $OpenBSD: varfunction.sh,v 1.1 2003/12/15 05:28:40 otto Exp $
@@ -8846,8 +9222,8 @@ stdin:
        EOFI
        #IORDWR_IODUP
        sh  1<>/dev/console  0<&1  2>&1
        EOFI
        #IORDWR_IODUP
        sh  1<>/dev/console  0<&1  2>&1
-       #COMSUB_EXPRSUB
-       echo $(true) $((1+ 2))
+       #COMSUB_EXPRSUB_FUNSUB_VALSUB
+       echo $(true) $((1+ 2)) ${  :;} ${| REPLY=x;}
        #QCHAR_OQUOTE_CQUOTE
        echo fo\ob\"a\`r\'b\$az
        echo "fo\ob\"a\`r\'b\$az"
        #QCHAR_OQUOTE_CQUOTE
        echo fo\ob\"a\`r\'b\$az
        echo "fo\ob\"a\`r\'b\$az"
@@ -9041,7 +9417,7 @@ expected-stdout:
        }
        inline_TWHILE() {
                i=1 
        }
        inline_TWHILE() {
                i=1 
-               while let " i < 10 " 
+               while let] " i < 10 " 
                do
                        echo $i 
                        let ++i 
                do
                        echo $i 
                        let ++i 
@@ -9051,20 +9427,20 @@ expected-stdout:
                i=1; while (( i < 10 )); do echo $i; let ++i; done
        ); }
        function comsub_TWHILE {
                i=1; while (( i < 10 )); do echo $i; let ++i; done
        ); }
        function comsub_TWHILE {
-               x=$(i=1 ; while let " i < 10 " ; do echo $i ; let ++i ; done ) 
+               x=$(i=1 ; while let] " i < 10 " ; do echo $i ; let ++i ; done ) 
        } 
        function reread_TWHILE { x=$((
                i=1; while (( i < 10 )); do echo $i; let ++i; done
        )|tr u x); }
        function reread_TWHILE {
        } 
        function reread_TWHILE { x=$((
                i=1; while (( i < 10 )); do echo $i; let ++i; done
        )|tr u x); }
        function reread_TWHILE {
-               x=$(( i=1 ; while let " i < 10 " ; do echo $i ; let ++i ; done ) | tr u x ) 
+               x=$(( i=1 ; while let] " i < 10 " ; do echo $i ; let ++i ; done ) | tr u x ) 
        } 
        inline_TUNTIL() {
                i=10; until  (( !--i )) ; do echo $i; done
        }
        inline_TUNTIL() {
                i=10 
        } 
        inline_TUNTIL() {
                i=10; until  (( !--i )) ; do echo $i; done
        }
        inline_TUNTIL() {
                i=10 
-               until let " !--i " 
+               until let] " !--i " 
                do
                        echo $i 
                done 
                do
                        echo $i 
                done 
@@ -9073,13 +9449,13 @@ expected-stdout:
                i=10; until  (( !--i )) ; do echo $i; done
        ); }
        function comsub_TUNTIL {
                i=10; until  (( !--i )) ; do echo $i; done
        ); }
        function comsub_TUNTIL {
-               x=$(i=10 ; until let " !--i " ; do echo $i ; done ) 
+               x=$(i=10 ; until let] " !--i " ; do echo $i ; done ) 
        } 
        function reread_TUNTIL { x=$((
                i=10; until  (( !--i )) ; do echo $i; done
        )|tr u x); }
        function reread_TUNTIL {
        } 
        function reread_TUNTIL { x=$((
                i=10; until  (( !--i )) ; do echo $i; done
        )|tr u x); }
        function reread_TUNTIL {
-               x=$(( i=10 ; until let " !--i " ; do echo $i ; done ) | tr u x ) 
+               x=$(( i=10 ; until let] " !--i " ; do echo $i ; done ) | tr u x ) 
        } 
        inline_TCOPROC() {
                cat  *  |&  ls
        } 
        inline_TCOPROC() {
                cat  *  |&  ls
@@ -9229,23 +9605,23 @@ expected-stdout:
        function reread_IORDWR_IODUP {
                x=$(( sh 1<>/dev/console <&1 2>&1 ) | tr u x ) 
        } 
        function reread_IORDWR_IODUP {
                x=$(( sh 1<>/dev/console <&1 2>&1 ) | tr u x ) 
        } 
-       inline_COMSUB_EXPRSUB() {
-               echo $(true) $((1+ 2))
+       inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
+               echo $(true) $((1+ 2)) ${  :;} ${| REPLY=x;}
        }
        }
-       inline_COMSUB_EXPRSUB() {
-               echo $(true ) $((1+ 2)) 
+       inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
+               echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} 
        } 
        } 
-       function comsub_COMSUB_EXPRSUB { x=$(
-               echo $(true) $((1+ 2))
+       function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$(
+               echo $(true) $((1+ 2)) ${  :;} ${| REPLY=x;}
        ); }
        ); }
-       function comsub_COMSUB_EXPRSUB {
-               x=$(echo $(true ) $((1+ 2)) ) 
+       function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB {
+               x=$(echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} 
        } 
        } 
-       function reread_COMSUB_EXPRSUB { x=$((
-               echo $(true) $((1+ 2))
+       function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$((
+               echo $(true) $((1+ 2)) ${  :;} ${| REPLY=x;}
        )|tr u x); }
        )|tr u x); }
-       function reread_COMSUB_EXPRSUB {
-               x=$(( echo $(true ) $((1+ 2)) ) | tr u x ) 
+       function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB {
+               x=$(( echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} ) | tr u x ) 
        } 
        inline_QCHAR_OQUOTE_CQUOTE() {
                echo fo\ob\"a\`r\'b\$az
        } 
        inline_QCHAR_OQUOTE_CQUOTE() {
                echo fo\ob\"a\`r\'b\$az
@@ -9693,7 +10069,7 @@ expected-stdout:
        }
        inline_TWHILE() {
                i=1 
        }
        inline_TWHILE() {
                i=1 
-               while let " i < 10 " >&3 
+               while let] " i < 10 " >&3 
                do
                        echo $i 
                        let ++i 
                do
                        echo $i 
                        let ++i 
@@ -9703,20 +10079,20 @@ expected-stdout:
                i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
        ); }
        function comsub_TWHILE {
                i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
        ); }
        function comsub_TWHILE {
-               x=$(i=1 ; while let " i < 10 " >&3 ; do echo $i ; let ++i ; done >&3 ) 
+               x=$(i=1 ; while let] " i < 10 " >&3 ; do echo $i ; let ++i ; done >&3 ) 
        } 
        function reread_TWHILE { x=$((
                i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
        )|tr u x); }
        function reread_TWHILE {
        } 
        function reread_TWHILE { x=$((
                i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
        )|tr u x); }
        function reread_TWHILE {
-               x=$(( i=1 ; while let " i < 10 " >&3 ; do echo $i ; let ++i ; done >&3 ) | tr u x ) 
+               x=$(( i=1 ; while let] " i < 10 " >&3 ; do echo $i ; let ++i ; done >&3 ) | tr u x ) 
        } 
        inline_TUNTIL() {
                i=10; until  (( !--i )) >&3 ; do echo $i; done >&3
        }
        inline_TUNTIL() {
                i=10 
        } 
        inline_TUNTIL() {
                i=10; until  (( !--i )) >&3 ; do echo $i; done >&3
        }
        inline_TUNTIL() {
                i=10 
-               until let " !--i " >&3 
+               until let] " !--i " >&3 
                do
                        echo $i 
                done >&3 
                do
                        echo $i 
                done >&3 
@@ -9725,13 +10101,13 @@ expected-stdout:
                i=10; until  (( !--i )) >&3 ; do echo $i; done >&3
        ); }
        function comsub_TUNTIL {
                i=10; until  (( !--i )) >&3 ; do echo $i; done >&3
        ); }
        function comsub_TUNTIL {
-               x=$(i=10 ; until let " !--i " >&3 ; do echo $i ; done >&3 ) 
+               x=$(i=10 ; until let] " !--i " >&3 ; do echo $i ; done >&3 ) 
        } 
        function reread_TUNTIL { x=$((
                i=10; until  (( !--i )) >&3 ; do echo $i; done >&3
        )|tr u x); }
        function reread_TUNTIL {
        } 
        function reread_TUNTIL { x=$((
                i=10; until  (( !--i )) >&3 ; do echo $i; done >&3
        )|tr u x); }
        function reread_TUNTIL {
-               x=$(( i=10 ; until let " !--i " >&3 ; do echo $i ; done >&3 ) | tr u x ) 
+               x=$(( i=10 ; until let] " !--i " >&3 ; do echo $i ; done >&3 ) | tr u x ) 
        } 
        inline_TCOPROC() {
                cat  *  >&3 |&  >&3 ls
        } 
        inline_TCOPROC() {
                cat  *  >&3 |&  >&3 ls
@@ -9831,6 +10207,38 @@ expected-stdout:
        2:ya x2,1,0.
        3:ya,1,3.
 ---
        2:ya x2,1,0.
        3:ya,1,3.
 ---
+name: valsub-1
+description:
+       Check that "value substitutions" work as advertised
+stdin:
+       x=1
+       y=2
+       z=3
+       REPLY=4
+       echo "before:   x<$x> y<$y> z<$z> R<$REPLY>"
+       x=${|
+               local y
+               echo "begin:    x<$x> y<$y> z<$z> R<$REPLY>"
+               x=5
+               y=6
+               z=7
+               REPLY=8
+               echo "end:      x<$x> y<$y> z<$z> R<$REPLY>"
+       }
+       echo "after:    x<$x> y<$y> z<$z> R<$REPLY>"
+       # ensure trailing newlines are kept
+       t=${|REPLY=$'foo\n\n';}
+       typeset -p t
+       echo -n this used to segfault
+       echo ${|true;}$(true).
+expected-stdout:
+       before: x<1> y<2> z<3> R<4>
+       begin:  x<1> y<> z<3> R<>
+       end:    x<5> y<6> z<7> R<8>
+       after:  x<8> y<2> z<7> R<4>
+       typeset t=$'foo\n\n'
+       this used to segfault.
+---
 name: test-stnze-1
 description:
        Check that the short form [ $x ] works
 name: test-stnze-1
 description:
        Check that the short form [ $x ] works
@@ -10156,7 +10564,7 @@ description:
 time-limit: 3
 stdin:
        baz() {
 time-limit: 3
 stdin:
        baz() {
-               typeset -n foo=foo
+               typeset -n foo=fnord fnord=foo
                foo[0]=bar
        }
        set -A foo bad
                foo[0]=bar
        }
        set -A foo bad
@@ -10165,7 +10573,9 @@ stdin:
        echo blah $foo .
 expected-stdout:
        sind bad .
        echo blah $foo .
 expected-stdout:
        sind bad .
-       blah bar .
+       blah bad .
+expected-stderr-pattern:
+       /fnord: expression recurses on parameter/
 ---
 name: better-parens-1a
 description:
 ---
 name: better-parens-1a
 description:
@@ -10743,3 +11153,19 @@ stdin:
        done
        Lb64decode $s >/dev/null
 ---
        done
        Lb64decode $s >/dev/null
 ---
+name: xtrace-1
+description:
+       Check that "set -x" doesn't redirect too quickly
+stdin:
+       print '#!'"$__progname" >bash
+       cat >>bash <<'EOF'
+       echo 'GNU bash, version 2.05b.0(1)-release (i386-ecce-mirbsd10)
+       Copyright (C) 2002 Free Software Foundation, Inc.'
+       EOF
+       chmod +x bash
+       "$__progname" -xc 'foo=$(./bash --version 2>&1 | head -1); echo "=$foo="'
+expected-stdout:
+       =GNU bash, version 2.05b.0(1)-release (i386-ecce-mirbsd10)=
+expected-stderr-pattern:
+       /.*/
+---
index 5ea4b91..cbd13ed 100644 (file)
@@ -1,5 +1,5 @@
 # $Id$
 # $Id$
-# $MirOS: src/bin/mksh/dot.mkshrc,v 1.77 2013/02/17 15:58:26 tg Exp $
+# $MirOS: src/bin/mksh/dot.mkshrc,v 1.84 2013/08/10 13:43:50 tg Exp $
 #-
 # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
 #              2011, 2012, 2013
 #-
 # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
 #              2011, 2012, 2013
 #-
 # ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells
 
 #-
 # ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells
 
+# catch non-mksh (including lksh) trying to shell this file
+case $KSH_VERSION in
+*MIRBSD\ KSH*) ;;
+*) return 0 ;;
+esac
+
 PS1='#'; (( USER_ID )) && PS1='$'; [[ ${HOSTNAME:=$(ulimit -c 0; hostname -s \
     2>/dev/null)} = *([         ]|localhost) ]] && HOSTNAME=$(ulimit -c 0; hostname \
     2>/dev/null); : ${EDITOR:=/bin/ed} ${HOSTNAME:=nil} ${TERM:=vt100}
 PS1='#'; (( USER_ID )) && PS1='$'; [[ ${HOSTNAME:=$(ulimit -c 0; hostname -s \
     2>/dev/null)} = *([         ]|localhost) ]] && HOSTNAME=$(ulimit -c 0; hostname \
     2>/dev/null); : ${EDITOR:=/bin/ed} ${HOSTNAME:=nil} ${TERM:=vt100}
-function precmd {
+: ${MKSH:=$(whence -p mksh)}; PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
        local e=$?
 
        local e=$?
 
-       (( e )) && print -n "$e|"
-       # precmd is required to retain the errorlevel when ${ …;} is used
+       (( e )) && REPLY+="$e|"
+       REPLY+=${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?)}
+       REPLY+=@${HOSTNAME%%.*}:
+
+       local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~}
+       local m=${%d} n p=...; (( m > 0 )) || m=${#d}
+       (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
+       REPLY+=$p$d
+
        return $e
        return $e
-}
-PS1=$'\001\r''${ precmd;}${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?
-       )}@${HOSTNAME%%.*}:${ local e=$? d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || \
-       d=${d/#$p/~}; local m=${%d} n p=...; (( m > 0 )) || m=${#d}
-       (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || \
-       p=; print -nr -- "$p$d"; return $e;} '"$PS1 "
-: ${MKSH:=$(whence -p mksh)}; export EDITOR HOSTNAME MKSH TERM USER
+} '"$PS1 "; export EDITOR HOSTNAME MKSH TERM USER
 alias ls=ls
 unalias ls
 alias l='ls -F'
 alias la='l -a'
 alias ll='l -l'
 alias lo='l -alo'
 alias ls=ls
 unalias ls
 alias l='ls -F'
 alias la='l -a'
 alias ll='l -l'
 alias lo='l -alo'
+alias doch='sudo mksh -c "$(fc -ln -1)"'
 whence -p rot13 >/dev/null || alias rot13='tr \
     abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
     nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
 whence -p rot13 >/dev/null || alias rot13='tr \
     abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
     nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
-whence -p hd >/dev/null || function hd {
-       hexdump -e '"%08.8_ax  " 8/1 "%02X " " - " 8/1 "%02X "' \
-           -e '"  |" "%_p"' -e '"|\n"' "$@"
-}
+if whence -p hd >/dev/null; then :; elif whence -p hexdump >/dev/null; then
+       function hd {
+               hexdump -e '"%08.8_ax  " 8/1 "%02X " " - " 8/1 "%02X "' \
+                   -e '"  |" "%_p"' -e '"|\n"' "$@"
+       }
+else
+       function hd {
+               local -Uui16 -Z11 pos=0
+               local -Uui16 -Z5 hv=2147483647
+               local dasc line i
+
+               cat "$@" | { set +U; if read -arN -1 line; then
+                       typeset -i1 line
+                       i=0
+                       while (( i < ${#line[*]} )); do
+                               hv=${line[i++]}
+                               if (( (pos & 15) == 0 )); then
+                                       (( pos )) && print -r -- "$dasc|"
+                                       print -n "${pos#16#}  "
+                                       dasc=' |'
+                               fi
+                               print -n "${hv#16#} "
+                               if (( (hv < 32) || (hv > 126) )); then
+                                       dasc+=.
+                               else
+                                       dasc+=${line[i-1]#1#}
+                               fi
+                               (( (pos++ & 15) == 7 )) && print -n -- '- '
+                       done
+                       while (( pos & 15 )); do
+                               print -n '   '
+                               (( (pos++ & 15) == 7 )) && print -n -- '- '
+                       done
+                       (( hv == 2147483647 )) || print -r -- "$dasc|"
+               fi; }
+       }
+fi
 
 # Berkeley C shell compatible dirs, popd, and pushd functions
 # Z shell compatible chpwd() hook, used to update DIRSTACK[0]
 
 # Berkeley C shell compatible dirs, popd, and pushd functions
 # Z shell compatible chpwd() hook, used to update DIRSTACK[0]
@@ -222,7 +263,7 @@ function Lb64decode {
        [[ -o utf8-mode ]]; local u=$?
        set +U
        local c s="$*" t=
        [[ -o utf8-mode ]]; local u=$?
        set +U
        local c s="$*" t=
-       [[ -n $s ]] || { s=$(cat;print x); s=${s%x}; }
+       [[ -n $s ]] || { s=$(cat; print x); s=${s%x}; }
        local -i i=0 j=0 n=${#s} p=0 v x
        local -i16 o
 
        local -i i=0 j=0 n=${#s} p=0 v x
        local -i16 o
 
index 12fb4eb..675e7ed 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: edit.c,v 1.37 2013/01/21 10:13:24 halex Exp $ */
+/*     $OpenBSD: edit.c,v 1.38 2013/06/03 15:41:59 tedu 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: 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 $        */
@@ -28,7 +28,7 @@
 
 #ifndef MKSH_NO_CMDLINE_EDITING
 
 
 #ifndef MKSH_NO_CMDLINE_EDITING
 
-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.265 2013/02/10 19:05:36 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.270 2013/08/14 20:26:17 tg Exp $");
 
 /*
  * in later versions we might use libtermcap for this, but since external
 
 /*
  * in later versions we might use libtermcap for this, but since external
@@ -66,7 +66,7 @@ static X_chars edchars;
 static char editmode;
 static int xx_cols;                    /* for Emacs mode */
 static int modified;                   /* buffer has been "modified" */
 static char editmode;
 static int xx_cols;                    /* for Emacs mode */
 static int modified;                   /* buffer has been "modified" */
-static char holdbuf[LINE];             /* place to hold last edit buffer */
+static char *holdbufp;                 /* place to hold last edit buffer */
 
 static int x_getc(void);
 static void x_putcf(int);
 
 static int x_getc(void);
 static void x_putcf(int);
@@ -81,10 +81,10 @@ static char *x_glob_hlp_tilde_and_rem_qchar(char *, bool);
 static int x_basename(const char *, const char *);
 static void x_free_words(int, char **);
 static int x_escape(const char *, size_t, int (*)(const char *, size_t));
 static int x_basename(const char *, const char *);
 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 *, size_t);
+static int x_emacs(char *);
 static void x_init_prompt(void);
 #if !MKSH_S_NOVI
 static void x_init_prompt(void);
 #if !MKSH_S_NOVI
-static int x_vi(char *, size_t);
+static int x_vi(char *);
 #endif
 
 #define x_flush()      shf_flush(shl_out)
 #endif
 
 #define x_flush()      shf_flush(shl_out)
@@ -110,17 +110,17 @@ static int x_e_rebuildline(const char *);
  * read an edited command line
  */
 int
  * read an edited command line
  */
 int
-x_read(char *buf, size_t len)
+x_read(char *buf)
 {
        int i;
 
        x_mode(true);
        modified = 1;
        if (Flag(FEMACS) || Flag(FGMACS))
 {
        int i;
 
        x_mode(true);
        modified = 1;
        if (Flag(FEMACS) || Flag(FGMACS))
-               i = x_emacs(buf, len);
+               i = x_emacs(buf);
 #if !MKSH_S_NOVI
        else if (Flag(FVI))
 #if !MKSH_S_NOVI
        else if (Flag(FVI))
-               i = x_vi(buf, len);
+               i = x_vi(buf);
 #endif
        else
                /* internal error */
 #endif
        else
                /* internal error */
@@ -919,7 +919,6 @@ static bool x_adj_ok;
  */
 static int x_adj_done;         /* is incremented by x_adjust() */
 
  */
 static int x_adj_done;         /* is incremented by x_adjust() */
 
-static int x_col;
 static int x_displen;
 static int x_arg;              /* general purpose arg */
 static bool x_arg_defaulted;   /* x_arg not explicitly set; defaulted to 1 */
 static int x_displen;
 static int x_arg;              /* general purpose arg */
 static bool x_arg_defaulted;   /* x_arg not explicitly set; defaulted to 1 */
@@ -944,9 +943,6 @@ static int x_curprefix;
 static char *macroptr;         /* bind key macro active? */
 #endif
 #if !MKSH_S_NOVI
 static char *macroptr;         /* bind key macro active? */
 #endif
 #if !MKSH_S_NOVI
-static int cur_col;            /* current column on line */
-static int pwidth;             /* width of prompt */
-static int prompt_trunc;       /* how much of prompt to truncate */
 static int winwidth;           /* width of window */
 static char *wbuf[2];          /* window buffers */
 static int wbuf_len;           /* length of window buffers (x_cols - 3) */
 static int winwidth;           /* width of window */
 static char *wbuf[2];          /* window buffers */
 static int wbuf_len;           /* length of window buffers (x_cols - 3) */
@@ -955,13 +951,16 @@ static char morec;                /* more character at right of window */
 static int lastref;            /* argument to last refresh() */
 static int holdlen;            /* length of holdbuf */
 #endif
 static int lastref;            /* argument to last refresh() */
 static int holdlen;            /* length of holdbuf */
 #endif
-static bool prompt_redraw;     /* false if newline forced after prompt */
+static int pwidth;             /* width of prompt */
+static int prompt_trunc;       /* how much of prompt to truncate or -1 */
+static int x_col;              /* current column on line */
 
 static int x_ins(const char *);
 static void x_delete(size_t, bool);
 static size_t x_bword(void);
 static size_t x_fword(bool);
 static void x_goto(char *);
 
 static int x_ins(const char *);
 static void x_delete(size_t, bool);
 static size_t x_bword(void);
 static size_t x_fword(bool);
 static void x_goto(char *);
+static char *x_bs0(char *, char *);
 static void x_bs3(char **);
 static int x_size_str(char *);
 static int x_size2(char *, char **);
 static void x_bs3(char **);
 static int x_size_str(char *);
 static int x_size2(char *, char **);
@@ -1170,30 +1169,25 @@ x_e_getmbc(char *sbuf)
 static void
 x_init_prompt(void)
 {
 static void
 x_init_prompt(void)
 {
-       x_col = promptlen(prompt);
-       x_adj_ok = true;
-       prompt_redraw = true;
-       if (x_col >= xx_cols)
-               x_col %= xx_cols;
-       x_displen = xx_cols - 2 - x_col;
-       x_adj_done = 0;
-
-       pprompt(prompt, 0);
-       if (x_displen < 1) {
-               x_col = 0;
-               x_displen = xx_cols - 2;
+       prompt_trunc = pprompt(prompt, 0);
+       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');
                x_e_putc2('\n');
-               prompt_redraw = false;
        }
 }
 
 static int
        }
 }
 
 static int
-x_emacs(char *buf, size_t len)
+x_emacs(char *buf)
 {
        int c, i;
        unsigned char f;
 
 {
        int c, i;
        unsigned char f;
 
-       xbp = xbuf = buf; xend = buf + len;
+       xbp = xbuf = buf;
+       xend = buf + LINE;
        xlp = xcp = xep = buf;
        *xcp = 0;
        xlp_valid = true;
        xlp = xcp = xep = buf;
        *xcp = 0;
        xlp_valid = true;
@@ -1202,8 +1196,10 @@ x_emacs(char *buf, size_t len)
        x_histp = histptr + 1;
        x_last_command = XFUNC_error;
 
        x_histp = histptr + 1;
        x_last_command = XFUNC_error;
 
-       xx_cols = x_cols;
        x_init_prompt();
        x_init_prompt();
+       x_displen = (xx_cols = x_cols) - 2 - (x_col = pwidth);
+       x_adj_done = 0;
+       x_adj_ok = true;
 
        x_histncp = NULL;
        if (x_nextcmd >= 0) {
 
        x_histncp = NULL;
        if (x_nextcmd >= 0) {
@@ -1561,11 +1557,7 @@ x_fword(bool move)
 static void
 x_goto(char *cp)
 {
 static void
 x_goto(char *cp)
 {
-       if (cp >= xep)
-               cp = xep;
-       else if (UTFMODE)
-               while ((cp > xbuf) && ((*cp & 0xC0) == 0x80))
-                       --cp;
+       cp = cp >= xep ? xep : x_bs0(cp, xbuf);
        if (cp < xbp || cp >= utf_skipcols(xbp, x_displen)) {
                /* we are heading off screen */
                xcp = cp;
        if (cp < xbp || cp >= utf_skipcols(xbp, x_displen)) {
                /* we are heading off screen */
                xcp = cp;
@@ -1581,16 +1573,22 @@ x_goto(char *cp)
        }
 }
 
        }
 }
 
+static char *
+x_bs0(char *cp, char *lower_bound)
+{
+       if (UTFMODE)
+               while ((!lower_bound || (cp > lower_bound)) &&
+                   ((*(unsigned char *)cp & 0xC0) == 0x80))
+                       --cp;
+       return (cp);
+}
+
 static void
 x_bs3(char **p)
 {
        int i;
 
 static void
 x_bs3(char **p)
 {
        int i;
 
-       (*p)--;
-       if (UTFMODE)
-               while (((unsigned char)**p & 0xC0) == 0x80)
-                       (*p)--;
-
+       *p = x_bs0((*p) - 1, NULL);
        i = x_size2(*p, NULL);
        while (i--)
                x_e_putc2('\b');
        i = x_size2(*p, NULL);
        while (i--)
                x_e_putc2('\b');
@@ -1824,7 +1822,7 @@ x_load_hist(char **hp)
        char *sp = NULL;
 
        if (hp == histptr + 1) {
        char *sp = NULL;
 
        if (hp == histptr + 1) {
-               sp = holdbuf;
+               sp = holdbufp;
                modified = 0;
        } else if (hp < history || hp > histptr) {
                x_e_putc2(7);
                modified = 0;
        } else if (hp < history || hp > histptr) {
                x_e_putc2(7);
@@ -1835,7 +1833,7 @@ x_load_hist(char **hp)
        x_histp = hp;
        oldsize = x_size_str(xbuf);
        if (modified)
        x_histp = hp;
        oldsize = x_size_str(xbuf);
        if (modified)
-               strlcpy(holdbuf, xbuf, sizeof(holdbuf));
+               strlcpy(holdbufp, xbuf, LINE);
        strlcpy(xbuf, sp, xend - xbuf);
        xbp = xbuf;
        xep = xcp = xbuf + strlen(xbuf);
        strlcpy(xbuf, sp, xend - xbuf);
        xbp = xbuf;
        xep = xcp = xbuf + strlen(xbuf);
@@ -2080,7 +2078,7 @@ x_cls(int c MKSH_A_UNUSED)
 static void
 x_redraw(int limit)
 {
 static void
 x_redraw(int limit)
 {
-       int i, j, x_trunc = 0;
+       int i, j;
        char *cp;
 
        x_adj_ok = false;
        char *cp;
 
        x_adj_ok = false;
@@ -2090,19 +2088,11 @@ x_redraw(int limit)
                x_e_putc2('\r');
        x_flush();
        if (xbp == xbuf) {
                x_e_putc2('\r');
        x_flush();
        if (xbp == xbuf) {
-               x_col = promptlen(prompt);
-               if (x_col >= xx_cols)
-                       x_trunc = (x_col / xx_cols) * xx_cols;
-               if (prompt_redraw)
-                       pprompt(prompt, x_trunc);
-       }
-       if (x_col >= xx_cols)
-               x_col %= xx_cols;
-       x_displen = xx_cols - 2 - x_col;
-       if (x_displen < 1) {
-               x_col = 0;
-               x_displen = xx_cols - 2;
+               if (prompt_trunc != -1)
+                       pprompt(prompt, prompt_trunc);
+               x_col = pwidth;
        }
        }
+       x_displen = xx_cols - 2 - x_col;
        xlp_valid = false;
        x_zots(xbp);
        if (xbp != xbuf || xep > xlp)
        xlp_valid = false;
        x_zots(xbp);
        if (xbp != xbuf || xep > xlp)
@@ -2816,16 +2806,42 @@ do_complete(
 static void
 x_adjust(void)
 {
 static void
 x_adjust(void)
 {
-       /* flag the fact that we were called. */
+       int col_left, n;
+
+       /* flag the fact that we were called */
        x_adj_done++;
        x_adj_done++;
+
        /*
        /*
-        * we had a problem if the prompt length > xx_cols / 2
+        * calculate the amount of columns we need to "go back"
+        * from xcp to set xbp to (but never < xbuf) to 2/3 of
+        * the display width; take care of pwidth though
         */
         */
-       if ((xbp = xcp - (x_displen / 2)) < xbuf)
-               xbp = xbuf;
-       if (UTFMODE)
-               while ((xbp > xbuf) && ((*xbp & 0xC0) == 0x80))
-                       --xbp;
+       if ((col_left = xx_cols * 2 / 3) < MIN_EDIT_SPACE) {
+               /*
+                * cowardly refuse to do anything
+                * if the available space is too small;
+                * fall back to dumb pdksh code
+                */
+               if ((xbp = xcp - (x_displen / 2)) < xbuf)
+                       xbp = xbuf;
+               /* elide UTF-8 fixup as penalty */
+               goto x_adjust_out;
+       }
+
+       /* fix up xbp to just past a character end first */
+       xbp = xcp >= xep ? xep : x_bs0(xcp, xbuf);
+       /* walk backwards */
+       while (xbp > xbuf && col_left > 0) {
+               xbp = x_bs0(xbp - 1, xbuf);
+               col_left -= (n = x_size2(xbp, NULL));
+       }
+       /* check if we hit the prompt */
+       if (xbp == xbuf && xcp != xbuf && col_left >= 0 && col_left < pwidth) {
+               /* so we did; force scrolling occurs */
+               xbp += utf_ptradj(xbp);
+       }
+
+ x_adjust_out:
        xlp_valid = false;
        x_redraw(xx_cols);
        x_flush();
        xlp_valid = false;
        x_redraw(xx_cols);
        x_flush();
@@ -3345,9 +3361,9 @@ static void yank_range(int, int);
 static int bracktype(int);
 static void save_cbuf(void);
 static void restore_cbuf(void);
 static int bracktype(int);
 static void save_cbuf(void);
 static void restore_cbuf(void);
-static int putbuf(const char *, ssize_t, int);
+static int putbuf(const char *, ssize_t, bool);
 static void del_range(int, int);
 static void del_range(int, int);
-static int findch(int, int, int, int);
+static int findch(int, int, bool, bool);
 static int forwword(int);
 static int backword(int);
 static int endword(int);
 static int forwword(int);
 static int backword(int);
 static int endword(int);
@@ -3411,11 +3427,11 @@ static const unsigned char classify[128] = {
 /* 8   @       A       B       C       D       E       F       G       */
        vC|vX,  vC,     vM,     vC,     vC,     vM,     vM|vX,  vC|vU|vZ,
 /* 9   H       I       J       K       L       M       N       O       */
 /* 8   @       A       B       C       D       E       F       G       */
        vC|vX,  vC,     vM,     vC,     vC,     vM,     vM|vX,  vC|vU|vZ,
 /* 9   H       I       J       K       L       M       N       O       */
-       0,      vC,     0,      0,      0,      0,      vC|vU,  0,
+       0,      vC,     0,      0,      0,      0,      vC|vU,  vU,
 /* A   P       Q       R       S       T       U       V       W       */
        vC,     0,      vC,     vC,     vM|vX,  vC,     0,      vM,
 /* B   X       Y       Z       [       \       ]       ^       _       */
 /* A   P       Q       R       S       T       U       V       W       */
        vC,     0,      vC,     vC,     vM|vX,  vC,     0,      vM,
 /* B   X       Y       Z       [       \       ]       ^       _       */
-       vC,     vC|vU,  0,      0,      vC|vZ,  0,      vM,     vC|vZ,
+       vC,     vC|vU,  0,      vU,     vC|vZ,  0,      vM,     vC|vZ,
 /* C   `       a       b       c       d       e       f       g       */
        0,      vC,     vM,     vE,     vE,     vM,     vM|vX,  vC|vZ,
 /* D   h       i       j       k       l       m       n       o       */
 /* C   `       a       b       c       d       e       f       g       */
        0,      vC,     vM,     vE,     vE,     vM,     vM|vX,  vC|vZ,
 /* D   h       i       j       k       l       m       n       o       */
@@ -3443,25 +3459,24 @@ static const unsigned char classify[128] = {
 #define VLIT           8               /* ^V */
 #define VSEARCH                9               /* /, ? */
 #define VVERSION       10              /* <ESC> ^V */
 #define VLIT           8               /* ^V */
 #define VSEARCH                9               /* /, ? */
 #define VVERSION       10              /* <ESC> ^V */
-
-static char            undocbuf[LINE];
+#define VPREFIX2       11              /* ^[[ and ^[O in insert mode */
 
 static struct edstate  *save_edstate(struct edstate *old);
 static void            restore_edstate(struct edstate *old, struct edstate *news);
 static void            free_edstate(struct edstate *old);
 
 static struct edstate  ebuf;
 
 static struct edstate  *save_edstate(struct edstate *old);
 static void            restore_edstate(struct edstate *old, struct edstate *news);
 static void            free_edstate(struct edstate *old);
 
 static struct edstate  ebuf;
-static struct edstate  undobuf = { undocbuf, 0, LINE, 0, 0 };
+static struct edstate  undobuf;
 
 
-static struct edstate  *es;                    /* current editor state */
+static struct edstate  *es;            /* current editor state */
 static struct edstate  *undo;
 
 static struct edstate  *undo;
 
-static char ibuf[LINE];                        /* input buffer */
-static int first_insert;               /* set when starting in insert mode */
+static char *ibuf;                     /* input buffer */
+static bool first_insert;              /* set when starting in insert mode */
 static int saved_inslen;               /* saved inslen for first insert */
 static int inslen;                     /* length of input buffer */
 static int srchlen;                    /* length of current search pattern */
 static int saved_inslen;               /* saved inslen for first insert */
 static int inslen;                     /* length of input buffer */
 static int srchlen;                    /* length of current search pattern */
-static char ybuf[LINE];                        /* yank buffer */
+static char *ybuf;                     /* yank buffer */
 static int yanklen;                    /* length of yank buffer */
 static int fsavecmd = ' ';             /* last find command */
 static int fsavech;                    /* character to find */
 static int yanklen;                    /* length of yank buffer */
 static int fsavecmd = ' ';             /* last find command */
 static int fsavech;                    /* character to find */
@@ -3469,7 +3484,7 @@ static char lastcmd[MAXVICMD];            /* last non-move command */
 static int lastac;                     /* argcnt for lastcmd */
 static int lastsearch = ' ';           /* last search command */
 static char srchpat[SRCHLEN];          /* last search pattern */
 static int lastac;                     /* argcnt for lastcmd */
 static int lastsearch = ' ';           /* last search command */
 static char srchpat[SRCHLEN];          /* last search pattern */
-static int insert;                     /* non-zero in insert mode */
+static int insert;                     /* <>0 in insert mode */
 static int hnum;                       /* position in history */
 static int ohnum;                      /* history line copied (after mod) */
 static int hlast;                      /* 1 past last position in history */
 static int hnum;                       /* position in history */
 static int ohnum;                      /* history line copied (after mod) */
 static int hlast;                      /* 1 past last position in history */
@@ -3495,7 +3510,7 @@ static enum expand_mode {
 } expanded;
 
 static int
 } expanded;
 
 static int
-x_vi(char *buf, size_t len)
+x_vi(char *buf)
 {
        int c;
 
 {
        int c;
 
@@ -3503,36 +3518,29 @@ x_vi(char *buf, size_t len)
        ohnum = hnum = hlast = histnum(-1) + 1;
        insert = INSERT;
        saved_inslen = inslen;
        ohnum = hnum = hlast = histnum(-1) + 1;
        insert = INSERT;
        saved_inslen = inslen;
-       first_insert = 1;
+       first_insert = true;
        inslen = 0;
        vi_macro_reset();
 
        inslen = 0;
        vi_macro_reset();
 
+       ebuf.cbuf = buf;
+       if (undobuf.cbuf == NULL) {
+               ibuf = alloc(LINE, AEDIT);
+               ybuf = alloc(LINE, AEDIT);
+               undobuf.cbuf = alloc(LINE, AEDIT);
+       }
+       undobuf.cbufsize = ebuf.cbufsize = LINE;
+       undobuf.linelen = ebuf.linelen = 0;
+       undobuf.cursor = ebuf.cursor = 0;
+       undobuf.winleft = ebuf.winleft = 0;
        es = &ebuf;
        es = &ebuf;
-       es->cbuf = buf;
        undo = &undobuf;
        undo = &undobuf;
-       undo->cbufsize = es->cbufsize = len > LINE ? LINE : len;
-
-       es->linelen = undo->linelen = 0;
-       es->cursor = undo->cursor = 0;
-       es->winleft = undo->winleft = 0;
 
 
-       cur_col = promptlen(prompt);
-       prompt_trunc = (cur_col / x_cols) * x_cols;
-       cur_col -= prompt_trunc;
-
-       pprompt(prompt, 0);
-       if ((mksh_uari_t)cur_col > (mksh_uari_t)x_cols - 3 - MIN_EDIT_SPACE) {
-               prompt_redraw = false;
-               cur_col = 0;
-               x_putc('\n');
-       } else
-               prompt_redraw = true;
-       pwidth = cur_col;
+       x_init_prompt();
+       x_col = pwidth;
 
 
-       if (!wbuf_len || wbuf_len != x_cols - 3) {
-               wbuf_len = x_cols - 3;
-               wbuf[0] = aresize(wbuf[0], wbuf_len, APERM);
-               wbuf[1] = aresize(wbuf[1], wbuf_len, APERM);
+       if (wbuf_len != x_cols - 3 && ((wbuf_len = x_cols - 3))) {
+               wbuf[0] = aresize(wbuf[0], wbuf_len, AEDIT);
+               wbuf[1] = aresize(wbuf[1], wbuf_len, AEDIT);
        }
        if (wbuf_len) {
                memset(wbuf[0], ' ', wbuf_len);
        }
        if (wbuf_len) {
                memset(wbuf[0], ' ', wbuf_len);
@@ -3589,11 +3597,11 @@ x_vi(char *buf, size_t len)
        x_putc('\n');
        x_flush();
 
        x_putc('\n');
        x_flush();
 
-       if (c == -1 || (ssize_t)len <= es->linelen)
+       if (c == -1 || (ssize_t)LINE <= es->linelen)
                return (-1);
 
        if (es->cbuf != buf)
                return (-1);
 
        if (es->cbuf != buf)
-               memmove(buf, es->cbuf, es->linelen);
+               memcpy(buf, es->cbuf, es->linelen);
 
        buf[es->linelen++] = '\n';
 
 
        buf[es->linelen++] = '\n';
 
@@ -3644,10 +3652,8 @@ vi_hook(int ch)
                                        save_cbuf();
                                        es->cursor = 0;
                                        es->linelen = 0;
                                        save_cbuf();
                                        es->cursor = 0;
                                        es->linelen = 0;
-                                       if (ch == '/') {
-                                               if (putbuf("/", 1, 0) != 0)
-                                                       return (-1);
-                                       } else if (putbuf("?", 1, 0) != 0)
+                                       if (putbuf(ch == '/' ? "/" : "?", 1,
+                                           false) != 0)
                                                return (-1);
                                        refresh(0);
                                }
                                                return (-1);
                                        refresh(0);
                                }
@@ -3656,7 +3662,7 @@ vi_hook(int ch)
                                        es->cursor = 0;
                                        es->linelen = 0;
                                        putbuf(KSH_VERSION,
                                        es->cursor = 0;
                                        es->linelen = 0;
                                        putbuf(KSH_VERSION,
-                                           strlen(KSH_VERSION), 0);
+                                           strlen(KSH_VERSION), false);
                                        refresh(0);
                                }
                        }
                                        refresh(0);
                                }
                        }
@@ -3805,10 +3811,35 @@ vi_hook(int ch)
                        return (0);
                }
                break;
                        return (0);
                }
                break;
+
+       case VPREFIX2:
+               state = VFAIL;
+               switch (ch) {
+               case 'A':
+                       /* the cursor may not be at the BOL */
+                       if (!es->cursor)
+                               break;
+                       /* nor further in the line than we can search for */
+                       if ((size_t)es->cursor >= sizeof(srchpat) - 1)
+                               es->cursor = sizeof(srchpat) - 2;
+                       /* anchor the search pattern */
+                       srchpat[0] = '^';
+                       /* take the current line up to the cursor */
+                       memmove(srchpat + 1, es->cbuf, es->cursor);
+                       srchpat[es->cursor + 1] = '\0';
+                       /* set a magic flag */
+                       argc1 = 2 + (int)es->cursor;
+                       /* and emulate a backwards history search */
+                       lastsearch = '/';
+                       *curcmd = 'n';
+                       goto pseudo_VCMD;
+               }
+               break;
        }
 
        switch (state) {
        case VCMD:
        }
 
        switch (state) {
        case VCMD:
+ pseudo_VCMD:
                state = VNORMAL;
                switch (vi_cmd(argc1, curcmd)) {
                case -1:
                state = VNORMAL;
                switch (vi_cmd(argc1, curcmd)) {
                case -1:
@@ -3962,7 +3993,7 @@ vi_insert(int ch)
        case Ctrl('['):
                expanded = NONE;
                if (first_insert) {
        case Ctrl('['):
                expanded = NONE;
                if (first_insert) {
-                       first_insert = 0;
+                       first_insert = false;
                        if (inslen == 0) {
                                inslen = saved_inslen;
                                return (redo_insert(0));
                        if (inslen == 0) {
                                inslen = saved_inslen;
                                return (redo_insert(0));
@@ -4074,12 +4105,12 @@ vi_cmd(int argcnt, const char *cmd)
                                 * at this point, it's fairly reasonable that
                                 * nlen + olen + 2 doesn't overflow
                                 */
                                 * at this point, it's fairly reasonable that
                                 * nlen + olen + 2 doesn't overflow
                                 */
-                               nbuf = alloc(nlen + 1 + olen, APERM);
+                               nbuf = alloc(nlen + 1 + olen, AEDIT);
                                memcpy(nbuf, ap->val.s, nlen);
                                nbuf[nlen++] = cmd[1];
                                if (macro.p) {
                                        memcpy(nbuf + nlen, macro.p, olen);
                                memcpy(nbuf, ap->val.s, nlen);
                                nbuf[nlen++] = cmd[1];
                                if (macro.p) {
                                        memcpy(nbuf + nlen, macro.p, olen);
-                                       afree(macro.buf, APERM);
+                                       afree(macro.buf, AEDIT);
                                        nlen += olen;
                                } else {
                                        nbuf[nlen++] = '\0';
                                        nlen += olen;
                                } else {
                                        nbuf[nlen++] = '\0';
@@ -4164,7 +4195,8 @@ vi_cmd(int argcnt, const char *cmd)
                        hnum = hlast;
                        if (es->linelen != 0)
                                es->cursor++;
                        hnum = hlast;
                        if (es->linelen != 0)
                                es->cursor++;
-                       while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
+                       while (putbuf(ybuf, yanklen, false) == 0 &&
+                           --argcnt > 0)
                                ;
                        if (es->cursor != 0)
                                es->cursor--;
                                ;
                        if (es->cursor != 0)
                                es->cursor--;
@@ -4176,7 +4208,8 @@ vi_cmd(int argcnt, const char *cmd)
                        modified = 1;
                        hnum = hlast;
                        any = 0;
                        modified = 1;
                        hnum = hlast;
                        any = 0;
-                       while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
+                       while (putbuf(ybuf, yanklen, false) == 0 &&
+                           --argcnt > 0)
                                any = 1;
                        if (any && es->cursor != 0)
                                es->cursor--;
                                any = 1;
                        if (any && es->cursor != 0)
                                es->cursor--;
@@ -4378,6 +4411,11 @@ vi_cmd(int argcnt, const char *cmd)
                                hnum = c2;
                                ohnum = hnum;
                        }
                                hnum = c2;
                                ohnum = hnum;
                        }
+                       if (argcnt >= 2) {
+                               /* flag from cursor-up command */
+                               es->cursor = argcnt - 2;
+                               return (0);
+                       }
                        break;
                case '_':
                        {
                        break;
                case '_':
                        {
@@ -4422,8 +4460,8 @@ vi_cmd(int argcnt, const char *cmd)
                                        argcnt++;
                                        p++;
                                }
                                        argcnt++;
                                        p++;
                                }
-                               if (putbuf(" ", 1, 0) != 0 ||
-                                   putbuf(sp, argcnt, 0) != 0) {
+                               if (putbuf(" ", 1, false) != 0 ||
+                                   putbuf(sp, argcnt, false) != 0) {
                                        if (es->cursor != 0)
                                                es->cursor--;
                                        return (-1);
                                        if (es->cursor != 0)
                                                es->cursor--;
                                        return (-1);
@@ -4498,6 +4536,16 @@ vi_cmd(int argcnt, const char *cmd)
                case Ctrl('x'):
                        expand_word(1);
                        break;
                case Ctrl('x'):
                        expand_word(1);
                        break;
+
+
+               /* mksh: cursor movement */
+               case '[':
+               case 'O':
+                       state = VPREFIX2;
+                       if (es->linelen != 0)
+                               es->cursor++;
+                       insert = INSERT;
+                       return (0);
                }
                if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
                        es->cursor--;
                }
                if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
                        es->cursor--;
@@ -4556,7 +4604,8 @@ domove(int argcnt, const char *cmd, int sub)
                t = fsavecmd > 'a';
                if (*cmd == ',')
                        t = !t;
                t = fsavecmd > 'a';
                if (*cmd == ',')
                        t = !t;
-               if ((ncursor = findch(fsavech, argcnt, t, i)) < 0)
+               if ((ncursor = findch(fsavech, argcnt, tobool(t),
+                   tobool(i))) < 0)
                        return (-1);
                if (sub && t)
                        ncursor++;
                        return (-1);
                if (sub && t)
                        ncursor++;
@@ -4656,7 +4705,7 @@ static int
 redo_insert(int count)
 {
        while (count-- > 0)
 redo_insert(int count)
 {
        while (count-- > 0)
-               if (putbuf(ibuf, inslen, insert == REPLACE) != 0)
+               if (putbuf(ibuf, inslen, tobool(insert == REPLACE)) != 0)
                        return (-1);
        if (es->cursor > 0)
                es->cursor--;
                        return (-1);
        if (es->cursor > 0)
                es->cursor--;
@@ -4707,9 +4756,9 @@ bracktype(int ch)
 static void
 save_cbuf(void)
 {
 static void
 save_cbuf(void)
 {
-       memmove(holdbuf, es->cbuf, es->linelen);
+       memmove(holdbufp, es->cbuf, es->linelen);
        holdlen = es->linelen;
        holdlen = es->linelen;
-       holdbuf[holdlen] = '\0';
+       holdbufp[holdlen] = '\0';
 }
 
 static void
 }
 
 static void
@@ -4717,7 +4766,7 @@ restore_cbuf(void)
 {
        es->cursor = 0;
        es->linelen = holdlen;
 {
        es->cursor = 0;
        es->linelen = holdlen;
-       memmove(es->cbuf, holdbuf, holdlen);
+       memmove(es->cbuf, holdbufp, holdlen);
 }
 
 /* return a new edstate */
 }
 
 /* return a new edstate */
@@ -4726,8 +4775,8 @@ save_edstate(struct edstate *old)
 {
        struct edstate *news;
 
 {
        struct edstate *news;
 
-       news = alloc(sizeof(struct edstate), APERM);
-       news->cbuf = alloc(old->cbufsize, APERM);
+       news = alloc(sizeof(struct edstate), AEDIT);
+       news->cbuf = alloc(old->cbufsize, AEDIT);
        memcpy(news->cbuf, old->cbuf, old->linelen);
        news->cbufsize = old->cbufsize;
        news->linelen = old->linelen;
        memcpy(news->cbuf, old->cbuf, old->linelen);
        news->cbufsize = old->cbufsize;
        news->linelen = old->linelen;
@@ -4749,8 +4798,8 @@ restore_edstate(struct edstate *news, struct edstate *old)
 static void
 free_edstate(struct edstate *old)
 {
 static void
 free_edstate(struct edstate *old)
 {
-       afree(old->cbuf, APERM);
-       afree(old, APERM);
+       afree(old->cbuf, AEDIT);
+       afree(old, AEDIT);
 }
 
 /*
 }
 
 /*
@@ -4759,11 +4808,11 @@ free_edstate(struct edstate *old)
 static int
 x_vi_putbuf(const char *s, size_t len)
 {
 static int
 x_vi_putbuf(const char *s, size_t len)
 {
-       return (putbuf(s, len, 0));
+       return (putbuf(s, len, false));
 }
 
 static int
 }
 
 static int
-putbuf(const char *buf, ssize_t len, int repl)
+putbuf(const char *buf, ssize_t len, bool repl)
 {
        if (len == 0)
                return (0);
 {
        if (len == 0)
                return (0);
@@ -4793,7 +4842,7 @@ del_range(int a, int b)
 }
 
 static int
 }
 
 static int
-findch(int ch, int cnt, int forw, int incl)
+findch(int ch, int cnt, bool forw, bool incl)
 {
        int ncursor;
 
 {
        int ncursor;
 
@@ -4989,8 +5038,8 @@ grabsearch(int save, int start, int fwd, const char *pat)
                start--;
        anchored = *pat == '^' ? (++pat, 1) : 0;
        if ((hist = findhist(start, fwd, pat, anchored)) < 0) {
                start--;
        anchored = *pat == '^' ? (++pat, 1) : 0;
        if ((hist = findhist(start, fwd, pat, anchored)) < 0) {
-               /* (start != 0 && fwd && match(holdbuf, pat) >= 0) */
-               if (start != 0 && fwd && strcmp(holdbuf, pat) >= 0) {
+               /* (start != 0 && fwd && match(holdbufp, pat) >= 0) */
+               if (start != 0 && fwd && strcmp(holdbufp, pat) >= 0) {
                        restore_cbuf();
                        return (0);
                } else
                        restore_cbuf();
                        return (0);
                } else
@@ -5016,9 +5065,9 @@ redraw_line(bool newl)
                x_putc('\r');
                x_putc('\n');
        }
                x_putc('\r');
                x_putc('\n');
        }
-       if (prompt_redraw)
+       if (prompt_trunc != -1)
                pprompt(prompt, prompt_trunc);
                pprompt(prompt, prompt_trunc);
-       cur_col = pwidth;
+       x_col = pwidth;
        morec = ' ';
 }
 
        morec = ' ';
 }
 
@@ -5136,10 +5185,10 @@ display(char *wb1, char *wb2, int leftside)
        twb2 = wb2;
        while (cnt--) {
                if (*twb1 != *twb2) {
        twb2 = wb2;
        while (cnt--) {
                if (*twb1 != *twb2) {
-                       if (cur_col != col)
+                       if (x_col != col)
                                ed_mov_opt(col, wb1);
                        x_putc(*twb1);
                                ed_mov_opt(col, wb1);
                        x_putc(*twb1);
-                       cur_col++;
+                       x_col++;
                }
                twb1++;
                twb2++;
                }
                twb1++;
                twb2++;
@@ -5160,34 +5209,34 @@ display(char *wb1, char *wb2, int leftside)
        if (mc != morec) {
                ed_mov_opt(pwidth + winwidth + 1, wb1);
                x_putc(mc);
        if (mc != morec) {
                ed_mov_opt(pwidth + winwidth + 1, wb1);
                x_putc(mc);
-               cur_col++;
+               x_col++;
                morec = mc;
        }
                morec = mc;
        }
-       if (cur_col != ncol)
+       if (x_col != ncol)
                ed_mov_opt(ncol, wb1);
 }
 
 static void
 ed_mov_opt(int col, char *wb)
 {
                ed_mov_opt(ncol, wb1);
 }
 
 static void
 ed_mov_opt(int col, char *wb)
 {
-       if (col < cur_col) {
-               if (col + 1 < cur_col - col) {
+       if (col < x_col) {
+               if (col + 1 < x_col - col) {
                        x_putc('\r');
                        x_putc('\r');
-                       if (prompt_redraw)
+                       if (prompt_trunc != -1)
                                pprompt(prompt, prompt_trunc);
                                pprompt(prompt, prompt_trunc);
-                       cur_col = pwidth;
-                       while (cur_col++ < col)
+                       x_col = pwidth;
+                       while (x_col++ < col)
                                x_putcf(*wb++);
                } else {
                                x_putcf(*wb++);
                } else {
-                       while (cur_col-- > col)
+                       while (x_col-- > col)
                                x_putc('\b');
                }
        } else {
                                x_putc('\b');
                }
        } else {
-               wb = &wb[cur_col - pwidth];
-               while (cur_col++ < col)
+               wb = &wb[x_col - pwidth];
+               while (x_col++ < col)
                        x_putcf(*wb++);
        }
                        x_putcf(*wb++);
        }
-       cur_col = col;
+       x_col = col;
 }
 
 
 }
 
 
@@ -5229,7 +5278,7 @@ expand_word(int cmd)
                        rval = -1;
                        break;
                }
                        rval = -1;
                        break;
                }
-               if (++i < nwords && putbuf(" ", 1, 0) != 0) {
+               if (++i < nwords && putbuf(" ", 1, false) != 0) {
                        rval = -1;
                        break;
                }
                        rval = -1;
                        break;
                }
@@ -5347,7 +5396,7 @@ complete_word(int cmd, int count)
                 */
                if (match_len > 0 && match[match_len - 1] != '/' &&
                    !(flags & XCF_IS_NOSPACE))
                 */
                if (match_len > 0 && match[match_len - 1] != '/' &&
                    !(flags & XCF_IS_NOSPACE))
-                       rval = putbuf(" ", 1, 0);
+                       rval = putbuf(" ", 1, false);
        }
        x_free_words(nwords, words);
 
        }
        x_free_words(nwords, words);
 
@@ -5404,7 +5453,7 @@ static void
 vi_macro_reset(void)
 {
        if (macro.p) {
 vi_macro_reset(void)
 {
        if (macro.p) {
-               afree(macro.buf, APERM);
+               afree(macro.buf, AEDIT);
                memset((char *)&macro, 0, sizeof(macro));
        }
 }
                memset((char *)&macro, 0, sizeof(macro));
        }
 }
@@ -5425,8 +5474,11 @@ x_init(void)
        /* ^W */
        edchars.werase = 027;
 
        /* ^W */
        edchars.werase = 027;
 
-       /* initialise Emacs command line editing mode */
+       /* command line editing specific memory allocation */
        ainit(AEDIT);
        ainit(AEDIT);
+       holdbufp = alloc(LINE, AEDIT);
+
+       /* initialise Emacs command line editing mode */
        x_nextcmd = -1;
 
        x_tab = alloc2(X_NTABS, sizeof(*x_tab), AEDIT);
        x_nextcmd = -1;
 
        x_tab = alloc2(X_NTABS, sizeof(*x_tab), AEDIT);
index 4b1f5a0..b6ff1dc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: eval.c,v 1.37 2011/10/11 14:32:43 otto Exp $  */
+/*     $OpenBSD: eval.c,v 1.39 2013/07/01 17:25:27 jca Exp $   */
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.136 2013/02/10 23:43:59 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.142 2013/07/24 18:03:57 tg Exp $");
 
 /*
  * string expansion
 
 /*
  * string expansion
@@ -33,15 +33,21 @@ __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.136 2013/02/10 23:43:59 tg Exp $");
  */
 
 /* expansion generator state */
  */
 
 /* expansion generator state */
-typedef struct Expand {
-       /* int type; */                 /* see expand() */
-       const char *str;                /* string */
+typedef struct {
+       /* not including an "int type;" member, see expand() */
+       /* string */
+       const char *str;
+       /* source */
        union {
        union {
-               const char **strv;      /* string[] */
-               struct shf *shf;        /* file */
-       } u;                            /* source */
-       struct tbl *var;                /* variable in ${var..} */
-       bool split;                     /* split "$@" / call waitlast $() */
+               /* string[] */
+               const char **strv;
+               /* file */
+               struct shf *shf;
+       } u;
+       /* variable in ${var...} */
+       struct tbl *var;
+       /* split "$@" / call waitlast in $() */
+       bool split;
 } Expand;
 
 #define        XBASE           0       /* scanning original */
 } Expand;
 
 #define        XBASE           0       /* scanning original */
@@ -59,7 +65,7 @@ typedef struct Expand {
 
 static int varsub(Expand *, const char *, const char *, int *, int *);
 static int comsub(Expand *, const char *, int);
 
 static int varsub(Expand *, const char *, const char *, int *, int *);
 static int comsub(Expand *, const char *, int);
-static void funsub(struct op *);
+static char *valsub(struct op *, Area *);
 static char *trimsub(char *, char *, int);
 static void glob(char *, XPtrV *, bool);
 static void globit(XString *, char **, char *, XPtrV *, int);
 static char *trimsub(char *, char *, int);
 static void glob(char *, XPtrV *, bool);
 static void globit(XString *, char **, char *, XPtrV *, int);
@@ -198,33 +204,46 @@ typedef struct SubType {
 } SubType;
 
 void
 } SubType;
 
 void
-expand(const char *cp, /* input word */
-    XPtrV *wp,         /* output words */
-    int f)             /* DO* flags */
+expand(
+    /* input word */
+    const char *ccp,
+    /* output words */
+    XPtrV *wp,
+    /* DO* flags */
+    int f)
 {
        int c = 0;
 {
        int c = 0;
-       int type;               /* expansion type */
-       int quote = 0;          /* quoted */
-       XString ds;             /* destination string */
-       char *dp;               /* destination */
-       const char *sp;         /* source */
-       int fdo, word;          /* second pass flags; have word */
-       int doblank;            /* field splitting of parameter/command subst */
+       /* expansion type */
+       int type;
+       /* quoted */
+       int quote = 0;
+       /* destination string and live pointer */
+       XString ds;
+       char *dp;
+       /* source */
+       const char *sp;
+       /* second pass flags */
+       int fdo;
+       /* have word */
+       int word;
+       /* field splitting of parameter/command substitution */
+       int doblank;
+       /* expansion variables */
        Expand x = {
        Expand x = {
-               /* expansion variables */
                NULL, { NULL }, NULL, 0
        };
        SubType st_head, *st;
                NULL, { NULL }, NULL, 0
        };
        SubType st_head, *st;
-       /* For trailing newlines in COMSUB */
+       /* record number of trailing newlines in COMSUB */
        int newlines = 0;
        bool saw_eq, make_magic;
        int tilde_ok;
        size_t len;
        int newlines = 0;
        bool saw_eq, make_magic;
        int tilde_ok;
        size_t len;
+       char *cp;
 
 
-       if (cp == NULL)
+       if (ccp == NULL)
                internal_errorf("expand(NULL)");
        /* for alias, readonly, set, typeset commands */
                internal_errorf("expand(NULL)");
        /* for alias, readonly, set, typeset commands */
-       if ((f & DOVACHECK) && is_wdvarassign(cp)) {
+       if ((f & DOVACHECK) && is_wdvarassign(ccp)) {
                f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE);
                f |= DOASNTILDE;
        }
                f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE);
                f |= DOASNTILDE;
        }
@@ -238,7 +257,7 @@ expand(const char *cp,      /* input word */
        /* init destination string */
        Xinit(ds, dp, 128, ATEMP);
        type = XBASE;
        /* init destination string */
        Xinit(ds, dp, 128, ATEMP);
        type = XBASE;
-       sp = cp;
+       sp = ccp;
        fdo = 0;
        saw_eq = false;
        /* must be 1/0 */
        fdo = 0;
        saw_eq = false;
        /* must be 1/0 */
@@ -279,27 +298,26 @@ expand(const char *cp,    /* input word */
                                continue;
                        case COMSUB:
                        case FUNSUB:
                                continue;
                        case COMSUB:
                        case FUNSUB:
+                       case VALSUB:
                                tilde_ok = 0;
                                if (f & DONTRUNCOMMAND) {
                                        word = IFS_WORD;
                                        *dp++ = '$';
                                tilde_ok = 0;
                                if (f & DONTRUNCOMMAND) {
                                        word = IFS_WORD;
                                        *dp++ = '$';
-                                       if (c == FUNSUB) {
-                                               *dp++ = '{';
-                                               *dp++ = ' ';
-                                       } else
-                                               *dp++ = '(';
+                                       *dp++ = c == COMSUB ? '(' : '{';
+                                       if (c != COMSUB)
+                                               *dp++ = c == FUNSUB ? ' ' : '|';
                                        while (*sp != '\0') {
                                                Xcheck(ds, dp);
                                                *dp++ = *sp++;
                                        }
                                        while (*sp != '\0') {
                                                Xcheck(ds, dp);
                                                *dp++ = *sp++;
                                        }
-                                       if (c == FUNSUB) {
+                                       if (c != COMSUB) {
                                                *dp++ = ';';
                                                *dp++ = '}';
                                        } else
                                                *dp++ = ')';
                                } else {
                                        type = comsub(&x, sp, c);
                                                *dp++ = ';';
                                                *dp++ = '}';
                                        } else
                                                *dp++ = ')';
                                } else {
                                        type = comsub(&x, sp, c);
-                                       if (type == XCOM && (f&DOBLANK))
+                                       if (type != XBASE && (f & DOBLANK))
                                                doblank++;
                                        sp = strnul(sp) + 1;
                                        newlines = 0;
                                                doblank++;
                                        sp = strnul(sp) + 1;
                                        newlines = 0;
@@ -317,7 +335,6 @@ expand(const char *cp,      /* input word */
                                        *dp++ = ')'; *dp++ = ')';
                                } else {
                                        struct tbl v;
                                        *dp++ = ')'; *dp++ = ')';
                                } else {
                                        struct tbl v;
-                                       char *p;
 
                                        v.flag = DEFINED|ISSET|INTEGER;
                                        /* not default */
 
                                        v.flag = DEFINED|ISSET|INTEGER;
                                        /* not default */
@@ -326,9 +343,10 @@ expand(const char *cp,     /* input word */
                                        v_evaluate(&v, substitute(sp, 0),
                                            KSH_UNWIND_ERROR, true);
                                        sp = strnul(sp) + 1;
                                        v_evaluate(&v, substitute(sp, 0),
                                            KSH_UNWIND_ERROR, true);
                                        sp = strnul(sp) + 1;
-                                       for (p = str_val(&v); *p; ) {
+                                       cp = str_val(&v);
+                                       while (*cp) {
                                                Xcheck(ds, dp);
                                                Xcheck(ds, dp);
-                                               *dp++ = *p++;
+                                               *dp++ = *cp++;
                                        }
                                }
                                continue;
                                        }
                                }
                                continue;
@@ -394,8 +412,7 @@ expand(const char *cp,      /* input word */
                                        if (stype)
                                                sp += slen;
                                        switch (stype & 0x17F) {
                                        if (stype)
                                                sp += slen;
                                        switch (stype & 0x17F) {
-                                       case 0x100 | '#':
-                                           {
+                                       case 0x100 | '#': {
                                                char *beg, *end;
                                                mksh_ari_t seed;
                                                register uint32_t h;
                                                char *beg, *end;
                                                mksh_ari_t seed;
                                                register uint32_t h;
@@ -416,8 +433,7 @@ expand(const char *cp,      /* input word */
                                                    (unsigned int)h);
                                                break;
                                        }
                                                    (unsigned int)h);
                                                break;
                                        }
-                                       case 0x100 | 'Q':
-                                           {
+                                       case 0x100 | 'Q': {
                                                struct shf shf;
 
                                                shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
                                                struct shf shf;
 
                                                shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
@@ -839,7 +855,10 @@ expand(const char *cp,     /* input word */
                                if (c == 0) {
                                        if (quote && !x.split)
                                                continue;
                                if (c == 0) {
                                        if (quote && !x.split)
                                                continue;
+                                       /* this is so we don't terminate */
                                        c = ' ';
                                        c = ' ';
+                                       /* now force-emit a word */
+                                       goto emit_word;
                                }
                                if (quote && x.split) {
                                        /* terminate word for "$@" */
                                }
                                if (quote && x.split) {
                                        /* terminate word for "$@" */
@@ -850,14 +869,19 @@ expand(const char *cp,    /* input word */
                        break;
 
                case XCOM:
                        break;
 
                case XCOM:
-                       if (newlines) {
-                               /* Spit out saved NLs */
+                       if (x.u.shf == NULL) {
+                               /* $(<...) failed */
+                               subst_exstat = 1;
+                               /* fake EOF */
+                               c = EOF;
+                       } else if (newlines) {
+                               /* spit out saved NLs */
                                c = '\n';
                                --newlines;
                        } else {
                                while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
                                        if (c == '\n')
                                c = '\n';
                                --newlines;
                        } else {
                                while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
                                        if (c == '\n')
-                                               /* Save newlines */
+                                               /* save newlines */
                                                newlines++;
                                if (newlines && c != EOF) {
                                        shf_ungetc(c, x.u.shf);
                                                newlines++;
                                if (newlines && c != EOF) {
                                        shf_ungetc(c, x.u.shf);
@@ -867,7 +891,8 @@ expand(const char *cp,      /* input word */
                        }
                        if (c == EOF) {
                                newlines = 0;
                        }
                        if (c == EOF) {
                                newlines = 0;
-                               shf_close(x.u.shf);
+                               if (x.u.shf)
+                                       shf_close(x.u.shf);
                                if (x.split)
                                        subst_exstat = waitlast();
                                type = XBASE;
                                if (x.split)
                                        subst_exstat = waitlast();
                                type = XBASE;
@@ -895,21 +920,21 @@ expand(const char *cp,    /* input word */
                         */
                        if (word == IFS_WORD ||
                            (!ctype(c, C_IFSWS) && c && word == IFS_NWS)) {
                         */
                        if (word == IFS_WORD ||
                            (!ctype(c, C_IFSWS) && c && word == IFS_NWS)) {
-                               char *p;
-
+ emit_word:
                                *dp++ = '\0';
                                *dp++ = '\0';
-                               p = Xclose(ds, dp);
+                               cp = Xclose(ds, dp);
                                if (fdo & DOBRACE)
                                        /* also does globbing */
                                if (fdo & DOBRACE)
                                        /* also does globbing */
-                                       alt_expand(wp, p, p,
-                                           p + Xlength(ds, (dp - 1)),
+                                       alt_expand(wp, cp, cp,
+                                           cp + Xlength(ds, (dp - 1)),
                                            fdo | (f & DOMARKDIRS));
                                else if (fdo & DOGLOB)
                                            fdo | (f & DOMARKDIRS));
                                else if (fdo & DOGLOB)
-                                       glob(p, wp, tobool(f & DOMARKDIRS));
+                                       glob(cp, wp, tobool(f & DOMARKDIRS));
                                else if ((f & DOPAT) || !(fdo & DOMAGIC))
                                else if ((f & DOPAT) || !(fdo & DOMAGIC))
-                                       XPput(*wp, p);
+                                       XPput(*wp, cp);
                                else
                                else
-                                       XPput(*wp, debunk(p, p, strlen(p) + 1));
+                                       XPput(*wp, debunk(cp, cp,
+                                           strlen(cp) + 1));
                                fdo = 0;
                                saw_eq = false;
                                tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
                                fdo = 0;
                                saw_eq = false;
                                tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
@@ -920,10 +945,8 @@ expand(const char *cp,     /* input word */
                                return;
                        } else if (type == XSUB && ctype(c, C_IFS) &&
                            !ctype(c, C_IFSWS) && Xlength(ds, dp) == 0) {
                                return;
                        } else if (type == XSUB && ctype(c, C_IFS) &&
                            !ctype(c, C_IFSWS) && Xlength(ds, dp) == 0) {
-                               char *p;
-
-                               *(p = alloc(1, ATEMP)) = '\0';
-                               XPput(*wp, p);
+                               *(cp = alloc(1, ATEMP)) = '\0';
+                               XPput(*wp, cp);
                                type = XSUBMID;
                        }
                        if (word != IFS_NWS)
                                type = XSUBMID;
                        }
                        if (word != IFS_NWS)
@@ -932,10 +955,8 @@ expand(const char *cp,     /* input word */
                        if (type == XSUB) {
                                if (word == IFS_NWS &&
                                    Xlength(ds, dp) == 0) {
                        if (type == XSUB) {
                                if (word == IFS_NWS &&
                                    Xlength(ds, dp) == 0) {
-                                       char *p;
-
-                                       *(p = alloc(1, ATEMP)) = '\0';
-                                       XPput(*wp, p);
+                                       *(cp = alloc(1, ATEMP)) = '\0';
+                                       XPput(*wp, cp);
                                }
                                type = XSUBMID;
                        }
                                }
                                type = XSUBMID;
                        }
@@ -1002,18 +1023,17 @@ expand(const char *cp,  /* input word */
                                        if (type == XBASE &&
                                            (f & (DOTILDE|DOASNTILDE)) &&
                                            (tilde_ok & 2)) {
                                        if (type == XBASE &&
                                            (f & (DOTILDE|DOASNTILDE)) &&
                                            (tilde_ok & 2)) {
-                                               const char *p;
-                                               char *dp_x;
+                                               const char *tcp;
+                                               char *tdp = dp;
 
 
-                                               dp_x = dp;
-                                               p = maybe_expand_tilde(sp,
-                                                   &ds, &dp_x,
+                                               tcp = maybe_expand_tilde(sp,
+                                                   &ds, &tdp,
                                                    f & DOASNTILDE);
                                                    f & DOASNTILDE);
-                                               if (p) {
-                                                       if (dp != dp_x)
+                                               if (tcp) {
+                                                       if (dp != tdp)
                                                                word = IFS_WORD;
                                                                word = IFS_WORD;
-                                                       dp = dp_x;
-                                                       sp = p;
+                                                       dp = tdp;
+                                                       sp = tcp;
                                                        continue;
                                                }
                                        }
                                                        continue;
                                                }
                                        }
@@ -1176,8 +1196,10 @@ varsub(Expand *xp, const char *sp, const char *word,
        c = sp[0];
        if (c == '*' || c == '@') {
                switch (stype & 0x17F) {
        c = sp[0];
        if (c == '*' || c == '@') {
                switch (stype & 0x17F) {
-               case '=':       /* can't assign to a vector */
-               case '%':       /* can't trim a vector (yet) */
+               /* can't assign to a vector */
+               case '=':
+               /* can't trim a vector (yet) */
+               case '%':
                case '#':
                case '0':
                case '/':
                case '#':
                case '0':
                case '/':
@@ -1204,8 +1226,10 @@ varsub(Expand *xp, const char *sp, const char *word,
                        XPtrV wv;
 
                        switch (stype & 0x17F) {
                        XPtrV wv;
 
                        switch (stype & 0x17F) {
-                       case '=':       /* can't assign to a vector */
-                       case '%':       /* can't trim a vector (yet) */
+                       /* can't assign to a vector */
+                       case '=':
+                       /* can't trim a vector (yet) */
+                       case '%':
                        case '#':
                        case '?':
                        case '0':
                        case '#':
                        case '?':
                        case '0':
@@ -1317,33 +1341,41 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
                shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
                        SHF_MAPHI|SHF_CLEXEC);
                if (shf == NULL)
                shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
                        SHF_MAPHI|SHF_CLEXEC);
                if (shf == NULL)
-                       errorf("%s: %s %s", name, "can't open", "$() input");
+                       warningf(!Flag(FTALKING), "%s: %s %s: %s", name,
+                           "can't open", "$(<...) input", cstrerror(errno));
        } else if (fn == FUNSUB) {
                int ofd1;
                struct temp *tf = NULL;
 
        } else if (fn == FUNSUB) {
                int ofd1;
                struct temp *tf = NULL;
 
-               /* create a temporary file, open for writing */
+               /*
+                * create a temporary file, open for reading and writing,
+                * with an shf open for reading (buffered) but yet unused
+                */
                maketemp(ATEMP, TT_FUNSUB, &tf);
                if (!tf->shf) {
                        errorf("can't %s temporary file %s: %s",
                            "create", tf->tffn, cstrerror(errno));
                }
                maketemp(ATEMP, TT_FUNSUB, &tf);
                if (!tf->shf) {
                        errorf("can't %s temporary file %s: %s",
                            "create", tf->tffn, cstrerror(errno));
                }
-               /* save stdout and make the temporary file it */
+               /* extract shf from temporary file, unlink and free it */
+               shf = tf->shf;
+               unlink(tf->tffn);
+               afree(tf, ATEMP);
+               /* save stdout and let it point to the tempfile */
                ofd1 = savefd(1);
                ofd1 = savefd(1);
-               ksh_dup2(shf_fileno(tf->shf), 1, false);
+               ksh_dup2(shf_fileno(shf), 1, false);
                /*
                 * run tree, with output thrown into the tempfile,
                 * in a new function block
                 */
                /*
                 * run tree, with output thrown into the tempfile,
                 * in a new function block
                 */
-               funsub(t);
+               valsub(t, NULL);
                subst_exstat = exstat & 0xFF;
                subst_exstat = exstat & 0xFF;
-               /* close the tempfile and restore regular stdout */
-               shf_close(tf->shf);
+               /* rewind the tempfile and restore regular stdout */
+               lseek(shf_fileno(shf), (off_t)0, SEEK_SET);
                restfd(1, ofd1);
                restfd(1, ofd1);
-               /* now open, unlink and free the tempfile for reading */
-               shf = shf_open(tf->tffn, O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
-               unlink(tf->tffn);
-               afree(tf, ATEMP);
+       } else if (fn == VALSUB) {
+               xp->str = valsub(t, ATEMP);
+               subst_exstat = exstat & 0xFF;
+               return (XSUB);
        } else {
                int ofd1, pv[2];
 
        } else {
                int ofd1, pv[2];
 
@@ -1495,11 +1527,11 @@ globit(XString *xs,     /* dest string */
                 */
                if ((check & GF_EXCHECK) ||
                    ((check & GF_MARKDIR) && (check & GF_GLOBBED))) {
                 */
                if ((check & GF_EXCHECK) ||
                    ((check & GF_MARKDIR) && (check & GF_GLOBBED))) {
-#define stat_check()   (stat_done ? stat_done : \
-                           (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \
-                               ? -1 : 1))
+#define stat_check()   (stat_done ? stat_done : (stat_done = \
+                           stat(Xstring(*xs, xp), &statb) < 0 ? -1 : 1))
                        struct stat lstatb, statb;
                        struct stat lstatb, statb;
-                       int stat_done = 0;       /* -1: failed, 1 ok */
+                       /* -1: failed, 1 ok, 0 not yet done */
+                       int stat_done = 0;
 
                        if (mksh_lstat(Xstring(*xs, xp), &lstatb) < 0)
                                return;
 
                        if (mksh_lstat(Xstring(*xs, xp), &lstatb) < 0)
                                return;
@@ -1801,12 +1833,21 @@ alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
 }
 
 /* helper function due to setjmp/longjmp woes */
 }
 
 /* helper function due to setjmp/longjmp woes */
-static void
-funsub(struct op *t)
+static char *
+valsub(struct op *t, Area *ap)
 {
 {
+       char * volatile cp = NULL;
+       struct tbl * volatile vp = NULL;
+
+       newenv(E_FUNC);
        newblock();
        newblock();
-       e->type = E_FUNC;
+       if (ap)
+               vp = local("REPLY", false);
        if (!kshsetjmp(e->jbuf))
                execute(t, XXCOM | XERROK, NULL);
        if (!kshsetjmp(e->jbuf))
                execute(t, XXCOM | XERROK, NULL);
-       popblock();
+       if (vp)
+               strdupx(cp, str_val(vp), ap);
+       quitenv(NULL);
+
+       return (cp);
 }
 }
index 9a384db..50ec9ca 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: exec.c,v 1.49 2009/01/29 23:27:26 jaredy Exp $        */
+/*     $OpenBSD: exec.c,v 1.50 2013/06/10 21:09:27 millert Exp $       */
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.116 2013/02/17 05:40:15 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.125 2013/07/21 20:44:44 tg Exp $");
 
 #ifndef MKSH_DEFAULT_EXECSHELL
 #define MKSH_DEFAULT_EXECSHELL "/bin/sh"
 
 #ifndef MKSH_DEFAULT_EXECSHELL
 #define MKSH_DEFAULT_EXECSHELL "/bin/sh"
@@ -106,7 +106,7 @@ execute(struct op * volatile t,
                        /* set variable to its expanded value */
                        z = strlen(cp) + 1;
                        if (notoktomul(z, 2) || notoktoadd(z * 2, n))
                        /* set variable to its expanded value */
                        z = strlen(cp) + 1;
                        if (notoktomul(z, 2) || notoktoadd(z * 2, n))
-                               internal_errorf(Toomem, (unsigned long)-1);
+                               internal_errorf(Toomem, (size_t)-1);
                        dp = alloc(z * 2 + n, ATEMP);
                        memcpy(dp, t->vars[0], n);
                        t->vars[0] = dp;
                        dp = alloc(z * 2 + n, ATEMP);
                        memcpy(dp, t->vars[0], n);
                        t->vars[0] = dp;
@@ -138,14 +138,6 @@ execute(struct op * volatile t,
                        /* Allow option parsing (bizarre, but POSIX) */
                        timex_hook(t, &up);
                ap = (const char **)up;
                        /* Allow option parsing (bizarre, but POSIX) */
                        timex_hook(t, &up);
                ap = (const char **)up;
-               if (Flag(FXTRACE) && ap[0]) {
-                       shf_puts(substitute(str_val(global("PS4")), 0),
-                           shl_out);
-                       for (i = 0; ap[i]; i++)
-                               shf_fprintf(shl_out, "%s%c", ap[i],
-                                   ap[i + 1] ? ' ' : '\n');
-                       shf_flush(shl_out);
-               }
                if (ap[0])
                        tp = findcom(ap[0], FC_BI|FC_FUNC);
        }
                if (ap[0])
                        tp = findcom(ap[0], FC_BI|FC_FUNC);
        }
@@ -305,10 +297,12 @@ execute(struct op * volatile t,
        case TAND:
                rv = execute(t->left, XERROK, xerrok);
                if ((rv == 0) == (t->type == TAND))
        case TAND:
                rv = execute(t->left, XERROK, xerrok);
                if ((rv == 0) == (t->type == TAND))
-                       rv = execute(t->right, XERROK, xerrok);
-               flags |= XERROK;
-               if (xerrok)
-                       *xerrok = 1;
+                       rv = execute(t->right, flags & XERROK, xerrok);
+               else {
+                       flags |= XERROK;
+                       if (xerrok)
+                               *xerrok = 1;
+               }
                break;
 
        case TBANG:
                break;
 
        case TBANG:
@@ -335,6 +329,7 @@ execute(struct op * volatile t,
        case TFOR:
        case TSELECT: {
                volatile bool is_first = true;
        case TFOR:
        case TSELECT: {
                volatile bool is_first = true;
+
                ap = (t->vars == NULL) ? e->loc->argv + 1 :
                    (const char **)eval((const char **)t->vars,
                    DOBLANK | DOGLOB | DOTILDE);
                ap = (t->vars == NULL) ? e->loc->argv + 1 :
                    (const char **)eval((const char **)t->vars,
                    DOBLANK | DOGLOB | DOTILDE);
@@ -639,27 +634,44 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
        l_assign = e->loc;
        if (Flag(FEXPORT))
                type_flags |= EXPORT;
        l_assign = e->loc;
        if (Flag(FEXPORT))
                type_flags |= EXPORT;
+       if (Flag(FXTRACE))
+               change_xtrace(2, false);
        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);
                e->loc = l_assign;
        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);
                e->loc = l_assign;
-               /* but assign in there as usual */
-
                if (Flag(FXTRACE)) {
                if (Flag(FXTRACE)) {
-                       if (i == 0)
-                               shf_puts(substitute(str_val(global("PS4")), 0),
-                                   shl_out);
-                       shf_fprintf(shl_out, "%s%c", cp,
-                           t->vars[i + 1] ? ' ' : '\n');
-                       if (!t->vars[i + 1])
-                               shf_flush(shl_out);
+                       const char *ccp;
+
+                       ccp = skip_varname(cp, true);
+                       if (*ccp == '+')
+                               ++ccp;
+                       if (*ccp == '=')
+                               ++ccp;
+                       shf_write(cp, ccp - cp, shl_xtrace);
+                       print_value_quoted(shl_xtrace, ccp);
+                       shf_putc(' ', shl_xtrace);
                }
                }
+               /* 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, type_flags, 0, 0, 0);
                if (bourne_function_call && !(type_flags & EXPORT))
                        typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
        }
 
+       if (Flag(FXTRACE)) {
+               change_xtrace(2, false);
+               if (ap[rv = 0]) {
+ xtrace_ap_loop:
+                       print_value_quoted(shl_xtrace, ap[rv]);
+                       if (ap[++rv]) {
+                               shf_putc(' ', shl_xtrace);
+                               goto xtrace_ap_loop;
+                       }
+               }
+               change_xtrace(1, false);
+       }
+
        if ((cp = *ap) == NULL) {
                rv = subst_exstat;
                goto Leave;
        if ((cp = *ap) == NULL) {
                rv = subst_exstat;
                goto Leave;
@@ -700,10 +712,9 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
                                break;
                        }
                        if (include(tp->u.fpath, 0, NULL, false) < 0) {
                                break;
                        }
                        if (include(tp->u.fpath, 0, NULL, false) < 0) {
-                               rv = errno;
                                warningf(true, "%s: %s %s %s: %s", cp,
                                    "can't open", "function definition file",
                                warningf(true, "%s: %s %s %s: %s", cp,
                                    "can't open", "function definition file",
-                                   tp->u.fpath, cstrerror(rv));
+                                   tp->u.fpath, cstrerror(errno));
                                rv = 127;
                                break;
                        }
                                rv = 127;
                                break;
                        }
@@ -740,9 +751,9 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
                        getopts_reset(1);
                }
 
                        getopts_reset(1);
                }
 
-               old_xflag = Flag(FXTRACE);
-               Flag(FXTRACE) |= tp->flag & TRACE ? 1 : 0;
-
+               old_xflag = Flag(FXTRACE) ? 1 : 0;
+               change_xtrace((Flag(FXTRACEREC) ? old_xflag : 0) |
+                   ((tp->flag & TRACE) ? 1 : 0), false);
                old_inuse = tp->flag & FINUSE;
                tp->flag |= FINUSE;
 
                old_inuse = tp->flag & FINUSE;
                tp->flag |= FINUSE;
 
@@ -751,9 +762,11 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
                        execute(tp->val.t, flags & XERROK, NULL);
                        i = LRETURN;
                }
                        execute(tp->val.t, flags & XERROK, NULL);
                        i = LRETURN;
                }
+
                kshname = old_kshname;
                kshname = old_kshname;
-               Flag(FXTRACE) = old_xflag;
+               change_xtrace(old_xflag, false);
                tp->flag = (tp->flag & ~FINUSE) | old_inuse;
                tp->flag = (tp->flag & ~FINUSE) | old_inuse;
+
                /*
                 * Were we deleted while executing? If so, free the
                 * execution tree. TODO: Unfortunately, the table entry
                /*
                 * Were we deleted while executing? If so, free the
                 * execution tree. TODO: Unfortunately, the table entry
@@ -1033,25 +1046,23 @@ const char *
 builtin(const char *name, int (*func) (const char **))
 {
        struct tbl *tp;
 builtin(const char *name, int (*func) (const char **))
 {
        struct tbl *tp;
-       uint32_t flag;
+       uint32_t flag = DEFINED;
 
        /* see if any flags should be set for this builtin */
 
        /* see if any flags should be set for this builtin */
-       for (flag = 0; ; name++) {
+       while (1) {
                if (*name == '=')
                        /* command does variable assignment */
                        flag |= KEEPASN;
                else if (*name == '*')
                        /* POSIX special builtin */
                        flag |= SPEC_BI;
                if (*name == '=')
                        /* command does variable assignment */
                        flag |= KEEPASN;
                else if (*name == '*')
                        /* POSIX special builtin */
                        flag |= SPEC_BI;
-               else if (*name == '+')
-                       /* POSIX regular builtin */
-                       flag |= REG_BI;
                else
                        break;
                else
                        break;
+               name++;
        }
 
        tp = ktenter(&builtins, name, hash(name));
        }
 
        tp = ktenter(&builtins, name, hash(name));
-       tp->flag = DEFINED | flag;
+       tp->flag = flag;
        tp->type = CSHELL;
        tp->val.f = func;
 
        tp->type = CSHELL;
        tp->val.f = func;
 
@@ -1083,7 +1094,7 @@ findcom(const char *name, int flags)
        tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL;
        /*
         * POSIX says special builtins first, then functions, then
        tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL;
        /*
         * POSIX says special builtins first, then functions, then
-        * POSIX regular builtins, then search path...
+        * regular builtins, then search path...
         */
        if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
                tp = tbi;
         */
        if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
                tp = tbi;
@@ -1098,9 +1109,7 @@ findcom(const char *name, int flags)
                                    &tp->u2.errnov);
                }
        }
                                    &tp->u2.errnov);
                }
        }
-       if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
-               tp = tbi;
-       if (!tp && (flags & FC_UNREGBI) && tbi)
+       if (!tp && (flags & FC_NORMBI) && tbi)
                tp = tbi;
        if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
                tp = ktsearch(&taliases, name, h);
                tp = tbi;
        if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
                tp = ktsearch(&taliases, name, h);
@@ -1298,10 +1307,11 @@ iosetup(struct ioword *iop, struct tbl *tp)
        iotmp.name = (iotype == IOHERE) ? NULL : cp;
        iotmp.flag |= IONAMEXP;
 
        iotmp.name = (iotype == IOHERE) ? NULL : cp;
        iotmp.flag |= IONAMEXP;
 
-       if (Flag(FXTRACE))
-               shellf("%s%s\n",
-                   substitute(str_val(global("PS4")), 0),
-                   snptreef(NULL, 32, "%R", &iotmp));
+       if (Flag(FXTRACE)) {
+               change_xtrace(2, false);
+               fptreef(shl_xtrace, 0, "%R", &iotmp);
+               change_xtrace(1, false);
+       }
 
        switch (iotype) {
        case IOREAD:
 
        switch (iotype) {
        case IOREAD:
@@ -1345,8 +1355,11 @@ iosetup(struct ioword *iop, struct tbl *tp)
                } else if ((u = check_fd(cp,
                    X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
                    &emsg)) < 0) {
                } else if ((u = check_fd(cp,
                    X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
                    &emsg)) < 0) {
+                       char *sp;
+
                        warningf(true, "%s: %s",
                        warningf(true, "%s: %s",
-                           snptreef(NULL, 32, "%R", &iotmp), emsg);
+                           (sp = snptreef(NULL, 32, "%R", &iotmp)), emsg);
+                       afree(sp, ATEMP);
                        return (-1);
                }
                if (u == iop->unit)
                        return (-1);
                }
                if (u == iop->unit)
@@ -1395,12 +1408,14 @@ iosetup(struct ioword *iop, struct tbl *tp)
        else if (u != iop->unit) {
                if (ksh_dup2(u, iop->unit, true) < 0) {
                        int eno;
        else if (u != iop->unit) {
                if (ksh_dup2(u, iop->unit, true) < 0) {
                        int eno;
+                       char *sp;
 
                        eno = errno;
                        warningf(true, "%s %s %s",
                            "can't finish (dup) redirection",
 
                        eno = errno;
                        warningf(true, "%s %s %s",
                            "can't finish (dup) redirection",
-                           snptreef(NULL, 32, "%R", &iotmp),
+                           (sp = snptreef(NULL, 32, "%R", &iotmp)),
                            cstrerror(eno));
                            cstrerror(eno));
+                       afree(sp, ATEMP);
                        if (iotype != IODUP)
                                close(u);
                        return (-1);
                        if (iotype != IODUP)
                                close(u);
                        return (-1);
@@ -1548,10 +1563,8 @@ do_selectargs(const char **ap, bool print_menu)
                if (call_builtin(findcom("read", FC_BI), read_args, Tselect))
                        return (NULL);
                s = str_val(global("REPLY"));
                if (call_builtin(findcom("read", FC_BI), read_args, Tselect))
                        return (NULL);
                s = str_val(global("REPLY"));
-               if (*s) {
-                       getn(s, &i);
+               if (*s && getn(s, &i))
                        return ((i >= 1 && i <= argct) ? ap[i - 1] : null);
                        return ((i >= 1 && i <= argct) ? ap[i - 1] : null);
-               }
                print_menu = true;
        }
 }
                print_menu = true;
        }
 }
index 321c31e..e91c0da 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: expr.c,v 1.21 2009/06/01 19:00:57 deraadt Exp $       */
+/*     $OpenBSD: expr.c,v 1.22 2013/03/28 08:39:28 nicm Exp $  */
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 
 #include "sh.h"
 
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.61 2013/02/15 18:36:48 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.72 2013/07/21 18:38:56 tg Exp $");
 
 
-#if !HAVE_SILENT_IDIVWRAPV
-#if !defined(MKSH_LEGACY_MODE) || HAVE_LONG_32BIT
-#define IDIVWRAPV_VL   (mksh_uari_t)0x80000000UL
-#define IDIVWRAPV_VR   (mksh_uari_t)0xFFFFFFFFUL
-#elif HAVE_LONG_64BIT
-#define IDIVWRAPV_VL   (mksh_uari_t)0x8000000000000000UL
-#define IDIVWRAPV_VR   (mksh_uari_t)0xFFFFFFFFFFFFFFFFUL
-#else
-# warning "cannot guarantee integer division wraparound"
-#undef HAVE_SILENT_IDIVWRAPV
-#define HAVE_SILENT_IDIVWRAPV 1
-#endif
-#endif
-
-/* The order of these enums is constrained by the order of opinfo[] */
+/* the order of these enums is constrained by the order of opinfo[] */
 enum token {
        /* some (long) unary operators */
        O_PLUSPLUS = 0, O_MINUSMINUS,
 enum token {
        /* some (long) unary operators */
        O_PLUSPLUS = 0, O_MINUSMINUS,
@@ -47,7 +33,14 @@ enum token {
        O_EQ, O_NE,
        /* assignments are assumed to be in range O_ASN .. O_BORASN */
        O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
        O_EQ, O_NE,
        /* assignments are assumed to be in range O_ASN .. O_BORASN */
        O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
+#ifndef MKSH_LEGACY_MODE
+       O_ROLASN, O_RORASN,
+#endif
        O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
        O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
+       /* binary non-assignment operators */
+#ifndef MKSH_LEGACY_MODE
+       O_ROL, O_ROR,
+#endif
        O_LSHIFT, O_RSHIFT,
        O_LE, O_GE, O_LT, O_GT,
        O_LAND,
        O_LSHIFT, O_RSHIFT,
        O_LE, O_GE, O_LT, O_GT,
        O_LAND,
@@ -67,14 +60,13 @@ enum token {
        /* things that don't appear in the opinfo[] table */
        VAR, LIT, END, BAD
 };
        /* things that don't appear in the opinfo[] table */
        VAR, LIT, END, BAD
 };
-#define IS_BINOP(op) (((int)op) >= (int)O_EQ && ((int)op) <= (int)O_COMMA)
 #define IS_ASSIGNOP(op)        ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
 
 /* precisions; used to be enum prec but we do arithmetics on it */
 #define IS_ASSIGNOP(op)        ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
 
 /* precisions; used to be enum prec but we do arithmetics on it */
-#define P_PRIMARY      0       /* VAR, LIT, (), ~ ! - + */
+#define P_PRIMARY      0       /* VAR, LIT, (), ! ~ ++ -- */
 #define P_MULT         1       /* * / % */
 #define P_ADD          2       /* + - */
 #define P_MULT         1       /* * / % */
 #define P_ADD          2       /* + - */
-#define P_SHIFT                3       /* << >> */
+#define P_SHIFT                3       /* <<< >>> << >> */
 #define P_RELATION     4       /* < <= > >= */
 #define P_EQUALITY     5       /* == != */
 #define P_BAND         6       /* & */
 #define P_RELATION     4       /* < <= > >= */
 #define P_EQUALITY     5       /* == != */
 #define P_BAND         6       /* & */
@@ -83,60 +75,72 @@ enum token {
 #define P_LAND         9       /* && */
 #define P_LOR          10      /* || */
 #define P_TERN         11      /* ?: */
 #define P_LAND         9       /* && */
 #define P_LOR          10      /* || */
 #define P_TERN         11      /* ?: */
-#define P_ASSIGN       12      /* = *= /= %= += -= <<= >>= &= ^= |= */
+       /* = += -= *= /= %= <<<= >>>= <<= >>= &= ^= |= */
+#define P_ASSIGN       12
 #define P_COMMA                13      /* , */
 #define MAX_PREC       P_COMMA
 
 struct opinfo {
 #define P_COMMA                13      /* , */
 #define MAX_PREC       P_COMMA
 
 struct opinfo {
-       char            name[4];
-       int             len;    /* name length */
-       int             prec;   /* precedence: lower is higher */
+       char name[5];
+       /* name length */
+       uint8_t len;
+       /* precedence: lower is higher */
+       uint8_t prec;
 };
 
 };
 
-/* Tokens in this table must be ordered so the longest are first
+/*
+ * Tokens in this table must be ordered so the longest are first
  * (eg, += before +). If you change something, change the order
  * of enum token too.
  */
 static const struct opinfo opinfo[] = {
  * (eg, += before +). If you change something, change the order
  * of enum token too.
  */
 static const struct opinfo opinfo[] = {
-       { "++",  2, P_PRIMARY },        /* before + */
-       { "--",  2, P_PRIMARY },        /* before - */
-       { "==",  2, P_EQUALITY },       /* before = */
-       { "!=",  2, P_EQUALITY },       /* before ! */
-       { "=",   1, P_ASSIGN },         /* keep assigns in a block */
-       { "*=",  2, P_ASSIGN },
-       { "/=",  2, P_ASSIGN },
-       { "%=",  2, P_ASSIGN },
-       { "+=",  2, P_ASSIGN },
-       { "-=",  2, P_ASSIGN },
-       { "<<=", 3, P_ASSIGN },
-       { ">>=", 3, P_ASSIGN },
-       { "&=",  2, P_ASSIGN },
-       { "^=",  2, P_ASSIGN },
-       { "|=",  2, P_ASSIGN },
-       { "<<",  2, P_SHIFT },
-       { ">>",  2, P_SHIFT },
-       { "<=",  2, P_RELATION },
-       { ">=",  2, P_RELATION },
-       { "<",   1, P_RELATION },
-       { ">",   1, P_RELATION },
-       { "&&",  2, P_LAND },
-       { "||",  2, P_LOR },
-       { "*",   1, P_MULT },
-       { "/",   1, P_MULT },
-       { "%",   1, P_MULT },
-       { "+",   1, P_ADD },
-       { "-",   1, P_ADD },
-       { "&",   1, P_BAND },
-       { "^",   1, P_BXOR },
-       { "|",   1, P_BOR },
-       { "?",   1, P_TERN },
-       { ",",   1, P_COMMA },
-       { "~",   1, P_PRIMARY },
-       { "!",   1, P_PRIMARY },
-       { "(",   1, P_PRIMARY },
-       { ")",   1, P_PRIMARY },
-       { ":",   1, P_PRIMARY },
-       { "",    0, P_PRIMARY }
+       { "++",   2, P_PRIMARY },       /* before + */
+       { "--",   2, P_PRIMARY },       /* before - */
+       { "==",   2, P_EQUALITY },      /* before = */
+       { "!=",   2, P_EQUALITY },      /* before ! */
+       { "=",    1, P_ASSIGN },        /* keep assigns in a block */
+       { "*=",   2, P_ASSIGN },
+       { "/=",   2, P_ASSIGN },
+       { "%=",   2, P_ASSIGN },
+       { "+=",   2, P_ASSIGN },
+       { "-=",   2, P_ASSIGN },
+#ifndef MKSH_LEGACY_MODE
+       { "<<<=", 4, P_ASSIGN },        /* before <<< */
+       { ">>>=", 4, P_ASSIGN },        /* before >>> */
+#endif
+       { "<<=",  3, P_ASSIGN },
+       { ">>=",  3, P_ASSIGN },
+       { "&=",   2, P_ASSIGN },
+       { "^=",   2, P_ASSIGN },
+       { "|=",   2, P_ASSIGN },
+#ifndef MKSH_LEGACY_MODE
+       { "<<<",  3, P_SHIFT },         /* before << */
+       { ">>>",  3, P_SHIFT },         /* before >> */
+#endif
+       { "<<",   2, P_SHIFT },
+       { ">>",   2, P_SHIFT },
+       { "<=",   2, P_RELATION },
+       { ">=",   2, P_RELATION },
+       { "<",    1, P_RELATION },
+       { ">",    1, P_RELATION },
+       { "&&",   2, P_LAND },
+       { "||",   2, P_LOR },
+       { "*",    1, P_MULT },
+       { "/",    1, P_MULT },
+       { "%",    1, P_MULT },
+       { "+",    1, P_ADD },
+       { "-",    1, P_ADD },
+       { "&",    1, P_BAND },
+       { "^",    1, P_BXOR },
+       { "|",    1, P_BOR },
+       { "?",    1, P_TERN },
+       { ",",    1, P_COMMA },
+       { "~",    1, P_PRIMARY },
+       { "!",    1, P_PRIMARY },
+       { "(",    1, P_PRIMARY },
+       { ")",    1, P_PRIMARY },
+       { ":",    1, P_PRIMARY },
+       { "",     0, P_PRIMARY }
 };
 
 typedef struct expr_state {
 };
 
 typedef struct expr_state {
@@ -151,18 +155,13 @@ typedef struct expr_state {
        /* token from token() */
        enum token tok;
        /* don't do assignments (for ?:, &&, ||) */
        /* token from token() */
        enum token tok;
        /* don't do assignments (for ?:, &&, ||) */
-       short noassign;
+       uint8_t noassign;
        /* evaluating an $(()) expression? */
        bool arith;
        /* unsigned arithmetic calculation */
        bool natural;
 } Expr_state;
 
        /* evaluating an $(()) expression? */
        bool arith;
        /* unsigned arithmetic calculation */
        bool natural;
 } Expr_state;
 
-#define bivui(x, op, y)        (es->natural ?                  \
-       (mksh_uari_t)((x)->val.u op (y)->val.u) :       \
-       (mksh_uari_t)((x)->val.i op (y)->val.i)         \
-)
-
 enum error_type {
        ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
        ET_LVALUE, ET_RDONLY, ET_STR
 enum error_type {
        ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
        ET_LVALUE, ET_RDONLY, ET_STR
@@ -170,7 +169,7 @@ enum error_type {
 
 static void evalerr(Expr_state *, enum error_type, const char *)
     MKSH_A_NORETURN;
 
 static void evalerr(Expr_state *, enum error_type, const char *)
     MKSH_A_NORETURN;
-static struct tbl *evalexpr(Expr_state *, int);
+static struct tbl *evalexpr(Expr_state *, unsigned int);
 static void exprtoken(Expr_state *);
 static struct tbl *do_ppmm(Expr_state *, enum token, struct tbl *, bool);
 static void assign_check(Expr_state *, enum token, struct tbl *);
 static void exprtoken(Expr_state *);
 static struct tbl *do_ppmm(Expr_state *, enum token, struct tbl *, bool);
 static void assign_check(Expr_state *, enum token, struct tbl *);
@@ -185,7 +184,7 @@ evaluate(const char *expr, mksh_ari_t *rval, int error_ok, bool arith)
        struct tbl v;
        int ret;
 
        struct tbl v;
        int ret;
 
-       v.flag = DEFINED|INTEGER;
+       v.flag = DEFINED | INTEGER;
        v.type = 0;
        ret = v_evaluate(&v, expr, error_ok, arith);
        *rval = v.val.i;
        v.type = 0;
        ret = v_evaluate(&v, expr, error_ok, arith);
        *rval = v.val.i;
@@ -307,52 +306,103 @@ evalerr(Expr_state *es, enum error_type type, const char *str)
        unwind(LAEXPR);
 }
 
        unwind(LAEXPR);
 }
 
+/* do a ++ or -- operation */
 static struct tbl *
 static struct tbl *
-evalexpr(Expr_state *es, int prec)
+do_ppmm(Expr_state *es, enum token op, struct tbl *vasn, bool is_prefix)
+{
+       struct tbl *vl;
+       mksh_uari_t oval;
+
+       assign_check(es, op, vasn);
+
+       vl = intvar(es, vasn);
+       oval = vl->val.u;
+       if (op == O_PLUSPLUS)
+               ++vl->val.u;
+       else
+               --vl->val.u;
+       if (!es->noassign) {
+               if (vasn->flag & INTEGER)
+                       setint_v(vasn, vl, es->arith);
+               else
+                       setint(vasn, vl->val.i);
+       }
+       if (!is_prefix)
+               /* undo the increment/decrement */
+               vl->val.u = oval;
+
+       return (vl);
+}
+
+static struct tbl *
+evalexpr(Expr_state *es, unsigned int prec)
 {
        struct tbl *vl, *vr = NULL, *vasn;
        enum token op;
 {
        struct tbl *vl, *vr = NULL, *vasn;
        enum token op;
-       mksh_uari_t res = 0;
+       mksh_uari_t res = 0, t1, t2, t3;
 
        if (prec == P_PRIMARY) {
 
        if (prec == P_PRIMARY) {
-               op = es->tok;
-               if (op == O_BNOT || op == O_LNOT || op == O_MINUS ||
-                   op == O_PLUS) {
+               switch ((int)(op = es->tok)) {
+               case O_BNOT:
+               case O_LNOT:
+               case O_MINUS:
+               case O_PLUS:
                        exprtoken(es);
                        vl = intvar(es, evalexpr(es, P_PRIMARY));
                        exprtoken(es);
                        vl = intvar(es, evalexpr(es, P_PRIMARY));
-                       if (op == O_BNOT)
-                               vl->val.i = ~vl->val.i;
-                       else if (op == O_LNOT)
-                               vl->val.i = !vl->val.i;
-                       else if (op == O_MINUS)
-                               vl->val.i = -vl->val.i;
-                       /* op == O_PLUS is a no-op */
-               } else if (op == OPEN_PAREN) {
+                       switch ((int)op) {
+                       case O_BNOT:
+                               vl->val.u = ~vl->val.u;
+                               break;
+                       case O_LNOT:
+                               vl->val.u = !vl->val.u;
+                               break;
+                       case O_MINUS:
+                               vl->val.u = -vl->val.u;
+                               break;
+                       case O_PLUS:
+                               /* nop */
+                               break;
+                       }
+                       break;
+
+               case OPEN_PAREN:
                        exprtoken(es);
                        vl = evalexpr(es, MAX_PREC);
                        if (es->tok != CLOSE_PAREN)
                                evalerr(es, ET_STR, "missing )");
                        exprtoken(es);
                        exprtoken(es);
                        vl = evalexpr(es, MAX_PREC);
                        if (es->tok != CLOSE_PAREN)
                                evalerr(es, ET_STR, "missing )");
                        exprtoken(es);
-               } else if (op == O_PLUSPLUS || op == O_MINUSMINUS) {
+                       break;
+
+               case O_PLUSPLUS:
+               case O_MINUSMINUS:
                        exprtoken(es);
                        vl = do_ppmm(es, op, es->val, true);
                        exprtoken(es);
                        exprtoken(es);
                        vl = do_ppmm(es, op, es->val, true);
                        exprtoken(es);
-               } else if (op == VAR || op == LIT) {
+                       break;
+
+               case VAR:
+               case LIT:
                        vl = es->val;
                        exprtoken(es);
                        vl = es->val;
                        exprtoken(es);
-               } else {
+                       break;
+
+               default:
                        evalerr(es, ET_UNEXPECTED, NULL);
                        /* NOTREACHED */
                }
                        evalerr(es, ET_UNEXPECTED, NULL);
                        /* NOTREACHED */
                }
+
                if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
                        vl = do_ppmm(es, es->tok, vl, false);
                        exprtoken(es);
                }
                if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
                        vl = do_ppmm(es, es->tok, vl, false);
                        exprtoken(es);
                }
+
                return (vl);
                return (vl);
+               /* prec == P_PRIMARY */
        }
        }
+
        vl = evalexpr(es, prec - 1);
        vl = evalexpr(es, prec - 1);
-       for (op = es->tok; IS_BINOP(op) && opinfo[(int)op].prec == prec;
-           op = es->tok) {
+       while ((int)(op = es->tok) >= (int)O_EQ && (int)op <= (int)O_COMMA &&
+           opinfo[(int)op].prec == prec) {
                exprtoken(es);
                vasn = vl;
                if (op != O_ASN)
                exprtoken(es);
                vasn = vl;
                if (op != O_ASN)
@@ -362,152 +412,204 @@ evalexpr(Expr_state *es, int prec)
                        if (!es->noassign)
                                assign_check(es, op, vasn);
                        vr = intvar(es, evalexpr(es, P_ASSIGN));
                        if (!es->noassign)
                                assign_check(es, op, vasn);
                        vr = intvar(es, evalexpr(es, P_ASSIGN));
-               } else if (op != O_TERN && op != O_LAND && op != O_LOR)
+               } else if (op == O_TERN) {
+                       bool ev = vl->val.u != 0;
+
+                       if (!ev)
+                               es->noassign++;
+                       vl = evalexpr(es, MAX_PREC);
+                       if (!ev)
+                               es->noassign--;
+                       if (es->tok != CTERN)
+                               evalerr(es, ET_STR, "missing :");
+                       exprtoken(es);
+                       if (ev)
+                               es->noassign++;
+                       vr = evalexpr(es, P_TERN);
+                       if (ev)
+                               es->noassign--;
+                       vl = ev ? vl : vr;
+                       continue;
+               } else if (op != O_LAND && op != O_LOR)
                        vr = intvar(es, evalexpr(es, prec - 1));
                        vr = intvar(es, evalexpr(es, prec - 1));
-               if ((op == O_DIV || op == O_MOD || op == O_DIVASN ||
-                   op == O_MODASN) && vr->val.i == 0) {
-                       if (es->noassign)
-                               vr->val.i = 1;
-                       else
-                               evalerr(es, ET_STR, "zero divisor");
+
+               /* common ops setup */
+               switch ((int)op) {
+               case O_DIV:
+               case O_DIVASN:
+               case O_MOD:
+               case O_MODASN:
+                       if (vr->val.u == 0) {
+                               if (!es->noassign)
+                                       evalerr(es, ET_STR, "zero divisor");
+                               vr->val.u = 1;
+                       }
+                       /* calculate the absolute values */
+                       t1 = vl->val.i < 0 ? -vl->val.u : vl->val.u;
+                       t2 = vr->val.i < 0 ? -vr->val.u : vr->val.u;
+                       break;
+#ifndef MKSH_LEGACY_MODE
+               case O_LSHIFT:
+               case O_LSHIFTASN:
+               case O_RSHIFT:
+               case O_RSHIFTASN:
+               case O_ROL:
+               case O_ROLASN:
+               case O_ROR:
+               case O_RORASN:
+                       t1 = vl->val.u;
+                       t2 = vr->val.u & 31;
+                       break;
+#endif
+               case O_LAND:
+               case O_LOR:
+                       t1 = vl->val.u;
+                       t2 = 0; /* gcc */
+                       break;
+               default:
+                       t1 = vl->val.u;
+                       t2 = vr->val.u;
+                       break;
                }
                }
+
+#define cmpop(op)      (es->natural ?                  \
+       (mksh_uari_t)(vl->val.u op vr->val.u) :         \
+       (mksh_uari_t)(vl->val.i op vr->val.i)           \
+)
+
+               /* op calculation */
                switch ((int)op) {
                case O_TIMES:
                case O_TIMESASN:
                switch ((int)op) {
                case O_TIMES:
                case O_TIMESASN:
-                       res = bivui(vl, *, vr);
+                       res = t1 * t2;
                        break;
                        break;
+               case O_MOD:
+               case O_MODASN:
+                       if (es->natural) {
+                               res = vl->val.u % vr->val.u;
+                               break;
+                       }
+                       goto signed_division;
                case O_DIV:
                case O_DIVASN:
                case O_DIV:
                case O_DIVASN:
-#if !HAVE_SILENT_IDIVWRAPV
+                       if (es->natural) {
+                               res = vl->val.u / vr->val.u;
+                               break;
+                       }
+ signed_division:
                        /*
                        /*
-                        * we are doing the comparisons here for the
-                        * signed arithmetics (!es->natural) case,
-                        * but the exact value checks and the bypass
-                        * case assignments are done unsignedly as
-                        * several compilers bitch around otherwise
+                        * a / b = abs(a) / abs(b) * sgn((u)a^(u)b)
                         */
                         */
-                       if (!es->natural &&
-                           vl->val.u == IDIVWRAPV_VL &&
-                           vr->val.u == IDIVWRAPV_VR) {
-                               /* -2147483648 / -1 = 2147483648 */
-                               /* this ^ is really (1 << 31) though */
-                               res = IDIVWRAPV_VL;
-                       } else
-#endif
-                               res = bivui(vl, /, vr);
-                       break;
-               case O_MOD:
-               case O_MODASN:
-#if !HAVE_SILENT_IDIVWRAPV
-                       /* see O_DIV / O_DIVASN for the reason behind this */
-                       if (!es->natural &&
-                           vl->val.u == IDIVWRAPV_VL &&
-                           vr->val.u == IDIVWRAPV_VR) {
-                               /* -2147483648 % -1 = 0 */
-                               res = 0;
-                       } else
+                       t3 = t1 / t2;
+#ifndef MKSH_LEGACY_MODE
+                       res = ((vl->val.u ^ vr->val.u) & 0x80000000) ? -t3 : t3;
+#else
+                       res = ((t1 == vl->val.u ? 0 : 1) ^
+                           (t2 == vr->val.u ? 0 : 1)) ? -t3 : t3;
 #endif
 #endif
-                               res = bivui(vl, %, vr);
+                       if (op == O_MOD || op == O_MODASN) {
+                               /*
+                                * primitive modulo, to get the sign of
+                                * the result correct:
+                                * (a % b) = a - ((a / b) * b)
+                                * the subtraction and multiplication
+                                * are, amazingly enough, sign ignorant
+                                */
+                               res = vl->val.u - (res * vr->val.u);
+                       }
                        break;
                case O_PLUS:
                case O_PLUSASN:
                        break;
                case O_PLUS:
                case O_PLUSASN:
-                       res = bivui(vl, +, vr);
+                       res = t1 + t2;
                        break;
                case O_MINUS:
                case O_MINUSASN:
                        break;
                case O_MINUS:
                case O_MINUSASN:
-                       res = bivui(vl, -, vr);
+                       res = t1 - t2;
+                       break;
+#ifndef MKSH_LEGACY_MODE
+               case O_ROL:
+               case O_ROLASN:
+                       res = (t1 << t2) | (t1 >> (32 - t2));
                        break;
                        break;
+               case O_ROR:
+               case O_RORASN:
+                       res = (t1 >> t2) | (t1 << (32 - t2));
+                       break;
+#endif
                case O_LSHIFT:
                case O_LSHIFTASN:
                case O_LSHIFT:
                case O_LSHIFTASN:
-                       res = bivui(vl, <<, vr);
+                       res = t1 << t2;
                        break;
                case O_RSHIFT:
                case O_RSHIFTASN:
                        break;
                case O_RSHIFT:
                case O_RSHIFTASN:
-                       res = bivui(vl, >>, vr);
+                       res = es->natural || vl->val.i >= 0 ?
+                           t1 >> t2 :
+                           ~(~t1 >> t2);
                        break;
                case O_LT:
                        break;
                case O_LT:
-                       res = bivui(vl, <, vr);
+                       res = cmpop(<);
                        break;
                case O_LE:
                        break;
                case O_LE:
-                       res = bivui(vl, <=, vr);
+                       res = cmpop(<=);
                        break;
                case O_GT:
                        break;
                case O_GT:
-                       res = bivui(vl, >, vr);
+                       res = cmpop(>);
                        break;
                case O_GE:
                        break;
                case O_GE:
-                       res = bivui(vl, >=, vr);
+                       res = cmpop(>=);
                        break;
                case O_EQ:
                        break;
                case O_EQ:
-                       res = bivui(vl, ==, vr);
+                       res = t1 == t2;
                        break;
                case O_NE:
                        break;
                case O_NE:
-                       res = bivui(vl, !=, vr);
+                       res = t1 != t2;
                        break;
                case O_BAND:
                case O_BANDASN:
                        break;
                case O_BAND:
                case O_BANDASN:
-                       res = bivui(vl, &, vr);
+                       res = t1 & t2;
                        break;
                case O_BXOR:
                case O_BXORASN:
                        break;
                case O_BXOR:
                case O_BXORASN:
-                       res = bivui(vl, ^, vr);
+                       res = t1 ^ t2;
                        break;
                case O_BOR:
                case O_BORASN:
                        break;
                case O_BOR:
                case O_BORASN:
-                       res = bivui(vl, |, vr);
+                       res = t1 | t2;
                        break;
                case O_LAND:
                        break;
                case O_LAND:
-                       if (!vl->val.i)
+                       if (!t1)
                                es->noassign++;
                        vr = intvar(es, evalexpr(es, prec - 1));
                                es->noassign++;
                        vr = intvar(es, evalexpr(es, prec - 1));
-                       res = bivui(vl, &&, vr);
-                       if (!vl->val.i)
+                       res = t1 && vr->val.u;
+                       if (!t1)
                                es->noassign--;
                        break;
                case O_LOR:
                                es->noassign--;
                        break;
                case O_LOR:
-                       if (vl->val.i)
+                       if (t1)
                                es->noassign++;
                        vr = intvar(es, evalexpr(es, prec - 1));
                                es->noassign++;
                        vr = intvar(es, evalexpr(es, prec - 1));
-                       res = bivui(vl, ||, vr);
-                       if (vl->val.i)
+                       res = t1 || vr->val.u;
+                       if (t1)
                                es->noassign--;
                        break;
                                es->noassign--;
                        break;
-               case O_TERN:
-                       {
-                               bool ev = vl->val.i != 0;
-
-                               if (!ev)
-                                       es->noassign++;
-                               vl = evalexpr(es, MAX_PREC);
-                               if (!ev)
-                                       es->noassign--;
-                               if (es->tok != CTERN)
-                                       evalerr(es, ET_STR, "missing :");
-                               exprtoken(es);
-                               if (ev)
-                                       es->noassign++;
-                               vr = evalexpr(es, P_TERN);
-                               if (ev)
-                                       es->noassign--;
-                               vl = ev ? vl : vr;
-                       }
-                       break;
                case O_ASN:
                case O_ASN:
-                       res = vr->val.u;
-                       break;
                case O_COMMA:
                case O_COMMA:
-                       res = vr->val.u;
+                       res = t2;
                        break;
                }
                        break;
                }
+
+#undef cmpop
+
                if (IS_ASSIGNOP(op)) {
                        vr->val.u = res;
                        if (!es->noassign) {
                                if (vasn->flag & INTEGER)
                                        setint_v(vasn, vr, es->arith);
                                else
                if (IS_ASSIGNOP(op)) {
                        vr->val.u = res;
                        if (!es->noassign) {
                                if (vasn->flag & INTEGER)
                                        setint_v(vasn, vr, es->arith);
                                else
-                                       setint(vasn, (mksh_ari_t)res);
+                                       setint(vasn, vr->val.i);
                        }
                        vl = vr;
                        }
                        vl = vr;
-               } else if (op != O_TERN)
+               } else
                        vl->val.u = res;
        }
        return (vl);
                        vl->val.u = res;
        }
        return (vl);
@@ -520,13 +622,14 @@ exprtoken(Expr_state *es)
        int c;
        char *tvar;
 
        int c;
        char *tvar;
 
-       /* skip white space */
+       /* skip whitespace */
  skip_spaces:
        while ((c = *cp), ksh_isspace(c))
                ++cp;
        if (es->tokp == es->expression && c == '#') {
                /* expression begins with # */
  skip_spaces:
        while ((c = *cp), ksh_isspace(c))
                ++cp;
        if (es->tokp == es->expression && c == '#') {
                /* expression begins with # */
-               es->natural = true;     /* switch to unsigned */
+               /* switch to unsigned */
+               es->natural = true;
                ++cp;
                goto skip_spaces;
        }
                ++cp;
                goto skip_spaces;
        }
@@ -544,12 +647,6 @@ exprtoken(Expr_state *es)
                        if (len == 0)
                                evalerr(es, ET_STR, "missing ]");
                        cp += len;
                        if (len == 0)
                                evalerr(es, ET_STR, "missing ]");
                        cp += len;
-               } else if (c == '(' /*)*/ ) {
-                       /* todo: add math functions (all take single argument):
-                        * abs acos asin atan cos cosh exp int log sin sinh sqrt
-                        * tan tanh
-                        */
-                       ;
                }
                if (es->noassign) {
                        es->val = tempvar();
                }
                if (es->noassign) {
                        es->val = tempvar();
@@ -610,39 +707,6 @@ exprtoken(Expr_state *es)
        es->tokp = cp;
 }
 
        es->tokp = cp;
 }
 
-/* Do a ++ or -- operation */
-static struct tbl *
-do_ppmm(Expr_state *es, enum token op, struct tbl *vasn, bool is_prefix)
-{
-       struct tbl *vl;
-       mksh_ari_t oval;
-
-       assign_check(es, op, vasn);
-
-       vl = intvar(es, vasn);
-       oval = vl->val.i;
-       if (op == O_PLUSPLUS) {
-               if (es->natural)
-                       ++vl->val.u;
-               else
-                       ++vl->val.i;
-       } else {
-               if (es->natural)
-                       --vl->val.u;
-               else
-                       --vl->val.i;
-       }
-       if (vasn->flag & INTEGER)
-               setint_v(vasn, vl, es->arith);
-       else
-               setint(vasn, vl->val.i);
-       if (!is_prefix)
-               /* undo the increment/decrement */
-               vl->val.i = oval;
-
-       return (vl);
-}
-
 static void
 assign_check(Expr_state *es, enum token op, struct tbl *vasn)
 {
 static void
 assign_check(Expr_state *es, enum token op, struct tbl *vasn)
 {
@@ -833,129 +897,6 @@ utf_wctomb(char *dst, unsigned int wc)
        return ((char *)d - dst);
 }
 
        return ((char *)d - dst);
 }
 
-
-#ifndef MKSH_mirbsd_wcwidth
-/* --- begin of wcwidth.c excerpt --- */
-/*-
- * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
- *
- * Permission to use, copy, modify, and distribute this software
- * for any purpose and without fee is hereby granted. The author
- * disclaims all warranties with regard to this software.
- */
-
-__RCSID("$miros: src/lib/libc/i18n/wcwidth.c,v 1.11 2012/09/01 23:46:43 tg Exp $");
-
-int
-utf_wcwidth(unsigned int c)
-{
-       static const struct cbset {
-               unsigned short first;
-               unsigned short last;
-       } comb[] = {
-               /* Unicode 6.1.0 BMP */
-               { 0x0300, 0x036F }, { 0x0483, 0x0489 }, { 0x0591, 0x05BD },
-               { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 },
-               { 0x05C7, 0x05C7 }, { 0x0600, 0x0604 }, { 0x0610, 0x061A },
-               { 0x064B, 0x065F }, { 0x0670, 0x0670 }, { 0x06D6, 0x06DD },
-               { 0x06DF, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
-               { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
-               { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0816, 0x0819 },
-               { 0x081B, 0x0823 }, { 0x0825, 0x0827 }, { 0x0829, 0x082D },
-               { 0x0859, 0x085B }, { 0x08E4, 0x08FE }, { 0x0900, 0x0902 },
-               { 0x093A, 0x093A }, { 0x093C, 0x093C }, { 0x0941, 0x0948 },
-               { 0x094D, 0x094D }, { 0x0951, 0x0957 }, { 0x0962, 0x0963 },
-               { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 },
-               { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 },
-               { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 },
-               { 0x0A4B, 0x0A4D }, { 0x0A51, 0x0A51 }, { 0x0A70, 0x0A71 },
-               { 0x0A75, 0x0A75 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
-               { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
-               { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
-               { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B44 }, { 0x0B4D, 0x0B4D },
-               { 0x0B56, 0x0B56 }, { 0x0B62, 0x0B63 }, { 0x0B82, 0x0B82 },
-               { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 },
-               { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 },
-               { 0x0C62, 0x0C63 }, { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF },
-               { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, { 0x0CE2, 0x0CE3 },
-               { 0x0D41, 0x0D44 }, { 0x0D4D, 0x0D4D }, { 0x0D62, 0x0D63 },
-               { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
-               { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
-               { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
-               { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
-               { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
-               { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F8D, 0x0F97 },
-               { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
-               { 0x1032, 0x1037 }, { 0x1039, 0x103A }, { 0x103D, 0x103E },
-               { 0x1058, 0x1059 }, { 0x105E, 0x1060 }, { 0x1071, 0x1074 },
-               { 0x1082, 0x1082 }, { 0x1085, 0x1086 }, { 0x108D, 0x108D },
-               { 0x109D, 0x109D }, { 0x1160, 0x11FF }, { 0x135D, 0x135F },
-               { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
-               { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
-               { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
-               { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
-               { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
-               { 0x1A17, 0x1A18 }, { 0x1A56, 0x1A56 }, { 0x1A58, 0x1A5E },
-               { 0x1A60, 0x1A60 }, { 0x1A62, 0x1A62 }, { 0x1A65, 0x1A6C },
-               { 0x1A73, 0x1A7C }, { 0x1A7F, 0x1A7F }, { 0x1B00, 0x1B03 },
-               { 0x1B34, 0x1B34 }, { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C },
-               { 0x1B42, 0x1B42 }, { 0x1B6B, 0x1B73 }, { 0x1B80, 0x1B81 },
-               { 0x1BA2, 0x1BA5 }, { 0x1BA8, 0x1BA9 }, { 0x1BAB, 0x1BAB },
-               { 0x1BE6, 0x1BE6 }, { 0x1BE8, 0x1BE9 }, { 0x1BED, 0x1BED },
-               { 0x1BEF, 0x1BF1 }, { 0x1C2C, 0x1C33 }, { 0x1C36, 0x1C37 },
-               { 0x1CD0, 0x1CD2 }, { 0x1CD4, 0x1CE0 }, { 0x1CE2, 0x1CE8 },
-               { 0x1CED, 0x1CED }, { 0x1CF4, 0x1CF4 }, { 0x1DC0, 0x1DE6 },
-               { 0x1DFC, 0x1DFF }, { 0x200B, 0x200F }, { 0x202A, 0x202E },
-               { 0x2060, 0x2064 }, { 0x206A, 0x206F }, { 0x20D0, 0x20F0 },
-               { 0x2CEF, 0x2CF1 }, { 0x2D7F, 0x2D7F }, { 0x2DE0, 0x2DFF },
-               { 0x302A, 0x302D }, { 0x3099, 0x309A }, { 0xA66F, 0xA672 },
-               { 0xA674, 0xA67D }, { 0xA69F, 0xA69F }, { 0xA6F0, 0xA6F1 },
-               { 0xA802, 0xA802 }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
-               { 0xA825, 0xA826 }, { 0xA8C4, 0xA8C4 }, { 0xA8E0, 0xA8F1 },
-               { 0xA926, 0xA92D }, { 0xA947, 0xA951 }, { 0xA980, 0xA982 },
-               { 0xA9B3, 0xA9B3 }, { 0xA9B6, 0xA9B9 }, { 0xA9BC, 0xA9BC },
-               { 0xAA29, 0xAA2E }, { 0xAA31, 0xAA32 }, { 0xAA35, 0xAA36 },
-               { 0xAA43, 0xAA43 }, { 0xAA4C, 0xAA4C }, { 0xAAB0, 0xAAB0 },
-               { 0xAAB2, 0xAAB4 }, { 0xAAB7, 0xAAB8 }, { 0xAABE, 0xAABF },
-               { 0xAAC1, 0xAAC1 }, { 0xAAEC, 0xAAED }, { 0xAAF6, 0xAAF6 },
-               { 0xABE5, 0xABE5 }, { 0xABE8, 0xABE8 }, { 0xABED, 0xABED },
-               { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE26 },
-               { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }
-       };
-       size_t min = 0, mid, max = NELEM(comb) - 1;
-
-       /* test for 8-bit control characters */
-       if (c < 32 || (c >= 0x7F && c < 0xA0))
-               return (c ? -1 : 0);
-
-       /* binary search in table of non-spacing characters */
-       if (c >= comb[0].first && c <= comb[max].last)
-               while (max >= min) {
-                       mid = (min + max) / 2;
-                       if (c > comb[mid].last)
-                               min = mid + 1;
-                       else if (c < comb[mid].first)
-                               max = mid - 1;
-                       else
-                               return (0);
-               }
-
-       /* if we arrive here, c is not a combining or C0/C1 control char */
-
-       return ((c >= 0x1100 && (
-           c <= 0x115F || /* Hangul Jamo init. consonants */
-           c == 0x2329 || c == 0x232A ||
-           (c >= 0x2E80 && c <= 0xA4CF && c != 0x303F) || /* CJK ... Yi */
-           (c >= 0xAC00 && c <= 0xD7A3) || /* Hangul Syllables */
-           (c >= 0xF900 && c <= 0xFAFF) || /* CJK Compatibility Ideographs */
-           (c >= 0xFE10 && c <= 0xFE19) || /* Vertical forms */
-           (c >= 0xFE30 && c <= 0xFE6F) || /* CJK Compatibility Forms */
-           (c >= 0xFF00 && c <= 0xFF60) || /* Fullwidth Forms */
-           (c >= 0xFFE0 && c <= 0xFFE6))) ? 2 : 1);
-}
-/* --- end of wcwidth.c excerpt --- */
-#endif
-
 /*
  * Wrapper around access(2) because it says root can execute everything
  * on some operating systems. Does not set errno, no user needs it. Use
 /*
  * Wrapper around access(2) because it says root can execute everything
  * on some operating systems. Does not set errno, no user needs it. Use
@@ -974,3 +915,277 @@ ksh_access(const char *fn, int mode)
 
        return (rv);
 }
 
        return (rv);
 }
+
+#ifndef MKSH_mirbsd_wcwidth
+/* From: X11/xc/programs/xterm/wcwidth.c,v 1.6 2013/05/31 23:27:09 tg Exp $ */
+
+struct mb_ucsrange {
+       unsigned short beg;
+       unsigned short end;
+};
+
+static int mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems,
+    unsigned int val);
+
+/*
+ * Generated by MirOS: contrib/code/Snippets/eawparse,v 1.1 2013/05/31 23:27:16 tg Exp $
+ * from Unicode 6.2.0
+ */
+
+static const struct mb_ucsrange mb_ucs_combining[] = {
+       { 0x0300, 0x036F },
+       { 0x0483, 0x0489 },
+       { 0x0591, 0x05BD },
+       { 0x05BF, 0x05BF },
+       { 0x05C1, 0x05C2 },
+       { 0x05C4, 0x05C5 },
+       { 0x05C7, 0x05C7 },
+       { 0x0600, 0x0604 },
+       { 0x0610, 0x061A },
+       { 0x064B, 0x065F },
+       { 0x0670, 0x0670 },
+       { 0x06D6, 0x06DD },
+       { 0x06DF, 0x06E4 },
+       { 0x06E7, 0x06E8 },
+       { 0x06EA, 0x06ED },
+       { 0x070F, 0x070F },
+       { 0x0711, 0x0711 },
+       { 0x0730, 0x074A },
+       { 0x07A6, 0x07B0 },
+       { 0x07EB, 0x07F3 },
+       { 0x0816, 0x0819 },
+       { 0x081B, 0x0823 },
+       { 0x0825, 0x0827 },
+       { 0x0829, 0x082D },
+       { 0x0859, 0x085B },
+       { 0x08E4, 0x08FE },
+       { 0x0900, 0x0902 },
+       { 0x093A, 0x093A },
+       { 0x093C, 0x093C },
+       { 0x0941, 0x0948 },
+       { 0x094D, 0x094D },
+       { 0x0951, 0x0957 },
+       { 0x0962, 0x0963 },
+       { 0x0981, 0x0981 },
+       { 0x09BC, 0x09BC },
+       { 0x09C1, 0x09C4 },
+       { 0x09CD, 0x09CD },
+       { 0x09E2, 0x09E3 },
+       { 0x0A01, 0x0A02 },
+       { 0x0A3C, 0x0A3C },
+       { 0x0A41, 0x0A42 },
+       { 0x0A47, 0x0A48 },
+       { 0x0A4B, 0x0A4D },
+       { 0x0A51, 0x0A51 },
+       { 0x0A70, 0x0A71 },
+       { 0x0A75, 0x0A75 },
+       { 0x0A81, 0x0A82 },
+       { 0x0ABC, 0x0ABC },
+       { 0x0AC1, 0x0AC5 },
+       { 0x0AC7, 0x0AC8 },
+       { 0x0ACD, 0x0ACD },
+       { 0x0AE2, 0x0AE3 },
+       { 0x0B01, 0x0B01 },
+       { 0x0B3C, 0x0B3C },
+       { 0x0B3F, 0x0B3F },
+       { 0x0B41, 0x0B44 },
+       { 0x0B4D, 0x0B4D },
+       { 0x0B56, 0x0B56 },
+       { 0x0B62, 0x0B63 },
+       { 0x0B82, 0x0B82 },
+       { 0x0BC0, 0x0BC0 },
+       { 0x0BCD, 0x0BCD },
+       { 0x0C3E, 0x0C40 },
+       { 0x0C46, 0x0C48 },
+       { 0x0C4A, 0x0C4D },
+       { 0x0C55, 0x0C56 },
+       { 0x0C62, 0x0C63 },
+       { 0x0CBC, 0x0CBC },
+       { 0x0CBF, 0x0CBF },
+       { 0x0CC6, 0x0CC6 },
+       { 0x0CCC, 0x0CCD },
+       { 0x0CE2, 0x0CE3 },
+       { 0x0D41, 0x0D44 },
+       { 0x0D4D, 0x0D4D },
+       { 0x0D62, 0x0D63 },
+       { 0x0DCA, 0x0DCA },
+       { 0x0DD2, 0x0DD4 },
+       { 0x0DD6, 0x0DD6 },
+       { 0x0E31, 0x0E31 },
+       { 0x0E34, 0x0E3A },
+       { 0x0E47, 0x0E4E },
+       { 0x0EB1, 0x0EB1 },
+       { 0x0EB4, 0x0EB9 },
+       { 0x0EBB, 0x0EBC },
+       { 0x0EC8, 0x0ECD },
+       { 0x0F18, 0x0F19 },
+       { 0x0F35, 0x0F35 },
+       { 0x0F37, 0x0F37 },
+       { 0x0F39, 0x0F39 },
+       { 0x0F71, 0x0F7E },
+       { 0x0F80, 0x0F84 },
+       { 0x0F86, 0x0F87 },
+       { 0x0F8D, 0x0F97 },
+       { 0x0F99, 0x0FBC },
+       { 0x0FC6, 0x0FC6 },
+       { 0x102D, 0x1030 },
+       { 0x1032, 0x1037 },
+       { 0x1039, 0x103A },
+       { 0x103D, 0x103E },
+       { 0x1058, 0x1059 },
+       { 0x105E, 0x1060 },
+       { 0x1071, 0x1074 },
+       { 0x1082, 0x1082 },
+       { 0x1085, 0x1086 },
+       { 0x108D, 0x108D },
+       { 0x109D, 0x109D },
+       { 0x1160, 0x11FF },
+       { 0x135D, 0x135F },
+       { 0x1712, 0x1714 },
+       { 0x1732, 0x1734 },
+       { 0x1752, 0x1753 },
+       { 0x1772, 0x1773 },
+       { 0x17B4, 0x17B5 },
+       { 0x17B7, 0x17BD },
+       { 0x17C6, 0x17C6 },
+       { 0x17C9, 0x17D3 },
+       { 0x17DD, 0x17DD },
+       { 0x180B, 0x180D },
+       { 0x18A9, 0x18A9 },
+       { 0x1920, 0x1922 },
+       { 0x1927, 0x1928 },
+       { 0x1932, 0x1932 },
+       { 0x1939, 0x193B },
+       { 0x1A17, 0x1A18 },
+       { 0x1A56, 0x1A56 },
+       { 0x1A58, 0x1A5E },
+       { 0x1A60, 0x1A60 },
+       { 0x1A62, 0x1A62 },
+       { 0x1A65, 0x1A6C },
+       { 0x1A73, 0x1A7C },
+       { 0x1A7F, 0x1A7F },
+       { 0x1B00, 0x1B03 },
+       { 0x1B34, 0x1B34 },
+       { 0x1B36, 0x1B3A },
+       { 0x1B3C, 0x1B3C },
+       { 0x1B42, 0x1B42 },
+       { 0x1B6B, 0x1B73 },
+       { 0x1B80, 0x1B81 },
+       { 0x1BA2, 0x1BA5 },
+       { 0x1BA8, 0x1BA9 },
+       { 0x1BAB, 0x1BAB },
+       { 0x1BE6, 0x1BE6 },
+       { 0x1BE8, 0x1BE9 },
+       { 0x1BED, 0x1BED },
+       { 0x1BEF, 0x1BF1 },
+       { 0x1C2C, 0x1C33 },
+       { 0x1C36, 0x1C37 },
+       { 0x1CD0, 0x1CD2 },
+       { 0x1CD4, 0x1CE0 },
+       { 0x1CE2, 0x1CE8 },
+       { 0x1CED, 0x1CED },
+       { 0x1CF4, 0x1CF4 },
+       { 0x1DC0, 0x1DE6 },
+       { 0x1DFC, 0x1DFF },
+       { 0x200B, 0x200F },
+       { 0x202A, 0x202E },
+       { 0x2060, 0x2064 },
+       { 0x206A, 0x206F },
+       { 0x20D0, 0x20F0 },
+       { 0x2CEF, 0x2CF1 },
+       { 0x2D7F, 0x2D7F },
+       { 0x2DE0, 0x2DFF },
+       { 0x302A, 0x302D },
+       { 0x3099, 0x309A },
+       { 0xA66F, 0xA672 },
+       { 0xA674, 0xA67D },
+       { 0xA69F, 0xA69F },
+       { 0xA6F0, 0xA6F1 },
+       { 0xA802, 0xA802 },
+       { 0xA806, 0xA806 },
+       { 0xA80B, 0xA80B },
+       { 0xA825, 0xA826 },
+       { 0xA8C4, 0xA8C4 },
+       { 0xA8E0, 0xA8F1 },
+       { 0xA926, 0xA92D },
+       { 0xA947, 0xA951 },
+       { 0xA980, 0xA982 },
+       { 0xA9B3, 0xA9B3 },
+       { 0xA9B6, 0xA9B9 },
+       { 0xA9BC, 0xA9BC },
+       { 0xAA29, 0xAA2E },
+       { 0xAA31, 0xAA32 },
+       { 0xAA35, 0xAA36 },
+       { 0xAA43, 0xAA43 },
+       { 0xAA4C, 0xAA4C },
+       { 0xAAB0, 0xAAB0 },
+       { 0xAAB2, 0xAAB4 },
+       { 0xAAB7, 0xAAB8 },
+       { 0xAABE, 0xAABF },
+       { 0xAAC1, 0xAAC1 },
+       { 0xAAEC, 0xAAED },
+       { 0xAAF6, 0xAAF6 },
+       { 0xABE5, 0xABE5 },
+       { 0xABE8, 0xABE8 },
+       { 0xABED, 0xABED },
+       { 0xFB1E, 0xFB1E },
+       { 0xFE00, 0xFE0F },
+       { 0xFE20, 0xFE26 },
+       { 0xFEFF, 0xFEFF },
+       { 0xFFF9, 0xFFFB }
+};
+
+static const struct mb_ucsrange mb_ucs_fullwidth[] = {
+       { 0x1100, 0x115F },
+       { 0x2329, 0x232A },
+       { 0x2E80, 0x303E },
+       { 0x3040, 0xA4CF },
+       { 0xA960, 0xA97F },
+       { 0xAC00, 0xD7A3 },
+       { 0xF900, 0xFAFF },
+       { 0xFE10, 0xFE19 },
+       { 0xFE30, 0xFE6F },
+       { 0xFF00, 0xFF60 },
+       { 0xFFE0, 0xFFE6 }
+};
+
+/* simple binary search in ranges, with bounds optimisation */
+static int
+mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems, unsigned int val)
+{
+       size_t min = 0, mid, max = elems;
+
+       if (val < arr[min].beg || val > arr[max - 1].end)
+               return (0);
+
+       while (min < max) {
+               mid = (min + max) / 2;
+
+               if (val < arr[mid].beg)
+                       max = mid;
+               else if (val > arr[mid].end)
+                       min = mid + 1;
+               else
+                       return (1);
+       }
+       return (0);
+}
+
+/* Unix column width of a wide character (Unicode code point, really) */
+int
+utf_wcwidth(unsigned int wc)
+{
+       /* except NUL, C0/C1 control characters and DEL yield -1 */
+       if (wc < 0x20 || (wc >= 0x7F && wc < 0xA0))
+               return (wc ? -1 : 0);
+
+       /* combining characters use 0 screen columns */
+       if (mb_ucsbsearch(mb_ucs_combining, NELEM(mb_ucs_combining), wc))
+               return (0);
+
+       /* all others use 1 or 2 screen columns */
+       if (mb_ucsbsearch(mb_ucs_fullwidth, NELEM(mb_ucs_fullwidth), wc))
+               return (2);
+       return (1);
+}
+#endif
index e23ec8b..6698f5e 100644 (file)
@@ -1,5 +1,5 @@
 /*     $OpenBSD: c_ksh.c,v 1.33 2009/02/07 14:03:24 kili Exp $ */
 /*     $OpenBSD: c_ksh.c,v 1.33 2009/02/07 14:03:24 kili Exp $ */
-/*     $OpenBSD: c_sh.c,v 1.41 2010/03/27 09:10:01 jmc Exp $   */
+/*     $OpenBSD: c_sh.c,v 1.43 2013/04/19 17:39:45 deraadt 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_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 $   */
 
@@ -38,7 +38,7 @@
 #endif
 #endif
 
 #endif
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.238 2013/02/18 22:47:32 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.244 2013/06/03 22:28:32 tg Exp $");
 
 #if HAVE_KILLPG
 /*
 
 #if HAVE_KILLPG
 /*
@@ -84,70 +84,69 @@ c_false(const char **wp MKSH_A_UNUSED)
 }
 
 /*
 }
 
 /*
- * A leading = means assignments before command are kept;
- * a leading * means a POSIX special builtin;
- * a leading + means a POSIX regular builtin
- * (* and + should not be combined).
+ * A leading = means assignments before command are kept.
+ * A leading * means a POSIX special builtin.
  */
 const struct builtin mkshbuiltins[] = {
        {"*=.", c_dot},
        {"*=:", c_true},
        {"[", c_test},
  */
 const struct builtin mkshbuiltins[] = {
        {"*=.", c_dot},
        {"*=:", c_true},
        {"[", c_test},
+       /* no =: AT&T manual wrong */
+       {Talias, c_alias},
        {"*=break", c_brkcont},
        {Tgbuiltin, c_builtin},
        {"*=break", c_brkcont},
        {Tgbuiltin, c_builtin},
+       {"cat", c_cat},
+       {"cd", c_cd},
+       /* dash compatibility hack */
+       {"chdir", c_cd},
+       {"command", c_command},
        {"*=continue", c_brkcont},
        {"*=continue", c_brkcont},
+       {"echo", c_print},
        {"*=eval", c_eval},
        {"*=exec", c_exec},
        {"*=exit", c_exitreturn},
        {"*=eval", c_eval},
        {"*=exec", c_exec},
        {"*=exit", c_exitreturn},
-       {"+false", c_false},
-       {"*=return", c_exitreturn},
-       {Tsgset, c_set},
-       {"*=shift", c_shift},
-       {"=times", c_times},
-       {"*=trap", c_trap},
-       {"+=wait", c_wait},
-       {"+read", c_read},
-       {"test", c_test},
-       {"+true", c_true},
-       {"ulimit", c_ulimit},
-       {"+umask", c_umask},
-       {Tsgunset, c_unset},
-       /* no =: AT&T manual wrong */
-       {Tpalias, c_alias},
-       {"+cd", c_cd},
-       /* dash compatibility hack */
-       {"chdir", c_cd},
-       {"+command", c_command},
-       {"echo", c_print},
        {Tsgexport, c_typeset},
        {Tsgexport, c_typeset},
-       {"+fc", c_fc},
-       {"+getopts", c_getopts},
+       {"false", c_false},
+       {"fc", c_fc},
+       {"getopts", c_getopts},
        {"=global", c_typeset},
        {"=global", c_typeset},
-       {"+jobs", c_jobs},
-       {"+kill", c_kill},
+       {"jobs", c_jobs},
+       {"kill", c_kill},
        {"let", c_let},
        {"let", c_let},
+       {"let]", c_let},
        {"print", c_print},
        {"print", c_print},
-#ifdef MKSH_PRINTF_BUILTIN
-       {"printf", c_printf},
-#endif
        {"pwd", c_pwd},
        {"pwd", c_pwd},
+       {"read", c_read},
        {Tsgreadonly, c_typeset},
        {Tsgreadonly, c_typeset},
+       {"realpath", c_realpath},
+       {"rename", c_rename},
+       {"*=return", c_exitreturn},
+       {Tsgset, c_set},
+       {"*=shift", c_shift},
+       {"test", c_test},
+       {"*=times", c_times},
+       {"*=trap", c_trap},
+       {"true", c_true},
        {T_typeset, c_typeset},
        {T_typeset, c_typeset},
-       {Tpunalias, c_unalias},
+       {"ulimit", c_ulimit},
+       {"umask", c_umask},
+       {Tunalias, c_unalias},
+       {Tsgunset, c_unset},
+       {"=wait", c_wait},
        {"whence", c_whence},
 #ifndef MKSH_UNEMPLOYED
        {"whence", c_whence},
 #ifndef MKSH_UNEMPLOYED
-       {"+bg", c_fgbg},
-       {"+fg", c_fgbg},
+       {"bg", c_fgbg},
+       {"fg", c_fgbg},
 #endif
 #ifndef MKSH_NO_CMDLINE_EDITING
        {"bind", c_bind},
 #endif
 #endif
 #ifndef MKSH_NO_CMDLINE_EDITING
        {"bind", c_bind},
 #endif
-       {"cat", c_cat},
 #if HAVE_MKNOD
        {"mknod", c_mknod},
 #endif
 #if HAVE_MKNOD
        {"mknod", c_mknod},
 #endif
-       {"realpath", c_realpath},
-       {"rename", c_rename},
+#ifdef MKSH_PRINTF_BUILTIN
+       {"printf", c_printf},
+#endif
 #if HAVE_SELECT
        {"sleep", c_sleep},
 #endif
 #if HAVE_SELECT
        {"sleep", c_sleep},
 #endif
@@ -836,7 +835,7 @@ c_typeset(const char **wp)
                                        shf_putc('\n', shl_stdout);
                                }
                        } else if (!typeset(wp[i], fset, fclr, field, base)) {
                                        shf_putc('\n', shl_stdout);
                                }
                        } else if (!typeset(wp[i], fset, fclr, field, base)) {
-                               bi_errorf("%s: %s", wp[i], "not identifier");
+                               bi_errorf("%s: %s", wp[i], "is not an identifier");
                                goto errout;
                        }
                }
                                goto errout;
                        }
                }
@@ -2253,7 +2252,7 @@ c_trap(const char **wp)
        wp += builtin_opt.optind;
 
        if (*wp == NULL) {
        wp += builtin_opt.optind;
 
        if (*wp == NULL) {
-               for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
+               for (p = sigtraps, i = NSIG + 1; --i >= 0; p++)
                        if (p->trap != NULL) {
                                shf_puts("trap -- ", shl_stdout);
                                print_value_quoted(shl_stdout, p->trap);
                        if (p->trap != NULL) {
                                shf_puts("trap -- ", shl_stdout);
                                print_value_quoted(shl_stdout, p->trap);
@@ -2427,12 +2426,13 @@ c_set(const char **wp)
         * which assumes the exit value set will be that of the $()
         * (subst_exstat is cleared in execute() so that it will be 0
         * if there are no command substitutions).
         * which assumes the exit value set will be that of the $()
         * (subst_exstat is cleared in execute() so that it will be 0
         * if there are no command substitutions).
-        * Switched ksh (!posix !sh) to POSIX in mksh R39b.
         */
 #ifdef MKSH_LEGACY_MODE
         */
 #ifdef MKSH_LEGACY_MODE
-       return (subst_exstat);
+       /* traditional behaviour, unless set -o posix */
+       return (Flag(FPOSIX) ? 0 : subst_exstat);
 #else
 #else
-       return (Flag(FSH) ? subst_exstat : 0);
+       /* conformant behaviour, unless set -o sh +o posix */
+       return (Flag(FSH) && !Flag(FPOSIX) ? subst_exstat : 0);
 #endif
 }
 
 #endif
 }
 
@@ -3726,7 +3726,7 @@ c_cat(const char **wp)
        rv = 0;
 
        if ((buf = malloc_osfunc(MKSH_CAT_BUFSIZ)) == NULL) {
        rv = 0;
 
        if ((buf = malloc_osfunc(MKSH_CAT_BUFSIZ)) == NULL) {
-               bi_errorf(Toomem, (unsigned long)MKSH_CAT_BUFSIZ);
+               bi_errorf(Toomem, (size_t)MKSH_CAT_BUFSIZ);
                return (1);
        }
 
                return (1);
        }
 
index 4be7356..3277c78 100644 (file)
@@ -1,7 +1,8 @@
-/*     $OpenBSD: jobs.c,v 1.38 2009/12/12 04:28:44 deraadt Exp $       */
+/*     $OpenBSD: jobs.c,v 1.39 2009/12/13 04:36:48 deraadt Exp $       */
 
 /*-
 
 /*-
- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
+ *              2012, 2013
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -22,7 +23,7 @@
 
 #include "sh.h"
 
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.94 2012/12/28 02:28:36 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.100 2013/07/26 20:33:23 tg Exp $");
 
 #if HAVE_KILLPG
 #define mksh_killpg            killpg
 
 #if HAVE_KILLPG
 #define mksh_killpg            killpg
@@ -44,12 +45,11 @@ struct proc {
        int state;
        int status;             /* wait status */
        /* process command string from vistree */
        int state;
        int status;             /* wait status */
        /* process command string from vistree */
-       char command[64 - (ALLOC_SIZE + sizeof(Proc *) + sizeof(pid_t) +
+       char command[256 - (ALLOC_SIZE + sizeof(Proc *) + sizeof(pid_t) +
            2 * sizeof(int))];
 };
 
 /* Notify/print flag - j_print() argument */
            2 * sizeof(int))];
 };
 
 /* Notify/print flag - j_print() argument */
-#define JP_NONE                0       /* don't print anything */
 #define JP_SHORT       1       /* print signals processes were killed by */
 #define JP_MEDIUM      2       /* print [job-num] -/+ command */
 #define JP_LONG                3       /* print [job-num] -/+ pid command */
 #define JP_SHORT       1       /* print signals processes were killed by */
 #define JP_MEDIUM      2       /* print [job-num] -/+ command */
 #define JP_LONG                3       /* print [job-num] -/+ pid command */
@@ -102,17 +102,14 @@ struct job {
 #define JW_PIPEST      0x08    /* want PIPESTATUS */
 
 /* Error codes for j_lookup() */
 #define JW_PIPEST      0x08    /* want PIPESTATUS */
 
 /* Error codes for j_lookup() */
-#define JL_OK          0
-#define JL_NOSUCH      1       /* no such job */
-#define JL_AMBIG       2       /* %foo or %?foo is ambiguous */
-#define JL_INVALID     3       /* non-pid, non-% job id */
+#define JL_NOSUCH      0       /* no such job */
+#define JL_AMBIG       1       /* %foo or %?foo is ambiguous */
+#define JL_INVALID     2       /* non-pid, non-% job id */
 
 static const char * const lookup_msgs[] = {
 
 static const char * const lookup_msgs[] = {
-       null,
        "no such job",
        "ambiguous",
        "no such job",
        "ambiguous",
-       "argument must be %job or process id",
-       NULL
+       "argument must be %job or process id"
 };
 
 static Job *job_list;          /* job list */
 };
 
 static Job *job_list;          /* job list */
@@ -463,7 +460,7 @@ exchild(struct op *t, int flags,
                forksleep <<= 1;
        }
        /* ensure $RANDOM changes between parent and child */
                forksleep <<= 1;
        }
        /* ensure $RANDOM changes between parent and child */
-       rndset((long)cldpid);
+       rndset((unsigned long)cldpid);
        /* fork failed? */
        if (cldpid < 0) {
                kill_job(j, SIGKILL);
        /* fork failed? */
        if (cldpid < 0) {
                kill_job(j, SIGKILL);
@@ -506,9 +503,6 @@ exchild(struct op *t, int flags,
                /* Do this before restoring signal */
                if (flags & XCOPROC)
                        coproc_cleanup(false);
                /* Do this before restoring signal */
                if (flags & XCOPROC)
                        coproc_cleanup(false);
-#ifndef MKSH_NOPROSPECTOFWORK
-               sigprocmask(SIG_SETMASK, &omask, NULL);
-#endif
                cleanup_parents_env();
 #ifndef MKSH_UNEMPLOYED
                /*
                cleanup_parents_env();
 #ifndef MKSH_UNEMPLOYED
                /*
@@ -543,6 +537,10 @@ exchild(struct op *t, int flags,
                }
                /* in case of $(jobs) command */
                remove_job(j, "child");
                }
                /* in case of $(jobs) command */
                remove_job(j, "child");
+#ifndef MKSH_NOPROSPECTOFWORK
+               /* remove_job needs SIGCHLD blocked still */
+               sigprocmask(SIG_SETMASK, &omask, NULL);
+#endif
                nzombie = 0;
 #ifndef MKSH_UNEMPLOYED
                ttypgrp_ok = false;
                nzombie = 0;
 #ifndef MKSH_UNEMPLOYED
                ttypgrp_ok = false;
@@ -906,7 +904,7 @@ j_jobs(const char *cp, int slp,
                zflag = 1;
        }
        if (cp) {
                zflag = 1;
        }
        if (cp) {
-               int     ecode;
+               int ecode;
 
                if ((j = j_lookup(cp, &ecode)) == NULL) {
 #ifndef MKSH_NOPROSPECTOFWORK
 
                if ((j = j_lookup(cp, &ecode)) == NULL) {
 #ifndef MKSH_NOPROSPECTOFWORK
@@ -1220,6 +1218,8 @@ j_waitj(Job *j,
                            ARRAY | INT_U | AINDEX;
  got_array:
                        vp->val.i = proc_errorlevel(p);
                            ARRAY | INT_U | AINDEX;
  got_array:
                        vp->val.i = proc_errorlevel(p);
+                       if (Flag(FPIPEFAIL) && vp->val.i)
+                               rv = vp->val.i;
                        p = p->next;
                }
        }
                        p = p->next;
                }
        }
@@ -1251,8 +1251,7 @@ j_waitj(Job *j,
 static void
 j_sigchld(int sig MKSH_A_UNUSED)
 {
 static void
 j_sigchld(int sig MKSH_A_UNUSED)
 {
-       /* this runs inside interrupt context, with errno saved */
-
+       int saved_errno = errno;
        Job *j;
        Proc *p = NULL;
        pid_t pid;
        Job *j;
        Proc *p = NULL;
        pid_t pid;
@@ -1340,7 +1339,7 @@ j_sigchld(int sig MKSH_A_UNUSED)
 #ifdef MKSH_NO_SIGSUSPEND
        sigprocmask(SIG_SETMASK, &omask, NULL);
 #endif
 #ifdef MKSH_NO_SIGSUSPEND
        sigprocmask(SIG_SETMASK, &omask, NULL);
 #endif
-       /* nothing */;
+       errno = saved_errno;
 }
 
 /*
 }
 
 /*
index daaee57..f5dc830 100644 (file)
@@ -1,5 +1,5 @@
 /*-
 /*-
- * Copyright (c) 2009, 2010, 2011
+ * Copyright (c) 2009, 2010, 2011, 2013
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -20,7 +20,7 @@
 
 #include "sh.h"
 
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.19 2011/09/07 15:24:16 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.20 2013/06/03 22:28:33 tg Exp $");
 
 /* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */
 #if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0)
 
 /* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */
 #if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0)
@@ -100,7 +100,7 @@ aresize(void *ptr, size_t numb, Area *ap)
            || ALLOC_ISUNALIGNED(lp)
 #endif
            )
            || ALLOC_ISUNALIGNED(lp)
 #endif
            )
-               internal_errorf(Toomem, (unsigned long)numb);
+               internal_errorf(Toomem, numb);
        /* this only works because Area is an ALLOC_ITEM */
        lp->next = ap->next;
        ap->next = lp;
        /* this only works because Area is an ALLOC_ITEM */
        lp->next = ap->next;
        ap->next = lp;
index 3f60742..e58d8b8 100644 (file)
--- a/src/lex.c
+++ b/src/lex.c
@@ -1,4 +1,4 @@
-/*     $OpenBSD: lex.c,v 1.46 2013/01/20 14:47:46 stsp Exp $   */
+/*     $OpenBSD: lex.c,v 1.47 2013/03/03 19:11:34 guenther Exp $       */
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.182 2013/02/19 18:45:20 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.188 2013/08/10 13:44:31 tg Exp $");
 
 /*
  * states while lexing word
 
 /*
  * states while lexing word
@@ -102,8 +102,6 @@ static void gethere(bool);
 static Lex_state *push_state_i(State_info *, Lex_state *);
 static Lex_state *pop_state_i(State_info *, Lex_state *);
 
 static Lex_state *push_state_i(State_info *, Lex_state *);
 static Lex_state *pop_state_i(State_info *, Lex_state *);
 
-static int dopprompt(const char *, int, bool);
-
 static int backslash_skip;
 static int ignore_backslash_newline;
 
 static int backslash_skip;
 static int ignore_backslash_newline;
 
@@ -338,7 +336,9 @@ yylex(int cf)
                                }
                                break;
                        case '\'':
                                }
                                break;
                        case '\'':
- open_ssquote:
+ open_ssquote_unless_heredoc:
+                               if ((cf & HEREDOC))
+                                       goto store_char;
                                *wp++ = OQUOTE;
                                ignore_backslash_newline++;
                                PUSH_STATE(SSQUOTE);
                                *wp++ = OQUOTE;
                                ignore_backslash_newline++;
                                PUSH_STATE(SSQUOTE);
@@ -421,8 +421,14 @@ yylex(int cf)
                                                wp += cz;
                                        }
                                } else if (c == '{') /*}*/ {
                                                wp += cz;
                                        }
                                } else if (c == '{') /*}*/ {
-                                       c = getsc();
-                                       if (ctype(c, C_IFSWS)) {
+                                       if ((c = getsc()) == '|') {
+                                               /*
+                                                * non-subenvironment
+                                                * value substitution
+                                                */
+                                               c = VALSUB;
+                                               goto subst_command2;
+                                       } else if (ctype(c, C_IFSWS)) {
                                                /*
                                                 * non-subenvironment
                                                 * "command" substitution
                                                /*
                                                 * non-subenvironment
                                                 * "command" substitution
@@ -495,7 +501,8 @@ yylex(int cf)
                                                        PUSH_STATE(STBRACEKORN);
                                        } else {
                                                ungetsc(c);
                                                        PUSH_STATE(STBRACEKORN);
                                        } else {
                                                ungetsc(c);
-                                               if (state == SDQUOTE)
+                                               if (state == SDQUOTE ||
+                                                   state == SQBRACE)
                                                        PUSH_STATE(SQBRACE);
                                                else
                                                        PUSH_STATE(SBRACE);
                                                        PUSH_STATE(SQBRACE);
                                                else
                                                        PUSH_STATE(SBRACE);
@@ -616,6 +623,8 @@ yylex(int cf)
                case SSQUOTE:
                        if (c == '\'') {
                                POP_STATE();
                case SSQUOTE:
                        if (c == '\'') {
                                POP_STATE();
+                               if ((cf & HEREDOC) || state == SQBRACE)
+                                       goto store_char;
                                *wp++ = CQUOTE;
                                ignore_backslash_newline--;
                        } else {
                                *wp++ = CQUOTE;
                                ignore_backslash_newline--;
                        } else {
@@ -693,7 +702,7 @@ yylex(int cf)
 
                case SBRACE:
                        if (c == '\'')
 
                case SBRACE:
                        if (c == '\'')
-                               goto open_ssquote;
+                               goto open_ssquote_unless_heredoc;
                        else if (c == '\\')
                                goto getsc_qchar;
  common_SQBRACE:
                        else if (c == '\\')
                                goto getsc_qchar;
  common_SQBRACE:
@@ -812,7 +821,7 @@ yylex(int cf)
                                }
                                break;
                        case '\'':
                                }
                                break;
                        case '\'':
-                               goto open_ssquote;
+                               goto open_ssquote_unless_heredoc;
                        case '$':
                                if ((c2 = getsc()) == '\'') {
  open_sequote:
                        case '$':
                                if ((c2 = getsc()) == '\'') {
  open_sequote:
@@ -898,7 +907,11 @@ yylex(int cf)
                state = SBASE;
 
        dp = Xstring(ws, wp);
                state = SBASE;
 
        dp = Xstring(ws, wp);
-       if ((c == '<' || c == '>' || c == '&') && state == SBASE) {
+       if (state == SBASE && (
+#ifndef MKSH_LEGACY_MODE
+           (c == '&' && !Flag(FSH) && !Flag(FPOSIX)) ||
+#endif
+           c == '<' || c == '>')) {
                struct ioword *iop = alloc(sizeof(struct ioword), ATEMP);
 
                if (Xlength(ws, wp) == 0)
                struct ioword *iop = alloc(sizeof(struct ioword), ATEMP);
 
                if (Xlength(ws, wp) == 0)
@@ -1374,7 +1387,7 @@ getsc_line(Source *s)
            Flag(FEMACS) || Flag(FGMACS))) {
                int nread;
 
            Flag(FEMACS) || Flag(FGMACS))) {
                int nread;
 
-               nread = x_read(xp, LINE);
+               nread = x_read(xp);
                if (nread < 0)
                        /* read error */
                        nread = 0;
                if (nread < 0)
                        /* read error */
                        nread = 0;
@@ -1505,8 +1518,8 @@ set_prompt(int to, Source *s)
        }
 }
 
        }
 }
 
-static int
-dopprompt(const char *cp, int ntruncate, bool doprint)
+int
+pprompt(const char *cp, int ntruncate)
 {
        int columns = 0, lines = 0;
        bool indelimit = false;
 {
        int columns = 0, lines = 0;
        bool indelimit = false;
@@ -1539,35 +1552,21 @@ dopprompt(const char *cp, int ntruncate, bool doprint)
                else if (UTFMODE && ((unsigned char)*cp > 0x7F)) {
                        const char *cp2;
                        columns += utf_widthadj(cp, &cp2);
                else if (UTFMODE && ((unsigned char)*cp > 0x7F)) {
                        const char *cp2;
                        columns += utf_widthadj(cp, &cp2);
-                       if (doprint && (indelimit ||
-                           (ntruncate < (x_cols * lines + columns))))
+                       if (indelimit ||
+                           (ntruncate < (x_cols * lines + columns)))
                                shf_write(cp, cp2 - cp, shl_out);
                        cp = cp2 - /* loop increment */ 1;
                        continue;
                } else
                        columns++;
                                shf_write(cp, cp2 - cp, shl_out);
                        cp = cp2 - /* loop increment */ 1;
                        continue;
                } else
                        columns++;
-               if (doprint && (*cp != delimiter) &&
+               if ((*cp != delimiter) &&
                    (indelimit || (ntruncate < (x_cols * lines + columns))))
                        shf_putc(*cp, shl_out);
        }
                    (indelimit || (ntruncate < (x_cols * lines + columns))))
                        shf_putc(*cp, shl_out);
        }
-       if (doprint)
-               shf_flush(shl_out);
+       shf_flush(shl_out);
        return (x_cols * lines + columns);
 }
 
        return (x_cols * lines + columns);
 }
 
-
-void
-pprompt(const char *cp, int ntruncate)
-{
-       dopprompt(cp, ntruncate, true);
-}
-
-int
-promptlen(const char *cp)
-{
-       return (dopprompt(cp, 0, false));
-}
-
 /*
  * Read the variable part of a ${...} expression (i.e. up to but not
  * including the :[-+?=#%] or close-brace).
 /*
  * Read the variable part of a ${...} expression (i.e. up to but not
  * including the :[-+?=#%] or close-brace).
diff --git a/src/lksh.1 b/src/lksh.1
new file mode 100644 (file)
index 0000000..31dc6ff
--- /dev/null
@@ -0,0 +1,297 @@
+.\" $MirOS: src/bin/mksh/lksh.1,v 1.5 2013/05/22 18:18:06 tg Exp $
+.\"-
+.\" Copyright (c) 2008, 2009, 2010, 2012, 2013
+.\"    Thorsten “mirabilos” Glaser <tg@mirbsd.org>
+.\"
+.\" Provided that these terms and disclaimer and all copyright notices
+.\" are retained or reproduced in an accompanying document, permission
+.\" 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.
+.\"-
+.\" Try to make GNU groff and AT&T nroff more compatible
+.\" * ` generates ‘ in gnroff, so use \`
+.\" * ' generates ’ in gnroff, \' generates ´, so use \*(aq
+.\" * - generates ‐ in gnroff, \- generates −, so .tr it to -
+.\"   thus use - for hyphens and \- for minus signs and option dashes
+.\" * ~ is size-reduced and placed atop in groff, so use \*(TI
+.\" * ^ is size-reduced and placed atop in groff, so use \*(ha
+.\" * \(en does not work in nroff, so use \*(en
+.\" * <>| are problematic, so redefine and use \*(Lt\*(Gt\*(Ba
+.\" Also make sure to use \& especially with two-letter words.
+.\" The section after the "doc" macropackage has been loaded contains
+.\" additional code to convene between the UCB mdoc macropackage (and
+.\" its variant as BSD mdoc in groff) and the GNU mdoc macropackage.
+.\"
+.ie \n(.g \{\
+.      if \ 1\*[.T]\ 1ascii\ 1 .tr \-\N'45'
+.      if \ 1\*[.T]\ 1latin1\ 1 .tr \-\N'45'
+.      if \ 1\*[.T]\ 1utf8\ 1 .tr \-\N'45'
+.      ds <= \[<=]
+.      ds >= \[>=]
+.      ds Rq \[rq]
+.      ds Lq \[lq]
+.      ds sL \(aq
+.      ds sR \(aq
+.      if \ 1\*[.T]\ 1utf8\ 1 .ds sL `
+.      if \ 1\*[.T]\ 1ps\ 1 .ds sL `
+.      if \ 1\*[.T]\ 1utf8\ 1 .ds sR '
+.      if \ 1\*[.T]\ 1ps\ 1 .ds sR '
+.      ds aq \(aq
+.      ds TI \(ti
+.      ds ha \(ha
+.      ds en \(en
+.\}
+.el \{\
+.      ds aq '
+.      ds TI ~
+.      ds ha ^
+.      ds en \(em
+.\}
+.\"
+.\" Implement .Dd with the Mdocdate RCS keyword
+.\"
+.rn Dd xD
+.de Dd
+.ie \a\\$1\a$Mdocdate:\a \{\
+.      xD \\$2 \\$3, \\$4
+.\}
+.el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+..
+.\"
+.\" .Dd must come before definition of .Mx, because when called
+.\" with -mandoc, it might implement .Mx itself, but we want to
+.\" use our own definition. And .Dd must come *first*, always.
+.\"
+.Dd $Mdocdate: May 22 2013 $
+.\"
+.\" Check which macro package we use, and do other -mdoc setup.
+.\"
+.ie \n(.g \{\
+.      if \ 1\*[.T]\ 1utf8\ 1 .tr \[la]\*(Lt
+.      if \ 1\*[.T]\ 1utf8\ 1 .tr \[ra]\*(Gt
+.      ie d volume-ds-1 .ds tT gnu
+.      el .ds tT bsd
+.\}
+.el .ds tT ucb
+.\"
+.\" Implement .Mx (MirBSD)
+.\"
+.ie "\*(tT"gnu" \{\
+.      eo
+.      de Mx
+.      nr curr-font \n[.f]
+.      nr curr-size \n[.ps]
+.      ds str-Mx \f[\n[curr-font]]\s[\n[curr-size]u]
+.      ds str-Mx1 \*[Tn-font-size]\%MirOS\*[str-Mx]
+.      if !\n[arg-limit] \
+.      if \n[.$] \{\
+.      ds macro-name Mx
+.      parse-args \$@
+.      \}
+.      if (\n[arg-limit] > \n[arg-ptr]) \{\
+.      nr arg-ptr +1
+.      ie (\n[type\n[arg-ptr]] == 2) \
+.      as str-Mx1 \~\*[arg\n[arg-ptr]]
+.      el \
+.      nr arg-ptr -1
+.      \}
+.      ds arg\n[arg-ptr] "\*[str-Mx1]
+.      nr type\n[arg-ptr] 2
+.      ds space\n[arg-ptr] "\*[space]
+.      nr num-args (\n[arg-limit] - \n[arg-ptr])
+.      nr arg-limit \n[arg-ptr]
+.      if \n[num-args] \
+.      parse-space-vector
+.      print-recursive
+..
+.      ec
+.      ds sP \s0
+.      ds tN \*[Tn-font-size]
+.\}
+.el \{\
+.      de Mx
+.      nr cF \\n(.f
+.      nr cZ \\n(.s
+.      ds aa \&\f\\n(cF\s\\n(cZ
+.      if \\n(aC==0 \{\
+.              ie \\n(.$==0 \&MirOS\\*(aa
+.              el .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+.      \}
+.      if \\n(aC>\\n(aP \{\
+.              nr aP \\n(aP+1
+.              ie \\n(C\\n(aP==2 \{\
+.                      as b1 \&MirOS\ #\&\\*(A\\n(aP\\*(aa
+.                      ie \\n(aC>\\n(aP \{\
+.                              nr aP \\n(aP+1
+.                              nR
+.                      \}
+.                      el .aZ
+.              \}
+.              el \{\
+.                      as b1 \&MirOS\\*(aa
+.                      nR
+.              \}
+.      \}
+..
+.\}
+.\"-
+.Dt LKSH 1
+.Os MirBSD
+.Sh NAME
+.Nm lksh
+.Nd Legacy Korn shell built on mksh
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl +abCefhiklmnprUuvXx
+.Op Fl +o Ar opt
+.Oo
+.Fl c Ar string \*(Ba
+.Fl s \*(Ba
+.Ar file
+.Op Ar args ...
+.Oc
+.Ek
+.Sh DESCRIPTION
+.Nm
+is a command interpreter intended exclusively for running legacy
+shell scripts.
+It is built on
+.Nm mksh ;
+refer to its manual page for details on the scripting language.
+It is recommended to port scripts to
+.Nm mksh
+instead of relying on legacy or idiotic POSIX-mandated behaviour,
+since the MirBSD Korn Shell scripting language is much more consistent.
+.Sh LEGACY MODE
+.Nm
+has the following differences from
+.Nm mksh :
+.Bl -bullet
+.It
+There is no explicit support for interactive use,
+nor any command line editing or history code.
+Hence,
+.Nm
+is not suitable as a user's login shell, either; use
+.Nm mksh
+instead.
+.It
+The
+.Ev KSH_VERSION
+string identifies
+.Nm
+as
+.Dq LEGACY KSH
+instead of
+.Dq MIRBSD KSH .
+.It
+.Nm
+only offers the traditional ten file descriptors to scripts.
+.It
+.Nm
+uses
+.Tn POSIX
+arithmetics, which has quite a few implications:
+The data type for arithmetics is the host ISO C
+.Vt long
+data type.
+Signed integer wraparound is Undefined Behaviour.
+The sign of the result of a modulo operation with at least one
+negative operand is unspecified.
+Shift operations on negative numbers are unspecified.
+Division of the largest negative number by \-1 is Undefined Behaviour.
+The compiler is permitted to delete all data and crash the system
+if Undefined Behaviour occurs.
+.It
+The rotation arithmetic operators are not available.
+.It
+The shift arithmetic operators take all bits of the second operand into
+account; if they exceed permitted precision, the result is unspecified.
+.It
+The
+.Tn GNU
+.Nm bash
+extension &\*(Gt to redirect stdout and stderr in one go is not parsed.
+.It
+The
+.Nm mksh
+command line option
+.Fl T
+is not available.
+.It
+Unless
+.Ic set -o posix
+is active,
+.Nm
+always uses traditional mode for constructs like:
+.Bd -literal -offset indent
+$ set -- $(getopt ab:c "$@")
+$ echo $?
+.Ed
+.Pp
+POSIX mandates this to show 0, but traditional mode
+passes through the errorlevel from the
+.Xr getopt 1
+command.
+.It
+.Nm lksh ,
+unlike
+.At
+.Nm ksh ,
+does not keep file descriptors \*(Gt 2 private.
+.El
+.Sh SEE ALSO
+.Xr mksh 1
+.Pp
+.Pa https://www.mirbsd.org/mksh.htm
+.Pp
+.Pa https://www.mirbsd.org/ksh\-chan.htm
+.Sh CAVEATS
+To use
+.Nm
+as
+.Pa /bin/sh ,
+compilation to enable
+.Ic set -o posix
+by default is highly recommended for better standards compliance.
+.Pp
+.Nm
+tries to make a cross between a legacy bourne/posix compatibl-ish
+shell and a legacy pdksh-alike but
+.Dq legacy
+is not exactly specified.
+.Pp
+The
+.Ic set
+built-in command does not have all options one would expect
+from a full-blown
+.Nm mksh
+or
+.Nm pdksh .
+.Pp
+Talk to the
+.Mx
+development team using the mailing list at
+.Aq miros\-mksh@mirbsd.org
+or the
+.Li \&#\&!/bin/mksh
+.Pq or Li \&#ksh
+IRC channel at
+.Pa irc.freenode.net
+.Pq Port 6697 SSL, 6667 unencrypted
+if you need any further quirks or assistance,
+and consider migrating your legacy scripts to work with
+.Nm mksh
+instead of requiring
+.Nm .
index 61b09e2..291ab40 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: main.c,v 1.51 2012/09/10 01:25:30 tedu Exp $  */
+/*     $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: table.c,v 1.15 2012/02/19 07:52:30 otto 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: table.c,v 1.15 2012/02/19 07:52:30 otto Exp $ */
@@ -34,7 +34,7 @@
 #include <locale.h>
 #endif
 
 #include <locale.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.260 2013/02/10 21:42:16 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.269 2013/07/25 18:07:46 tg Exp $");
 
 extern char **environ;
 
 
 extern char **environ;
 
@@ -48,6 +48,7 @@ extern char **environ;
 
 static uint8_t isuc(const char *);
 static int main_init(int, const char *[], Source **, struct block **);
 
 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 *);
 void chvt_reinit(void);
 static void reclaim(void);
 static void remove_temps(struct temp *);
@@ -137,15 +138,25 @@ rndsetup(void)
        /* introduce variation (and yes, second arg MBZ for portability) */
        mksh_TIME(bufptr->tv);
 
        /* introduce variation (and yes, second arg MBZ for portability) */
        mksh_TIME(bufptr->tv);
 
+       h = chvt_rndsetup(bufptr, sizeof(*bufptr));
+
+       afree(cp, APERM);
+       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 */
        NZATInit(h);
        /* variation through pid, ppid, and the works */
        NZATUpdateMem(h, &rndsetupstate, sizeof(rndsetupstate));
        /* some variation, some possibly entropy, depending on OE */
-       NZATUpdateMem(h, bufptr, sizeof(*bufptr));
+       NZATUpdateMem(h, bp, sz);
        NZAATFinish(h);
 
        NZAATFinish(h);
 
-       afree(cp, APERM);
-       return ((mksh_uari_t)h);
+       return (h);
 }
 
 void
 }
 
 void
@@ -238,7 +249,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
 
        /* define built-in commands and see if we were called as one */
        ktinit(APERM, &builtins,
 
        /* define built-in commands and see if we were called as one */
        ktinit(APERM, &builtins,
-           /* currently up to 50 builtins: 75% of 128 = 2^7 */
+           /* currently up to 51 builtins: 75% of 128 = 2^7 */
            7);
        for (i = 0; mkshbuiltins[i].name != NULL; i++)
                if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
            7);
        for (i = 0; mkshbuiltins[i].name != NULL; i++)
                if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
@@ -251,11 +262,20 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
                if (argi < 0)
                        return (1);
 
                if (argi < 0)
                        return (1);
 
+#if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED)
+               /* are we called as -sh or /bin/sh or so? */
+               if (!strcmp(ccp, "sh")) {
+                       /* either also turns off braceexpand */
+#ifdef MKSH_BINSHPOSIX
+                       /* enable better POSIX conformance */
+                       change_flag(FPOSIX, OF_FIRSTTIME, true);
+#endif
 #ifdef MKSH_BINSHREDUCED
 #ifdef MKSH_BINSHREDUCED
-               /* set FSH if we're called as -sh or /bin/sh or so */
-               if (!strcmp(ccp, "sh"))
+                       /* enable kludge/compat mode */
                        change_flag(FSH, OF_FIRSTTIME, true);
 #endif
                        change_flag(FSH, OF_FIRSTTIME, true);
 #endif
+               }
+#endif
        }
 
        initvar();
        }
 
        initvar();
@@ -323,6 +343,11 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
         */
        Flag(FBRACEEXPAND) = 1;
 
         */
        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
 #ifndef MKSH_NO_CMDLINE_EDITING
        /*
         * Set edit mode to emacs by default, may be overridden
@@ -411,7 +436,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
                        return (1);
        }
 
                        return (1);
        }
 
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(MKSH_LEGACY_MODE)
        /* test wraparound of arithmetic types */
        {
                volatile long xl;
        /* test wraparound of arithmetic types */
        {
                volatile long xl;
@@ -442,7 +467,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
                xc = 0;
                --xc;
                if ((xua2 != 2147483648UL) ||
                xc = 0;
                --xc;
                if ((xua2 != 2147483648UL) ||
-                   (xl != -2147483648L) || (xul != 2147483648UL) ||
+                   (xl != (-2147483647L-1)) || (xul != 2147483648UL) ||
                    (xi != -1) || (xui != 4294967295U) ||
                    (xa != 0) || (xua != 0) || (xc != 255))
                        errorf("integer wraparound test failed");
                    (xi != -1) || (xui != 4294967295U) ||
                    (xa != 0) || (xua != 0) || (xc != 255))
                        errorf("integer wraparound test failed");
@@ -889,8 +914,9 @@ unwind(int i)
        }
 
        /* ordering for EXIT vs ERR is a bit odd (this is what AT&T ksh does) */
        }
 
        /* ordering for EXIT vs ERR is a bit odd (this is what AT&T ksh does) */
-       if (i == LEXIT ||
-           ((i == LERROR || i == LINTR) && sigtraps[ksh_SIGEXIT].trap)) {
+       if (i == LEXIT || ((i == LERROR || i == LINTR) &&
+           sigtraps[ksh_SIGEXIT].trap &&
+           (!Flag(FTALKING) || Flag(FERREXIT)))) {
                ++trap_nested;
                runtrap(&sigtraps[ksh_SIGEXIT], trap_nested == 1);
                --trap_nested;
                ++trap_nested;
                runtrap(&sigtraps[ksh_SIGEXIT], trap_nested == 1);
                --trap_nested;
@@ -1006,6 +1032,10 @@ quitenv(struct shf *shf)
 #ifndef MKSH_NO_CMDLINE_EDITING
                x_done();
 #endif
 #ifndef MKSH_NO_CMDLINE_EDITING
                x_done();
 #endif
+#ifndef MKSH_NOPROSPECTOFWORK
+               /* block at least SIGCHLD during/after afreeall */
+               sigprocmask(SIG_BLOCK, &sm_sigchld, NULL);
+#endif
                afreeall(APERM);
                for (fd = 3; fd < NUFILE; fd++)
                        if ((i = fcntl(fd, F_GETFD, 0)) != -1 &&
                afreeall(APERM);
                for (fd = 3; fd < NUFILE; fd++)
                        if ((i = fcntl(fd, F_GETFD, 0)) != -1 &&
@@ -1364,7 +1394,7 @@ initio(void)
        /* force buffer allocation */
        shf_fdopen(1, SHF_WR, shl_stdout);
        shf_fdopen(2, SHF_WR, shl_out);
        /* force buffer allocation */
        shf_fdopen(1, SHF_WR, shl_stdout);
        shf_fdopen(2, SHF_WR, shl_out);
-       shf_fdopen(2, SHF_WR, shl_spare);
+       shf_fdopen(2, SHF_WR, shl_xtrace);
 #ifdef DF
        if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
                if ((lfp = getenv("HOME")) == NULL || *lfp != '/')
 #ifdef DF
        if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
                if ((lfp = getenv("HOME")) == NULL || *lfp != '/')
@@ -1594,7 +1624,7 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist)
 {
        char *cp;
        size_t len;
 {
        char *cp;
        size_t len;
-       int i;
+       int i, j;
        struct temp *tp;
        const char *dir;
        struct stat sb;
        struct temp *tp;
        const char *dir;
        struct stat sb;
@@ -1644,17 +1674,19 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist)
        }
 
        if (type == TT_FUNSUB) {
        }
 
        if (type == TT_FUNSUB) {
-               int nfd;
-
                /* map us high and mark as close-on-exec */
                /* map us high and mark as close-on-exec */
-               if ((nfd = savefd(i)) != i) {
+               if ((j = savefd(i)) != i) {
                        close(i);
                        close(i);
-                       i = nfd;
+                       i = j;
                }
                }
-       }
+
+               /* operation mode for the shf */
+               j = SHF_RD;
+       } else
+               j = SHF_WR;
 
        /* shf_fdopen cannot fail, so no fd leak */
 
        /* shf_fdopen cannot fail, so no fd leak */
-       tp->shf = shf_fdopen(i, SHF_WR, NULL);
+       tp->shf = shf_fdopen(i, j, NULL);
 
  maketemp_out:
        tp->next = *tlist;
 
  maketemp_out:
        tp->next = *tlist;
index 988f98c..adf4bc4 100644 (file)
@@ -3,7 +3,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *              2011, 2012
+ *              2011, 2012, 2013
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -30,7 +30,7 @@
 #include <grp.h>
 #endif
 
 #include <grp.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.205 2012/12/17 23:18:08 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.214 2013/08/11 14:57:09 tg Exp $");
 
 #define KSH_CHVT_FLAG
 #ifdef MKSH_SMALL
 
 #define KSH_CHVT_FLAG
 #ifdef MKSH_SMALL
@@ -54,7 +54,7 @@ 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);
 #ifdef KSH_CHVT_CODE
     const unsigned char *, const unsigned char *);
 static const unsigned char *cclass(const unsigned char *, unsigned char);
 #ifdef KSH_CHVT_CODE
-static void chvt(const char *);
+static void chvt(const Getopt *);
 #endif
 
 /*XXX this should go away */
 #endif
 
 /*XXX this should go away */
@@ -123,10 +123,15 @@ Xcheck_grow(XString *xsp, const char *xp, size_t more)
        return (xsp->beg + (xp - old_beg));
 }
 
        return (xsp->beg + (xp - old_beg));
 }
 
+
 #define SHFLAGS_DEFNS
 #include "sh_flags.h"
 
 #define SHFLAGS_DEFNS
 #include "sh_flags.h"
 
-const struct shoption options[] = {
+#define OFC(i) (options[i][-2])
+#define OFF(i) (((const unsigned char *)options[i])[-1])
+#define OFN(i) (options[i])
+
+const char * const options[] = {
 #define SHFLAGS_ITEMS
 #include "sh_flags.h"
 };
 #define SHFLAGS_ITEMS
 #include "sh_flags.h"
 };
@@ -137,15 +142,20 @@ const struct shoption options[] = {
 size_t
 option(const char *n)
 {
 size_t
 option(const char *n)
 {
-       size_t i;
+       size_t i = 0;
 
 
-       if ((n[0] == '-' || n[0] == '+') && n[1] && !n[2]) {
-               for (i = 0; i < NELEM(options); i++)
-                       if (options[i].c == n[1])
+       if ((n[0] == '-' || n[0] == '+') && n[1] && !n[2])
+               while (i < NELEM(options)) {
+                       if (OFC(i) == n[1])
+                               return (i);
+                       ++i;
+               }
+       else
+               while (i < NELEM(options)) {
+                       if (!strcmp(OFN(i), n))
                                return (i);
                                return (i);
-       } else for (i = 0; i < NELEM(options); i++)
-               if (options[i].name && strcmp(options[i].name, n) == 0)
-                       return (i);
+                       ++i;
+               }
 
        return ((size_t)-1);
 }
 
        return ((size_t)-1);
 }
@@ -165,7 +175,7 @@ options_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
        const struct options_info *oi = (const struct options_info *)arg;
 
        shf_snprintf(buf, buflen, "%-*s %s",
        const struct options_info *oi = (const struct options_info *)arg;
 
        shf_snprintf(buf, buflen, "%-*s %s",
-           oi->opt_width, options[oi->opts[i]].name,
+           oi->opt_width, OFN(oi->opts[i]),
            Flag(oi->opts[i]) ? "on" : "off");
        return (buf);
 }
            Flag(oi->opts[i]) ? "on" : "off");
        return (buf);
 }
@@ -184,12 +194,11 @@ printoptions(bool verbose)
 
                oi.opt_width = 0;
                while (i < NELEM(options)) {
 
                oi.opt_width = 0;
                while (i < NELEM(options)) {
-                       if (options[i].name) {
+                       if ((len = strlen(OFN(i)))) {
                                oi.opts[n++] = i;
                                oi.opts[n++] = i;
-                               len = strlen(options[i].name);
                                if (len > octs)
                                        octs = len;
                                if (len > octs)
                                        octs = len;
-                               len = utf_mbswidth(options[i].name);
+                               len = utf_mbswidth(OFN(i));
                                if ((int)len > oi.opt_width)
                                        oi.opt_width = (int)len;
                        }
                                if ((int)len > oi.opt_width)
                                        oi.opt_width = (int)len;
                        }
@@ -200,10 +209,9 @@ printoptions(bool verbose)
        } else {
                /* short version like AT&T ksh93 */
                shf_puts(Tset, shl_stdout);
        } else {
                /* short version like AT&T ksh93 */
                shf_puts(Tset, shl_stdout);
-               while (i < (int)NELEM(options)) {
-                       if (Flag(i) && options[i].name)
-                               shprintf("%s %s %s", null, "-o",
-                                   options[i].name);
+               while (i < NELEM(options)) {
+                       if (Flag(i) && OFN(i)[0])
+                               shprintf(" -o %s", OFN(i));
                        ++i;
                }
                shf_putc('\n', shl_stdout);
                        ++i;
                }
                shf_putc('\n', shl_stdout);
@@ -213,13 +221,15 @@ printoptions(bool verbose)
 char *
 getoptions(void)
 {
 char *
 getoptions(void)
 {
-       size_t i;
-       char m[(int)FNFLAGS + 1];
+       size_t i = 0;
+       char c, m[(int)FNFLAGS + 1];
        char *cp = m;
 
        char *cp = m;
 
-       for (i = 0; i < NELEM(options); i++)
-               if (options[i].c && Flag(i))
-                       *cp++ = options[i].c;
+       while (i < NELEM(options)) {
+               if ((c = OFC(i)) && Flag(i))
+                       *cp++ = c;
+               ++i;
+       }
        strndupx(cp, m, cp - m, ATEMP);
        return (cp);
 }
        strndupx(cp, m, cp - m, ATEMP);
        return (cp);
 }
@@ -229,8 +239,12 @@ void
 change_flag(enum sh_flag f, int what, bool newset)
 {
        unsigned char oldval;
 change_flag(enum sh_flag f, int what, bool newset)
 {
        unsigned char oldval;
-       unsigned char newval;
+       unsigned char newval = (newset ? 1 : 0);
 
 
+       if (f == FXTRACE) {
+               change_xtrace(newval, true);
+               return;
+       }
        oldval = Flag(f);
        Flag(f) = newval = (newset ? 1 : 0);
 #ifndef MKSH_UNEMPLOYED
        oldval = Flag(f);
        Flag(f) = newval = (newset ? 1 : 0);
 #ifndef MKSH_UNEMPLOYED
@@ -277,16 +291,46 @@ change_flag(enum sh_flag f, int what, bool newset)
                setgid(kshegid);
 #endif
        } else if ((f == FPOSIX || f == FSH) && newval) {
                setgid(kshegid);
 #endif
        } else if ((f == FPOSIX || f == FSH) && newval) {
-               Flag(FPOSIX) = Flag(FSH) = Flag(FBRACEEXPAND) = 0;
-               Flag(f) = newval;
-       }
-       /* Changing interactive flag? */
-       if (f == FTALKING) {
+               /* Turning on -o posix or -o sh? */
+               Flag(FBRACEEXPAND) = 0;
+       } else if (f == FTALKING) {
+               /* Changing interactive flag? */
                if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid)
                        Flag(FTALKING_I) = newval;
        }
 }
 
                if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid)
                        Flag(FTALKING_I) = newval;
        }
 }
 
+void
+change_xtrace(unsigned char newval, bool dosnapshot)
+{
+       if (!dosnapshot && newval == Flag(FXTRACE))
+               return;
+
+       if (Flag(FXTRACE) == 2) {
+               shf_putc('\n', shl_xtrace);
+               Flag(FXTRACE) = 1;
+               shf_flush(shl_xtrace);
+       }
+
+       if (!dosnapshot && Flag(FXTRACE) == 1)
+               switch (newval) {
+               case 1:
+                       return;
+               case 2:
+                       goto changed_xtrace;
+               }
+
+       shf_flush(shl_xtrace);
+       if (shl_xtrace->fd != 2)
+               close(shl_xtrace->fd);
+       if (!newval || (shl_xtrace->fd = savefd(2)) == -1)
+               shl_xtrace->fd = 2;
+
+ changed_xtrace:
+       if ((Flag(FXTRACE) = newval) == 2)
+               shf_puts(substitute(str_val(global("PS4")), 0), shl_xtrace);
+}
+
 /*
  * Parse command line and set command arguments. Returns the index of
  * non-option arguments, -1 if there is an error.
 /*
  * Parse command line and set command arguments. Returns the index of
  * non-option arguments, -1 if there is an error.
@@ -306,10 +350,11 @@ parse_args(const char **argv,
        size_t i;
        int optc, arrayset = 0;
        bool sortargs = false;
        size_t i;
        int optc, arrayset = 0;
        bool sortargs = false;
+       bool fcompatseen = false;
 
        /* First call? Build option strings... */
        if (cmd_opts[0] == '\0') {
 
        /* First call? Build option strings... */
        if (cmd_opts[0] == '\0') {
-               char *p = cmd_opts, *q = set_opts;
+               char ch, *p = cmd_opts, *q = set_opts;
 
                /* see cmd_opts[] declaration */
                *p++ = 'o';
 
                /* see cmd_opts[] declaration */
                *p++ = 'o';
@@ -326,11 +371,11 @@ parse_args(const char **argv,
                *q++ = 's';
 
                for (i = 0; i < NELEM(options); i++) {
                *q++ = 's';
 
                for (i = 0; i < NELEM(options); i++) {
-                       if (options[i].c) {
-                               if (options[i].flags & OF_CMDLINE)
-                                       *p++ = options[i].c;
-                               if (options[i].flags & OF_SET)
-                                       *q++ = options[i].c;
+                       if ((ch = OFC(i))) {
+                               if (OFF(i) & OF_CMDLINE)
+                                       *p++ = ch;
+                               if (OFF(i) & OF_SET)
+                                       *q++ = ch;
                        }
                }
                *p = '\0';
                        }
                }
                *p = '\0';
@@ -379,6 +424,17 @@ parse_args(const char **argv,
                                break;
                        }
                        i = option(go.optarg);
                                break;
                        }
                        i = option(go.optarg);
+                       if ((i == FPOSIX || i == FSH) && set && !fcompatseen) {
+                               /*
+                                * If running 'set -o posix' or
+                                * 'set -o sh', turn off the other;
+                                * if running 'set -o posix -o sh'
+                                * allow both to be set though.
+                                */
+                               Flag(FPOSIX) = 0;
+                               Flag(FSH) = 0;
+                               fcompatseen = true;
+                       }
                        if ((i != (size_t)-1) && (set ? 1U : 0U) == Flag(i))
                                /*
                                 * Don't check the context if the flag
                        if ((i != (size_t)-1) && (set ? 1U : 0U) == Flag(i))
                                /*
                                 * Don't check the context if the flag
@@ -387,7 +443,7 @@ parse_args(const char **argv,
                                 * if the output of "set +o" is to be used.
                                 */
                                ;
                                 * if the output of "set +o" is to be used.
                                 */
                                ;
-                       else if ((i != (size_t)-1) && (options[i].flags & what))
+                       else if ((i != (size_t)-1) && (OFF(i) & what))
                                change_flag((enum sh_flag)i, what, set);
                        else {
                                bi_errorf("%s: %s", go.optarg, "bad option");
                                change_flag((enum sh_flag)i, what, set);
                        else {
                                bi_errorf("%s: %s", go.optarg, "bad option");
@@ -403,7 +459,7 @@ parse_args(const char **argv,
                        errorf("no TIOCSCTTY ioctl");
 #else
                        change_flag(FTALKING, OF_CMDLINE, true);
                        errorf("no TIOCSCTTY ioctl");
 #else
                        change_flag(FTALKING, OF_CMDLINE, true);
-                       chvt(go.optarg);
+                       chvt(&go);
                        break;
 #endif
 #endif
                        break;
 #endif
 #endif
@@ -420,8 +476,8 @@ parse_args(const char **argv,
                                break;
                        }
                        for (i = 0; i < NELEM(options); i++)
                                break;
                        }
                        for (i = 0; i < NELEM(options); i++)
-                               if (optc == options[i].c &&
-                                   (what & options[i].flags)) {
+                               if (optc == OFC(i) &&
+                                   (what & OFF(i))) {
                                        change_flag((enum sh_flag)i, what, set);
                                        break;
                                }
                                        change_flag((enum sh_flag)i, what, set);
                                        break;
                                }
@@ -433,8 +489,10 @@ parse_args(const char **argv,
            (argv[go.optind][0] == '-' || argv[go.optind][0] == '+') &&
            argv[go.optind][1] == '\0') {
                /* lone - clears -v and -x flags */
            (argv[go.optind][0] == '-' || argv[go.optind][0] == '+') &&
            argv[go.optind][1] == '\0') {
                /* lone - clears -v and -x flags */
-               if (argv[go.optind][0] == '-')
-                       Flag(FVERBOSE) = Flag(FXTRACE) = 0;
+               if (argv[go.optind][0] == '-') {
+                       Flag(FVERBOSE) = 0;
+                       change_xtrace(0, false);
+               }
                /* set skips lone - or + option */
                go.optind++;
        }
                /* set skips lone - or + option */
                go.optind++;
        }
@@ -472,9 +530,11 @@ int
 getn(const char *s, int *ai)
 {
        char c;
 getn(const char *s, int *ai)
 {
        char c;
-       unsigned int i = 0;
+       mksh_ari_u num;
        bool neg = false;
 
        bool neg = false;
 
+       num.u = 0;
+
        do {
                c = *s++;
        } while (ksh_isspace(c));
        do {
                c = *s++;
        } while (ksh_isspace(c));
@@ -492,18 +552,20 @@ getn(const char *s, int *ai)
                if (!ksh_isdigit(c))
                        /* not numeric */
                        return (0);
                if (!ksh_isdigit(c))
                        /* not numeric */
                        return (0);
-               if (i > 214748364U)
+               if (num.u > 214748364U)
                        /* overflow on multiplication */
                        return (0);
                        /* overflow on multiplication */
                        return (0);
-               i = i * 10U + (unsigned int)(c - '0');
-               /* now: i <= 2147483649U */
+               num.u = num.u * 10U + (unsigned int)(c - '0');
+               /* now: num.u <= 2147483649U */
        } while ((c = *s++));
 
        } while ((c = *s++));
 
-       if (i > (neg ? 2147483648U : 2147483647U))
+       if (num.u > (neg ? 2147483648U : 2147483647U))
                /* overflow for signed 32-bit int */
                return (0);
 
                /* overflow for signed 32-bit int */
                return (0);
 
-       *ai = neg ? -(int)i : (int)i;
+       if (neg)
+               num.u = -num.u;
+       *ai = num.i;
        return (1);
 }
 
        return (1);
 }
 
@@ -1206,20 +1268,19 @@ print_columns(struct shf *shf, unsigned int n,
        /* if we can only print one column anyway, skip the goo */
        if (cols < 2) {
                for (i = 0; i < n; ++i)
        /* if we can only print one column anyway, skip the goo */
        if (cols < 2) {
                for (i = 0; i < n; ++i)
-                       shf_fprintf(shf, "%s \n",
+                       shf_fprintf(shf, "%s\n",
                            (*func)(str, max_oct, i, arg));
                goto out;
        }
 
        rows = (n + cols - 1) / cols;
        if (prefcol && cols > rows) {
                            (*func)(str, max_oct, i, arg));
                goto out;
        }
 
        rows = (n + cols - 1) / cols;
        if (prefcol && cols > rows) {
-               i = rows;
-               rows = cols > n ? n : cols;
-               cols = i;
+               cols = rows;
+               rows = (n + cols - 1) / cols;
        }
 
        }
 
+       nspace = (x_cols - max_col * cols) / cols;
        max_col = -max_col;
        max_col = -max_col;
-       nspace = (x_cols + max_col * cols) / cols;
        if (nspace <= 0)
                nspace = 1;
        for (r = 0; r < rows; r++) {
        if (nspace <= 0)
                nspace = 1;
        for (r = 0; r < rows; r++) {
@@ -1911,59 +1972,69 @@ c_cd(const char **wp)
 
 
 #ifdef KSH_CHVT_CODE
 
 
 #ifdef KSH_CHVT_CODE
+extern uint32_t chvt_rndsetup(const void *, size_t);
 extern void chvt_reinit(void);
 
 static void
 extern void chvt_reinit(void);
 
 static void
-chvt(const char *fn)
+chvt(const Getopt *go)
 {
 {
-       char dv[20];
-       struct stat sb;
+       const char *dv = go->optarg;
+       char *cp = NULL;
        int fd;
 
        int fd;
 
-       if (*fn == '-') {
-               memcpy(dv, "-/dev/null", sizeof("-/dev/null"));
-               fn = dv + 1;
-       } else {
-               if (stat(fn, &sb)) {
-                       memcpy(dv, "/dev/ttyC", 9);
-                       strlcpy(dv + 9, fn, sizeof(dv) - 9);
+       switch (*dv) {
+       case '-':
+               dv = "/dev/null";
+               break;
+       case '!':
+               ++dv;
+               /* FALLTHROUGH */
+       default: {
+               struct stat sb;
+
+               if (stat(dv, &sb)) {
+                       cp = shf_smprintf("/dev/ttyC%s", dv);
+                       dv = cp;
                        if (stat(dv, &sb)) {
                        if (stat(dv, &sb)) {
-                               strlcpy(dv + 8, fn, sizeof(dv) - 8);
-                               if (stat(dv, &sb))
-                                       errorf("%s: %s %s", "chvt",
-                                           "can't find tty", fn);
+                               memmove(cp + 1, cp, /* /dev/tty */ 8);
+                               dv = cp + 1;
+                               if (stat(dv, &sb)) {
+                                       errorf("%s: %s: %s", "chvt",
+                                           "can't find tty", go->optarg);
+                               }
                        }
                        }
-                       fn = dv;
                }
                if (!(sb.st_mode & S_IFCHR))
                }
                if (!(sb.st_mode & S_IFCHR))
-                       errorf("%s %s %s", "chvt: not a char", "device", fn);
-               if ((sb.st_uid != 0) && chown(fn, 0, 0))
-                       warningf(false, "%s: %s %s", "chvt", "can't chown root", fn);
-               if (((sb.st_mode & 07777) != 0600) && chmod(fn, (mode_t)0600))
-                       warningf(false, "%s: %s %s", "chvt", "can't chmod 0600", fn);
+                       errorf("%s: %s: %s", "chvt", "not a char device", dv);
+#ifndef MKSH_DISABLE_REVOKE_WARNING
 #if HAVE_REVOKE
 #if HAVE_REVOKE
-               if (revoke(fn))
+               if (revoke(dv))
 #endif
                        warningf(false, "%s: %s %s", "chvt",
                            "new shell is potentially insecure, can't revoke",
 #endif
                        warningf(false, "%s: %s %s", "chvt",
                            "new shell is potentially insecure, can't revoke",
-                           fn);
+                           dv);
+#endif
+           }
        }
        }
-       if ((fd = open(fn, O_RDWR)) < 0) {
+       if ((fd = open(dv, O_RDWR)) < 0) {
                sleep(1);
                sleep(1);
-               if ((fd = open(fn, O_RDWR)) < 0)
-                       errorf("%s: %s %s", "chvt", "can't open", fn);
+               if ((fd = open(dv, O_RDWR)) < 0) {
+                       errorf("%s: %s %s", "chvt", "can't open", dv);
+               }
        }
        }
-       switch (fork()) {
-       case -1:
-               errorf("%s: %s %s", "chvt", "fork", "failed");
-       case 0:
-               break;
-       default:
-               exit(0);
+       if (go->optarg[0] != '!') {
+               switch (fork()) {
+               case -1:
+                       errorf("%s: %s %s", "chvt", "fork", "failed");
+               case 0:
+                       break;
+               default:
+                       exit(0);
+               }
        }
        if (setsid() == -1)
                errorf("%s: %s %s", "chvt", "setsid", "failed");
        }
        if (setsid() == -1)
                errorf("%s: %s %s", "chvt", "setsid", "failed");
-       if (fn != dv + 1) {
+       if (go->optarg[0] != '-') {
                if (ioctl(fd, TIOCSCTTY, NULL) == -1)
                        errorf("%s: %s %s", "chvt", "TIOCSCTTY", "failed");
                if (tcflush(fd, TCIOFLUSH))
                if (ioctl(fd, TIOCSCTTY, NULL) == -1)
                        errorf("%s: %s %s", "chvt", "TIOCSCTTY", "failed");
                if (tcflush(fd, TCIOFLUSH))
@@ -1974,14 +2045,7 @@ chvt(const char *fn)
        ksh_dup2(fd, 2, false);
        if (fd > 2)
                close(fd);
        ksh_dup2(fd, 2, false);
        if (fd > 2)
                close(fd);
-       {
-               register uint32_t h;
-
-               NZATInit(h);
-               NZATUpdateMem(h, &rndsetupstate, sizeof(rndsetupstate));
-               NZAATFinish(h);
-               rndset((long)h);
-       }
+       rndset((unsigned long)chvt_rndsetup(go, sizeof(Getopt)));
        chvt_reinit();
 }
 #endif
        chvt_reinit();
 }
 #endif
index 51800fc..621aa97 100644 (file)
@@ -1,5 +1,5 @@
-.\" $MirOS: src/bin/mksh/mksh.1,v 1.305 2013/02/19 18:45:20 tg Exp $
-.\" $OpenBSD: ksh.1,v 1.145 2013/01/17 21:20:25 jmc Exp $
+.\" $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 $
 .\"-
 .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
 .\"            2010, 2011, 2012, 2013
 .\"-
 .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
 .\"            2010, 2011, 2012, 2013
@@ -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.
 .\"
 .\" with -mandoc, it might implement .Mx itself, but we want to
 .\" use our own definition. And .Dd must come *first*, always.
 .\"
-.Dd $Mdocdate: February 19 2013 $
+.Dd $Mdocdate: August 10 2013 $
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
 .Nm
 .Bk -words
 .Op Fl +abCefhiklmnprUuvXx
 .Nm
 .Bk -words
 .Op Fl +abCefhiklmnprUuvXx
-.Op Fl T Ar /dev/ttyCn \*(Ba \-
+.Oo
+.Fl T Oo Ar \&! Oc Ns Ar tty
+\*(Ba
+.Ar \&\-
+.Oc
 .Op Fl +o Ar option
 .Oo
 .Fl c Ar string \*(Ba
 .Op Fl +o Ar option
 .Oo
 .Fl c Ar string \*(Ba
@@ -295,16 +299,28 @@ Redirections that create files can't be used (i.e.\&
 .It Fl s
 The shell reads commands from standard input; all non-option arguments
 are positional parameters.
 .It Fl s
 The shell reads commands from standard input; all non-option arguments
 are positional parameters.
-.It Fl T Ar tty
+.It Fl T Ar name
 Spawn
 .Nm
 on the
 .Xr tty 4
 device given.
 Spawn
 .Nm
 on the
 .Xr tty 4
 device given.
-Superuser only.
+The paths
+.Ar name ,
+.Pa /dev/ttyC Ns Ar name
+and
+.Pa /dev/tty Ns Ar name
+are attempted in order.
+Unless
+.Ar name
+begins with an exclamation mark
+.Pq Sq \&! ,
+this is done in a subshell and returns immediately.
 If
 If
-.Ar tty
-is a dash, detach from controlling terminal (daemonise) instead.
+.Ar name
+is a dash
+.Pq Sq \&\- ,
+detach from controlling terminal (daemonise) instead.
 .El
 .Pp
 In addition to the above, the options described in the
 .El
 .Pp
 In addition to the above, the options described in the
@@ -514,7 +530,9 @@ token to form pipelines, in which the standard output of each command but the
 last is piped (see
 .Xr pipe 2 )
 to the standard input of the following command.
 last is piped (see
 .Xr pipe 2 )
 to the standard input of the following command.
-The exit status of a pipeline is that of its last command.
+The exit status of a pipeline is that of its last command, unless the
+.Ic pipefail
+option is set (see there).
 All commands of a pipeline are executed in separate subshells;
 this is allowed by POSIX but differs from both variants of
 .At
 All commands of a pipeline are executed in separate subshells;
 this is allowed by POSIX but differs from both variants of
 .At
@@ -1180,6 +1198,15 @@ work, and in that
 .Ic exit
 terminates the parent shell.
 .Pp
 .Ic exit
 terminates the parent shell.
 .Pp
+Another variant of substitution are the valsubs (value substitutions)
+.Pf ${\*(Ba\& Ns Ar command Ns \&;}
+which are also executed in the current environment, like funsubs, but
+share their I/O with the parent; instead, they evaluate to whatever
+the, initially empty, expression-local variable
+.Ev REPLY
+is set to within the
+.Ar command Ns No s .
+.Pp
 If a substitution appears outside of double quotes, the results of the
 substitution are generally subject to word or field splitting according to
 the current value of the
 If a substitution appears outside of double quotes, the results of the
 substitution are generally subject to word or field splitting according to
 the current value of the
@@ -2037,6 +2064,9 @@ Parameter, command, and arithmetic substitutions are performed
 before it is printed.
 The default is
 .Sq +\ \& .
 before it is printed.
 The default is
 .Sq +\ \& .
+You may want to set it to
+.Sq \&[$EPOCHREALTIME]\ \&
+instead, to include timestamps.
 .It Ev PWD
 The current working directory.
 May be unset or
 .It Ev PWD
 The current working directory.
 May be unset or
@@ -2431,6 +2461,13 @@ in
 .Nm
 but a syntax error in GNU
 .Nm bash .
 .Nm
 but a syntax error in GNU
 .Nm bash .
+Setting the
+.Fl o Ar posix
+or
+.Fl o Ar sh
+shell options disable parsing of this redirection;
+it's a compatibility feature to legacy scripts, to
+not be used when writing new shell code.
 .It Xo
 .No &\*(Gt\*(Ba Ar file ,
 .No &\*(Gt\*(Gt Ar file ,
 .It Xo
 .No &\*(Gt\*(Ba Ar file ,
 .No &\*(Gt\*(Gt Ar file ,
@@ -2515,15 +2552,15 @@ Unary operators:
 Binary operators:
 .Bd -literal -offset indent
 ,
 Binary operators:
 .Bd -literal -offset indent
 ,
-= *= /= %= += \-= \*(Lt\*(Lt= \*(Gt\*(Gt= &= \*(ha= \*(Ba=
+= += \-= *= /= %= \*(Lt\*(Lt\*(Lt= \*(Gt\*(Gt\*(Gt= \*(Lt\*(Lt= \*(Gt\*(Gt= &= \*(ha= \*(Ba=
 \*(Ba\*(Ba
 &&
 \*(Ba
 \*(ha
 &
 == !=
 \*(Ba\*(Ba
 &&
 \*(Ba
 \*(ha
 &
 == !=
-\*(Lt \*(Lt= \*(Gt= \*(Gt
-\*(Lt\*(Lt \*(Gt\*(Gt
+\*(Lt \*(Lt= \*(Gt \*(Gt=
+\*(Lt\*(Lt\*(Lt \*(Gt\*(Gt\*(Gt \*(Lt\*(Lt \*(Gt\*(Gt
 + \-
 * / %
 .Ed
 + \-
 * / %
 .Ed
@@ -2553,9 +2590,14 @@ Additionally, base-16 integers may be specified by prefixing them with
 in all forms of arithmetic expressions, except as numeric arguments to the
 .Ic test
 built-in command.
 in all forms of arithmetic expressions, except as numeric arguments to the
 .Ic test
 built-in command.
-It is discouraged to prefix numbers with a sole zero
-.Pq Sq 0 ,
-because some shells may interpret them as base-8 integers.
+Prefixing numbers with a sole digit zero
+.Pq Sq 0
+leads to the shell interpreting it as base-8 integer in
+.Ic posix
+mode
+.Em only ;
+historically, (pd)ksh has never done so either anyway,
+and it's unsafe to do that, but POSIX demands it nowadays.
 As a special
 .Nm mksh
 extension, numbers to the base of one are treated as either (8-bit
 As a special
 .Nm mksh
 extension, numbers to the base of one are treated as either (8-bit
@@ -2609,8 +2651,8 @@ The result is the value of the expression on the right-hand side.
 .It =
 Assignment; the variable on the left is set to the value on the right.
 .It Xo
 .It =
 Assignment; the variable on the left is set to the value on the right.
 .It Xo
-.No *= /= += \-= \*(Lt\*(Lt=
-.No \*(Gt\*(Gt= &= \*(ha= \*(Ba=
+.No += \-= *= /= %= \*(Lt\*(Lt\*(Lt= \*(Gt\*(Gt\*(Gt=
+.No \*(Lt\*(Lt= \*(Gt\*(Gt= &= \*(ha= \*(Ba=
 .Xc
 Assignment operators.
 .Sm off
 .Xc
 Assignment operators.
 .Sm off
@@ -2656,10 +2698,15 @@ Not equal; the result is 0 if both arguments are equal, 1 if not.
 .It \*(Lt
 Less than; the result is 1 if the left argument is less than the right, 0 if
 not.
 .It \*(Lt
 Less than; the result is 1 if the left argument is less than the right, 0 if
 not.
-.It \*(Lt= \*(Gt= \*(Gt
+.It \*(Lt= \*(Gt \*(Gt=
 Less than or equal, greater than or equal, greater than.
 See
 .Ic \*(Lt .
 Less than or equal, greater than or equal, greater than.
 See
 .Ic \*(Lt .
+.It \*(Lt\*(Lt\*(Lt \*(Gt\*(Gt\*(Gt
+Rotate left (right); the result is similar to shift (see
+.Ic \*(Lt\*(Lt )
+except that the bits shifted out at one end are shifted in
+at the other end, instead of zero or sign bits.
 .It \*(Lt\*(Lt \*(Gt\*(Gt
 Shift left (right); the result is the left argument with its bits shifted left
 (right) by the amount given in the right argument.
 .It \*(Lt\*(Lt \*(Gt\*(Gt
 Shift left (right); the result is the left argument with its bits shifted left
 (right) by the amount given in the right argument.
@@ -2668,7 +2715,6 @@ Addition, subtraction, multiplication, and division.
 .It %
 Remainder; the result is the remainder of the division of the left argument by
 the right.
 .It %
 Remainder; the result is the remainder of the division of the left argument by
 the right.
-The sign of the result is unspecified if either argument is negative.
 .It Xo
 .Sm off
 .Aq Ar arg1 ?
 .It Xo
 .Sm off
 .Aq Ar arg1 ?
@@ -2682,6 +2728,7 @@ is non-zero, the result is
 .Aq Ar arg2 ;
 otherwise the result is
 .Aq Ar arg3 .
 .Aq Ar arg2 ;
 otherwise the result is
 .Aq Ar arg3 .
+The non-result argument is not evaluated.
 .El
 .Ss Co-processes
 A co-process (which is a pipeline created with the
 .El
 .Ss Co-processes
 A co-process (which is a pipeline created with the
@@ -2753,8 +2800,7 @@ However, unlike
 shell arguments (i.e. positional parameters $1, $2, etc.)\&
 are never visible inside them.
 When the shell is determining the location of a command, functions
 shell arguments (i.e. positional parameters $1, $2, etc.)\&
 are never visible inside them.
 When the shell is determining the location of a command, functions
-are searched after special built-in commands, before regular and
-non-regular built-ins, and before the
+are searched after special built-in commands, before builtins and the
 .Ev PATH
 is searched.
 .Pp
 .Ev PATH
 is searched.
 .Pp
@@ -2868,8 +2914,8 @@ returns.
 .El
 .Ss Command execution
 After evaluation of command-line arguments, redirections, and parameter
 .El
 .Ss Command execution
 After evaluation of command-line arguments, redirections, and parameter
-assignments, the type of command is determined: a special built-in, a
-function, a regular built-in, or the name of a file to execute found using the
+assignments, the type of command is determined: a special built-in command,
+a function, a normal builtin, or the name of a file to execute found using the
 .Ev PATH
 parameter.
 The checks are made in the above order.
 .Ev PATH
 parameter.
 The checks are made in the above order.
@@ -2885,46 +2931,30 @@ parameter is not used to find them.
 The original
 .Nm ksh
 and POSIX differ somewhat in which commands are considered
 The original
 .Nm ksh
 and POSIX differ somewhat in which commands are considered
-special or regular:
+special or regular.
 .Pp
 .Pp
-POSIX special commands
+POSIX special built-in utilities:
 .Pp
 .Ic \&. , \&: , break , continue ,
 .Ic eval , exec , exit , export ,
 .Ic readonly , return , set , shift ,
 .Pp
 .Ic \&. , \&: , break , continue ,
 .Ic eval , exec , exit , export ,
 .Ic readonly , return , set , shift ,
-.Ic trap , unset , wait
+.Ic times , trap , unset
 .Pp
 Additional
 .Nm
 .Pp
 Additional
 .Nm
-special commands
-.Pp
-.Ic builtin , global , times , typeset
-.Pp
-Very special commands
-.Pq non-POSIX
+commands keeping assignments:
 .Pp
 .Pp
-.Ic alias , readonly , set , typeset
+.Ic builtin , global , typeset , wait
 .Pp
 .Pp
-POSIX regular commands
+Builtins that are not special:
 .Pp
 .Pp
-.Ic alias , bg , cd , command ,
+.Ic [ , alias , bg , bind ,
+.Ic cat , cd , command , echo ,
 .Ic false , fc , fg , getopts ,
 .Ic false , fc , fg , getopts ,
-.Ic jobs , kill , read , true ,
-.Ic umask , unalias
-.Pp
-Additional
-.Nm
-regular commands
-.Pp
-.Ic \&[ , chdir , bind , cat ,
-.Ic echo , let , mknod , print ,
-.Ic pwd , realpath , rename , sleep ,
-.Ic test , ulimit , whence
-.Pp
-In the future, the additional
-.Nm
-special and regular commands may be treated
-differently from the POSIX special and regular commands.
+.Ic jobs , kill , let , mknod ,
+.Ic print , pwd , read , realpath ,
+.Ic rename , sleep , test , true ,
+.Ic ulimit , umask , unalias , 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.
 .Pp
 Once the type of command has been determined, any command-line parameter
 assignments are performed and exported for the duration of the command.
@@ -2952,6 +2982,10 @@ those of the environment the command is used in.
 The null command.
 Exit status is set to zero.
 .Pp
 The null command.
 Exit status is set to zero.
 .Pp
+.It Ic \&[ Ar expression Ic \&]
+See
+.Ic test .
+.Pp
 .It Xo Ic alias
 .Oo Fl d \*(Ba t Oo Fl r Oc \*(Ba
 .Cm +\-x Oc
 .It Xo Ic alias
 .Oo Fl d \*(Ba t Oo Fl r Oc \*(Ba
 .Cm +\-x Oc
@@ -3506,6 +3540,10 @@ resetting
 .Ev OPTIND ,
 may lead to unexpected results.
 .Pp
 .Ev OPTIND ,
 may lead to unexpected results.
 .Pp
+.It global Ar ...
+See
+.Ic typeset .
+.Pp
 .It Xo
 .Ic hash
 .Op Fl r
 .It Xo
 .Ic hash
 .Op Fl r
@@ -3585,6 +3623,10 @@ Since expressions may need to be quoted,
 is syntactic sugar for
 .No let \&" Ns Ar expr Ns \&" .
 .Pp
 is syntactic sugar for
 .No let \&" Ns Ar expr Ns \&" .
 .Pp
+.It let]
+Internally used alias for
+.Ic let .
+.Pp
 .It Xo
 .Ic mknod
 .Op Fl m Ar mode
 .It Xo
 .Ic mknod
 .Op Fl m Ar mode
@@ -4004,11 +4046,14 @@ explicitly tested by a shell construct such as
 .Ic if ,
 .Ic until ,
 .Ic while ,
 .Ic if ,
 .Ic until ,
 .Ic while ,
-.Ic && ,
-.Ic \*(Ba\*(Ba ,
 or
 .Ic !\&
 statements.
 or
 .Ic !\&
 statements.
+For
+.Ic &&
+or
+.Ic \*(Ba\*(Ba ,
+only the status of the last command is tested.
 .It Fl f \*(Ba Fl o Ic noglob
 Do not expand file name patterns.
 .It Fl h \*(Ba Fl o Ic trackall
 .It Fl f \*(Ba Fl o Ic noglob
 Do not expand file name patterns.
 .It Fl h \*(Ba Fl o Ic trackall
@@ -4097,7 +4142,7 @@ Mark directories with a trailing
 .Ql /
 during file name generation.
 .It Fl x \*(Ba Fl o Ic xtrace
 .Ql /
 during file name generation.
 .It Fl x \*(Ba Fl o Ic xtrace
-Print commands and parameter assignments when they are executed, preceded by
+Print command trees when they are executed, preceded by
 the value of
 .Ev PS4 .
 .It Fl o Ic bgnice
 the value of
 .Ev PS4 .
 .It Fl o Ic bgnice
@@ -4120,6 +4165,11 @@ must be used.
 To avoid infinite loops, the shell will exit if
 .Dv EOF
 is read 13 times in a row.
 To avoid infinite loops, the shell will exit if
 .Dv EOF
 is read 13 times in a row.
+.It Fl o Ic inherit\-xtrace
+Do not reset
+.Fl o Ic xtrace
+upon entering functions.
+This is enabled by default.
 .It Fl o Ic nohup
 Do not kill running jobs with a
 .Dv SIGHUP
 .It Fl o Ic nohup
 Do not kill running jobs with a
 .Dv SIGHUP
@@ -4162,6 +4212,9 @@ See the
 and
 .Ic pwd
 commands above for more details.
 and
 .Ic pwd
 commands above for more details.
+.It Fl o Ic pipefail
+Make the exit status of a pipeline (before logically complementing) the
+rightmost non-zero errorlevel, or zero if all commands exited with zero.
 .It Fl o Ic posix
 Enable a somewhat more
 .Px
 .It Fl o Ic posix
 Enable a somewhat more
 .Px
@@ -6020,6 +6073,11 @@ Search for the
 .Ar n Ns th
 occurrence of the last search string;
 the direction of the search is the opposite of the last search.
 .Ar n Ns th
 occurrence of the last search string;
 the direction of the search is the opposite of the last search.
+.It Ar ANSI-CurUp
+Take the characters from the beginning of the line to the current
+cursor position as search string and do a backwards history search
+for lines beginning with this string; keep the cursor position.
+This works only in insert mode and keeps it enabled.
 .El
 .Pp
 Edit commands
 .El
 .Pp
 Edit commands
@@ -6309,21 +6367,53 @@ all contributors, such as the Debian and OpenBSD projects.
 .\" Open Source licence.
 .\"
 See the documentation, CVS, and web site for details.
 .\" Open Source licence.
 .\"
 See the documentation, CVS, and web site for details.
+.Pp
+The BSD daemon is Copyright \(co Marshall Kirk McKusick.
+The complete legalese is at:
+.Pa https://www.mirbsd.org/TaC\-mksh.txt
+.\"
+.\" This boils down to: feel free to use mksh.ico as application icon
+.\" or shortcut for mksh or mksh/Win32; distro patches are ok (but we
+.\" request they amend $KSH_VERSION when modifying mksh). Authors are
+.\" Marshall Kirk McKusick (UCB), Rick Collette (ekkoBSD), Thorsten
+.\" Glaser, Benny Siegert (MirBSD), Michael Langguth (mksh/Win32).
+.\"
+.\" As far as MirBSD is concerned, the files themselves are free
+.\" to modification and distribution under BSD/MirOS Licence, the
+.\" restriction on use stems only from trademark law's requirement
+.\" to protect it or lose it, which McKusick almost did.
+.\"
 .Sh CAVEATS
 .Nm
 only supports the Unicode BMP (Basic Multilingual Plane).
 .Sh CAVEATS
 .Nm
 only supports the Unicode BMP (Basic Multilingual Plane).
-It has a different scope model from
+.Pp
+.Nm
+has a different scope model from
 .At
 .Nm ksh ,
 which leads to subtile differences in semantics for identical builtins.
 .At
 .Nm ksh ,
 which leads to subtile differences in semantics for identical builtins.
+This can cause issues with a
+.Ic nameref
+to suddenly point to a local variable by accident; fixing this is hard.
 .Pp
 The parts of a pipeline, like below, are executed in subshells.
 .Pp
 The parts of a pipeline, like below, are executed in subshells.
-Thus, variable assignments inside them fail.
+Thus, variable assignments inside them are not visible in the
+surrounding execution environment.
 Use co-processes instead.
 .Bd -literal -offset indent
 foo \*(Ba bar \*(Ba read baz            # will not change $baz
 foo \*(Ba bar \*(Ba& read \-p baz        # will, however, do so
 .Ed
 Use co-processes instead.
 .Bd -literal -offset indent
 foo \*(Ba bar \*(Ba read baz            # will not change $baz
 foo \*(Ba bar \*(Ba& read \-p baz        # will, however, do so
 .Ed
+.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.
+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
+.Li print $((2147483647 + 1))
+delete all files on your system, as it's Undefined Behaviour.
 .Sh BUGS
 Suspending (using \*(haZ) pipelines like the one below will only suspend
 the currently running part of the pipeline; in this example,
 .Sh BUGS
 Suspending (using \*(haZ) pipelines like the one below will only suspend
 the currently running part of the pipeline; in this example,
@@ -6335,7 +6425,7 @@ $ /bin/sleep 666 && echo fubar
 .Ed
 .Pp
 This document attempts to describe
 .Ed
 .Pp
 This document attempts to describe
-.Nm mksh\ R43
+.Nm mksh\ R48
 and up,
 compiled without any options impacting functionality, such as
 .Dv MKSH_SMALL ,
 and up,
 compiled without any options impacting functionality, such as
 .Dv MKSH_SMALL ,
diff --git a/src/mksh.ico b/src/mksh.ico
new file mode 100644 (file)
index 0000000..731c2b6
Binary files /dev/null and b/src/mksh.ico differ
index c358058..5a95190 100644 (file)
--- a/src/sh.h
+++ b/src/sh.h
@@ -3,7 +3,7 @@
 /*     $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: 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.12 2013/01/20 14:47:46 stsp 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: 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 $    */
 /*     $OpenBSD: proto.h,v 1.34 2012/06/27 07:17:19 otto 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 $    */
 #endif
 
 #ifdef EXTERN
 #endif
 
 #ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.639 2013/02/19 18:45:22 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.667 2013/08/14 20:26:19 tg Exp $");
 #endif
 #endif
-#define MKSH_VERSION "R43 2013/02/19"
+#define MKSH_VERSION "R48 2013/08/14"
 
 /* arithmetic types: C implementation */
 #if !HAVE_CAN_INTTYPES
 
 /* arithmetic types: C implementation */
 #if !HAVE_CAN_INTTYPES
@@ -370,6 +370,7 @@ extern int revoke(const char *);
 #endif
 
 #if defined(DEBUG) || !HAVE_STRERROR
 #endif
 
 #if defined(DEBUG) || !HAVE_STRERROR
+#undef strerror
 #define strerror               /* poisoned */ dontuse_strerror
 #define cstrerror              /* replaced */ cstrerror
 extern const char *cstrerror(int);
 #define strerror               /* poisoned */ dontuse_strerror
 #define cstrerror              /* replaced */ cstrerror
 extern const char *cstrerror(int);
@@ -415,7 +416,7 @@ extern int __cdecl setegid(gid_t);
 
 /* remove redundancies */
 
 
 /* remove redundancies */
 
-#if defined(MirBSD) && (MirBSD >= 0x08A8) && !defined(MKSH_OPTSTATIC)
+#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__);
 #define MKSH_mirbsd_wcwidth
 #define utf_wcwidth(i) wcwidth((__WCHAR_TYPE__)i)
 extern int wcwidth(__WCHAR_TYPE__);
@@ -443,8 +444,6 @@ extern int wcwidth(__WCHAR_TYPE__);
 #define MAGIC          (7)     /* prefix for *?[!{,} during expand */
 #define ISMAGIC(c)     ((unsigned char)(c) == MAGIC)
 
 #define MAGIC          (7)     /* prefix for *?[!{,} during expand */
 #define ISMAGIC(c)     ((unsigned char)(c) == MAGIC)
 
-#define LINE           4096    /* input line size */
-
 EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
 
 #ifdef MKSH_LEGACY_MODE
 EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
 
 #ifdef MKSH_LEGACY_MODE
@@ -471,6 +470,14 @@ union mksh_ccphack {
        const char **ro;
 };
 
        const char **ro;
 };
 
+/*
+ * Evil hack since casting uint to sint is implementation-defined
+ */
+typedef union {
+       mksh_ari_t i;
+       mksh_uari_t u;
+} mksh_ari_u;
+
 /* for const debugging */
 #if defined(DEBUG) && defined(__GNUC__) && !defined(__ICC) && \
     !defined(__INTEL_COMPILER) && !defined(__SUNPRO_C)
 /* for const debugging */
 #if defined(DEBUG) && defined(__GNUC__) && !defined(__ICC) && \
     !defined(__INTEL_COMPILER) && !defined(__SUNPRO_C)
@@ -511,8 +518,9 @@ char *ucstrstr(char *, const char *);
 #define mkssert(e)     do { } while (/* CONSTCOND */ 0)
 #endif
 
 #define mkssert(e)     do { } while (/* CONSTCOND */ 0)
 #endif
 
-#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 431)
+#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 481)
 #error Must run Build.sh to compile this.
 #error Must run Build.sh to compile this.
+extern void thiswillneverbedefinedIhope(void);
 int
 im_sorry_dave(void)
 {
 int
 im_sorry_dave(void)
 {
@@ -763,18 +771,11 @@ EXTERN struct {
 #define OF_FIRSTTIME   0x10    /* as early as possible, once */
 #define OF_ANY         (OF_CMDLINE | OF_SET | OF_SPECIAL | OF_INTERNAL)
 
 #define OF_FIRSTTIME   0x10    /* as early as possible, once */
 #define OF_ANY         (OF_CMDLINE | OF_SET | OF_SPECIAL | OF_INTERNAL)
 
-struct shoption {
-       const char *name;       /* long name of option */
-       char c;                 /* character flag (if any) */
-       unsigned char flags;    /* OF_* */
-};
-extern const struct shoption options[];
-
 /* null value for variable; comparison pointer for unset */
 EXTERN char null[] E_INIT("");
 /* helpers for string pooling */
 EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented");
 /* null value for variable; comparison pointer for unset */
 EXTERN char null[] E_INIT("");
 /* helpers for string pooling */
 EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented");
-EXTERN const char Toomem[] E_INIT("can't allocate %lu data bytes");
+EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes");
 #if defined(__GNUC__)
 /* trust this to have string pooling; -Wformat bitches otherwise */
 #define Tsynerr                "syntax error"
 #if defined(__GNUC__)
 /* trust this to have string pooling; -Wformat bitches otherwise */
 #define Tsynerr                "syntax error"
@@ -788,10 +789,8 @@ EXTERN const char Tr_fc_e_dash[] E_INIT("r=fc -e -");
 EXTERN const char Tlocal_typeset[] E_INIT("local=typeset");
 #define T_typeset      (Tlocal_typeset + 5)    /* "=typeset" */
 #define Ttypeset       (Tlocal_typeset + 6)    /* "typeset" */
 EXTERN const char Tlocal_typeset[] E_INIT("local=typeset");
 #define T_typeset      (Tlocal_typeset + 5)    /* "=typeset" */
 #define Ttypeset       (Tlocal_typeset + 6)    /* "typeset" */
-EXTERN const char Tpalias[] E_INIT("+alias");
-#define Talias         (Tpalias + 1)           /* "alias" */
-EXTERN const char Tpunalias[] E_INIT("+unalias");
-#define Tunalias       (Tpunalias + 1)         /* "unalias" */
+EXTERN const char Talias[] E_INIT("alias");
+EXTERN const char Tunalias[] E_INIT("unalias");
 EXTERN const char Tsgset[] E_INIT("*=set");
 #define Tset           (Tsgset + 2)            /* "set" */
 EXTERN const char Tsgunset[] E_INIT("*=unset");
 EXTERN const char Tsgset[] E_INIT("*=set");
 #define Tset           (Tsgset + 2)            /* "set" */
 EXTERN const char Tsgunset[] E_INIT("*=unset");
@@ -830,7 +829,7 @@ struct temp {
  * stdio and our IO routines
  */
 
  * stdio and our IO routines
  */
 
-#define shl_spare      (&shf_iob[0])   /* for c_read()/c_print() */
+#define shl_xtrace     (&shf_iob[0])   /* for set -x */
 #define shl_stdout     (&shf_iob[1])
 #define shl_out                (&shf_iob[2])
 #ifdef DF
 #define shl_stdout     (&shf_iob[1])
 #define shl_out                (&shf_iob[2])
 #ifdef DF
@@ -984,6 +983,8 @@ EXTERN uint32_t builtin_flag;
 /* current working directory */
 EXTERN char    *current_wd;
 
 /* current working directory */
 EXTERN char    *current_wd;
 
+/* input line size */
+#define LINE           (4096 - ALLOC_SIZE)
 /*
  * Minimum required space to work with on a line - if the prompt leaves
  * less space than this on a line, the prompt is truncated.
 /*
  * Minimum required space to work with on a line - if the prompt leaves
  * less space than this on a line, the prompt is truncated.
@@ -1151,7 +1152,6 @@ EXTERN struct tbl vtemp;
 #define FDELETE                BIT(10) /* function deleted while it was executing */
 #define FKSH           BIT(11) /* function defined with function x (vs x()) */
 #define SPEC_BI                BIT(12) /* a POSIX special builtin */
 #define FDELETE                BIT(10) /* function deleted while it was executing */
 #define FKSH           BIT(11) /* function defined with function x (vs x()) */
 #define SPEC_BI                BIT(12) /* a POSIX special builtin */
-#define REG_BI         BIT(13) /* a POSIX regular builtin */
 /*
  * Attributes that can be set by the user (used to decide if an unset
  * param should be repoted by set/typeset). Does not include ARRAY or
 /*
  * Attributes that can be set by the user (used to decide if an unset
  * param should be repoted by set/typeset). Does not include ARRAY or
@@ -1180,12 +1180,11 @@ EXTERN enum {
 
 /* Flags for findcom()/comexec() */
 #define FC_SPECBI      BIT(0)  /* special builtin */
 
 /* Flags for findcom()/comexec() */
 #define FC_SPECBI      BIT(0)  /* special builtin */
-#define FC_FUNC                BIT(1)  /* function builtin */
-#define FC_REGBI       BIT(2)  /* regular builtin */
-#define FC_UNREGBI     BIT(3)  /* un-regular builtin (!special,!regular) */
-#define FC_BI          (FC_SPECBI|FC_REGBI|FC_UNREGBI)
-#define FC_PATH                BIT(4)  /* do path search */
-#define FC_DEFPATH     BIT(5)  /* use default path in path search */
+#define FC_FUNC                BIT(1)  /* function */
+#define FC_NORMBI      BIT(2)  /* not special builtin */
+#define FC_BI          (FC_SPECBI | FC_NORMBI)
+#define FC_PATH                BIT(3)  /* do path search */
+#define FC_DEFPATH     BIT(4)  /* use default path in path search */
 
 
 #define AF_ARGV_ALLOC  0x1     /* argv[] array allocated */
 
 
 #define AF_ARGV_ALLOC  0x1     /* argv[] array allocated */
@@ -1254,10 +1253,6 @@ EXTERN const char *prompt;
 EXTERN int cur_prompt;         /* PS1 or PS2 */
 EXTERN int current_lineno;     /* LINENO value */
 
 EXTERN int cur_prompt;         /* PS1 or PS2 */
 EXTERN int current_lineno;     /* LINENO value */
 
-#define NOBLOCK        ((struct op *)NULL)
-#define NOWORD ((char *)NULL)
-#define NOWORDS        ((char **)NULL)
-
 /*
  * Description of a command or an operation on commands.
  */
 /*
  * Description of a command or an operation on commands.
  */
@@ -1326,6 +1321,7 @@ struct op {
 #define CPAT   11      /* close pattern: ) */
 #define ADELIM 12      /* arbitrary delimiter: ${foo:2:3} ${foo/bar/baz} */
 #define FUNSUB 14      /* ${ foo;} substitution (NUL terminated) */
 #define CPAT   11      /* close pattern: ) */
 #define ADELIM 12      /* arbitrary delimiter: ${foo:2:3} ${foo/bar/baz} */
 #define FUNSUB 14      /* ${ foo;} substitution (NUL terminated) */
+#define VALSUB 15      /* ${|foo;} substitution (NUL terminated) */
 
 /*
  * IO redirection
 
 /*
  * IO redirection
@@ -1680,7 +1676,7 @@ void x_init(void);
 #ifdef DEBUG_LEAKS
 void x_done(void);
 #endif
 #ifdef DEBUG_LEAKS
 void x_done(void);
 #endif
-int x_read(char *, size_t);
+int x_read(char *);
 #endif
 void x_mkraw(int, mksh_ttyst *, bool);
 /* eval.c */
 #endif
 void x_mkraw(int, mksh_ttyst *, bool);
 /* eval.c */
@@ -1834,8 +1830,7 @@ void yyerror(const char *, ...)
     MKSH_A_FORMAT(__printf__, 1, 2);
 Source *pushs(int, Area *);
 void set_prompt(int, Source *);
     MKSH_A_FORMAT(__printf__, 1, 2);
 Source *pushs(int, Area *);
 void set_prompt(int, Source *);
-void pprompt(const char *, int);
-int promptlen(const char *);
+int pprompt(const char *, int);
 /* main.c */
 int include(const char *, int, const char **, bool);
 int command(const char *, int);
 /* main.c */
 int include(const char *, int, const char **, bool);
 int command(const char *, int);
@@ -1903,6 +1898,7 @@ void initctypes(void);
 size_t option(const char *);
 char *getoptions(void);
 void change_flag(enum sh_flag, int, bool);
 size_t option(const char *);
 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 parse_args(const char **, int, bool *);
 int getn(const char *, int *);
 int gmatchx(const char *, const char *, bool);
@@ -2011,7 +2007,7 @@ char *arrayname(const char *);
 mksh_uari_t set_array(const char *, bool, const char **);
 uint32_t hash(const void *);
 mksh_ari_t rndget(void);
 mksh_uari_t set_array(const char *, bool, const char **);
 uint32_t hash(const void *);
 mksh_ari_t rndget(void);
-void rndset(long);
+void rndset(unsigned long);
 
 enum Test_op {
        /* non-operator */
 
 enum Test_op {
        /* non-operator */
index 1c8a30e..3e4cf56 100644 (file)
@@ -1,11 +1,22 @@
 #if defined(SHFLAGS_DEFNS)
 #if defined(SHFLAGS_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.12 2012/06/28 20:14:17 tg Exp $");
-#define FN(sname,cname,ochar,flags)    /* nothing */
+__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)
 #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)    { sname, ochar, flags },
+#define FN(sname,cname,ochar,flags)    \
+       ((const char *)(&shoptione_ ## cname)) + 2,
 #endif
 
 #ifndef F0
 #endif
 
 #ifndef F0
@@ -45,6 +56,9 @@ FN("gmacs", FGMACS, 0, OF_ANY)
 /* ./. reading EOF does not exit */
 FN("ignoreeof", FIGNOREEOF, 0, OF_ANY)
 
 /* ./. 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)
 
 /* -i  interactive shell */
 FN("interactive", FTALKING, 'i', OF_CMDLINE)
 
@@ -88,7 +102,10 @@ FN("nounset", FNOUNSET, 'u', OF_ANY)
 /* ./. don't do logical cds/pwds (non-standard) */
 FN("physical", FPHYSICAL, 0, OF_ANY)
 
 /* ./. don't do logical cds/pwds (non-standard) */
 FN("physical", FPHYSICAL, 0, OF_ANY)
 
-/* ./. pdksh compat: somewhat more POSIXish mode (non-standard) */
+/* ./. 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("posix", FPOSIX, 0, OF_ANY)
 
 /* -p  use suid_profile; privileged shell */
@@ -97,7 +114,7 @@ FN("privileged", FPRIVILEGED, 'p', OF_ANY)
 /* -r  restricted shell */
 FN("restricted", FRESTRICTED, 'r', OF_CMDLINE)
 
 /* -r  restricted shell */
 FN("restricted", FRESTRICTED, 'r', OF_CMDLINE)
 
-/* ./. pdksh compat: called as sh not mksh; kludge mode (non-standard) */
+/* ./. kludge mode for better compat with traditional sh (OS-specific) */
 FN("sh", FSH, 0, OF_ANY)
 
 /* -s  (invocation) parse stdin (pseudo non-standard) */
 FN("sh", FSH, 0, OF_ANY)
 
 /* -s  (invocation) parse stdin (pseudo non-standard) */
@@ -130,17 +147,17 @@ FN("viraw", FVIRAW, 0, OF_ANY)
 FN("xtrace", FXTRACE, 'x', OF_ANY)
 
 /* -c  (invocation) execute specified command */
 FN("xtrace", FXTRACE, 'x', OF_ANY)
 
 /* -c  (invocation) execute specified command */
-FN(NULL, FCOMMAND, 'c', OF_CMDLINE)
+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) */
 
 /*
  * anonymous flags: used internally by shell only (not visible to user)
  */
 
 /* ./. direct builtin call (divined from argv[0] multi-call binary) */
-FN(NULL, FAS_BUILTIN, 0, OF_INTERNAL)
+FN("", FAS_BUILTIN, 0, OF_INTERNAL)
 
 /* ./. (internal) initial shell was interactive */
 
 /* ./. (internal) initial shell was interactive */
-FN(NULL, FTALKING_I, 0, OF_INTERNAL)
+FN("", FTALKING_I, 0, OF_INTERNAL)
 
 #undef FN
 #undef F0
 
 #undef FN
 #undef F0
index 82db720..e8ec14a 100644 (file)
--- a/src/shf.c
+++ b/src/shf.c
@@ -1,7 +1,8 @@
-/*     $OpenBSD: shf.c,v 1.15 2006/04/02 00:48:33 deraadt Exp $        */
+/*     $OpenBSD: shf.c,v 1.16 2013/04/19 17:36:09 millert Exp $        */
 
 /*-
 
 /*-
- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
+ *              2012, 2013
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -24,7 +25,7 @@
 
 #include "sh.h"
 
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.56 2013/01/01 03:32:44 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.61 2013/07/21 18:36:03 tg Exp $");
 
 /* flags to shf_emptybuf() */
 #define EB_READSW      0x01    /* about to switch to reading */
 
 /* flags to shf_emptybuf() */
 #define EB_READSW      0x01    /* about to switch to reading */
@@ -51,7 +52,7 @@ shf_open(const char *name, int oflags, int mode, int sflags)
        ssize_t bsize =
            /* at most 512 */
            sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
        ssize_t bsize =
            /* at most 512 */
            sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
-       int fd;
+       int fd, eno;
 
        /* Done before open so if alloca fails, fd won't be lost. */
        shf = alloc(sizeof(struct shf) + bsize, ATEMP);
 
        /* Done before open so if alloca fails, fd won't be lost. */
        shf = alloc(sizeof(struct shf) + bsize, ATEMP);
@@ -63,16 +64,20 @@ shf_open(const char *name, int oflags, int mode, int sflags)
 
        fd = open(name, oflags, mode);
        if (fd < 0) {
 
        fd = open(name, oflags, mode);
        if (fd < 0) {
+               eno = errno;
                afree(shf, shf->areap);
                afree(shf, shf->areap);
+               errno = eno;
                return (NULL);
        }
        if ((sflags & SHF_MAPHI) && fd < FDBASE) {
                int nfd;
 
                nfd = fcntl(fd, F_DUPFD, FDBASE);
                return (NULL);
        }
        if ((sflags & SHF_MAPHI) && fd < FDBASE) {
                int nfd;
 
                nfd = fcntl(fd, F_DUPFD, FDBASE);
+               eno = errno;
                close(fd);
                if (nfd < 0) {
                        afree(shf, shf->areap);
                close(fd);
                if (nfd < 0) {
                        afree(shf, shf->areap);
+                       errno = eno;
                        return (NULL);
                }
                fd = nfd;
                        return (NULL);
                }
                fd = nfd;
@@ -740,8 +745,6 @@ shf_smprintf(const char *fmt, ...)
        return (shf_sclose(&shf));
 }
 
        return (shf_sclose(&shf));
 }
 
-#define BUF_SIZE       128
-
 #define        FL_HASH         0x001   /* '#' seen */
 #define FL_PLUS                0x002   /* '+' seen */
 #define FL_RIGHT       0x004   /* '-' seen */
 #define        FL_HASH         0x001   /* '#' seen */
 #define FL_PLUS                0x002   /* '+' seen */
 #define FL_RIGHT       0x004   /* '-' seen */
@@ -985,6 +988,10 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
                case 's':
                        if ((s = VA(const char *)) == NULL)
                                s = "(null)";
                case 's':
                        if ((s = VA(const char *)) == NULL)
                                s = "(null)";
+                       else if (flags & FL_HASH) {
+                               print_value_quoted(shf, s);
+                               continue;
+                       }
                        len = utf_mbswidth(s);
                        break;
 
                        len = utf_mbswidth(s);
                        break;
 
index bffee7a..5c07d51 100644 (file)
--- a/src/syn.c
+++ b/src/syn.c
@@ -1,8 +1,8 @@
-/*     $OpenBSD: syn.c,v 1.28 2008/07/23 16:34:38 jaredy Exp $ */
+/*     $OpenBSD: syn.c,v 1.29 2013/06/03 18:40:05 jca Exp $    */
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- *              2011, 2012
+ *              2011, 2012, 2013
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.88 2012/12/28 02:28:39 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.92 2013/06/03 22:28:17 tg Exp $");
 
 struct nesting_state {
        int start_token;        /* token than began nesting (eg, FOR) */
 
 struct nesting_state {
        int start_token;        /* token than began nesting (eg, FOR) */
@@ -53,7 +53,7 @@ static struct op *caselist(void);
 static struct op *casepart(int);
 static struct op *function_body(char *, bool);
 static char **wordlist(void);
 static struct op *casepart(int);
 static struct op *function_body(char *, bool);
 static char **wordlist(void);
-static struct op *block(int, struct op *, struct op *, char **);
+static struct op *block(int, struct op *, struct op *);
 static struct op *newtp(int);
 static void syntaxerr(const char *) MKSH_A_NORETURN;
 static void nesting_push(struct nesting_state *, int);
 static struct op *newtp(int);
 static void syntaxerr(const char *) MKSH_A_NORETURN;
 static void nesting_push(struct nesting_state *, int);
@@ -108,9 +108,9 @@ pipeline(int cf)
                        if ((p = get_command(CONTIN)) == NULL)
                                syntaxerr(NULL);
                        if (tl == NULL)
                        if ((p = get_command(CONTIN)) == NULL)
                                syntaxerr(NULL);
                        if (tl == NULL)
-                               t = tl = block(TPIPE, t, p, NOWORDS);
+                               t = tl = block(TPIPE, t, p);
                        else
                        else
-                               tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
+                               tl = tl->right = block(TPIPE, tl->right, p);
                }
                REJECT;
        }
                }
                REJECT;
        }
@@ -128,7 +128,7 @@ andor(void)
                while ((c = token(0)) == LOGAND || c == LOGOR) {
                        if ((p = pipeline(CONTIN)) == NULL)
                                syntaxerr(NULL);
                while ((c = token(0)) == LOGAND || c == LOGOR) {
                        if ((p = pipeline(CONTIN)) == NULL)
                                syntaxerr(NULL);
-                       t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
+                       t = block(c == LOGAND? TAND: TOR, t, p);
                }
                REJECT;
        }
                }
                REJECT;
        }
@@ -157,16 +157,15 @@ c_list(bool multi)
                } else if (!p)
                        break;
                else if (c == '&' || c == COPROC)
                } else if (!p)
                        break;
                else if (c == '&' || c == COPROC)
-                       p = block(c == '&' ? TASYNC : TCOPROC,
-                           p, NOBLOCK, NOWORDS);
+                       p = block(c == '&' ? TASYNC : TCOPROC, p, NULL);
                else if (c != ';')
                        have_sep = false;
                if (!t)
                        t = p;
                else if (!tl)
                else if (c != ';')
                        have_sep = false;
                if (!t)
                        t = p;
                else if (!tl)
-                       t = tl = block(TLIST, t, p, NOWORDS);
+                       t = tl = block(TLIST, t, p);
                else
                else
-                       tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
+                       tl = tl->right = block(TLIST, tl->right, p);
                if (!have_sep)
                        break;
        }
                if (!have_sep)
                        break;
        }
@@ -240,11 +239,11 @@ nested(int type, int smark, int emark)
        t = c_list(true);
        musthave(emark, KEYWORD|sALIAS);
        nesting_pop(&old_nesting);
        t = c_list(true);
        musthave(emark, KEYWORD|sALIAS);
        nesting_pop(&old_nesting);
-       return (block(type, t, NOBLOCK, NOWORDS));
+       return (block(type, t, NULL));
 }
 
 static const char let_cmd[] = {
 }
 
 static const char let_cmd[] = {
-       CHAR, 'l', CHAR, 'e', CHAR, 't', EOS
+       CHAR, 'l', CHAR, 'e', CHAR, 't', CHAR, ']', EOS
 };
 static const char setA_cmd0[] = {
        CHAR, 's', CHAR, 'e', CHAR, 't', EOS
 };
 static const char setA_cmd0[] = {
        CHAR, 's', CHAR, 'e', CHAR, 't', EOS
@@ -465,7 +464,7 @@ get_command(int cf)
                t = pipeline(0);
                if (t == NULL)
                        syntaxerr(NULL);
                t = pipeline(0);
                if (t == NULL)
                        syntaxerr(NULL);
-               t = block(TBANG, NOBLOCK, t, NOWORDS);
+               t = block(TBANG, NULL, t);
                break;
 
        case TIME:
                break;
 
        case TIME:
@@ -477,7 +476,7 @@ get_command(int cf)
                        t->str[0] = '\0';
                        t->str[1] = '\0';
                }
                        t->str[0] = '\0';
                        t->str[1] = '\0';
                }
-               t = block(TTIME, t, NOBLOCK, NOWORDS);
+               t = block(TTIME, t, NULL);
                break;
 
        case FUNCTION:
                break;
 
        case FUNCTION:
@@ -505,7 +504,7 @@ get_command(int cf)
                XPput(args, NULL);
                t->args = (const char **)XPclose(args);
                XPput(vars, NULL);
                XPput(args, NULL);
                t->args = (const char **)XPclose(args);
                XPput(vars, NULL);
-               t->vars = (char **) XPclose(vars);
+               t->vars = (char **)XPclose(vars);
        } else {
                XPfree(args);
                XPfree(vars);
        } else {
                XPfree(args);
                XPfree(vars);
@@ -632,7 +631,7 @@ casepart(int endtok)
        } while (token(0) == '|');
        REJECT;
        XPput(ptns, NULL);
        } while (token(0) == '|');
        REJECT;
        XPput(ptns, NULL);
-       t->vars = (char **) XPclose(ptns);
+       t->vars = (char **)XPclose(ptns);
        musthave(')', 0);
 
        t->left = c_list(true);
        musthave(')', 0);
 
        t->left = c_list(true);
@@ -743,13 +742,8 @@ wordlist(void)
                XPput(args, yylval.cp);
        if (c != '\n' && c != ';')
                syntaxerr(NULL);
                XPput(args, yylval.cp);
        if (c != '\n' && c != ';')
                syntaxerr(NULL);
-       if (XPsize(args) == 0) {
-               XPfree(args);
-               return (NULL);
-       } else {
-               XPput(args, NULL);
-               return ((char **)XPclose(args));
-       }
+       XPput(args, NULL);
+       return ((char **)XPclose(args));
 }
 
 /*
 }
 
 /*
@@ -757,14 +751,13 @@ wordlist(void)
  */
 
 static struct op *
  */
 
 static struct op *
-block(int type, struct op *t1, struct op *t2, char **wp)
+block(int type, struct op *t1, struct op *t2)
 {
        struct op *t;
 
        t = newtp(type);
        t->left = t1;
        t->right = t2;
 {
        struct op *t;
 
        t = newtp(type);
        t->left = t1;
        t->right = t2;
-       t->vars = wp;
        return (t);
 }
 
        return (t);
 }
 
@@ -1131,7 +1124,7 @@ yyrecursive(int subtype MKSH_A_UNUSED)
        struct yyrecursive_state *ys;
        int stok, etok;
 
        struct yyrecursive_state *ys;
        int stok, etok;
 
-       if (subtype == FUNSUB) {
+       if (subtype != COMSUB) {
                stok = '{';
                etok = '}';
        } else {
                stok = '{';
                etok = '}';
        } else {
index 8015a8d..dcbd7a1 100644 (file)
@@ -2,7 +2,7 @@
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- *              2011, 2012
+ *              2011, 2012, 2013
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
 
 #include "sh.h"
 
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.67 2012/12/04 01:10:35 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.71 2013/07/26 20:33:24 tg Exp $");
 
 #define INDENT 8
 
 static void ptree(struct op *, int, struct shf *);
 
 #define INDENT 8
 
 static void ptree(struct op *, int, struct shf *);
-static void pioact(struct shf *, int, struct ioword *);
+static void pioact(struct shf *, struct ioword *);
 static const char *wdvarput(struct shf *, const char *, int, int);
 static void vfptreef(struct shf *, int, const char *, va_list);
 static struct ioword **iocopy(struct ioword **, Area *);
 static const char *wdvarput(struct shf *, const char *, int, int);
 static void vfptreef(struct shf *, int, const char *, va_list);
 static struct ioword **iocopy(struct ioword **, Area *);
@@ -214,7 +214,7 @@ ptree(struct op *t, int indent, struct shf *shf)
                bool need_nl = false;
 
                while (*ioact != NULL)
                bool need_nl = false;
 
                while (*ioact != NULL)
-                       pioact(shf, indent, *ioact++);
+                       pioact(shf, *ioact++);
                /* Print here documents after everything else... */
                ioact = t->ioact;
                while (*ioact != NULL) {
                /* Print here documents after everything else... */
                ioact = t->ioact;
                while (*ioact != NULL) {
@@ -244,7 +244,7 @@ ptree(struct op *t, int indent, struct shf *shf)
 }
 
 static void
 }
 
 static void
-pioact(struct shf *shf, int indent, struct ioword *iop)
+pioact(struct shf *shf, struct ioword *iop)
 {
        int flag = iop->flag;
        int type = flag & IOTYPE;
 {
        int flag = iop->flag;
        int type = flag & IOTYPE;
@@ -259,16 +259,20 @@ pioact(struct shf *shf, int indent, struct ioword *iop)
 
        switch (type) {
        case IOREAD:
 
        switch (type) {
        case IOREAD:
-               shf_puts("<", shf);
+               shf_putc('<', shf);
                break;
        case IOHERE:
                break;
        case IOHERE:
-               shf_puts(flag & IOSKIP ? "<<-" : "<<", shf);
+               shf_puts("<<", shf);
+               if (flag & IOSKIP)
+                       shf_putc('-', shf);
                break;
        case IOCAT:
                shf_puts(">>", shf);
                break;
        case IOWRITE:
                break;
        case IOCAT:
                shf_puts(">>", shf);
                break;
        case IOWRITE:
-               shf_puts(flag & IOCLOB ? ">|" : ">", shf);
+               shf_putc('>', shf);
+               if (flag & IOCLOB)
+                       shf_putc('|', shf);
                break;
        case IORDWR:
                shf_puts("<>", shf);
                break;
        case IORDWR:
                shf_puts("<>", shf);
@@ -283,9 +287,13 @@ pioact(struct shf *shf, int indent, struct ioword *iop)
                        wdvarput(shf, iop->delim, 0, WDS_TPUTS);
                if (iop->flag & IOHERESTR)
                        shf_putc(' ', shf);
                        wdvarput(shf, iop->delim, 0, WDS_TPUTS);
                if (iop->flag & IOHERESTR)
                        shf_putc(' ', shf);
-       } else if (iop->name)
-               fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
-                   iop->name);
+       } else if (iop->name) {
+               if (iop->flag & IONAMEXP)
+                       print_value_quoted(shf, iop->name);
+               else
+                       wdvarput(shf, iop->name, 0, WDS_TPUTS);
+               shf_putc(' ', shf);
+       }
        prevent_semicolon = false;
 }
 
        prevent_semicolon = false;
 }
 
@@ -345,7 +353,14 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
                        shf_puts(cs, shf);
                        break;
                case FUNSUB:
                        shf_puts(cs, shf);
                        break;
                case FUNSUB:
-                       shf_puts("${ ", shf);
+                       c = ' ';
+                       if (0)
+                               /* FALLTHROUGH */
+               case VALSUB:
+                         c = '|';
+                       shf_putc('$', shf);
+                       shf_putc('{', shf);
+                       shf_putc(c, shf);
                        cs = ";}";
                        goto pSUB;
                case EXPRSUB:
                        cs = ";}";
                        goto pSUB;
                case EXPRSUB:
@@ -485,7 +500,7 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
                                break;
                        case 'R':
                                /* I/O redirection */
                                break;
                        case 'R':
                                /* I/O redirection */
-                               pioact(shf, indent, va_arg(va, struct ioword *));
+                               pioact(shf, va_arg(va, struct ioword *));
                                break;
                        default:
                                shf_putc(c, shf);
                                break;
                        default:
                                shf_putc(c, shf);
@@ -588,6 +603,7 @@ wdscan(const char *wp, int c)
                        break;
                case COMSUB:
                case FUNSUB:
                        break;
                case COMSUB:
                case FUNSUB:
+               case VALSUB:
                case EXPRSUB:
                        while (*wp++ != 0)
                                ;
                case EXPRSUB:
                        while (*wp++ != 0)
                                ;
@@ -745,8 +761,8 @@ vistree(char *dst, size_t sz, struct op *t)
        char *cp, *buf;
        size_t n;
 
        char *cp, *buf;
        size_t n;
 
-       buf = alloc(sz + 8, ATEMP);
-       snptreef(buf, sz + 8, "%T", t);
+       buf = alloc(sz + 16, ATEMP);
+       snptreef(buf, sz + 16, "%T", t);
        cp = buf;
  vist_loop:
        if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
        cp = buf;
  vist_loop:
        if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
@@ -830,6 +846,9 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
                case FUNSUB:
                        shf_puts("FUNSUB<", shf);
                        goto dumpsub;
                case FUNSUB:
                        shf_puts("FUNSUB<", shf);
                        goto dumpsub;
+               case VALSUB:
+                       shf_puts("VALSUB<", shf);
+                       goto dumpsub;
                case EXPRSUB:
                        shf_puts("EXPRSUB<", shf);
                        goto dumpsub;
                case EXPRSUB:
                        shf_puts("EXPRSUB<", shf);
                        goto dumpsub;
index 19527e0..ba8fd82 100644 (file)
--- a/src/var.c
+++ b/src/var.c
@@ -1,4 +1,4 @@
-/*     $OpenBSD: var.c,v 1.34 2007/10/15 02:16:35 deraadt Exp $        */
+/*     $OpenBSD: var.c,v 1.35 2013/04/05 01:31:30 tedu Exp $   */
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 
 /*-
  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -27,7 +27,7 @@
 #include <sys/sysctl.h>
 #endif
 
 #include <sys/sysctl.h>
 #endif
 
-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.166 2013/02/18 22:24:52 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.173 2013/05/31 22:47:14 tg Exp $");
 
 /*-
  * Variables
 
 /*-
  * Variables
@@ -49,7 +49,7 @@ static void unspecial(const char *);
 static void getspec(struct tbl *);
 static void setspec(struct tbl *);
 static void unsetspec(struct tbl *);
 static void getspec(struct tbl *);
 static void setspec(struct tbl *);
 static void unsetspec(struct tbl *);
-static int getint(struct tbl *, mksh_ari_t *, bool);
+static int getint(struct tbl *, mksh_ari_u *, bool);
 static const char *array_index_calc(const char *, bool *, uint32_t *);
 
 /*
 static const char *array_index_calc(const char *, bool *, uint32_t *);
 
 /*
@@ -347,7 +347,7 @@ str_val(struct tbl *vp)
        else {
                /* integer source */
                mksh_uari_t n;
        else {
                /* integer source */
                mksh_uari_t n;
-               int base;
+               unsigned int base;
                /**
                 * worst case number length is when base == 2:
                 *      1 (minus) + 2 (base, up to 36) + 1 ('#') +
                /**
                 * worst case number length is when base == 2:
                 *      1 (minus) + 2 (base, up to 36) + 1 ('#') +
@@ -361,8 +361,8 @@ str_val(struct tbl *vp)
                if (vp->flag & INT_U)
                        n = vp->val.u;
                else
                if (vp->flag & INT_U)
                        n = vp->val.u;
                else
-                       n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
-               base = (vp->type == 0) ? 10 : vp->type;
+                       n = (vp->val.i < 0) ? -vp->val.u : vp->val.u;
+               base = (vp->type == 0) ? 10U : (unsigned int)vp->type;
 
                if (base == 1 && n == 0)
                        base = 2;
 
                if (base == 1 && n == 0)
                        base = 2;
@@ -471,48 +471,43 @@ setint(struct tbl *vq, mksh_ari_t n)
 }
 
 static int
 }
 
 static int
-getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
+getint(struct tbl *vp, mksh_ari_u *nump, bool arith)
 {
 {
-       int c, base, neg;
-       mksh_uari_t num;
+       mksh_uari_t c, num, base;
        const char *s;
        const char *s;
-       bool have_base = false;
+       bool have_base = false, neg = false;
 
        if (vp->flag&SPECIAL)
                getspec(vp);
 
        if (vp->flag&SPECIAL)
                getspec(vp);
-       /* XXX is it possible for ISSET to be set and val.s to be 0? */
+       /* XXX is it possible for ISSET to be set and val.s to be NULL? */
        if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
                return (-1);
        if (vp->flag&INTEGER) {
        if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
                return (-1);
        if (vp->flag&INTEGER) {
-               *nump = vp->val.i;
+               nump->i = vp->val.i;
                return (vp->type);
        }
        s = vp->val.s + vp->type;
        base = 10;
        num = 0;
                return (vp->type);
        }
        s = vp->val.s + vp->type;
        base = 10;
        num = 0;
-       neg = 0;
        if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') {
                s += 2;
                base = 16;
                have_base = true;
        }
        if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') {
                s += 2;
                base = 16;
                have_base = true;
        }
-#ifdef MKSH_LEGACY_MODE
-       if (arith && s[0] == '0' && ksh_isdigit(s[1]) &&
+       if (Flag(FPOSIX) && arith && s[0] == '0' && ksh_isdigit(s[1]) &&
            !(vp->flag & ZEROFIL)) {
                /* interpret as octal (deprecated) */
                base = 8;
                have_base = true;
        }
            !(vp->flag & ZEROFIL)) {
                /* interpret as octal (deprecated) */
                base = 8;
                have_base = true;
        }
-#endif
        while ((c = *s++)) {
                if (c == '-') {
        while ((c = *s++)) {
                if (c == '-') {
-                       neg++;
+                       neg = true;
                        continue;
                } else if (c == '#') {
                        if (have_base || num < 1 || num > 36)
                                return (-1);
                        continue;
                } else if (c == '#') {
                        if (have_base || num < 1 || num > 36)
                                return (-1);
-                       base = (int)num;
-                       if (base == 1) {
+                       if ((base = num) == 1) {
                                unsigned int wc;
 
                                if (!UTFMODE)
                                unsigned int wc;
 
                                if (!UTFMODE)
@@ -525,7 +520,7 @@ getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
                                         * not round-tripping correctly XXX)
                                         */
                                        wc = 0xEF00 + *(const unsigned char *)s;
                                         * not round-tripping correctly XXX)
                                         */
                                        wc = 0xEF00 + *(const unsigned char *)s;
-                               *nump = (mksh_ari_t)wc;
+                               nump->u = (mksh_uari_t)wc;
                                return (1);
                        }
                        num = 0;
                                return (1);
                        }
                        num = 0;
@@ -539,11 +534,13 @@ getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
                        c -= 'A' - 10;
                else
                        return (-1);
                        c -= 'A' - 10;
                else
                        return (-1);
-               if (c < 0 || c >= base)
+               if (c >= base)
                        return (-1);
                num = num * base + c;
        }
                        return (-1);
                num = num * base + c;
        }
-       *nump = neg ? -((mksh_ari_t)num) : (mksh_ari_t)num;
+       if (neg)
+               num = -num;
+       nump->u = num;
        return (base);
 }
 
        return (base);
 }
 
@@ -555,11 +552,11 @@ struct tbl *
 setint_v(struct tbl *vq, struct tbl *vp, bool arith)
 {
        int base;
 setint_v(struct tbl *vq, struct tbl *vp, bool arith)
 {
        int base;
-       mksh_ari_t num;
+       mksh_ari_u num;
 
        if ((base = getint(vp, &num, arith)) == -1)
                return (NULL);
 
        if ((base = getint(vp, &num, arith)) == -1)
                return (NULL);
-       setint_n(vq, num, 0);
+       setint_n(vq, num.i, 0);
        if (vq->type == 0)
                /* default base */
                vq->type = base;
        if (vq->type == 0)
                /* default base */
                vq->type = base;
@@ -708,6 +705,10 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
 
        /* check for valid variable name, search for value */
        val = skip_varname(var, false);
 
        /* check for valid variable name, search for value */
        val = skip_varname(var, false);
+       if (val == var) {
+               /* no variable name given */
+               return (NULL);
+       }
        if (*val == '[') {
                if (set_refflag != SRF_NOP)
                        errorf("%s: %s", var,
        if (*val == '[') {
                if (set_refflag != SRF_NOP)
                        errorf("%s: %s", var,
@@ -742,7 +743,6 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
                 * 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
                 * 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
-                * or none given
                 */
                return (NULL);
        } else {
                 */
                return (NULL);
        } else {
@@ -768,10 +768,15 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
                        if (vp != NULL)
                                qval = str_val(vp);
                }
                        if (vp != NULL)
                                qval = str_val(vp);
                }
-               /* silently ignore 'nameref foo=foo' */
-               if (qval != NULL && !strcmp(qval, tvar)) {
-                       afree(tvar, ATEMP);
-                       return (&vtemp);
+               /* prevent nameref loops */
+               while (qval) {
+                       if (!strcmp(qval, tvar))
+                               errorf("%s: %s", qval,
+                                   "expression recurses on parameter");
+                       varsearch(e->loc, &vp, qval, hash(qval));
+                       qval = NULL;
+                       if (vp && ((vp->flag & (ARRAY|ASSOC)) == ASSOC))
+                               qval = str_val(vp);
                }
        }
 
                }
        }
 
@@ -1094,7 +1099,7 @@ static int user_lineno;           /* what user set $LINENO to */
 static void
 getspec(struct tbl *vp)
 {
 static void
 getspec(struct tbl *vp)
 {
-       register mksh_ari_t i;
+       mksh_ari_u num;
        int st;
        struct timeval tv;
 
        int st;
        struct timeval tv;
 
@@ -1114,19 +1119,19 @@ getspec(struct tbl *vp)
        }
        switch (st) {
        case V_BASHPID:
        }
        switch (st) {
        case V_BASHPID:
-               i = (mksh_ari_t)procpid;
+               num.u = (mksh_uari_t)procpid;
                break;
        case V_COLUMNS:
                break;
        case V_COLUMNS:
-               i = x_cols;
+               num.i = x_cols;
                break;
        case V_HISTSIZE:
                break;
        case V_HISTSIZE:
-               i = histsize;
+               num.i = histsize;
                break;
        case V_LINENO:
                break;
        case V_LINENO:
-               i = current_lineno + user_lineno;
+               num.i = current_lineno + user_lineno;
                break;
        case V_LINES:
                break;
        case V_LINES:
-               i = x_lins;
+               num.i = x_lins;
                break;
        case V_EPOCHREALTIME: {
                /* 10(%u) + 1(.) + 6 + NUL */
                break;
        case V_EPOCHREALTIME: {
                /* 10(%u) + 1(.) + 6 + NUL */
@@ -1141,10 +1146,10 @@ getspec(struct tbl *vp)
                return;
        }
        case V_OPTIND:
                return;
        }
        case V_OPTIND:
-               i = user_opt.uoptind;
+               num.i = user_opt.uoptind;
                break;
        case V_RANDOM:
                break;
        case V_RANDOM:
-               i = rndget();
+               num.i = rndget();
                break;
        case V_SECONDS:
                /*
                break;
        case V_SECONDS:
                /*
@@ -1154,7 +1159,7 @@ getspec(struct tbl *vp)
                 */
                if (vp->flag & ISSET) {
                        mksh_TIME(tv);
                 */
                if (vp->flag & ISSET) {
                        mksh_TIME(tv);
-                       i = tv.tv_sec - seconds;
+                       num.i = tv.tv_sec - seconds;
                } else
                        return;
                break;
                } else
                        return;
                break;
@@ -1163,14 +1168,14 @@ getspec(struct tbl *vp)
                return;
        }
        vp->flag &= ~SPECIAL;
                return;
        }
        vp->flag &= ~SPECIAL;
-       setint_n(vp, i, 0);
+       setint_n(vp, num.i, 0);
        vp->flag |= SPECIAL;
 }
 
 static void
 setspec(struct tbl *vp)
 {
        vp->flag |= SPECIAL;
 }
 
 static void
 setspec(struct tbl *vp)
 {
-       mksh_ari_t i;
+       mksh_ari_u num;
        char *s;
        int st;
 
        char *s;
        int st;
 
@@ -1228,11 +1233,11 @@ setspec(struct tbl *vp)
        case V_SECONDS:
        case V_TMOUT:
                vp->flag &= ~SPECIAL;
        case V_SECONDS:
        case V_TMOUT:
                vp->flag &= ~SPECIAL;
-               if (getint(vp, &i, false) == -1) {
+               if (getint(vp, &num, false) == -1) {
                        s = str_val(vp);
                        if (st != V_RANDOM)
                                errorf("%s: %s: %s", vp->name, "bad number", s);
                        s = str_val(vp);
                        if (st != V_RANDOM)
                                errorf("%s: %s: %s", vp->name, "bad number", s);
-                       i = hash(s);
+                       num.u = hash(s);
                }
                vp->flag |= SPECIAL;
                break;
                }
                vp->flag |= SPECIAL;
                break;
@@ -1245,40 +1250,40 @@ setspec(struct tbl *vp)
 
        switch (st) {
        case V_COLUMNS:
 
        switch (st) {
        case V_COLUMNS:
-               if (i >= MIN_COLS)
-                       x_cols = i;
+               if (num.i >= MIN_COLS)
+                       x_cols = num.i;
                break;
        case V_HISTSIZE:
                break;
        case V_HISTSIZE:
-               sethistsize(i);
+               sethistsize(num.i);
                break;
        case V_LINENO:
                /* The -1 is because line numbering starts at 1. */
                break;
        case V_LINENO:
                /* The -1 is because line numbering starts at 1. */
-               user_lineno = (unsigned int)i - current_lineno - 1;
+               user_lineno = num.u - current_lineno - 1;
                break;
        case V_LINES:
                break;
        case V_LINES:
-               if (i >= MIN_LINS)
-                       x_lins = i;
+               if (num.i >= MIN_LINS)
+                       x_lins = num.i;
                break;
        case V_OPTIND:
                break;
        case V_OPTIND:
-               getopts_reset((int)i);
+               getopts_reset((int)num.i);
                break;
        case V_RANDOM:
                /*
                 * mksh R39d+ no longer has the traditional repeatability
                 * of $RANDOM sequences, but always retains state
                 */
                break;
        case V_RANDOM:
                /*
                 * mksh R39d+ no longer has the traditional repeatability
                 * of $RANDOM sequences, but always retains state
                 */
-               rndset((long)i);
+               rndset((unsigned long)num.u);
                break;
        case V_SECONDS:
                {
                        struct timeval tv;
 
                        mksh_TIME(tv);
                break;
        case V_SECONDS:
                {
                        struct timeval tv;
 
                        mksh_TIME(tv);
-                       seconds = tv.tv_sec - i;
+                       seconds = tv.tv_sec - num.i;
                }
                break;
        case V_TMOUT:
                }
                break;
        case V_TMOUT:
-               ksh_tmout = i >= 0 ? i : 0;
+               ksh_tmout = num.i >= 0 ? num.i : 0;
                break;
        }
 }
                break;
        }
 }
@@ -1534,7 +1539,7 @@ rndget(void)
 }
 
 void
 }
 
 void
-rndset(long v)
+rndset(unsigned long v)
 {
        register uint32_t h;
 
 {
        register uint32_t h;