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\" \
+               -Wno-deprecated-declarations \
                -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_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)
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/base/opengl/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 \
-    -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
-# who would have thought the AOSP devs are funny? -fno-builtin-sin
 addvar CFLAGS \
     -fno-exceptions \
     -Wno-multichar \
@@ -123,6 +121,7 @@ addvar CFLAGS \
 addvar LDFLAGS \
     -nostdlib \
     -Bdynamic \
+    -fPIE \
     -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,--fatal-warnings \
     -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 \
-    -lc \
     -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
 
@@ -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
 
-# 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
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
-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'
@@ -22,7 +23,34 @@ alias ll='l -l'
 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 {
index 31c559d..45af9dd 100644 (file)
@@ -1,5 +1,5 @@
 #!/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
@@ -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
 
+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
@@ -63,7 +66,7 @@ vq() {
 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
@@ -190,6 +193,7 @@ ac_testn() {
 ac_ifcpp() {
        expr=$1; shift
        ac_testn "$@" <<-EOF
+               extern int thiswillneverbedefinedIhope(void);
                int main(void) { return (
                #$expr
                    0
@@ -458,7 +462,7 @@ oswarn=
 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
@@ -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 -DMKSH__NO_SETEUGID
        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
@@ -766,7 +773,7 @@ esac
 
 : ${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"
 
@@ -876,6 +883,9 @@ ct="ucode"
 ct="uslc"
 #elif defined(__LCC__)
 ct="lcc"
+#elif defined(MKSH_MAYBE_KENCC)
+/* and none of the above matches */
+ct="kencc"
 #else
 ct="unknown"
 #endif
@@ -952,6 +962,9 @@ iar)
 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
@@ -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 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
-       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
-       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
@@ -1099,49 +1116,65 @@ if ac_ifcpp 'ifdef __TINYC__' couldbe_tcc '!' compiler_known 0 \
        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
-elif test $ct = mipspro; then
+       ;;
+kencc)
+       save_NOWARN=
+       DOWARN=
+       ;;
+mipspro)
        save_NOWARN=
        DOWARN="-diag_error 1-10000"
-elif test $ct = msc; then
+       ;;
+msc)
        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
-elif test $ct = ucode; then
+       ;;
+ucode)
        save_NOWARN=
        DOWARN=-w2
-elif test $ct = watcom; then
+       ;;
+watcom)
        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
-fi
-
-test $ct = icc && DOWARN="$DOWARN -wd1419"
+       test $ct = icc && DOWARN="$DOWARN -wd1419"
+       ;;
+esac
 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
-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
@@ -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
-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
-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
-fi
+       ;;
+esac
 # 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
-       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
@@ -1186,15 +1240,19 @@ if test $ct = gcc; then
        *\ -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'
-       else
+               ;;
+       lto)
+               fv=0
+               checks='1 2 3 4 5 6 7 8'
+               ;;
+       *)
                fv=1
-       fi
+               ;;
+       esac
        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
-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
-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'
-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
@@ -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'
-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
-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
@@ -1291,6 +1349,7 @@ test $ct = pcc && phase=u
 #
 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
@@ -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))
+       extern int thiswillneverbedefinedIhope(void);
        /* 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))
+       extern int thiswillneverbedefinedIhope(void);
        /* 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))
+       extern int thiswillneverbedefinedIhope(void);
        /* 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))
+       extern int thiswillneverbedefinedIhope(void);
        /* 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
-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" && \
@@ -1491,14 +1554,16 @@ ac_testn sig_t <<-'EOF'
        #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>
-       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
@@ -1509,7 +1574,8 @@ 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
@@ -1532,7 +1598,7 @@ else
                #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
@@ -1748,7 +1814,7 @@ EOF
 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'
@@ -1848,7 +1914,6 @@ ac_testdone
 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"
@@ -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);
-/* 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));
-#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 */
@@ -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));
+#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);
+/* 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));
@@ -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));
+/* 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
@@ -1957,71 +2015,6 @@ EOF
 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 '' \
@@ -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
-add_cppflags -DMKSH_BUILD_R=431
+add_cppflags -DMKSH_BUILD_R=481
 
 $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
-if test $cm = llvm; then
-       emitbc="-emit-llvm -c"
-elif test $cm = dragonegg; then
+case $cm in
+dragonegg)
        emitbc="-S -flto"
-else
+       ;;
+llvm)
+       emitbc="-emit-llvm -c"
+       ;;
+*)
        emitbc=-c
-fi
+       ;;
+esac
 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
-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"
@@ -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 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"
-$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
@@ -2351,7 +2350,7 @@ if test -f $tfn.cat1; then
            "/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.
@@ -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)
+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"
@@ -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_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
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
@@ -171,13 +172,15 @@ BEGIN {
 
 use Getopt::Std;
 use Config;
+use File::Temp qw/ :mktemp /;
 
 $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
@@ -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).
+       -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
@@ -229,12 +233,6 @@ EOF
        "os:$os", '1'
        );
 
-$temps = "/tmp/rts$$";
-$tempi = "/tmp/rti$$";
-$tempo = "/tmp/rto$$";
-$tempe = "/tmp/rte$$";
-$tempdir = "/tmp/rtd$$";
-
 $nfailed = 0;
 $nifailed = 0;
 $nxfailed = 0;
@@ -243,7 +241,7 @@ $nxpassed = 0;
 
 %known_tests = ();
 
-if (!getopts('C:e:Pp:s:t:v')) {
+if (!getopts('C:e:Pp:s:T:t:v')) {
     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;
+$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;
@@ -297,8 +296,6 @@ if (defined $opt_e) {
 }
 %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);
@@ -316,6 +313,17 @@ $SIG{'ALRM'} = 'catch_sigalrm';
 
 $| = 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);
@@ -433,6 +441,8 @@ run_test
     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;
@@ -444,8 +454,6 @@ run_test
        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;
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: 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
@@ -29,7 +31,7 @@
 # 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:
@@ -38,7 +40,7 @@ name: KSH_VERSION
 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:
@@ -290,6 +292,22 @@ stdin:
 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
@@ -363,30 +381,35 @@ expected-stdout:
 ---
 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
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #0
        let --sari --uari
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #1
        sari=2147483647 uari=2147483647
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #2
        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
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #4
        let ++sari ++uari
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #5
        sari=-2147483648 uari=-2147483648
-       print -r -- $((x++)):$sari=$uari.
+       print -r -- $((x++)):$sari=$uari. #6
        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.
@@ -396,6 +419,8 @@ expected-stdout:
        5:0=0.
        6:-2147483648=2147483648.
        7:2147483647=2147483647.
+       8:-3=2147483645.
+       9:-2=4294967294.
 ---
 name: arith-unsigned-1
 description:
@@ -2530,30 +2555,6 @@ expected-stdout:
        \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.
@@ -2736,6 +2737,131 @@ expected-stdout:
        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
@@ -3466,10 +3592,10 @@ stdin:
        showargs 3 $@
        showargs 4 "$@"
 expected-stdout:
-        <1> <A B C>
+        <1> <A> <B> <C>
         <2> <ABC>
-        <3> <A B C>
-        <4> <A B C>
+        <3> <A> <B> <C>
+        <4> <A> <B> <C>
 ---
 name: IFS-space-colon-1
 description:
@@ -3772,22 +3898,17 @@ expected-stdout:
 ---
 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:
-       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:
-       :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:
@@ -3913,6 +4034,13 @@ expected-stdout:
        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.
@@ -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).
-       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() {
@@ -4265,10 +4393,15 @@ stdin:
        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
+       FPOSIX=1 FSH=1 rv=0
 ---
 name: regression-10-legacy
 description:
@@ -4297,10 +4430,15 @@ stdin:
        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
-       FPOSIX=1 FSH=0 rv=1
+       FPOSIX=1 FSH=0 rv=0
+       FPOSIX=1 FSH=1 rv=0
 ---
 name: regression-11
 description:
@@ -4663,18 +4801,16 @@ expected-stdout:
 ---
 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:
+       set -e
        echo `false; echo hi`
-#expected-fail: yes
-#expected-stdout:
-#      hi
+       echo $?
 expected-stdout:
        
+       0
 ---
 name: regression-40
 description:
@@ -5984,6 +6120,27 @@ expected-stdout:
        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.
@@ -6178,7 +6335,7 @@ expected-stdout:
 ---
 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
@@ -6187,7 +6344,7 @@ stdin:
        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
@@ -6197,7 +6354,7 @@ expected-stdout:
 ---
 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
@@ -6206,7 +6363,7 @@ stdin:
        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
@@ -6275,6 +6432,28 @@ expected-stdout:
        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
@@ -7551,6 +7730,28 @@ stdin:
 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
@@ -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
+category: shell:legacy-no
 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
+category: shell:legacy-no
 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
+category: shell:legacy-no
 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
+category: shell:legacy-no
 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
+category: shell:legacy-no
 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
+category: shell:legacy-no
 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
+category: shell:legacy-no
 stdin:
        exec 3>&1
        function threeout {
@@ -8511,6 +8719,34 @@ expected-stdout:
        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
@@ -8534,10 +8770,57 @@ expected-stdout:
        bar
        baz
 ---
-name: oksh-shcrash
+name: oksh-eval
 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:
+       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
@@ -8554,6 +8837,99 @@ stdin:
                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 $
@@ -8846,8 +9222,8 @@ stdin:
        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"
@@ -9041,7 +9417,7 @@ expected-stdout:
        }
        inline_TWHILE() {
                i=1 
-               while let " i < 10 " 
+               while let] " i < 10 " 
                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 {
-               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 {
-               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 
-               until let " !--i " 
+               until let] " !--i " 
                do
                        echo $i 
                done 
@@ -9073,13 +9449,13 @@ expected-stdout:
                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 {
-               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
@@ -9229,23 +9605,23 @@ expected-stdout:
        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); }
-       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
@@ -9693,7 +10069,7 @@ expected-stdout:
        }
        inline_TWHILE() {
                i=1 
-               while let " i < 10 " >&3 
+               while let] " i < 10 " >&3 
                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 {
-               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 {
-               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 
-               until let " !--i " >&3 
+               until let] " !--i " >&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 {
-               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 {
-               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
@@ -9831,6 +10207,38 @@ expected-stdout:
        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
@@ -10156,7 +10564,7 @@ description:
 time-limit: 3
 stdin:
        baz() {
-               typeset -n foo=foo
+               typeset -n foo=fnord fnord=foo
                foo[0]=bar
        }
        set -A foo bad
@@ -10165,7 +10573,9 @@ stdin:
        echo blah $foo .
 expected-stdout:
        sind bad .
-       blah bar .
+       blah bad .
+expected-stderr-pattern:
+       /fnord: expression recurses on parameter/
 ---
 name: better-parens-1a
 description:
@@ -10743,3 +11153,19 @@ stdin:
        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$
-# $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
 #-
 # ${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}
-function precmd {
+: ${MKSH:=$(whence -p mksh)}; PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
        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
-}
-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 doch='sudo mksh -c "$(fc -ln -1)"'
 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]
@@ -222,7 +263,7 @@ function Lb64decode {
        [[ -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
 
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 $        */
@@ -28,7 +28,7 @@
 
 #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
@@ -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 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);
@@ -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_emacs(char *, size_t);
+static int x_emacs(char *);
 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)
@@ -110,17 +110,17 @@ static int x_e_rebuildline(const char *);
  * 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))
-               i = x_emacs(buf, len);
+               i = x_emacs(buf);
 #if !MKSH_S_NOVI
        else if (Flag(FVI))
-               i = x_vi(buf, len);
+               i = x_vi(buf);
 #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_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 */
@@ -944,9 +943,6 @@ static int x_curprefix;
 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) */
@@ -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 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 char *x_bs0(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)
 {
-       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');
-               prompt_redraw = false;
        }
 }
 
 static int
-x_emacs(char *buf, size_t len)
+x_emacs(char *buf)
 {
        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;
@@ -1202,8 +1196,10 @@ x_emacs(char *buf, size_t len)
        x_histp = histptr + 1;
        x_last_command = XFUNC_error;
 
-       xx_cols = x_cols;
        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) {
@@ -1561,11 +1557,7 @@ x_fword(bool move)
 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;
@@ -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;
 
-       (*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');
@@ -1824,7 +1822,7 @@ x_load_hist(char **hp)
        char *sp = NULL;
 
        if (hp == histptr + 1) {
-               sp = holdbuf;
+               sp = holdbufp;
                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)
-               strlcpy(holdbuf, xbuf, sizeof(holdbuf));
+               strlcpy(holdbufp, xbuf, LINE);
        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)
 {
-       int i, j, x_trunc = 0;
+       int i, j;
        char *cp;
 
        x_adj_ok = false;
@@ -2090,19 +2088,11 @@ x_redraw(int limit)
                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)
@@ -2816,16 +2806,42 @@ do_complete(
 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++;
+
        /*
-        * 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();
@@ -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 putbuf(const char *, ssize_t, int);
+static int putbuf(const char *, ssize_t, bool);
 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);
@@ -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       */
-       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       [       \       ]       ^       _       */
-       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       */
@@ -3443,25 +3459,24 @@ static const unsigned char classify[128] = {
 #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  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 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 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 */
@@ -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 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 */
@@ -3495,7 +3510,7 @@ static enum expand_mode {
 } expanded;
 
 static int
-x_vi(char *buf, size_t len)
+x_vi(char *buf)
 {
        int c;
 
@@ -3503,36 +3518,29 @@ x_vi(char *buf, size_t len)
        ohnum = hnum = hlast = histnum(-1) + 1;
        insert = INSERT;
        saved_inslen = inslen;
-       first_insert = 1;
+       first_insert = true;
        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->cbuf = buf;
        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);
@@ -3589,11 +3597,11 @@ x_vi(char *buf, size_t len)
        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)
-               memmove(buf, es->cbuf, es->linelen);
+               memcpy(buf, es->cbuf, es->linelen);
 
        buf[es->linelen++] = '\n';
 
@@ -3644,10 +3652,8 @@ vi_hook(int ch)
                                        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);
                                }
@@ -3656,7 +3662,7 @@ vi_hook(int ch)
                                        es->cursor = 0;
                                        es->linelen = 0;
                                        putbuf(KSH_VERSION,
-                                           strlen(KSH_VERSION), 0);
+                                           strlen(KSH_VERSION), false);
                                        refresh(0);
                                }
                        }
@@ -3805,10 +3811,35 @@ vi_hook(int ch)
                        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:
+ pseudo_VCMD:
                state = VNORMAL;
                switch (vi_cmd(argc1, curcmd)) {
                case -1:
@@ -3962,7 +3993,7 @@ vi_insert(int ch)
        case Ctrl('['):
                expanded = NONE;
                if (first_insert) {
-                       first_insert = 0;
+                       first_insert = false;
                        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
                                 */
-                               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);
-                                       afree(macro.buf, APERM);
+                                       afree(macro.buf, AEDIT);
                                        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++;
-                       while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
+                       while (putbuf(ybuf, yanklen, false) == 0 &&
+                           --argcnt > 0)
                                ;
                        if (es->cursor != 0)
                                es->cursor--;
@@ -4176,7 +4208,8 @@ vi_cmd(int argcnt, const char *cmd)
                        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--;
@@ -4378,6 +4411,11 @@ vi_cmd(int argcnt, const char *cmd)
                                hnum = c2;
                                ohnum = hnum;
                        }
+                       if (argcnt >= 2) {
+                               /* flag from cursor-up command */
+                               es->cursor = argcnt - 2;
+                               return (0);
+                       }
                        break;
                case '_':
                        {
@@ -4422,8 +4460,8 @@ vi_cmd(int argcnt, const char *cmd)
                                        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);
@@ -4498,6 +4536,16 @@ vi_cmd(int argcnt, const char *cmd)
                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--;
@@ -4556,7 +4604,8 @@ domove(int argcnt, const char *cmd, int sub)
                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++;
@@ -4656,7 +4705,7 @@ static int
 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--;
@@ -4707,9 +4756,9 @@ bracktype(int ch)
 static void
 save_cbuf(void)
 {
-       memmove(holdbuf, es->cbuf, es->linelen);
+       memmove(holdbufp, es->cbuf, es->linelen);
        holdlen = es->linelen;
-       holdbuf[holdlen] = '\0';
+       holdbufp[holdlen] = '\0';
 }
 
 static void
@@ -4717,7 +4766,7 @@ restore_cbuf(void)
 {
        es->cursor = 0;
        es->linelen = holdlen;
-       memmove(es->cbuf, holdbuf, holdlen);
+       memmove(es->cbuf, holdbufp, holdlen);
 }
 
 /* return a new edstate */
@@ -4726,8 +4775,8 @@ save_edstate(struct edstate *old)
 {
        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;
@@ -4749,8 +4798,8 @@ restore_edstate(struct edstate *news, 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)
 {
-       return (putbuf(s, len, 0));
+       return (putbuf(s, len, false));
 }
 
 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);
@@ -4793,7 +4842,7 @@ del_range(int a, int b)
 }
 
 static int
-findch(int ch, int cnt, int forw, int incl)
+findch(int ch, int cnt, bool forw, bool incl)
 {
        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 != 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
@@ -5016,9 +5065,9 @@ redraw_line(bool newl)
                x_putc('\r');
                x_putc('\n');
        }
-       if (prompt_redraw)
+       if (prompt_trunc != -1)
                pprompt(prompt, prompt_trunc);
-       cur_col = pwidth;
+       x_col = pwidth;
        morec = ' ';
 }
 
@@ -5136,10 +5185,10 @@ display(char *wb1, char *wb2, int leftside)
        twb2 = wb2;
        while (cnt--) {
                if (*twb1 != *twb2) {
-                       if (cur_col != col)
+                       if (x_col != col)
                                ed_mov_opt(col, wb1);
                        x_putc(*twb1);
-                       cur_col++;
+                       x_col++;
                }
                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);
-               cur_col++;
+               x_col++;
                morec = mc;
        }
-       if (cur_col != ncol)
+       if (x_col != ncol)
                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');
-                       if (prompt_redraw)
+                       if (prompt_trunc != -1)
                                pprompt(prompt, prompt_trunc);
-                       cur_col = pwidth;
-                       while (cur_col++ < col)
+                       x_col = pwidth;
+                       while (x_col++ < col)
                                x_putcf(*wb++);
                } else {
-                       while (cur_col-- > col)
+                       while (x_col-- > col)
                                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++);
        }
-       cur_col = col;
+       x_col = col;
 }
 
 
@@ -5229,7 +5278,7 @@ expand_word(int cmd)
                        rval = -1;
                        break;
                }
-               if (++i < nwords && putbuf(" ", 1, 0) != 0) {
+               if (++i < nwords && putbuf(" ", 1, false) != 0) {
                        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))
-                       rval = putbuf(" ", 1, 0);
+                       rval = putbuf(" ", 1, false);
        }
        x_free_words(nwords, words);
 
@@ -5404,7 +5453,7 @@ static void
 vi_macro_reset(void)
 {
        if (macro.p) {
-               afree(macro.buf, APERM);
+               afree(macro.buf, AEDIT);
                memset((char *)&macro, 0, sizeof(macro));
        }
 }
@@ -5425,8 +5474,11 @@ x_init(void)
        /* ^W */
        edchars.werase = 027;
 
-       /* initialise Emacs command line editing mode */
+       /* command line editing specific memory allocation */
        ainit(AEDIT);
+       holdbufp = alloc(LINE, AEDIT);
+
+       /* initialise Emacs command line editing mode */
        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,
@@ -23,7 +23,7 @@
 
 #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
@@ -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 */
-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 {
-               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 */
@@ -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 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);
@@ -198,33 +204,46 @@ typedef struct SubType {
 } 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 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 = {
-               /* expansion variables */
                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;
+       char *cp;
 
-       if (cp == NULL)
+       if (ccp == NULL)
                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;
        }
@@ -238,7 +257,7 @@ expand(const char *cp,      /* input word */
        /* init destination string */
        Xinit(ds, dp, 128, ATEMP);
        type = XBASE;
-       sp = cp;
+       sp = ccp;
        fdo = 0;
        saw_eq = false;
        /* must be 1/0 */
@@ -279,27 +298,26 @@ expand(const char *cp,    /* input word */
                                continue;
                        case COMSUB:
                        case FUNSUB:
+                       case VALSUB:
                                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++;
                                        }
-                                       if (c == FUNSUB) {
+                                       if (c != COMSUB) {
                                                *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;
@@ -317,7 +335,6 @@ expand(const char *cp,      /* input word */
                                        *dp++ = ')'; *dp++ = ')';
                                } else {
                                        struct tbl v;
-                                       char *p;
 
                                        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;
-                                       for (p = str_val(&v); *p; ) {
+                                       cp = str_val(&v);
+                                       while (*cp) {
                                                Xcheck(ds, dp);
-                                               *dp++ = *p++;
+                                               *dp++ = *cp++;
                                        }
                                }
                                continue;
@@ -394,8 +412,7 @@ expand(const char *cp,      /* input word */
                                        if (stype)
                                                sp += slen;
                                        switch (stype & 0x17F) {
-                                       case 0x100 | '#':
-                                           {
+                                       case 0x100 | '#': {
                                                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;
                                        }
-                                       case 0x100 | 'Q':
-                                           {
+                                       case 0x100 | 'Q': {
                                                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;
+                                       /* this is so we don't terminate */
                                        c = ' ';
+                                       /* now force-emit a word */
+                                       goto emit_word;
                                }
                                if (quote && x.split) {
                                        /* terminate word for "$@" */
@@ -850,14 +869,19 @@ expand(const char *cp,    /* input word */
                        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')
-                                               /* Save newlines */
+                                               /* save newlines */
                                                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;
-                               shf_close(x.u.shf);
+                               if (x.u.shf)
+                                       shf_close(x.u.shf);
                                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)) {
-                               char *p;
-
+ emit_word:
                                *dp++ = '\0';
-                               p = Xclose(ds, dp);
+                               cp = Xclose(ds, dp);
                                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)
-                                       glob(p, wp, tobool(f & DOMARKDIRS));
+                                       glob(cp, wp, tobool(f & DOMARKDIRS));
                                else if ((f & DOPAT) || !(fdo & DOMAGIC))
-                                       XPput(*wp, p);
+                                       XPput(*wp, cp);
                                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;
@@ -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) {
-                               char *p;
-
-                               *(p = alloc(1, ATEMP)) = '\0';
-                               XPput(*wp, p);
+                               *(cp = alloc(1, ATEMP)) = '\0';
+                               XPput(*wp, cp);
                                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) {
-                                       char *p;
-
-                                       *(p = alloc(1, ATEMP)) = '\0';
-                                       XPput(*wp, p);
+                                       *(cp = alloc(1, ATEMP)) = '\0';
+                                       XPput(*wp, cp);
                                }
                                type = XSUBMID;
                        }
@@ -1002,18 +1023,17 @@ expand(const char *cp,  /* input word */
                                        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);
-                                               if (p) {
-                                                       if (dp != dp_x)
+                                               if (tcp) {
+                                                       if (dp != tdp)
                                                                word = IFS_WORD;
-                                                       dp = dp_x;
-                                                       sp = p;
+                                                       dp = tdp;
+                                                       sp = tcp;
                                                        continue;
                                                }
                                        }
@@ -1176,8 +1196,10 @@ varsub(Expand *xp, const char *sp, const char *word,
        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 '/':
@@ -1204,8 +1226,10 @@ varsub(Expand *xp, const char *sp, const char *word,
                        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':
@@ -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)
-                       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;
 
-               /* 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));
                }
-               /* 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);
-               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
                 */
-               funsub(t);
+               valsub(t, NULL);
                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);
-               /* 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];
 
@@ -1495,11 +1527,11 @@ globit(XString *xs,     /* dest string */
                 */
                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;
-                       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;
@@ -1801,12 +1833,21 @@ alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
 }
 
 /* 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();
-       e->type = E_FUNC;
+       if (ap)
+               vp = local("REPLY", false);
        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,
@@ -23,7 +23,7 @@
 
 #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"
@@ -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))
-                               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;
@@ -138,14 +138,6 @@ execute(struct op * volatile t,
                        /* 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);
        }
@@ -305,10 +297,12 @@ execute(struct op * volatile t,
        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:
@@ -335,6 +329,7 @@ execute(struct op * volatile t,
        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);
@@ -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;
+       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;
-               /* but assign in there as usual */
-
                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);
        }
 
+       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;
@@ -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) {
-                               rv = errno;
                                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;
                        }
@@ -740,9 +751,9 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
                        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;
 
@@ -751,9 +762,11 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
                        execute(tp->val.t, flags & XERROK, NULL);
                        i = LRETURN;
                }
+
                kshname = old_kshname;
-               Flag(FXTRACE) = old_xflag;
+               change_xtrace(old_xflag, false);
                tp->flag = (tp->flag & ~FINUSE) | old_inuse;
+
                /*
                 * 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;
-       uint32_t flag;
+       uint32_t flag = DEFINED;
 
        /* 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;
-               else if (*name == '+')
-                       /* POSIX regular builtin */
-                       flag |= REG_BI;
                else
                        break;
+               name++;
        }
 
        tp = ktenter(&builtins, name, hash(name));
-       tp->flag = DEFINED | flag;
+       tp->flag = flag;
        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
-        * POSIX regular builtins, then search path...
+        * regular builtins, then search path...
         */
        if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
                tp = tbi;
@@ -1098,9 +1109,7 @@ findcom(const char *name, int flags)
                                    &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);
@@ -1298,10 +1307,11 @@ iosetup(struct ioword *iop, struct tbl *tp)
        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:
@@ -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) {
+                       char *sp;
+
                        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)
@@ -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;
+                       char *sp;
 
                        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));
+                       afree(sp, ATEMP);
                        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 (*s) {
-                       getn(s, &i);
+               if (*s && getn(s, &i))
                        return ((i >= 1 && i <= argct) ? ap[i - 1] : null);
-               }
                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,
 
 #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,
@@ -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,
+#ifndef MKSH_LEGACY_MODE
+       O_ROLASN, O_RORASN,
+#endif
        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,
@@ -67,14 +60,13 @@ enum token {
        /* 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 P_PRIMARY      0       /* VAR, LIT, (), ~ ! - + */
+#define P_PRIMARY      0       /* VAR, LIT, (), ! ~ ++ -- */
 #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       /* & */
@@ -83,60 +75,72 @@ enum token {
 #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 {
-       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[] = {
-       { "++",  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 {
@@ -151,18 +155,13 @@ typedef struct expr_state {
        /* 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;
 
-#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
@@ -170,7 +169,7 @@ enum error_type {
 
 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 *);
@@ -185,7 +184,7 @@ evaluate(const char *expr, mksh_ari_t *rval, int error_ok, bool arith)
        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;
@@ -307,52 +306,103 @@ evalerr(Expr_state *es, enum error_type type, const char *str)
        unwind(LAEXPR);
 }
 
+/* do a ++ or -- operation */
 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;
-       mksh_uari_t res = 0;
+       mksh_uari_t res = 0, t1, t2, t3;
 
        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));
-                       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);
-               } 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);
-               } else if (op == VAR || op == LIT) {
+                       break;
+
+               case VAR:
+               case LIT:
                        vl = es->val;
                        exprtoken(es);
-               } else {
+                       break;
+
+               default:
                        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);
                }
+
                return (vl);
+               /* prec == P_PRIMARY */
        }
+
        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)
@@ -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));
-               } 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));
-               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:
-                       res = bivui(vl, *, vr);
+                       res = t1 * t2;
                        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:
-#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
-                               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:
-                       res = bivui(vl, +, vr);
+                       res = t1 + t2;
                        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;
+               case O_ROR:
+               case O_RORASN:
+                       res = (t1 >> t2) | (t1 << (32 - t2));
+                       break;
+#endif
                case O_LSHIFT:
                case O_LSHIFTASN:
-                       res = bivui(vl, <<, vr);
+                       res = t1 << t2;
                        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:
-                       res = bivui(vl, <, vr);
+                       res = cmpop(<);
                        break;
                case O_LE:
-                       res = bivui(vl, <=, vr);
+                       res = cmpop(<=);
                        break;
                case O_GT:
-                       res = bivui(vl, >, vr);
+                       res = cmpop(>);
                        break;
                case O_GE:
-                       res = bivui(vl, >=, vr);
+                       res = cmpop(>=);
                        break;
                case O_EQ:
-                       res = bivui(vl, ==, vr);
+                       res = t1 == t2;
                        break;
                case O_NE:
-                       res = bivui(vl, !=, vr);
+                       res = t1 != t2;
                        break;
                case O_BAND:
                case O_BANDASN:
-                       res = bivui(vl, &, vr);
+                       res = t1 & t2;
                        break;
                case O_BXOR:
                case O_BXORASN:
-                       res = bivui(vl, ^, vr);
+                       res = t1 ^ t2;
                        break;
                case O_BOR:
                case O_BORASN:
-                       res = bivui(vl, |, vr);
+                       res = t1 | t2;
                        break;
                case O_LAND:
-                       if (!vl->val.i)
+                       if (!t1)
                                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:
-                       if (vl->val.i)
+                       if (t1)
                                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_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:
-                       res = vr->val.u;
-                       break;
                case O_COMMA:
-                       res = vr->val.u;
+                       res = t2;
                        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
-                                       setint(vasn, (mksh_ari_t)res);
+                                       setint(vasn, vr->val.i);
                        }
                        vl = vr;
-               } else if (op != O_TERN)
+               } else
                        vl->val.u = res;
        }
        return (vl);
@@ -520,13 +622,14 @@ exprtoken(Expr_state *es)
        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 # */
-               es->natural = true;     /* switch to unsigned */
+               /* switch to unsigned */
+               es->natural = true;
                ++cp;
                goto skip_spaces;
        }
@@ -544,12 +647,6 @@ exprtoken(Expr_state *es)
                        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();
@@ -610,39 +707,6 @@ exprtoken(Expr_state *es)
        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)
 {
@@ -833,129 +897,6 @@ utf_wctomb(char *dst, unsigned int wc)
        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
@@ -974,3 +915,277 @@ ksh_access(const char *fn, int mode)
 
        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_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 $   */
 
@@ -38,7 +38,7 @@
 #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
 /*
@@ -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},
+       /* no =: AT&T manual wrong */
+       {Talias, c_alias},
        {"*=break", c_brkcont},
        {Tgbuiltin, c_builtin},
+       {"cat", c_cat},
+       {"cd", c_cd},
+       /* dash compatibility hack */
+       {"chdir", c_cd},
+       {"command", c_command},
        {"*=continue", c_brkcont},
+       {"echo", c_print},
        {"*=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},
-       {"+fc", c_fc},
-       {"+getopts", c_getopts},
+       {"false", c_false},
+       {"fc", c_fc},
+       {"getopts", c_getopts},
        {"=global", c_typeset},
-       {"+jobs", c_jobs},
-       {"+kill", c_kill},
+       {"jobs", c_jobs},
+       {"kill", c_kill},
        {"let", c_let},
+       {"let]", c_let},
        {"print", c_print},
-#ifdef MKSH_PRINTF_BUILTIN
-       {"printf", c_printf},
-#endif
        {"pwd", c_pwd},
+       {"read", c_read},
        {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},
-       {Tpunalias, c_unalias},
+       {"ulimit", c_ulimit},
+       {"umask", c_umask},
+       {Tunalias, c_unalias},
+       {Tsgunset, c_unset},
+       {"=wait", c_wait},
        {"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
-       {"cat", c_cat},
 #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
@@ -836,7 +835,7 @@ c_typeset(const char **wp)
                                        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;
                        }
                }
@@ -2253,7 +2252,7 @@ c_trap(const char **wp)
        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);
@@ -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).
-        * Switched ksh (!posix !sh) to POSIX in mksh R39b.
         */
 #ifdef MKSH_LEGACY_MODE
-       return (subst_exstat);
+       /* traditional behaviour, unless set -o posix */
+       return (Flag(FPOSIX) ? 0 : subst_exstat);
 #else
-       return (Flag(FSH) ? subst_exstat : 0);
+       /* conformant behaviour, unless set -o sh +o posix */
+       return (Flag(FSH) && !Flag(FPOSIX) ? subst_exstat : 0);
 #endif
 }
 
@@ -3726,7 +3726,7 @@ c_cat(const char **wp)
        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);
        }
 
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
@@ -22,7 +23,7 @@
 
 #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
@@ -44,12 +45,11 @@ struct proc {
        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 */
-#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 */
@@ -102,17 +102,14 @@ struct job {
 #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[] = {
-       null,
        "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 */
@@ -463,7 +460,7 @@ exchild(struct op *t, int flags,
                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);
@@ -506,9 +503,6 @@ exchild(struct op *t, int flags,
                /* 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
                /*
@@ -543,6 +537,10 @@ exchild(struct op *t, int flags,
                }
                /* 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;
@@ -906,7 +904,7 @@ j_jobs(const char *cp, int slp,
                zflag = 1;
        }
        if (cp) {
-               int     ecode;
+               int ecode;
 
                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);
+                       if (Flag(FPIPEFAIL) && vp->val.i)
+                               rv = vp->val.i;
                        p = p->next;
                }
        }
@@ -1251,8 +1251,7 @@ j_waitj(Job *j,
 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;
@@ -1340,7 +1339,7 @@ j_sigchld(int sig MKSH_A_UNUSED)
 #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
@@ -20,7 +20,7 @@
 
 #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)
@@ -100,7 +100,7 @@ aresize(void *ptr, size_t numb, Area *ap)
            || 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;
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,
@@ -23,7 +23,7 @@
 
 #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
@@ -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 int dopprompt(const char *, int, bool);
-
 static int backslash_skip;
 static int ignore_backslash_newline;
 
@@ -338,7 +336,9 @@ yylex(int cf)
                                }
                                break;
                        case '\'':
- open_ssquote:
+ open_ssquote_unless_heredoc:
+                               if ((cf & HEREDOC))
+                                       goto store_char;
                                *wp++ = OQUOTE;
                                ignore_backslash_newline++;
                                PUSH_STATE(SSQUOTE);
@@ -421,8 +421,14 @@ yylex(int cf)
                                                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
@@ -495,7 +501,8 @@ yylex(int cf)
                                                        PUSH_STATE(STBRACEKORN);
                                        } else {
                                                ungetsc(c);
-                                               if (state == SDQUOTE)
+                                               if (state == SDQUOTE ||
+                                                   state == SQBRACE)
                                                        PUSH_STATE(SQBRACE);
                                                else
                                                        PUSH_STATE(SBRACE);
@@ -616,6 +623,8 @@ yylex(int cf)
                case SSQUOTE:
                        if (c == '\'') {
                                POP_STATE();
+                               if ((cf & HEREDOC) || state == SQBRACE)
+                                       goto store_char;
                                *wp++ = CQUOTE;
                                ignore_backslash_newline--;
                        } else {
@@ -693,7 +702,7 @@ yylex(int cf)
 
                case SBRACE:
                        if (c == '\'')
-                               goto open_ssquote;
+                               goto open_ssquote_unless_heredoc;
                        else if (c == '\\')
                                goto getsc_qchar;
  common_SQBRACE:
@@ -812,7 +821,7 @@ yylex(int cf)
                                }
                                break;
                        case '\'':
-                               goto open_ssquote;
+                               goto open_ssquote_unless_heredoc;
                        case '$':
                                if ((c2 = getsc()) == '\'') {
  open_sequote:
@@ -898,7 +907,11 @@ yylex(int cf)
                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)
@@ -1374,7 +1387,7 @@ getsc_line(Source *s)
            Flag(FEMACS) || Flag(FGMACS))) {
                int nread;
 
-               nread = x_read(xp, LINE);
+               nread = x_read(xp);
                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;
@@ -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);
-                       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++;
-               if (doprint && (*cp != delimiter) &&
+               if ((*cp != delimiter) &&
                    (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);
 }
 
-
-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).
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 $ */
@@ -34,7 +34,7 @@
 #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;
 
@@ -48,6 +48,7 @@ extern char **environ;
 
 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 *);
@@ -137,15 +138,25 @@ rndsetup(void)
        /* 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 */
-       NZATUpdateMem(h, bufptr, sizeof(*bufptr));
+       NZATUpdateMem(h, bp, sz);
        NZAATFinish(h);
 
-       afree(cp, APERM);
-       return ((mksh_uari_t)h);
+       return (h);
 }
 
 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,
-           /* 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,
@@ -251,11 +262,20 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
                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
-               /* 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
+               }
+#endif
        }
 
        initvar();
@@ -323,6 +343,11 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
         */
        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
@@ -411,7 +436,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
                        return (1);
        }
 
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(MKSH_LEGACY_MODE)
        /* 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) ||
-                   (xl != -2147483648L) || (xul != 2147483648UL) ||
+                   (xl != (-2147483647L-1)) || (xul != 2147483648UL) ||
                    (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) */
-       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;
@@ -1006,6 +1032,10 @@ quitenv(struct shf *shf)
 #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 &&
@@ -1364,7 +1394,7 @@ initio(void)
        /* 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 != '/')
@@ -1594,7 +1624,7 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist)
 {
        char *cp;
        size_t len;
-       int i;
+       int i, j;
        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) {
-               int nfd;
-
                /* map us high and mark as close-on-exec */
-               if ((nfd = savefd(i)) != i) {
+               if ((j = savefd(i)) != 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 */
-       tp->shf = shf_fdopen(i, SHF_WR, NULL);
+       tp->shf = shf_fdopen(i, j, NULL);
 
  maketemp_out:
        tp->next = *tlist;
index 988f98c..adf4bc4 100644 (file)
@@ -3,7 +3,7 @@
 
 /*-
  * 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
@@ -30,7 +30,7 @@
 #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
@@ -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
-static void chvt(const char *);
+static void chvt(const Getopt *);
 #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));
 }
 
+
 #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"
 };
@@ -137,15 +142,20 @@ const struct shoption options[] = {
 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);
-       } 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);
 }
@@ -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",
-           oi->opt_width, options[oi->opts[i]].name,
+           oi->opt_width, OFN(oi->opts[i]),
            Flag(oi->opts[i]) ? "on" : "off");
        return (buf);
 }
@@ -184,12 +194,11 @@ printoptions(bool verbose)
 
                oi.opt_width = 0;
                while (i < NELEM(options)) {
-                       if (options[i].name) {
+                       if ((len = strlen(OFN(i)))) {
                                oi.opts[n++] = i;
-                               len = strlen(options[i].name);
                                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;
                        }
@@ -200,10 +209,9 @@ printoptions(bool verbose)
        } 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);
@@ -213,13 +221,15 @@ printoptions(bool verbose)
 char *
 getoptions(void)
 {
-       size_t i;
-       char m[(int)FNFLAGS + 1];
+       size_t i = 0;
+       char c, m[(int)FNFLAGS + 1];
        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);
 }
@@ -229,8 +239,12 @@ void
 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
@@ -277,16 +291,46 @@ change_flag(enum sh_flag f, int what, bool newset)
                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;
        }
 }
 
+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.
@@ -306,10 +350,11 @@ parse_args(const char **argv,
        size_t i;
        int optc, arrayset = 0;
        bool sortargs = false;
+       bool fcompatseen = false;
 
        /* 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';
@@ -326,11 +371,11 @@ parse_args(const char **argv,
                *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';
@@ -379,6 +424,17 @@ parse_args(const char **argv,
                                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
@@ -387,7 +443,7 @@ parse_args(const char **argv,
                                 * 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");
@@ -403,7 +459,7 @@ parse_args(const char **argv,
                        errorf("no TIOCSCTTY ioctl");
 #else
                        change_flag(FTALKING, OF_CMDLINE, true);
-                       chvt(go.optarg);
+                       chvt(&go);
                        break;
 #endif
 #endif
@@ -420,8 +476,8 @@ parse_args(const char **argv,
                                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;
                                }
@@ -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 */
-               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++;
        }
@@ -472,9 +530,11 @@ int
 getn(const char *s, int *ai)
 {
        char c;
-       unsigned int i = 0;
+       mksh_ari_u num;
        bool neg = false;
 
+       num.u = 0;
+
        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 (i > 214748364U)
+               if (num.u > 214748364U)
                        /* 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++));
 
-       if (i > (neg ? 2147483648U : 2147483647U))
+       if (num.u > (neg ? 2147483648U : 2147483647U))
                /* 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);
 }
 
@@ -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)
-                       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) {
-               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;
-       nspace = (x_cols + max_col * cols) / cols;
        if (nspace <= 0)
                nspace = 1;
        for (r = 0; r < rows; r++) {
@@ -1911,59 +1972,69 @@ c_cd(const char **wp)
 
 
 #ifdef KSH_CHVT_CODE
+extern uint32_t chvt_rndsetup(const void *, size_t);
 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;
 
-       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)) {
-                               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))
-                       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 (revoke(fn))
+               if (revoke(dv))
 #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);
-               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 (fn != dv + 1) {
+       if (go->optarg[0] != '-') {
                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);
-       {
-               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
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
@@ -74,7 +74,7 @@
 .\" with -mandoc, it might implement .Mx itself, but we want to
 .\" use our own definition. And .Dd must come *first*, always.
 .\"
-.Dd $Mdocdate: February 19 2013 $
+.Dd $Mdocdate: August 10 2013 $
 .\"
 .\" Check which macro package we use, and do other -mdoc setup.
 .\"
 .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
@@ -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 T Ar tty
+.It Fl T Ar name
 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
-.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
@@ -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.
-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
@@ -1180,6 +1198,15 @@ work, and in that
 .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
@@ -2037,6 +2064,9 @@ Parameter, command, and arithmetic substitutions are performed
 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
@@ -2431,6 +2461,13 @@ in
 .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 ,
@@ -2515,15 +2552,15 @@ Unary operators:
 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
 &
 == !=
-\*(Lt \*(Lt= \*(Gt= \*(Gt
-\*(Lt\*(Lt \*(Gt\*(Gt
+\*(Lt \*(Lt= \*(Gt \*(Gt=
+\*(Lt\*(Lt\*(Lt \*(Gt\*(Gt\*(Gt \*(Lt\*(Lt \*(Gt\*(Gt
 + \-
 * / %
 .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.
-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
@@ -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
-.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
@@ -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= \*(Gt= \*(Gt
+.It \*(Lt= \*(Gt \*(Gt=
 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.
@@ -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.
-The sign of the result is unspecified if either argument is negative.
 .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 .
+The non-result argument is not evaluated.
 .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
-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
@@ -2868,8 +2914,8 @@ returns.
 .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.
@@ -2885,46 +2931,30 @@ parameter is not used to find them.
 The original
 .Nm ksh
 and POSIX differ somewhat in which commands are considered
-special or regular:
+special or regular.
 .Pp
-POSIX special commands
+POSIX special built-in utilities:
 .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
-special commands
-.Pp
-.Ic builtin , global , times , typeset
-.Pp
-Very special commands
-.Pq non-POSIX
+commands keeping assignments:
 .Pp
-.Ic alias , readonly , set , typeset
+.Ic builtin , global , typeset , wait
 .Pp
-POSIX regular commands
+Builtins that are not special:
 .Pp
-.Ic alias , bg , cd , command ,
+.Ic [ , alias , bg , bind ,
+.Ic cat , cd , command , echo ,
 .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.
@@ -2952,6 +2982,10 @@ those of the environment the command is used in.
 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
@@ -3506,6 +3540,10 @@ resetting
 .Ev OPTIND ,
 may lead to unexpected results.
 .Pp
+.It global Ar ...
+See
+.Ic typeset .
+.Pp
 .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
+.It let]
+Internally used alias for
+.Ic let .
+.Pp
 .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 && ,
-.Ic \*(Ba\*(Ba ,
 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
@@ -4097,7 +4142,7 @@ Mark directories with a trailing
 .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
@@ -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.
+.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
@@ -4162,6 +4212,9 @@ See the
 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
@@ -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.
+.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
@@ -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.
+.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).
-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.
+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.
-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
+.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,
@@ -6335,7 +6425,7 @@ $ /bin/sleep 666 && echo fubar
 .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 ,
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: 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 $    */
 #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
-#define MKSH_VERSION "R43 2013/02/19"
+#define MKSH_VERSION "R48 2013/08/14"
 
 /* arithmetic types: C implementation */
 #if !HAVE_CAN_INTTYPES
@@ -370,6 +370,7 @@ extern int revoke(const char *);
 #endif
 
 #if defined(DEBUG) || !HAVE_STRERROR
+#undef strerror
 #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 */
 
-#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__);
@@ -443,8 +444,6 @@ extern int wcwidth(__WCHAR_TYPE__);
 #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
@@ -471,6 +470,14 @@ union mksh_ccphack {
        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)
@@ -511,8 +518,9 @@ char *ucstrstr(char *, const char *);
 #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.
+extern void thiswillneverbedefinedIhope(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)
 
-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");
-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"
@@ -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 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");
@@ -830,7 +829,7 @@ struct temp {
  * 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
@@ -984,6 +983,8 @@ EXTERN uint32_t builtin_flag;
 /* 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.
@@ -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 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
@@ -1180,12 +1180,11 @@ EXTERN enum {
 
 /* 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 */
@@ -1254,10 +1253,6 @@ EXTERN const char *prompt;
 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.
  */
@@ -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 VALSUB 15      /* ${|foo;} substitution (NUL terminated) */
 
 /*
  * IO redirection
@@ -1680,7 +1676,7 @@ void x_init(void);
 #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 */
@@ -1834,8 +1830,7 @@ void yyerror(const char *, ...)
     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);
@@ -1903,6 +1898,7 @@ void initctypes(void);
 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);
@@ -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);
-void rndset(long);
+void rndset(unsigned long);
 
 enum Test_op {
        /* non-operator */
index 1c8a30e..3e4cf56 100644 (file)
@@ -1,11 +1,22 @@
 #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)
-#define FN(sname,cname,ochar,flags)    { sname, ochar, flags },
+#define FN(sname,cname,ochar,flags)    \
+       ((const char *)(&shoptione_ ## cname)) + 2,
 #endif
 
 #ifndef F0
@@ -45,6 +56,9 @@ FN("gmacs", FGMACS, 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)
 
@@ -88,7 +102,10 @@ FN("nounset", FNOUNSET, 'u', 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 */
@@ -97,7 +114,7 @@ FN("privileged", FPRIVILEGED, 'p', OF_ANY)
 /* -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) */
@@ -130,17 +147,17 @@ FN("viraw", FVIRAW, 0, OF_ANY)
 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) */
-FN(NULL, FAS_BUILTIN, 0, OF_INTERNAL)
+FN("", FAS_BUILTIN, 0, OF_INTERNAL)
 
 /* ./. (internal) initial shell was interactive */
-FN(NULL, FTALKING_I, 0, OF_INTERNAL)
+FN("", FTALKING_I, 0, OF_INTERNAL)
 
 #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
@@ -24,7 +25,7 @@
 
 #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 */
@@ -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;
-       int fd;
+       int fd, eno;
 
        /* 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) {
+               eno = errno;
                afree(shf, shf->areap);
+               errno = eno;
                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);
+                       errno = eno;
                        return (NULL);
                }
                fd = nfd;
@@ -740,8 +745,6 @@ shf_smprintf(const char *fmt, ...)
        return (shf_sclose(&shf));
 }
 
-#define BUF_SIZE       128
-
 #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)";
+                       else if (flags & FL_HASH) {
+                               print_value_quoted(shf, s);
+                               continue;
+                       }
                        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,
- *              2011, 2012
+ *              2011, 2012, 2013
  *     Thorsten Glaser <tg@mirbsd.org>
  *
  * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
 
 #include "sh.h"
 
-__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.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) */
@@ -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 *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);
@@ -108,9 +108,9 @@ pipeline(int cf)
                        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
-                               tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
+                               tl = tl->right = block(TPIPE, tl->right, p);
                }
                REJECT;
        }
@@ -128,7 +128,7 @@ andor(void)
                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;
        }
@@ -157,16 +157,15 @@ c_list(bool multi)
                } 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)
-                       t = tl = block(TLIST, t, p, NOWORDS);
+                       t = tl = block(TLIST, t, p);
                else
-                       tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
+                       tl = tl->right = block(TLIST, tl->right, p);
                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);
-       return (block(type, t, NOBLOCK, NOWORDS));
+       return (block(type, t, NULL));
 }
 
 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
@@ -465,7 +464,7 @@ get_command(int cf)
                t = pipeline(0);
                if (t == NULL)
                        syntaxerr(NULL);
-               t = block(TBANG, NOBLOCK, t, NOWORDS);
+               t = block(TBANG, NULL, t);
                break;
 
        case TIME:
@@ -477,7 +476,7 @@ get_command(int cf)
                        t->str[0] = '\0';
                        t->str[1] = '\0';
                }
-               t = block(TTIME, t, NOBLOCK, NOWORDS);
+               t = block(TTIME, t, NULL);
                break;
 
        case FUNCTION:
@@ -505,7 +504,7 @@ get_command(int cf)
                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);
@@ -632,7 +631,7 @@ casepart(int endtok)
        } while (token(0) == '|');
        REJECT;
        XPput(ptns, NULL);
-       t->vars = (char **) XPclose(ptns);
+       t->vars = (char **)XPclose(ptns);
        musthave(')', 0);
 
        t->left = c_list(true);
@@ -743,13 +742,8 @@ wordlist(void)
                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 *
-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;
-       t->vars = wp;
        return (t);
 }
 
@@ -1131,7 +1124,7 @@ yyrecursive(int subtype MKSH_A_UNUSED)
        struct yyrecursive_state *ys;
        int stok, etok;
 
-       if (subtype == FUNSUB) {
+       if (subtype != COMSUB) {
                stok = '{';
                etok = '}';
        } else {
index 8015a8d..dcbd7a1 100644 (file)
@@ -2,7 +2,7 @@
 
 /*-
  * 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
 
 #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 *);
-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 *);
@@ -214,7 +214,7 @@ ptree(struct op *t, int indent, struct shf *shf)
                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) {
@@ -244,7 +244,7 @@ ptree(struct op *t, int indent, struct shf *shf)
 }
 
 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;
@@ -259,16 +259,20 @@ pioact(struct shf *shf, int indent, struct ioword *iop)
 
        switch (type) {
        case IOREAD:
-               shf_puts("<", shf);
+               shf_putc('<', shf);
                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:
-               shf_puts(flag & IOCLOB ? ">|" : ">", shf);
+               shf_putc('>', shf);
+               if (flag & IOCLOB)
+                       shf_putc('|', 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);
-       } 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;
 }
 
@@ -345,7 +353,14 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
                        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:
@@ -485,7 +500,7 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
                                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);
@@ -588,6 +603,7 @@ wdscan(const char *wp, int c)
                        break;
                case COMSUB:
                case FUNSUB:
+               case VALSUB:
                case EXPRSUB:
                        while (*wp++ != 0)
                                ;
@@ -745,8 +761,8 @@ vistree(char *dst, size_t sz, struct op *t)
        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) {
@@ -830,6 +846,9 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
                case FUNSUB:
                        shf_puts("FUNSUB<", shf);
                        goto dumpsub;
+               case VALSUB:
+                       shf_puts("VALSUB<", 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,
@@ -27,7 +27,7 @@
 #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
@@ -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 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 *);
 
 /*
@@ -347,7 +347,7 @@ str_val(struct tbl *vp)
        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 ('#') +
@@ -361,8 +361,8 @@ str_val(struct tbl *vp)
                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;
@@ -471,48 +471,43 @@ setint(struct tbl *vq, mksh_ari_t n)
 }
 
 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;
-       bool have_base = false;
+       bool have_base = false, neg = false;
 
        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) {
-               *nump = vp->val.i;
+               nump->i = vp->val.i;
                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;
        }
-#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;
        }
-#endif
        while ((c = *s++)) {
                if (c == '-') {
-                       neg++;
+                       neg = true;
                        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)
@@ -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;
-                               *nump = (mksh_ari_t)wc;
+                               nump->u = (mksh_uari_t)wc;
                                return (1);
                        }
                        num = 0;
@@ -539,11 +534,13 @@ getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
                        c -= 'A' - 10;
                else
                        return (-1);
-               if (c < 0 || c >= base)
+               if (c >= base)
                        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);
 }
 
@@ -555,11 +552,11 @@ struct tbl *
 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);
-       setint_n(vq, num, 0);
+       setint_n(vq, num.i, 0);
        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);
+       if (val == var) {
+               /* no variable name given */
+               return (NULL);
+       }
        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
-                * or none given
                 */
                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);
                }
-               /* 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)
 {
-       register mksh_ari_t i;
+       mksh_ari_u num;
        int st;
        struct timeval tv;
 
@@ -1114,19 +1119,19 @@ getspec(struct tbl *vp)
        }
        switch (st) {
        case V_BASHPID:
-               i = (mksh_ari_t)procpid;
+               num.u = (mksh_uari_t)procpid;
                break;
        case V_COLUMNS:
-               i = x_cols;
+               num.i = x_cols;
                break;
        case V_HISTSIZE:
-               i = histsize;
+               num.i = histsize;
                break;
        case V_LINENO:
-               i = current_lineno + user_lineno;
+               num.i = current_lineno + user_lineno;
                break;
        case V_LINES:
-               i = x_lins;
+               num.i = x_lins;
                break;
        case V_EPOCHREALTIME: {
                /* 10(%u) + 1(.) + 6 + NUL */
@@ -1141,10 +1146,10 @@ getspec(struct tbl *vp)
                return;
        }
        case V_OPTIND:
-               i = user_opt.uoptind;
+               num.i = user_opt.uoptind;
                break;
        case V_RANDOM:
-               i = rndget();
+               num.i = rndget();
                break;
        case V_SECONDS:
                /*
@@ -1154,7 +1159,7 @@ getspec(struct tbl *vp)
                 */
                if (vp->flag & ISSET) {
                        mksh_TIME(tv);
-                       i = tv.tv_sec - seconds;
+                       num.i = tv.tv_sec - seconds;
                } else
                        return;
                break;
@@ -1163,14 +1168,14 @@ getspec(struct tbl *vp)
                return;
        }
        vp->flag &= ~SPECIAL;
-       setint_n(vp, i, 0);
+       setint_n(vp, num.i, 0);
        vp->flag |= SPECIAL;
 }
 
 static void
 setspec(struct tbl *vp)
 {
-       mksh_ari_t i;
+       mksh_ari_u num;
        char *s;
        int st;
 
@@ -1228,11 +1233,11 @@ setspec(struct tbl *vp)
        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);
-                       i = hash(s);
+                       num.u = hash(s);
                }
                vp->flag |= SPECIAL;
                break;
@@ -1245,40 +1250,40 @@ setspec(struct tbl *vp)
 
        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:
-               sethistsize(i);
+               sethistsize(num.i);
                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:
-               if (i >= MIN_LINS)
-                       x_lins = i;
+               if (num.i >= MIN_LINS)
+                       x_lins = num.i;
                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
                 */
-               rndset((long)i);
+               rndset((unsigned long)num.u);
                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:
-               ksh_tmout = i >= 0 ? i : 0;
+               ksh_tmout = num.i >= 0 ? num.i : 0;
                break;
        }
 }
@@ -1534,7 +1539,7 @@ rndget(void)
 }
 
 void
-rndset(long v)
+rndset(unsigned long v)
 {
        register uint32_t h;