Android-x86
Fork
Donation

  • R/O
  • HTTP
  • SSH
  • HTTPS

external-mksh: Commit

external/mksh


Commit MetaInfo

Revision811a575c0f6a5ef00a921d14c1830ef5ae1bd796 (tree)
Time2013-08-15 06:33:39
AuthorThorsten Glaser <tg@mirb...>
CommiterThorsten Glaser

Log Message

Update to mksh R48

Change-Id: I4d1bef9bf8ddc7899cfb32a6f2fa9e6f632bc53f

Change Summary

Incremental Difference

--- a/Android.mk
+++ b/Android.mk
@@ -37,6 +37,7 @@ LOCAL_C_INCLUDES:= $(LOCAL_PATH)/src
3737 LOCAL_CFLAGS:= -DMKSHRC_PATH=\"/system/etc/mkshrc\" \
3838 -DMKSH_DEFAULT_EXECSHELL=\"/system/bin/sh\" \
3939 -DMKSH_DEFAULT_TMPDIR=\"/data/local\" \
40+ -Wno-deprecated-declarations \
4041 -fno-asynchronous-unwind-tables -fwrapv \
4142 -DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_CONSERVATIVE_FDS \
4243 -DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH \
@@ -62,9 +63,8 @@ LOCAL_CFLAGS:= -DMKSHRC_PATH=\"/system/etc/mkshrc\" \
6263 -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 \
6364 -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \
6465 -DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 \
65- -DHAVE_PERSISTENT_HISTORY=0 -DHAVE_SILENT_IDIVWRAPV=0 \
66- -DMKSH_BUILD_R=431
66+ -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=481
6767
68-# check categories: shell:legacy-no int:32 android convfds no-histfile
68+# check_categories= shell:legacy-no int:32 android convfds no-histfile
6969
7070 include $(BUILD_EXECUTABLE)
--- a/mkmf.sh
+++ b/mkmf.sh
@@ -64,7 +64,6 @@ addvar CPPFLAGS \
6464 -isystem $aospdir/frameworks/native/opengl/include \
6565 -isystem $aospdir/frameworks/av/include \
6666 -isystem $aospdir/frameworks/base/include \
67- -isystem $aospdir/frameworks/base/opengl/include \
6867 -isystem $aospdir/external/skia/include \
6968 -isystem $aospdir/out/target/product/generic/obj/include \
7069 -isystem $aospdir/bionic/libc/arch-arm/include \
@@ -75,11 +74,10 @@ addvar CPPFLAGS \
7574 -isystem $aospdir/bionic/libm/include \
7675 -isystem $aospdir/bionic/libm/include/arm \
7776 -isystem $aospdir/bionic/libthread_db/include \
78- -D_FORTIFY_SOURCE=1 \
77+ -D_FORTIFY_SOURCE=2 \
7978 -include $aospdir/build/core/combo/include/arch/linux-arm/AndroidConfig.h \
8079 -I$aospdir/build/core/combo/include/arch/linux-arm/ \
8180 -DANDROID -DNDEBUG -UDEBUG
82-# who would have thought the AOSP devs are funny? -fno-builtin-sin
8381 addvar CFLAGS \
8482 -fno-exceptions \
8583 -Wno-multichar \
@@ -123,6 +121,7 @@ addvar CFLAGS \
123121 addvar LDFLAGS \
124122 -nostdlib \
125123 -Bdynamic \
124+ -fPIE \
126125 -pie \
127126 -Wl,-dynamic-linker,/system/bin/linker \
128127 -Wl,--gc-sections \
@@ -131,6 +130,7 @@ addvar LDFLAGS \
131130 -Wl,-z,relro \
132131 -Wl,-z,now \
133132 -Wl,--warn-shared-textrel \
133+ -Wl,--fatal-warnings \
134134 -Wl,--icf=safe \
135135 -Wl,--fix-cortex-a8 \
136136 -Wl,--no-undefined \
@@ -138,9 +138,9 @@ addvar LDFLAGS \
138138 addvar LIBS \
139139 -L$aospdir/out/target/product/generic/obj/lib \
140140 -Wl,-rpath-link=$aospdir/out/target/product/generic/obj/lib \
141- -lc \
142141 -Wl,--no-whole-archive \
143- $aospdir/out/target/product/generic/obj/STATIC_LIBRARIES/libcompiler-rt-extras_intermediates/libcompiler-rt-extras.a \
142+ $aospdir/out/target/product/generic/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a \
143+ -lc \
144144 $aospdir/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin/../lib/gcc/arm-linux-androideabi/4.7/armv7-a/libgcc.a \
145145 $aospdir/out/target/product/generic/obj/lib/crtend_android.o
146146
@@ -181,11 +181,6 @@ export HAVE_CAN_FNOSTRICTALIASING HAVE_CAN_FSTACKPROTECTORALL HAVE_CAN_WALL
181181 # even the idea of persistent history on a phone is funny
182182 HAVE_PERSISTENT_HISTORY=0; export HAVE_PERSISTENT_HISTORY
183183
184-# this is a run-time check and dependent on the target CPU
185-# architecture (at _least_!) and cannot be auto-detected,
186-# so always include the safety check even if unnecessary
187-HAVE_SILENT_IDIVWRAPV=0; export HAVE_SILENT_IDIVWRAPV
188-
189184 # ... and run it!
190185 export CC CPPFLAGS CFLAGS LDFLAGS LIBS TARGET_OS
191186 sh ../src/Build.sh $args
--- a/mkshrc
+++ b/mkshrc
@@ -9,12 +9,13 @@
99 : ${TERM:=vt100} ${HOME:=/data} ${MKSH:=/system/bin/sh} ${HOSTNAME:=$(getprop ro.product.device)}
1010 : ${SHELL:=$MKSH} ${USER:=$(typeset x=$(id); x=${x#*\(}; print -r -- ${x%%\)*})} ${HOSTNAME:=android}
1111 if (( USER_ID )); then PS1='$'; else PS1='#'; fi
12-function precmd {
13- typeset e=$?
12+PS4='[$EPOCHREALTIME] '; PS1='${|
13+ local e=$?
1414
15- (( e )) && print -n "$e|"
16-}
17-PS1='$(precmd)$USER@$HOSTNAME:${PWD:-?} '"$PS1 "
15+ (( e )) && REPLY+="$e|"
16+
17+ return $e
18+}$USER@$HOSTNAME:${PWD:-?} '"$PS1 "
1819 export HOME HOSTNAME MKSH SHELL TERM USER
1920 alias l='ls'
2021 alias la='l -a'
@@ -22,7 +23,34 @@ alias ll='l -l'
2223 alias lo='l -a -l'
2324
2425 function hd {
25- cat "$@" | command hd /proc/self/fd/0
26+ local -Uui16 -Z11 pos=0
27+ local -Uui16 -Z5 hv=2147483647
28+ local dasc line i
29+
30+ cat "$@" | { set +U; if read -arN -1 line; then
31+ typeset -i1 line
32+ i=0
33+ while (( i < ${#line[*]} )); do
34+ hv=${line[i++]}
35+ if (( (pos & 15) == 0 )); then
36+ (( pos )) && print -r -- "$dasc|"
37+ print -n "${pos#16#} "
38+ dasc=' |'
39+ fi
40+ print -n "${hv#16#} "
41+ if (( (hv < 32) || (hv > 126) )); then
42+ dasc+=.
43+ else
44+ dasc+=${line[i-1]#1#}
45+ fi
46+ (( (pos++ & 15) == 7 )) && print -n -- '- '
47+ done
48+ while (( pos & 15 )); do
49+ print -n ' '
50+ (( (pos++ & 15) == 7 )) && print -n -- '- '
51+ done
52+ (( hv == 2147483647 )) || print -r -- "$dasc|"
53+ fi; }
2654 }
2755
2856 function more {
--- a/src/Build.sh
+++ b/src/Build.sh
@@ -1,5 +1,5 @@
11 #!/bin/sh
2-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.622 2013/02/19 18:45:15 tg Exp $'
2+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.645 2013/08/10 13:44:25 tg Exp $'
33 #-
44 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
55 # 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 $'
2828 LC_ALL=C
2929 export LC_ALL
3030
31+echo "For the build logs, demonstrate that /dev/null and /dev/tty exist:"
32+ls -l /dev/null /dev/tty
33+
3134 case $ZSH_VERSION:$VERSION in
3235 :zsh*) ZSH_VERSION=2 ;;
3336 esac
@@ -63,7 +66,7 @@ vq() {
6366 rmf() {
6467 for _f in "$@"; do
6568 case $_f in
66- Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|mksh.1) ;;
69+ Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|*.ico|*.1) ;;
6770 *) rm -f "$_f" ;;
6871 esac
6972 done
@@ -190,6 +193,7 @@ ac_testn() {
190193 ac_ifcpp() {
191194 expr=$1; shift
192195 ac_testn "$@" <<-EOF
196+ extern int thiswillneverbedefinedIhope(void);
193197 int main(void) { return (
194198 #$expr
195199 0
@@ -458,7 +462,7 @@ oswarn=
458462 ccpc=-Wc,
459463 ccpl=-Wl,
460464 tsts=
461-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'
465+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'
462466
463467 # Evil hack
464468 if test x"$TARGET_OS" = x"Android"; then
@@ -686,8 +690,11 @@ Plan9)
686690 add_cppflags -D_SUSV2_SOURCE
687691 add_cppflags -DMKSH_ASSUME_UTF8; HAVE_ISSET_MKSH_ASSUME_UTF8=1
688692 add_cppflags -DMKSH_NO_CMDLINE_EDITING
693+ add_cppflags -DMKSH__NO_SETEUGID
689694 oswarn=' and will currently not work'
690695 add_cppflags -DMKSH_UNEMPLOYED
696+ # this is for detecting kencc
697+ add_cppflags -DMKSH_MAYBE_KENCC
691698 ;;
692699 PW32*)
693700 HAVE_SIG_T=0 # incompatible
@@ -766,7 +773,7 @@ esac
766773
767774 : ${HAVE_MKNOD=0}
768775
769-: ${AWK=awk} ${CC=cc} ${NROFF=nroff}
776+: ${AWK=awk} ${CC=cc} ${NROFF=nroff} ${SIZE=size}
770777 test 0 = $r && echo | $NROFF -v 2>&1 | grep GNU >/dev/null 2>&1 && \
771778 NROFF="$NROFF -c"
772779
@@ -876,6 +883,9 @@ ct="ucode"
876883 ct="uslc"
877884 #elif defined(__LCC__)
878885 ct="lcc"
886+#elif defined(MKSH_MAYBE_KENCC)
887+/* and none of the above matches */
888+ct="kencc"
879889 #else
880890 ct="unknown"
881891 #endif
@@ -952,6 +962,9 @@ iar)
952962 icc)
953963 vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN $LIBS -V"
954964 ;;
965+kencc)
966+ vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN -v conftest.c $LIBS"
967+ ;;
955968 lcc)
956969 vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN -v conftest.c $LIBS"
957970 add_cppflags -D__inline__=__inline
@@ -1074,19 +1087,23 @@ if ac_ifcpp 'if 0' compiler_fails '' \
10741087 'if the compiler does not fail correctly'; then
10751088 save_CFLAGS=$CFLAGS
10761089 : ${HAVE_CAN_DELEXE=x}
1077- if test $ct = dmc; then
1078- CFLAGS="$CFLAGS ${ccpl}/DELEXECUTABLE"
1079- ac_testn can_delexe compiler_fails 0 'for the /DELEXECUTABLE linker option' <<-EOF
1080- int main(void) { return (0); }
1081- EOF
1082- elif test $ct = dec; then
1090+ case $ct in
1091+ dec)
10831092 CFLAGS="$CFLAGS ${ccpl}-non_shared"
10841093 ac_testn can_delexe compiler_fails 0 'for the -non_shared linker option' <<-EOF
10851094 int main(void) { return (0); }
10861095 EOF
1087- else
1096+ ;;
1097+ dmc)
1098+ CFLAGS="$CFLAGS ${ccpl}/DELEXECUTABLE"
1099+ ac_testn can_delexe compiler_fails 0 'for the /DELEXECUTABLE linker option' <<-EOF
1100+ int main(void) { return (0); }
1101+ EOF
1102+ ;;
1103+ *)
10881104 exit 1
1089- fi
1105+ ;;
1106+ esac
10901107 test 1 = $HAVE_CAN_DELEXE || CFLAGS=$save_CFLAGS
10911108 ac_testn compiler_still_fails '' 'if the compiler still does not fail correctly' <<-EOF
10921109 EOF
@@ -1099,49 +1116,65 @@ if ac_ifcpp 'ifdef __TINYC__' couldbe_tcc '!' compiler_known 0 \
10991116 HAVE_COMPILER_KNOWN=1
11001117 fi
11011118
1102-if test $ct = sunpro; then
1103- test x"$save_NOWARN" = x"" && save_NOWARN='-errwarn=%none'
1104- ac_flags 0 errwarnnone "$save_NOWARN"
1105- test 1 = $HAVE_CAN_ERRWARNNONE || save_NOWARN=
1106- ac_flags 0 errwarnall "-errwarn=%all"
1107- test 1 = $HAVE_CAN_ERRWARNALL && DOWARN="-errwarn=%all"
1108-elif test $ct = hpcc; then
1119+case $ct in
1120+bcc)
1121+ save_NOWARN="${ccpc}-w"
1122+ DOWARN="${ccpc}-w!"
1123+ ;;
1124+dec)
1125+ # -msg_* flags not used yet, or is -w2 correct?
1126+ ;;
1127+dmc)
1128+ save_NOWARN="${ccpc}-w"
1129+ DOWARN="${ccpc}-wx"
1130+ ;;
1131+hpcc)
11091132 save_NOWARN=
11101133 DOWARN=+We
1111-elif test $ct = mipspro; then
1134+ ;;
1135+kencc)
1136+ save_NOWARN=
1137+ DOWARN=
1138+ ;;
1139+mipspro)
11121140 save_NOWARN=
11131141 DOWARN="-diag_error 1-10000"
1114-elif test $ct = msc; then
1142+ ;;
1143+msc)
11151144 save_NOWARN="${ccpc}/w"
11161145 DOWARN="${ccpc}/WX"
1117-elif test $ct = dmc; then
1118- save_NOWARN="${ccpc}-w"
1119- DOWARN="${ccpc}-wx"
1120-elif test $ct = bcc; then
1121- save_NOWARN="${ccpc}-w"
1122- DOWARN="${ccpc}-w!"
1123-elif test $ct = dec; then
1124- : -msg_* flags not used yet, or is -w2 correct?
1125-elif test $ct = xlc; then
1126- save_NOWARN=-qflag=i:e
1127- DOWARN=-qflag=i:i
1128-elif test $ct = tendra; then
1146+ ;;
1147+sunpro)
1148+ test x"$save_NOWARN" = x"" && save_NOWARN='-errwarn=%none'
1149+ ac_flags 0 errwarnnone "$save_NOWARN"
1150+ test 1 = $HAVE_CAN_ERRWARNNONE || save_NOWARN=
1151+ ac_flags 0 errwarnall "-errwarn=%all"
1152+ test 1 = $HAVE_CAN_ERRWARNALL && DOWARN="-errwarn=%all"
1153+ ;;
1154+tendra)
11291155 save_NOWARN=-w
1130-elif test $ct = ucode; then
1156+ ;;
1157+ucode)
11311158 save_NOWARN=
11321159 DOWARN=-w2
1133-elif test $ct = watcom; then
1160+ ;;
1161+watcom)
11341162 save_NOWARN=
11351163 DOWARN=-Wc,-we
1136-else
1164+ ;;
1165+xlc)
1166+ save_NOWARN=-qflag=i:e
1167+ DOWARN=-qflag=i:i
1168+ ;;
1169+*)
11371170 test x"$save_NOWARN" = x"" && save_NOWARN=-Wno-error
11381171 ac_flags 0 wnoerror "$save_NOWARN"
11391172 test 1 = $HAVE_CAN_WNOERROR || save_NOWARN=
11401173 ac_flags 0 werror -Werror
11411174 test 1 = $HAVE_CAN_WERROR && DOWARN=-Werror
1142-fi
1143-
1144-test $ct = icc && DOWARN="$DOWARN -wd1419"
1175+ test $ct = icc && DOWARN="$DOWARN -wd1419"
1176+ ;;
1177+esac
11451178 NOWARN=$save_NOWARN
11461179
11471180 #
@@ -1149,7 +1182,16 @@ NOWARN=$save_NOWARN
11491182 #
11501183 i=`echo :"$orig_CFLAGS" | sed 's/^://' | tr -c -d $alll$allu$alln`
11511184 # optimisation: only if orig_CFLAGS is empty
1152-test x"$i" = x"" && if test $ct = sunpro; then
1185+test x"$i" = x"" && case $ct in
1186+hpcc)
1187+ phase=u
1188+ ac_flags 1 otwo +O2
1189+ phase=x
1190+ ;;
1191+kencc|tcc|tendra)
1192+ # no special optimisation
1193+ ;;
1194+sunpro)
11531195 cat >x <<-'EOF'
11541196 int main(void) { return (0); }
11551197 #define __IDSTRING_CONCAT(l,p) __LINTED__ ## l ## _ ## p
@@ -1159,25 +1201,37 @@ test x"$i" = x"" && if test $ct = sunpro; then
11591201 yes pad | head -n 256 >>x
11601202 ac_flags - 1 otwo -xO2 <x
11611203 rmf x
1162-elif test $ct = hpcc; then
1163- phase=u
1164- ac_flags 1 otwo +O2
1165- phase=x
1166-elif test $ct = xlc; then
1204+ ;;
1205+xlc)
11671206 ac_flags 1 othree "-O3 -qstrict"
11681207 test 1 = $HAVE_CAN_OTHREE || ac_flags 1 otwo -O2
1169-elif test $ct = tcc || test $ct = tendra; then
1170- : no special optimisation
1171-else
1208+ ;;
1209+*)
11721210 ac_flags 1 otwo -O2
11731211 test 1 = $HAVE_CAN_OTWO || ac_flags 1 optimise -O
1174-fi
1212+ ;;
1213+esac
11751214 # other flags: just add them if they are supported
11761215 i=0
1177-if test $ct = gcc; then
1216+case $ct in
1217+bcc)
1218+ ac_flags 1 strpool "${ccpc}-d" 'if string pooling can be enabled'
1219+ ;;
1220+clang)
1221+ i=1
1222+ ;;
1223+dec)
1224+ ac_flags 0 verb -verbose
1225+ ac_flags 1 rodata -readonly_strings
1226+ ;;
1227+dmc)
1228+ ac_flags 1 decl "${ccpc}-r" 'for strict prototype checks'
1229+ ac_flags 1 schk "${ccpc}-s" 'for stack overflow checking'
1230+ ;;
1231+gcc)
11781232 # The following tests run with -Werror (gcc only) if possible
11791233 NOWARN=$DOWARN; phase=u
1180- ac_flags 0 wnooverflow -Wno-overflow
1234+ ac_flags 1 wnodeprecateddecls -Wno-deprecated-declarations
11811235 # mksh is not written in CFrustFrust!
11821236 ac_flags 1 no_eh_frame -fno-asynchronous-unwind-tables
11831237 ac_flags 1 fnostrictaliasing -fno-strict-aliasing
@@ -1186,15 +1240,19 @@ if test $ct = gcc; then
11861240 *\ -fplugin=*dragonegg*) ;;
11871241 *) ac_flags 1 fplugin_dragonegg -fplugin=dragonegg ;;
11881242 esac
1189- if test $cm = lto; then
1190- fv=0
1191- checks='1 2 3 4 5 6 7 8'
1192- elif test $cm = combine; then
1243+ case $cm in
1244+ combine)
11931245 fv=0
11941246 checks='7 8'
1195- else
1247+ ;;
1248+ lto)
1249+ fv=0
1250+ checks='1 2 3 4 5 6 7 8'
1251+ ;;
1252+ *)
11961253 fv=1
1197- fi
1254+ ;;
1255+ esac
11981256 test $fv = 1 || for what in $checks; do
11991257 test $fv = 1 && break
12001258 case $what in
@@ -1223,32 +1281,23 @@ if test $ct = gcc; then
12231281 "if gcc supports $t_cflags $t_ldflags" "$t_ldflags"
12241282 done
12251283 i=1
1226-elif test $ct = icc; then
1227- ac_flags 1 fnobuiltinsetmode -fno-builtin-setmode
1228- ac_flags 1 fnostrictaliasing -fno-strict-aliasing
1229- ac_flags 1 fstacksecuritycheck -fstack-security-check
1230- i=1
1231-elif test $ct = sunpro; then
1232- phase=u
1233- ac_flags 1 v -v
1234- ac_flags 1 ipo -xipo 'for cross-module optimisation'
1235- phase=x
1236-elif test $ct = hpcc; then
1284+ ;;
1285+hpcc)
12371286 phase=u
12381287 # probably not needed
12391288 #ac_flags 1 agcc -Agcc 'for support of GCC extensions'
12401289 phase=x
1241-elif test $ct = dec; then
1242- ac_flags 0 verb -verbose
1243- ac_flags 1 rodata -readonly_strings
1244-elif test $ct = dmc; then
1245- ac_flags 1 decl "${ccpc}-r" 'for strict prototype checks'
1246- ac_flags 1 schk "${ccpc}-s" 'for stack overflow checking'
1247-elif test $ct = bcc; then
1248- ac_flags 1 strpool "${ccpc}-d" 'if string pooling can be enabled'
1249-elif test $ct = mipspro; then
1290+ ;;
1291+icc)
1292+ ac_flags 1 fnobuiltinsetmode -fno-builtin-setmode
1293+ ac_flags 1 fnostrictaliasing -fno-strict-aliasing
1294+ ac_flags 1 fstacksecuritycheck -fstack-security-check
1295+ i=1
1296+ ;;
1297+mipspro)
12501298 ac_flags 1 fullwarn -fullwarn 'for remark output support'
1251-elif test $ct = msc; then
1299+ ;;
1300+msc)
12521301 ac_flags 1 strpool "${ccpc}/GF" 'if string pooling can be enabled'
12531302 echo 'int main(void) { char test[64] = ""; return (*test); }' >x
12541303 ac_flags - 1 stackon "${ccpc}/GZ" 'if stack checks can be enabled' <x
@@ -1257,24 +1306,33 @@ elif test $ct = msc; then
12571306 rmf x
12581307 ac_flags 1 wall "${ccpc}/Wall" 'to enable all warnings'
12591308 ac_flags 1 wp64 "${ccpc}/Wp64" 'to enable 64-bit warnings'
1260-elif test $ct = xlc; then
1309+ ;;
1310+nwcc)
1311+ i=1
1312+ #broken# ac_flags 1 ssp -stackprotect
1313+ ;;
1314+sunpro)
1315+ phase=u
1316+ ac_flags 1 v -v
1317+ ac_flags 1 ipo -xipo 'for cross-module optimisation'
1318+ phase=x
1319+ ;;
1320+tcc)
1321+ : #broken# ac_flags 1 boundschk -b
1322+ ;;
1323+tendra)
1324+ ac_flags 0 ysystem -Ysystem
1325+ test 1 = $HAVE_CAN_YSYSTEM && CPPFLAGS="-Ysystem $CPPFLAGS"
1326+ ac_flags 1 extansi -Xa
1327+ ;;
1328+xlc)
12611329 ac_flags 1 rodata "-qro -qroconst -qroptr"
12621330 ac_flags 1 rtcheck -qcheck=all
12631331 #ac_flags 1 rtchkc -qextchk # reported broken
12641332 ac_flags 1 wformat "-qformat=all -qformat=nozln"
12651333 #ac_flags 1 wp64 -qwarn64 # too verbose for now
1266-elif test $ct = tendra; then
1267- ac_flags 0 ysystem -Ysystem
1268- test 1 = $HAVE_CAN_YSYSTEM && CPPFLAGS="-Ysystem $CPPFLAGS"
1269- ac_flags 1 extansi -Xa
1270-elif test $ct = tcc; then
1271- : #broken# ac_flags 1 boundschk -b
1272-elif test $ct = clang; then
1273- i=1
1274-elif test $ct = nwcc; then
1275- i=1
1276- : #broken# ac_flags 1 ssp -stackprotect
1277-fi
1334+ ;;
1335+esac
12781336 # flags common to a subset of compilers (run with -Werror on gcc)
12791337 if test 1 = $i; then
12801338 ac_flags 1 wall -Wall
@@ -1291,6 +1349,7 @@ test $ct = pcc && phase=u
12911349 #
12921350 ac_test attribute_bounded '' 'for __attribute__((__bounded__))' <<-'EOF'
12931351 #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
1352+ extern int thiswillneverbedefinedIhope(void);
12941353 /* force a failure: TenDRA and gcc 1.42 have false positive here */
12951354 int main(void) { return (thiswillneverbedefinedIhope()); }
12961355 #else
@@ -1311,6 +1370,7 @@ ac_test attribute_bounded '' 'for __attribute__((__bounded__))' <<-'EOF'
13111370 EOF
13121371 ac_test attribute_format '' 'for __attribute__((__format__))' <<-'EOF'
13131372 #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
1373+ extern int thiswillneverbedefinedIhope(void);
13141374 /* force a failure: TenDRA and gcc 1.42 have false positive here */
13151375 int main(void) { return (thiswillneverbedefinedIhope()); }
13161376 #else
@@ -1325,6 +1385,7 @@ ac_test attribute_format '' 'for __attribute__((__format__))' <<-'EOF'
13251385 EOF
13261386 ac_test attribute_noreturn '' 'for __attribute__((__noreturn__))' <<-'EOF'
13271387 #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
1388+ extern int thiswillneverbedefinedIhope(void);
13281389 /* force a failure: TenDRA and gcc 1.42 have false positive here */
13291390 int main(void) { return (thiswillneverbedefinedIhope()); }
13301391 #else
@@ -1337,6 +1398,7 @@ ac_test attribute_noreturn '' 'for __attribute__((__noreturn__))' <<-'EOF'
13371398 EOF
13381399 ac_test attribute_unused '' 'for __attribute__((__unused__))' <<-'EOF'
13391400 #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
1401+ extern int thiswillneverbedefinedIhope(void);
13401402 /* force a failure: TenDRA and gcc 1.42 have false positive here */
13411403 int main(void) { return (thiswillneverbedefinedIhope()); }
13421404 #else
@@ -1346,6 +1408,7 @@ ac_test attribute_unused '' 'for __attribute__((__unused__))' <<-'EOF'
13461408 EOF
13471409 ac_test attribute_used '' 'for __attribute__((__used__))' <<-'EOF'
13481410 #if defined(__TenDRA__) || (defined(__GNUC__) && (__GNUC__ < 2))
1411+ extern int thiswillneverbedefinedIhope(void);
13491412 /* force a failure: TenDRA and gcc 1.42 have false positive here */
13501413 int main(void) { return (thiswillneverbedefinedIhope()); }
13511414 #else
@@ -1368,8 +1431,8 @@ if ac_ifcpp 'ifdef MKSH_SMALL' isset_MKSH_SMALL '' \
13681431 check_categories="$check_categories smksh"
13691432 HAVE_ISSET_MKSH_CONSERVATIVE_FDS=1 # from sh.h
13701433 fi
1371-ac_ifcpp 'ifdef MKSH_BINSHREDUCED' isset_MKSH_BINSHREDUCED '' \
1372- "if a reduced-feature sh is requested" && \
1434+ac_ifcpp 'if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED)' \
1435+ isset_MKSH_BINSH '' 'if invoking as sh should be handled specially' && \
13731436 check_categories="$check_categories binsh"
13741437 ac_ifcpp 'ifdef MKSH_UNEMPLOYED' isset_MKSH_UNEMPLOYED '' \
13751438 "if mksh will be built without job control" && \
@@ -1491,14 +1554,16 @@ ac_testn sig_t <<-'EOF'
14911554 #include <sys/types.h>
14921555 #include <signal.h>
14931556 #include <stddef.h>
1494- int main(void) { return ((int)(ptrdiff_t)(sig_t)(ptrdiff_t)kill(0,0)); }
1557+ volatile sig_t foo = (sig_t)0;
1558+ int main(void) { return (foo == (sig_t)0); }
14951559 EOF
14961560
14971561 ac_testn sighandler_t '!' sig_t 0 <<-'EOF'
14981562 #include <sys/types.h>
14991563 #include <signal.h>
15001564 #include <stddef.h>
1501- int main(void) { return ((int)(ptrdiff_t)(sighandler_t)(ptrdiff_t)kill(0,0)); }
1565+ volatile sighandler_t foo = (sighandler_t)0;
1566+ int main(void) { return (foo == (sighandler_t)0); }
15021567 EOF
15031568 if test 1 = $HAVE_SIGHANDLER_T; then
15041569 add_cppflags -Dsig_t=sighandler_t
@@ -1509,7 +1574,8 @@ ac_testn __sighandler_t '!' sig_t 0 <<-'EOF'
15091574 #include <sys/types.h>
15101575 #include <signal.h>
15111576 #include <stddef.h>
1512- int main(void) { return ((int)(ptrdiff_t)(__sighandler_t)(ptrdiff_t)kill(0,0)); }
1577+ volatile __sighandler_t foo = (__sighandler_t)0;
1578+ int main(void) { return (foo == (__sighandler_t)0); }
15131579 EOF
15141580 if test 1 = $HAVE___SIGHANDLER_T; then
15151581 add_cppflags -Dsig_t=__sighandler_t
@@ -1532,7 +1598,7 @@ else
15321598 #define EXTERN
15331599 #define MKSH_INCLUDES_ONLY
15341600 #include "sh.h"
1535- __RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.622 2013/02/19 18:45:15 tg Exp $");
1601+ __RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.645 2013/08/10 13:44:25 tg Exp $");
15361602 int main(void) { printf("Hello, World!\n"); return (0); }
15371603 EOF
15381604 case $cm in
@@ -1748,7 +1814,7 @@ EOF
17481814 ac_test setresugid <<-'EOF'
17491815 #include <sys/types.h>
17501816 #include <unistd.h>
1751- int main(void) { setresuid(0,0,0); return (setresgid(0,0,0)); }
1817+ int main(void) { return (setresuid(0,0,0) + setresgid(0,0,0)); }
17521818 EOF
17531819
17541820 ac_test setgroups setresugid 0 <<-'EOF'
@@ -1848,7 +1914,6 @@ ac_testdone
18481914 ac_cppflags
18491915
18501916 save_CFLAGS=$CFLAGS
1851-test x1 = x$HAVE_CAN_WNOOVERFLOW && CFLAGS="$CFLAGS -Wno-overflow"
18521917 ac_testn compile_time_asserts_$$ '' 'whether compile-time assertions pass' <<-'EOF'
18531918 #define MKSH_INCLUDES_ONLY
18541919 #include "sh.h"
@@ -1875,13 +1940,8 @@ cta(long_size_no_matter_of_signedness, sizeof(long) == sizeof(unsigned long));
18751940 #ifndef MKSH_LEGACY_MODE
18761941 /* the next assertion is probably not really needed */
18771942 cta(ari_is_4_char, sizeof(mksh_ari_t) == 4);
1878-/* but the next two are; we REQUIRE signed integer wraparound */
1943+/* but this is */
18791944 cta(ari_has_31_bit, 0 < (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1));
1880-#ifndef MKSH_GCC55009
1881-cta(ari_sign_32_bit_and_wrap,
1882- (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1) >
1883- (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 2));
1884-#endif
18851945 /* the next assertion is probably not really needed */
18861946 cta(uari_is_4_char, sizeof(mksh_uari_t) == 4);
18871947 /* 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
18901950 cta(uari_wrap_32_bit,
18911951 (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) >
18921952 (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4));
1953+#define NUM 22
1954+#else
1955+#define NUM 16
18931956 #endif
18941957 /* these are always required */
18951958 cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0);
18961959 cta(uari_is_unsigned, (mksh_uari_t)-1 > (mksh_uari_t)0);
1960+/* we require these to have the precisely same size and assume 2s complement */
1961+cta(ari_size_no_matter_of_signedness, sizeof(mksh_ari_t) == sizeof(mksh_uari_t));
18971962
18981963 cta(sizet_size_no_matter_of_signedness, sizeof(ssize_t) == sizeof(size_t));
18991964 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 *));
19011966 cta(ptrdifft_funcptr_same_size, sizeof(ptrdiff_t) == sizeof(void (*)(void)));
19021967 /* our formatting routines assume this */
19031968 cta(ptr_fits_in_long, sizeof(ptrdiff_t) <= sizeof(long));
1969+/* for struct alignment people */
1970+ char padding[64 - NUM];
19041971 };
1905-#ifndef MKSH_LEGACY_MODE
1906-#ifndef MKSH_GCC55009
1907-#define NUM 22
1908-#else
1909-#define NUM 21
1910-#endif
1911-#else
1912-#define NUM 15
1913-#endif
1914-char ctasserts_dblcheck[sizeof(struct ctasserts) == NUM ? 1 : -1];
1972+char ctasserts_dblcheck[sizeof(struct ctasserts) == 64 ? 1 : -1];
19151973 int main(void) { return (sizeof(ctasserts_dblcheck)); }
19161974 EOF
19171975 CFLAGS=$save_CFLAGS
@@ -1957,71 +2015,6 @@ EOF
19572015 fi
19582016
19592017 #
1960-# runtime checks
1961-# once this is more than one, check if we can do runtime
1962-# checks (not cross-compiling) first to save on warnings
1963-#
1964-$e "${bi}run-time checks follow$ao, please ignore any weird errors"
1965-
1966-if ac_testnnd silent_idivwrapv '' '(run-time) whether signed integer division overflows wrap silently' <<-'EOF'
1967- #define MKSH_INCLUDES_ONLY
1968- #include "sh.h"
1969- #if !defined(MKSH_LEGACY_MODE) || HAVE_LONG_32BIT
1970- #define IDIVWRAPV_VL (mksh_uari_t)0x80000000UL
1971- #elif HAVE_LONG_64BIT
1972- #define IDIVWRAPV_VL (mksh_uari_t)0x8000000000000000UL
1973- #else
1974- # error "cannot check this"
1975- #endif
1976- #ifdef SIGFPE
1977- static void fpe_catcher(int) MKSH_A_NORETURN;
1978- #endif
1979- int main(int ac, char **av) {
1980- mksh_ari_t o1, o2, r1, r2;
1981-
1982- #ifdef SIGFPE
1983- signal(SIGFPE, fpe_catcher);
1984- #endif
1985- o1 = (mksh_ari_t)IDIVWRAPV_VL;
1986- o2 = -ac;
1987- r1 = o1 / o2;
1988- r2 = o1 % o2;
1989- if (r1 == o1 && r2 == 0) {
1990- printf("si");
1991- return (0);
1992- }
1993- printf("no %d %d %d %d %s", (int)o1, (int)o2, (int)r1,
1994- (int)r2, av[0]);
1995- return (1);
1996- }
1997- #ifdef SIGFPE
1998- static const char fpe_msg[] = "no, got SIGFPE, what were they smoking?";
1999- #define fpe_msglen (sizeof(fpe_msg) - 1)
2000- static void fpe_catcher(int sig MKSH_A_UNUSED) {
2001- _exit(write(1, fpe_msg, fpe_msglen) == fpe_msglen ? 2 : 3);
2002- }
2003- #endif
2004-EOF
2005-then
2006- if test $fv = 0; then
2007- echo "| hrm, compiling this failed, but we will just failback"
2008- else
2009- echo "| running test programme; this will fail if cross-compiling"
2010- echo "| in which case we will gracefully degrade to the default"
2011- ./$tcfn >vv.out 2>&1
2012- rv=$?
2013- echo "| result: `cat vv.out`"
2014- fv=0
2015- test $rv = 0 && test x"`cat vv.out`" = x"si" && fv=1
2016- fi
2017- rmf conftest.c conftest.o ${tcfn}* vv.out
2018- ac_testdone
2019-fi
2020-ac_cppflags
2021-
2022-$e "${bi}end of run-time checks$ao"
2023-
2024-#
20252018 # Compiler: Praeprocessor (only if needed)
20262019 #
20272020 test 0 = $HAVE_SYS_SIGNAME && if ac_testinit cpp_dd '' \
@@ -2120,7 +2113,7 @@ addsrcs USE_PRINTF_BUILTIN printf.c
21202113 test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
21212114 test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
21222115 test -n "$LDSTATIC" && add_cppflags -DMKSH_OPTSTATIC
2123-add_cppflags -DMKSH_BUILD_R=431
2116+add_cppflags -DMKSH_BUILD_R=481
21242117
21252118 $e $bi$me: Finished configuration testing, now producing output.$ao
21262119
@@ -2219,13 +2212,17 @@ cat >test.sh <<-EOF
22192212 exit \$rv
22202213 EOF
22212214 chmod 755 test.sh
2222-if test $cm = llvm; then
2223- emitbc="-emit-llvm -c"
2224-elif test $cm = dragonegg; then
2215+case $cm in
2216+dragonegg)
22252217 emitbc="-S -flto"
2226-else
2218+ ;;
2219+llvm)
2220+ emitbc="-emit-llvm -c"
2221+ ;;
2222+*)
22272223 emitbc=-c
2228-fi
2224+ ;;
2225+esac
22292226 echo ": # work around NeXTstep bug" >Rebuild.sh
22302227 echo set -x >>Rebuild.sh
22312228 for file in $SRCS; do
@@ -2254,7 +2251,7 @@ dragonegg|llvm)
22542251 esac
22552252 echo tcfn=$mkshexe >>Rebuild.sh
22562253 echo "$CC $CFLAGS $LDFLAGS -o \$tcfn $lobjs $LIBS $ccpr" >>Rebuild.sh
2257-echo 'test -f $tcfn || exit 1; size $tcfn' >>Rebuild.sh
2254+echo "test -f \$tcfn || exit 1; $SIZE \$tcfn" >>Rebuild.sh
22582255 if test $cm = makefile; then
22592256 extras='emacsfn.h sh.h sh_flags.h var_spec.h'
22602257 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"
23352332 test -f $tcfn || exit 1
23362333 test 1 = $r || v "$NROFF -mdoc <'$srcdir/mksh.1' >$tfn.cat1" || \
23372334 rmf $tfn.cat1
2338-test 0 = $eq && v size $tcfn
2335+test 0 = $eq && v $SIZE $tcfn
23392336 i=install
23402337 test -f /usr/ucb/$i && i=/usr/ucb/$i
23412338 test 1 = $eq && e=:
23422339 $e
23432340 $e Installing the shell:
23442341 $e "# $i -c -s -o root -g bin -m 555 $tfn /bin/$tfn"
2345-$e "# grep -x /bin/$tfn /etc/shells >/dev/null || echo /bin/$tfn >>/etc/shells"
2346-$e "# $i -c -o root -g bin -m 444 dot.mkshrc /usr/share/doc/mksh/examples/"
2342+if test $legacy = 0; then
2343+ $e "# grep -x /bin/$tfn /etc/shells >/dev/null || echo /bin/$tfn >>/etc/shells"
2344+ $e "# $i -c -o root -g bin -m 444 dot.mkshrc /usr/share/doc/mksh/examples/"
2345+fi
23472346 $e
23482347 $e Installing the manual:
23492348 if test -f $tfn.cat1; then
@@ -2351,7 +2350,7 @@ if test -f $tfn.cat1; then
23512350 "/usr/share/man/cat1/$tfn.0"
23522351 $e or
23532352 fi
2354-$e "# $i -c -o root -g bin -m 444 mksh.1 /usr/share/man/man1/$tfn.1"
2353+$e "# $i -c -o root -g bin -m 444 $tfn.1 /usr/share/man/man1/$tfn.1"
23552354 $e
23562355 $e Run the regression test suite: ./test.sh
23572356 $e Please also read the sample file dot.mkshrc and the fine manual.
@@ -2389,6 +2388,7 @@ DEBUG_LEAKS enable freeing resources before exiting
23892388 MKSHRC_PATH "~/.mkshrc" (do not change)
23902389 MKSH_A4PB force use of arc4random_pushb
23912390 MKSH_ASSUME_UTF8 (0=disabled, 1=enabled; default: unset)
2391+MKSH_BINSHPOSIX if */sh or */-sh, enable set -o posix
23922392 MKSH_BINSHREDUCED if */sh or */-sh, enable set -o sh
23932393 MKSH_CLRTOEOL_STRING "\033[K"
23942394 MKSH_CLS_STRING "\033[;H\033[J"
@@ -2400,7 +2400,6 @@ MKSH_DISABLE_DEPRECATED disable code paths scheduled for later removal
24002400 MKSH_DISABLE_EXPERIMENTAL disable code not yet comfy for (LTS) snapshots
24012401 MKSH_DISABLE_TTY_WARNING shut up warning about ctty if OS cant be fixed
24022402 MKSH_DONT_EMIT_IDSTRING omit RCS IDs from binary
2403-MKSH_GCC55009 DANGER! see http://www.mirbsd.org/mksh.htm#p41
24042403 MKSH_MIDNIGHTBSD01ASH_COMPAT set -o sh: additional compatibility quirk
24052404 MKSH_NOPROSPECTOFWORK disable jobs, co-processes, etc. (do not use)
24062405 MKSH_NOPWNAM skip PAM calls, for -static on eglibc, Solaris
--- a/src/check.pl
+++ b/src/check.pl
@@ -1,7 +1,8 @@
1-# $MirOS: src/bin/mksh/check.pl,v 1.31 2012/04/06 12:22:14 tg Exp $
2-# $OpenBSD: th,v 1.13 2006/05/18 21:27:23 miod Exp $
1+# $MirOS: src/bin/mksh/check.pl,v 1.32 2013/07/21 18:35:56 tg Exp $
2+# $OpenBSD: th,v 1.16 2013/06/14 20:52:08 millert Exp $
33 #-
4-# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012
4+# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
5+# 2012, 2013
56 # Thorsten Glaser <tg@mirbsd.org>
67 #
78 # Provided that these terms and disclaimer and all copyright notices
@@ -171,13 +172,15 @@ BEGIN {
171172
172173 use Getopt::Std;
173174 use Config;
175+use File::Temp qw/ :mktemp /;
174176
175177 $os = defined $^O ? $^O : 'unknown';
176178
177179 ($prog = $0) =~ s#.*/##;
178180
179181 $Usage = <<EOF ;
180-Usage: $prog [-Pv] [-C cat] [-e e=v] [-p prog] [-s fn] [-t tmo] name ...
182+Usage: $prog [-Pv] [-C cat] [-e e=v] [-p prog] [-s fn] [-T dir] \
183+ [-t tmo] name ...
181184 -C c Specify the comma separated list of categories the program
182185 belongs to (see category field).
183186 -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 ...
188191 -p p Use p as the program to test
189192 -s s Read tests from file s; if s is a directory, it is recursively
190193 scaned for test files (which end in .t).
194+ -T dir Use dir instead of /tmp to hold temporary files
191195 -t t Use t as default time limit for tests (default is unlimited)
192196 -v Verbose mode: print reason test failed.
193197 name specifies the name of the test(s) to run; if none are
@@ -229,12 +233,6 @@ EOF
229233 "os:$os", '1'
230234 );
231235
232-$temps = "/tmp/rts$$";
233-$tempi = "/tmp/rti$$";
234-$tempo = "/tmp/rto$$";
235-$tempe = "/tmp/rte$$";
236-$tempdir = "/tmp/rtd$$";
237-
238236 $nfailed = 0;
239237 $nifailed = 0;
240238 $nxfailed = 0;
@@ -243,7 +241,7 @@ $nxpassed = 0;
243241
244242 %known_tests = ();
245243
246-if (!getopts('C:e:Pp:s:t:v')) {
244+if (!getopts('C:e:Pp:s:T:t:v')) {
247245 print STDERR $Usage;
248246 exit 1;
249247 }
@@ -253,6 +251,7 @@ die "$prog: no test set specified (use -s)\n" if !defined $opt_s;
253251 $test_prog = $opt_p;
254252 $verbose = defined $opt_v && $opt_v;
255253 $test_set = $opt_s;
254+$temp_dir = $opt_T || "/tmp";
256255 if (defined $opt_t) {
257256 die "$prog: bad -t argument (should be number > 0): $opt_t\n"
258257 if $opt_t !~ /^\d+$/ || $opt_t <= 0;
@@ -297,8 +296,6 @@ if (defined $opt_e) {
297296 }
298297 %old_env = %ENV;
299298
300-die "$prog: couldn't make directory $tempdir - $!\n" if !mkdir($tempdir, 0777);
301-
302299 chop($pwd = `pwd 2>/dev/null`);
303300 die "$prog: couldn't get current working directory\n" if $pwd eq '';
304301 die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd);
@@ -316,6 +313,17 @@ $SIG{'ALRM'} = 'catch_sigalrm';
316313
317314 $| = 1;
318315
316+# Create temp files
317+($fh, $temps) = mkstemp("${temp_dir}/rts.XXXXXXXX");
318+close($fh);
319+($fh, $tempi) = mkstemp("${temp_dir}/rti.XXXXXXXX");
320+close($fh);
321+($fh, $tempo) = mkstemp("${temp_dir}/rto.XXXXXXXX");
322+close($fh);
323+($fh, $tempe) = mkstemp("${temp_dir}/rte.XXXXXXXX");
324+close($fh);
325+$tempdir = mkdtemp("${temp_dir}/rtd.XXXXXXXX");
326+
319327 if (-d $test_set) {
320328 $file_prefix_skip = length($test_set) + 1;
321329 $ret = &process_test_dir($test_set);
@@ -433,6 +441,8 @@ run_test
433441 local(*test) = @_;
434442 local($name) = $test{':full-name'};
435443
444+ return undef if !&scrub_dir($tempdir);
445+
436446 if (defined $test{'stdin'}) {
437447 return undef if !&write_file($tempi, $test{'stdin'});
438448 $ifile = $tempi;
@@ -444,8 +454,6 @@ run_test
444454 return undef if !&write_file($temps, $test{'script'});
445455 }
446456
447- return undef if !&scrub_dir($tempdir);
448-
449457 if (!chdir($tempdir)) {
450458 print STDERR "$prog: couldn't cd to $tempdir - $!\n";
451459 return undef;
--- a/src/check.t
+++ b/src/check.t
@@ -1,7 +1,9 @@
1-# $MirOS: src/bin/mksh/check.t,v 1.597 2013/02/19 18:45:17 tg Exp $
1+# $MirOS: src/bin/mksh/check.t,v 1.629 2013/08/14 20:26:15 tg Exp $
22 # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
33 # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
44 # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
5+# $OpenBSD: regress.t,v 1.15 2013/07/01 17:25:27 jca Exp $
6+# $OpenBSD: obsd-regress.t,v 1.5 2013/07/01 17:25:27 jca Exp $
57 #-
68 # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
79 # 2011, 2012, 2013
@@ -29,7 +31,7 @@
2931 # http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD
3032
3133 expected-stdout:
32- @(#)MIRBSD KSH R43 2013/02/19
34+ @(#)MIRBSD KSH R48 2013/08/14
3335 description:
3436 Check version of shell.
3537 stdin:
@@ -38,7 +40,7 @@ name: KSH_VERSION
3840 category: shell:legacy-no
3941 ---
4042 expected-stdout:
41- @(#)LEGACY KSH R43 2013/02/19
43+ @(#)LEGACY KSH R48 2013/08/14
4244 description:
4345 Check version of legacy shell.
4446 stdin:
@@ -290,6 +292,22 @@ stdin:
290292 expected-stdout:
291293 = 4 2 =
292294 ---
295+name: arith-lazy-4
296+description:
297+ Check that preun/postun not done on non-evaluated side of ternary
298+ operator
299+stdin:
300+ (( m = n = 0, 1 ? n++ : m++ ? 2 : 3 ))
301+ echo "($n, $m)"
302+ m=0; echo $(( 0 ? ++m : 2 )); echo $m
303+ m=0; echo $(( 0 ? m++ : 2 )); echo $m
304+expected-stdout:
305+ (1, 0)
306+ 2
307+ 0
308+ 2
309+ 0
310+---
293311 name: arith-ternary-prec-1
294312 description:
295313 Check precedence of ternary operator vs assignment
@@ -363,30 +381,35 @@ expected-stdout:
363381 ---
364382 name: arith-mandatory
365383 description:
366- If MKSH_GCC55009 is set when compiling, passing of
367- this test is *mandatory* for a valid mksh executable!
384+ Passing of this test is *mandatory* for a valid mksh executable!
368385 category: shell:legacy-no
369386 stdin:
370387 typeset -i sari=0
371388 typeset -Ui uari=0
372389 typeset -i x=0
373- print -r -- $((x++)):$sari=$uari.
390+ print -r -- $((x++)):$sari=$uari. #0
374391 let --sari --uari
375- print -r -- $((x++)):$sari=$uari.
392+ print -r -- $((x++)):$sari=$uari. #1
376393 sari=2147483647 uari=2147483647
377- print -r -- $((x++)):$sari=$uari.
394+ print -r -- $((x++)):$sari=$uari. #2
378395 let ++sari ++uari
379- print -r -- $((x++)):$sari=$uari.
396+ print -r -- $((x++)):$sari=$uari. #3
380397 let --sari --uari
381398 let 'sari *= 2' 'uari *= 2'
382399 let ++sari ++uari
383- print -r -- $((x++)):$sari=$uari.
400+ print -r -- $((x++)):$sari=$uari. #4
384401 let ++sari ++uari
385- print -r -- $((x++)):$sari=$uari.
402+ print -r -- $((x++)):$sari=$uari. #5
386403 sari=-2147483648 uari=-2147483648
387- print -r -- $((x++)):$sari=$uari.
404+ print -r -- $((x++)):$sari=$uari. #6
388405 let --sari --uari
389- print -r -- $((x++)):$sari=$uari.
406+ print -r -- $((x++)):$sari=$uari. #7
407+ (( sari = -5 >> 1 ))
408+ ((# uari = -5 >> 1 ))
409+ print -r -- $((x++)):$sari=$uari. #8
410+ (( sari = -2 ))
411+ ((# uari = sari ))
412+ print -r -- $((x++)):$sari=$uari. #9
390413 expected-stdout:
391414 0:0=0.
392415 1:-1=4294967295.
@@ -396,6 +419,8 @@ expected-stdout:
396419 5:0=0.
397420 6:-2147483648=2147483648.
398421 7:2147483647=2147483647.
422+ 8:-3=2147483645.
423+ 9:-2=4294967294.
399424 ---
400425 name: arith-unsigned-1
401426 description:
@@ -2530,30 +2555,6 @@ expected-stdout:
25302555 \END
25312556 end
25322557 ---
2533-name: heredoc-quoting-unsubst
2534-description:
2535- Check for correct handling of quoted characters in
2536- here documents without substitution (marker is quoted).
2537-stdin:
2538- foo=bar
2539- cat <<-'EOF'
2540- x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
2541- EOF
2542-expected-stdout:
2543- x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
2544----
2545-name: heredoc-quoting-subst
2546-description:
2547- Check for correct handling of quoted characters in
2548- here documents with substitution (marker is not quoted).
2549-stdin:
2550- foo=bar
2551- cat <<-EOF
2552- x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
2553- EOF
2554-expected-stdout:
2555- x " \" \ \ $ $ baz `echo baz` bar $foo x
2556----
25572558 name: heredoc-tmpfile-1
25582559 description:
25592560 Check that heredoc temp files aren't removed too soon or too late.
@@ -2736,6 +2737,131 @@ expected-stdout:
27362737 hi
27372738 Left overs: *
27382739 ---
2740+name: heredoc-quoting-unsubst
2741+description:
2742+ Check for correct handling of quoted characters in
2743+ here documents without substitution (marker is quoted).
2744+stdin:
2745+ foo=bar
2746+ cat <<-'EOF'
2747+ x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
2748+ EOF
2749+expected-stdout:
2750+ x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
2751+---
2752+name: heredoc-quoting-subst
2753+description:
2754+ Check for correct handling of quoted characters in
2755+ here documents with substitution (marker is not quoted).
2756+stdin:
2757+ foo=bar
2758+ cat <<-EOF
2759+ x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
2760+ EOF
2761+expected-stdout:
2762+ x " \" \ \ $ $ baz `echo baz` bar $foo x
2763+---
2764+name: single-quotes-in-braces
2765+description:
2766+ Check that single quotes inside unquoted {} are treated as quotes
2767+stdin:
2768+ foo=1
2769+ echo ${foo:+'blah $foo'}
2770+expected-stdout:
2771+ blah $foo
2772+---
2773+name: single-quotes-in-quoted-braces
2774+description:
2775+ Check that single quotes inside quoted {} are treated as
2776+ normal char
2777+stdin:
2778+ foo=1
2779+ echo "${foo:+'blah $foo'}"
2780+expected-stdout:
2781+ 'blah 1'
2782+---
2783+name: single-quotes-in-braces-nested
2784+description:
2785+ Check that single quotes inside unquoted {} are treated as quotes,
2786+ even if that's inside a double-quoted command expansion
2787+stdin:
2788+ foo=1
2789+ echo "$( echo ${foo:+'blah $foo'})"
2790+expected-stdout:
2791+ blah $foo
2792+---
2793+name: single-quotes-in-brace-pattern
2794+description:
2795+ Check that single quotes inside {} pattern are treated as quotes
2796+stdin:
2797+ foo=1234
2798+ echo ${foo%'2'*} "${foo%'2'*}" ${foo%2'*'} "${foo%2'*'}"
2799+expected-stdout:
2800+ 1 1 1234 1234
2801+---
2802+name: single-quotes-in-heredoc-braces
2803+description:
2804+ Check that single quotes inside {} in heredoc are treated
2805+ as normal char
2806+stdin:
2807+ foo=1
2808+ cat <<EOM
2809+ ${foo:+'blah $foo'}
2810+ EOM
2811+expected-stdout:
2812+ 'blah 1'
2813+---
2814+name: single-quotes-in-nested-braces
2815+description:
2816+ Check that single quotes inside nested unquoted {} are
2817+ treated as quotes
2818+stdin:
2819+ foo=1
2820+ echo ${foo:+${foo:+'blah $foo'}}
2821+expected-stdout:
2822+ blah $foo
2823+---
2824+name: single-quotes-in-nested-quoted-braces
2825+description:
2826+ Check that single quotes inside nested quoted {} are treated
2827+ as normal char
2828+stdin:
2829+ foo=1
2830+ echo "${foo:+${foo:+'blah $foo'}}"
2831+expected-stdout:
2832+ 'blah 1'
2833+---
2834+name: single-quotes-in-nested-braces-nested
2835+description:
2836+ Check that single quotes inside nested unquoted {} are treated
2837+ as quotes, even if that's inside a double-quoted command expansion
2838+stdin:
2839+ foo=1
2840+ echo "$( echo ${foo:+${foo:+'blah $foo'}})"
2841+expected-stdout:
2842+ blah $foo
2843+---
2844+name: single-quotes-in-nested-brace-pattern
2845+description:
2846+ Check that single quotes inside nested {} pattern are treated as quotes
2847+stdin:
2848+ foo=1234
2849+ echo ${foo:+${foo%'2'*}} "${foo:+${foo%'2'*}}" ${foo:+${foo%2'*'}} "${foo:+${foo%2'*'}}"
2850+expected-stdout:
2851+ 1 1 1234 1234
2852+---
2853+name: single-quotes-in-heredoc-nested-braces
2854+description:
2855+ Check that single quotes inside nested {} in heredoc are treated
2856+ as normal char
2857+stdin:
2858+ foo=1
2859+ cat <<EOM
2860+ ${foo:+${foo:+'blah $foo'}}
2861+ EOM
2862+expected-stdout:
2863+ 'blah 1'
2864+---
27392865 name: history-basic
27402866 description:
27412867 See if we can test history at all
@@ -3466,10 +3592,10 @@ stdin:
34663592 showargs 3 $@
34673593 showargs 4 "$@"
34683594 expected-stdout:
3469- <1> <A B C>
3595+ <1> <A> <B> <C>
34703596 <2> <ABC>
3471- <3> <A B C>
3472- <4> <A B C>
3597+ <3> <A> <B> <C>
3598+ <4> <A> <B> <C>
34733599 ---
34743600 name: IFS-space-colon-1
34753601 description:
@@ -3772,22 +3898,17 @@ expected-stdout:
37723898 ---
37733899 name: integer-base-check-flat
37743900 description:
3775- Check behaviour does not match POSuX, because a not type-safe
3776- scripting language has *no* business interpreting "010" as octal
3777-category: shell:legacy-no
3901+ Check behaviour does not match POSuX (except if set -o posix),
3902+ because a not type-safe scripting language has *no* business
3903+ interpreting the string "010" as octal numer eight (dangerous).
37783904 stdin:
3779- echo :$((10)).$((010)).$((0x10)).
3905+ echo 1 "$("$__progname" -c 'echo :$((10))/$((010)),$((0x10)):')" .
3906+ echo 2 "$("$__progname" -o posix -c 'echo :$((10))/$((010)),$((0x10)):')" .
3907+ echo 3 "$("$__progname" -o sh -c 'echo :$((10))/$((010)),$((0x10)):')" .
37803908 expected-stdout:
3781- :10.10.16.
3782----
3783-name: integer-base-check-flat-legacy
3784-description:
3785- Check behaviour matches POSuX for LEGACY KSH
3786-category: shell:legacy-yes
3787-stdin:
3788- echo :$((10)).$((010)).$((0x10)).
3789-expected-stdout:
3790- :10.8.16.
3909+ 1 :10/10,16: .
3910+ 2 :10/8,16: .
3911+ 3 :10/10,16: .
37913912 ---
37923913 name: integer-base-check-numeric-from
37933914 description:
@@ -3913,6 +4034,13 @@ expected-stdout:
39134034 s:-9223372036854775808.-1.0.
39144035 u:9223372036854775808.18446744073709551615.0.
39154036 ---
4037+name: integer-size-FAIL-to-detect
4038+description:
4039+ Notify the user that their ints are not 32 or 64 bit
4040+category: int:u
4041+stdin:
4042+ :
4043+---
39164044 name: lineno-stdin
39174045 description:
39184046 See if $LINENO is updated and can be modified.
@@ -4245,7 +4373,7 @@ description:
42454373 should print 0 according to POSIX (dash, bash, ksh93, posh)
42464374 but not 0 according to the getopt(1) manual page, ksh88, and
42474375 Bourne sh (such as /bin/sh on Solaris).
4248- In mksh R39b, we honour POSIX except when -o sh is set.
4376+ We honour POSIX except when -o sh is set.
42494377 category: shell:legacy-no
42504378 stdin:
42514379 showf() {
@@ -4265,10 +4393,15 @@ stdin:
42654393 showf
42664394 set -- `false`
42674395 echo rv=$?
4396+ set -o posix -o sh
4397+ showf
4398+ set -- `false`
4399+ echo rv=$?
42684400 expected-stdout:
42694401 FPOSIX=0 FSH=0 rv=0
42704402 FPOSIX=0 FSH=1 rv=1
42714403 FPOSIX=1 FSH=0 rv=0
4404+ FPOSIX=1 FSH=1 rv=0
42724405 ---
42734406 name: regression-10-legacy
42744407 description:
@@ -4297,10 +4430,15 @@ stdin:
42974430 showf
42984431 set -- `false`
42994432 echo rv=$?
4433+ set -o posix -o sh
4434+ showf
4435+ set -- `false`
4436+ echo rv=$?
43004437 expected-stdout:
43014438 FPOSIX=0 FSH=0 rv=1
43024439 FPOSIX=0 FSH=1 rv=1
4303- FPOSIX=1 FSH=0 rv=1
4440+ FPOSIX=1 FSH=0 rv=0
4441+ FPOSIX=1 FSH=1 rv=0
43044442 ---
43054443 name: regression-11
43064444 description:
@@ -4663,18 +4801,16 @@ expected-stdout:
46634801 ---
46644802 name: regression-39
46654803 description:
4666- set -e: errors in command substitutions aren't ignored
4667- Not clear if they should be or not... bash passes here
4668- this may actually be required for make, so changed the
4669- test to make this an mksh feature, not a bug
4670-arguments: !-e!
4804+ Only posh and oksh(2013-07) say “hi” below; FreeBSD sh,
4805+ GNU bash in POSIX mode, dash, ksh93, mksh don’t. All of
4806+ them exit 0. The POSIX behaviour is needed by BSD make.
46714807 stdin:
4808+ set -e
46724809 echo `false; echo hi`
4673-#expected-fail: yes
4674-#expected-stdout:
4675-# hi
4810+ echo $?
46764811 expected-stdout:
46774812
4813+ 0
46784814 ---
46794815 name: regression-40
46804816 description:
@@ -5984,6 +6120,27 @@ expected-stdout:
59846120 EXtrap
59856121 = noeval-undef 1 .
59866122 ---
6123+name: exit-trap-interactive
6124+description:
6125+ Check that interactive shell doesn't exit via EXIT trap on syntax error
6126+arguments: !-i!
6127+stdin:
6128+ trap -- EXIT
6129+ echo Syntax error <
6130+ echo 'After error 1'
6131+ trap 'echo Exit trap' EXIT
6132+ echo Syntax error <
6133+ echo 'After error 2'
6134+ trap 'echo Exit trap' EXIT
6135+ exit
6136+ echo 'After exit'
6137+expected-stdout:
6138+ After error 1
6139+ After error 2
6140+ Exit trap
6141+expected-stderr-pattern:
6142+ /syntax error: 'newline' unexpected/
6143+---
59876144 name: test-stlt-1
59886145 description:
59896146 Check that test also can handle string1 < string2 etc.
@@ -6178,7 +6335,7 @@ expected-stdout:
61786335 ---
61796336 name: sh-mode-2a
61806337 description:
6181- Check that sh mode is *not* automatically turned on
6338+ Check that posix or sh mode is *not* automatically turned on
61826339 category: !binsh
61836340 stdin:
61846341 ln -s "$__progname" ksh || cp "$__progname" ksh
@@ -6187,7 +6344,7 @@ stdin:
61876344 ln -s "$__progname" ./-sh || cp "$__progname" ./-sh
61886345 for shell in {,-}{,k}sh; do
61896346 print -- $shell $(./$shell +l -c \
6190- '[[ $(set +o) == *@(-o sh)@(| *) ]] && echo sh || echo nosh')
6347+ '[[ $(set +o) == *"-o "@(sh|posix)@(| *) ]] && echo sh || echo nosh')
61916348 done
61926349 expected-stdout:
61936350 sh nosh
@@ -6197,7 +6354,7 @@ expected-stdout:
61976354 ---
61986355 name: sh-mode-2b
61996356 description:
6200- Check that sh mode *is* automatically turned on
6357+ Check that posix or sh mode *is* automatically turned on
62016358 category: binsh
62026359 stdin:
62036360 ln -s "$__progname" ksh || cp "$__progname" ksh
@@ -6206,7 +6363,7 @@ stdin:
62066363 ln -s "$__progname" ./-sh || cp "$__progname" ./-sh
62076364 for shell in {,-}{,k}sh; do
62086365 print -- $shell $(./$shell +l -c \
6209- '[[ $(set +o) == *@(-o sh)@(| *) ]] && echo sh || echo nosh')
6366+ '[[ $(set +o) == *"-o "@(sh|posix)@(| *) ]] && echo sh || echo nosh')
62106367 done
62116368 expected-stdout:
62126369 sh sh
@@ -6275,6 +6432,28 @@ expected-stdout:
62756432 PIPESTATUS[0]=0
62766433 8 PIPESTATUS[0]=0 PIPESTATUS[1]=0 .
62776434 ---
6435+name: pipeline-4
6436+description:
6437+ Check that "set -o pipefail" does what it's supposed to
6438+stdin:
6439+ echo 1 "$("$__progname" -c '(exit 12) | (exit 23) | (exit 42); echo $?')" .
6440+ echo 2 "$("$__progname" -c '! (exit 12) | (exit 23) | (exit 42); echo $?')" .
6441+ echo 3 "$("$__progname" -o pipefail -c '(exit 12) | (exit 23) | (exit 42); echo $?')" .
6442+ echo 4 "$("$__progname" -o pipefail -c '! (exit 12) | (exit 23) | (exit 42); echo $?')" .
6443+ echo 5 "$("$__progname" -c '(exit 23) | (exit 42) | :; echo $?')" .
6444+ echo 6 "$("$__progname" -c '! (exit 23) | (exit 42) | :; echo $?')" .
6445+ echo 7 "$("$__progname" -o pipefail -c '(exit 23) | (exit 42) | :; echo $?')" .
6446+ echo 8 "$("$__progname" -o pipefail -c '! (exit 23) | (exit 42) | :; echo $?')" .
6447+expected-stdout:
6448+ 1 42 .
6449+ 2 0 .
6450+ 3 42 .
6451+ 4 0 .
6452+ 5 0 .
6453+ 6 1 .
6454+ 7 42 .
6455+ 8 0 .
6456+---
62786457 name: persist-history-1
62796458 description:
62806459 Check if persistent history saving works
@@ -7551,6 +7730,28 @@ stdin:
75517730 expected-stdout:
75527731 ab
75537732 ---
7733+name: print-cr
7734+description:
7735+ Check that CR+LF is not collapsed into LF as some MSYS shells wrongly do
7736+stdin:
7737+ echo '#!'"$__progname" >foo
7738+ cat >>foo <<-'EOF'
7739+ 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'
7740+ print \?
7741+ EOF
7742+ chmod +x foo
7743+ echo "[$(./foo)]"
7744+ ./foo | while IFS= read -r line; do
7745+ print -r -- "{$line}"
7746+ done
7747+expected-stdout:
7748+ [220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT
7749+ 220->> Bitte keine Werbung einwerfen! <<
7750+ 220 Who do you wanna pretend to be today? ]
7751+ {220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT }
7752+ {220->> Bitte keine Werbung einwerfen! << }
7753+ {220 Who do you wanna pretend to be today? }
7754+---
75547755 name: print-nul-chars
75557756 description:
75567757 Check handling of NUL characters for print and COMSUB
@@ -8363,6 +8564,7 @@ name: bashiop-1
83638564 description:
83648565 Check if GNU bash-like I/O redirection works
83658566 Part 1: this is also supported by GNU bash
8567+category: shell:legacy-no
83668568 stdin:
83678569 exec 3>&1
83688570 function threeout {
@@ -8383,6 +8585,7 @@ name: bashiop-2a
83838585 description:
83848586 Check if GNU bash-like I/O redirection works
83858587 Part 2: this is *not* supported by GNU bash
8588+category: shell:legacy-no
83868589 stdin:
83878590 exec 3>&1
83888591 function threeout {
@@ -8403,6 +8606,7 @@ name: bashiop-2b
84038606 description:
84048607 Check if GNU bash-like I/O redirection works
84058608 Part 2: this is *not* supported by GNU bash
8609+category: shell:legacy-no
84068610 stdin:
84078611 exec 3>&1
84088612 function threeout {
@@ -8423,6 +8627,7 @@ name: bashiop-2c
84238627 description:
84248628 Check if GNU bash-like I/O redirection works
84258629 Part 2: this is supported by GNU bash 4 only
8630+category: shell:legacy-no
84268631 stdin:
84278632 echo mir >foo
84288633 set -o noclobber
@@ -8446,6 +8651,7 @@ name: bashiop-3a
84468651 description:
84478652 Check if GNU bash-like I/O redirection fails correctly
84488653 Part 1: this is also supported by GNU bash
8654+category: shell:legacy-no
84498655 stdin:
84508656 echo mir >foo
84518657 set -o noclobber
@@ -8467,6 +8673,7 @@ name: bashiop-3b
84678673 description:
84688674 Check if GNU bash-like I/O redirection fails correctly
84698675 Part 2: this is *not* supported by GNU bash
8676+category: shell:legacy-no
84708677 stdin:
84718678 echo mir >foo
84728679 set -o noclobber
@@ -8490,6 +8697,7 @@ description:
84908697 Check if GNU bash-like I/O redirection works
84918698 Part 4: this is also supported by GNU bash,
84928699 but failed in some mksh versions
8700+category: shell:legacy-no
84938701 stdin:
84948702 exec 3>&1
84958703 function threeout {
@@ -8511,6 +8719,34 @@ expected-stdout:
85118719 ras
85128720 dwa
85138721 ---
8722+name: bashiop-5-normal
8723+description:
8724+ Check if GNU bash-like I/O redirection is only supported
8725+ in !POSIX !sh mode as it breaks existing scripts' syntax
8726+category: shell:legacy-no
8727+stdin:
8728+ :>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
8729+ :>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
8730+ :>x; echo 3 "$("$__progname" -o sh -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
8731+expected-stdout:
8732+ 1 = foo echo bar .
8733+ 2 = bar .
8734+ 3 = bar .
8735+---
8736+name: bashiop-5-legacy
8737+description:
8738+ Check if GNU bash-like I/O redirection is not parsed
8739+ in lksh as it breaks existing scripts' syntax
8740+category: shell:legacy-yes
8741+stdin:
8742+ :>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
8743+ :>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
8744+ :>x; echo 3 "$("$__progname" -o sh -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
8745+expected-stdout:
8746+ 1 = bar .
8747+ 2 = bar .
8748+ 3 = bar .
8749+---
85148750 name: mkshiop-1
85158751 description:
85168752 Check for support of more than 9 file descriptors
@@ -8534,10 +8770,57 @@ expected-stdout:
85348770 bar
85358771 baz
85368772 ---
8537-name: oksh-shcrash
8773+name: oksh-eval
85388774 description:
8539- src/regress/bin/ksh/shcrash.sh,v 1.1
8775+ $OpenBSD: eval.sh,v 1.1 2010/03/24 08:29:44 fgsch Exp $
85408776 stdin:
8777+ a=
8778+ for n in ${a#*=}; do echo 1hu ${n} .; done
8779+ for n in "${a#*=}"; do echo 1hq ${n} .; done
8780+ for n in ${a##*=}; do echo 2hu ${n} .; done
8781+ for n in "${a##*=}"; do echo 2hq ${n} .; done
8782+ for n in ${a%=*}; do echo 1pu ${n} .; done
8783+ for n in "${a%=*}"; do echo 1pq ${n} .; done
8784+ for n in ${a%%=*}; do echo 2pu ${n} .; done
8785+ for n in "${a%%=*}"; do echo 2pq ${n} .; done
8786+expected-stdout:
8787+ 1hq .
8788+ 2hq .
8789+ 1pq .
8790+ 2pq .
8791+---
8792+name: oksh-and-list-error-1
8793+description:
8794+ Test exit status of rightmost element in 2 element && list in -e mode
8795+stdin:
8796+ true && false
8797+ echo "should not print"
8798+arguments: !-e!
8799+expected-exit: e != 0
8800+---
8801+name: oksh-and-list-error-2
8802+description:
8803+ Test exit status of rightmost element in 3 element && list in -e mode
8804+stdin:
8805+ true && true && false
8806+ echo "should not print"
8807+arguments: !-e!
8808+expected-exit: e != 0
8809+---
8810+name: oksh-or-list-error-1
8811+description:
8812+ Test exit status of || list in -e mode
8813+stdin:
8814+ false || false
8815+ echo "should not print"
8816+arguments: !-e!
8817+expected-exit: e != 0
8818+---
8819+name: oksh-longline-crash
8820+description:
8821+ This used to cause a core dump
8822+stdin:
8823+ ulimit -c 0
85418824 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"
85428825 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"
85438826 for deplib in $deplibs; do
@@ -8554,6 +8837,99 @@ stdin:
85548837 esac
85558838 done
85568839 ---
8840+name: oksh-seterror-1
8841+description:
8842+ The -e flag should be ignored when executing a compound list
8843+ followed by an if statement.
8844+stdin:
8845+ if true; then false && false; fi
8846+ true
8847+arguments: !-e!
8848+expected-exit: e == 0
8849+---
8850+name: oksh-seterror-2
8851+description:
8852+ The -e flag should be ignored when executing a compound list
8853+ followed by an if statement.
8854+stdin:
8855+ if true; then if true; then false && false; fi; fi
8856+ true
8857+arguments: !-e!
8858+expected-exit: e == 0
8859+---
8860+name: oksh-seterror-3
8861+description:
8862+ The -e flag should be ignored when executing a compound list
8863+ followed by an elif statement.
8864+stdin:
8865+ if true; then :; elif true; then false && false; fi
8866+arguments: !-e!
8867+expected-exit: e == 0
8868+---
8869+name: oksh-seterror-4
8870+description:
8871+ The -e flag should be ignored when executing a pipeline
8872+ beginning with '!'
8873+stdin:
8874+ for i in 1 2 3
8875+ do
8876+ false && false
8877+ true || false
8878+ done
8879+arguments: !-e!
8880+expected-exit: e == 0
8881+---
8882+name: oksh-seterror-5
8883+description:
8884+ The -e flag should be ignored when executing a pipeline
8885+ beginning with '!'
8886+stdin:
8887+ ! true | false
8888+ true
8889+arguments: !-e!
8890+expected-exit: e == 0
8891+---
8892+name: oksh-seterror-6
8893+description:
8894+ When trapping ERR and EXIT, both traps should run in -e mode
8895+ when an error occurs.
8896+stdin:
8897+ trap 'echo EXIT' EXIT
8898+ trap 'echo ERR' ERR
8899+ set -e
8900+ false
8901+ echo DONE
8902+ exit 0
8903+arguments: !-e!
8904+expected-exit: e != 0
8905+expected-stdout:
8906+ ERR
8907+ EXIT
8908+---
8909+name: oksh-seterror-7
8910+description:
8911+ The -e flag within a command substitution should be honored
8912+stdin:
8913+ echo $( set -e; false; echo foo )
8914+arguments: !-e!
8915+expected-stdout:
8916+
8917+---
8918+name: oksh-input-comsub
8919+description:
8920+ A command substitution using input redirection should exit with
8921+ failure if the input file does not exist.
8922+stdin:
8923+ var=$(< non-existent)
8924+expected-exit: e != 0
8925+expected-stderr-pattern: /non-existent/
8926+---
8927+name: oksh-empty-for-list
8928+description:
8929+ A for list which expands to zero items should not execute the body.
8930+stdin:
8931+ set foo bar baz ; for out in ; do echo $out ; done
8932+---
85578933 name: oksh-varfunction-mod1
85588934 description:
85598935 $OpenBSD: varfunction.sh,v 1.1 2003/12/15 05:28:40 otto Exp $
@@ -8846,8 +9222,8 @@ stdin:
88469222 EOFI
88479223 #IORDWR_IODUP
88489224 sh 1<>/dev/console 0<&1 2>&1
8849- #COMSUB_EXPRSUB
8850- echo $(true) $((1+ 2))
9225+ #COMSUB_EXPRSUB_FUNSUB_VALSUB
9226+ echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
88519227 #QCHAR_OQUOTE_CQUOTE
88529228 echo fo\ob\"a\`r\'b\$az
88539229 echo "fo\ob\"a\`r\'b\$az"
@@ -9041,7 +9417,7 @@ expected-stdout:
90419417 }
90429418 inline_TWHILE() {
90439419 i=1
9044- while let " i < 10 "
9420+ while let] " i < 10 "
90459421 do
90469422 echo $i
90479423 let ++i
@@ -9051,20 +9427,20 @@ expected-stdout:
90519427 i=1; while (( i < 10 )); do echo $i; let ++i; done
90529428 ); }
90539429 function comsub_TWHILE {
9054- x=$(i=1 ; while let " i < 10 " ; do echo $i ; let ++i ; done )
9430+ x=$(i=1 ; while let] " i < 10 " ; do echo $i ; let ++i ; done )
90559431 }
90569432 function reread_TWHILE { x=$((
90579433 i=1; while (( i < 10 )); do echo $i; let ++i; done
90589434 )|tr u x); }
90599435 function reread_TWHILE {
9060- x=$(( i=1 ; while let " i < 10 " ; do echo $i ; let ++i ; done ) | tr u x )
9436+ x=$(( i=1 ; while let] " i < 10 " ; do echo $i ; let ++i ; done ) | tr u x )
90619437 }
90629438 inline_TUNTIL() {
90639439 i=10; until (( !--i )) ; do echo $i; done
90649440 }
90659441 inline_TUNTIL() {
90669442 i=10
9067- until let " !--i "
9443+ until let] " !--i "
90689444 do
90699445 echo $i
90709446 done
@@ -9073,13 +9449,13 @@ expected-stdout:
90739449 i=10; until (( !--i )) ; do echo $i; done
90749450 ); }
90759451 function comsub_TUNTIL {
9076- x=$(i=10 ; until let " !--i " ; do echo $i ; done )
9452+ x=$(i=10 ; until let] " !--i " ; do echo $i ; done )
90779453 }
90789454 function reread_TUNTIL { x=$((
90799455 i=10; until (( !--i )) ; do echo $i; done
90809456 )|tr u x); }
90819457 function reread_TUNTIL {
9082- x=$(( i=10 ; until let " !--i " ; do echo $i ; done ) | tr u x )
9458+ x=$(( i=10 ; until let] " !--i " ; do echo $i ; done ) | tr u x )
90839459 }
90849460 inline_TCOPROC() {
90859461 cat * |& ls
@@ -9229,23 +9605,23 @@ expected-stdout:
92299605 function reread_IORDWR_IODUP {
92309606 x=$(( sh 1<>/dev/console <&1 2>&1 ) | tr u x )
92319607 }
9232- inline_COMSUB_EXPRSUB() {
9233- echo $(true) $((1+ 2))
9608+ inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
9609+ echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
92349610 }
9235- inline_COMSUB_EXPRSUB() {
9236- echo $(true ) $((1+ 2))
9611+ inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
9612+ echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;}
92379613 }
9238- function comsub_COMSUB_EXPRSUB { x=$(
9239- echo $(true) $((1+ 2))
9614+ function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$(
9615+ echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
92409616 ); }
9241- function comsub_COMSUB_EXPRSUB {
9242- x=$(echo $(true ) $((1+ 2)) )
9617+ function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB {
9618+ x=$(echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} )
92439619 }
9244- function reread_COMSUB_EXPRSUB { x=$((
9245- echo $(true) $((1+ 2))
9620+ function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$((
9621+ echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
92469622 )|tr u x); }
9247- function reread_COMSUB_EXPRSUB {
9248- x=$(( echo $(true ) $((1+ 2)) ) | tr u x )
9623+ function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB {
9624+ x=$(( echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} ) | tr u x )
92499625 }
92509626 inline_QCHAR_OQUOTE_CQUOTE() {
92519627 echo fo\ob\"a\`r\'b\$az
@@ -9693,7 +10069,7 @@ expected-stdout:
969310069 }
969410070 inline_TWHILE() {
969510071 i=1
9696- while let " i < 10 " >&3
10072+ while let] " i < 10 " >&3
969710073 do
969810074 echo $i
969910075 let ++i
@@ -9703,20 +10079,20 @@ expected-stdout:
970310079 i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
970410080 ); }
970510081 function comsub_TWHILE {
9706- x=$(i=1 ; while let " i < 10 " >&3 ; do echo $i ; let ++i ; done >&3 )
10082+ x=$(i=1 ; while let] " i < 10 " >&3 ; do echo $i ; let ++i ; done >&3 )
970710083 }
970810084 function reread_TWHILE { x=$((
970910085 i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
971010086 )|tr u x); }
971110087 function reread_TWHILE {
9712- x=$(( i=1 ; while let " i < 10 " >&3 ; do echo $i ; let ++i ; done >&3 ) | tr u x )
10088+ x=$(( i=1 ; while let] " i < 10 " >&3 ; do echo $i ; let ++i ; done >&3 ) | tr u x )
971310089 }
971410090 inline_TUNTIL() {
971510091 i=10; until (( !--i )) >&3 ; do echo $i; done >&3
971610092 }
971710093 inline_TUNTIL() {
971810094 i=10
9719- until let " !--i " >&3
10095+ until let] " !--i " >&3
972010096 do
972110097 echo $i
972210098 done >&3
@@ -9725,13 +10101,13 @@ expected-stdout:
972510101 i=10; until (( !--i )) >&3 ; do echo $i; done >&3
972610102 ); }
972710103 function comsub_TUNTIL {
9728- x=$(i=10 ; until let " !--i " >&3 ; do echo $i ; done >&3 )
10104+ x=$(i=10 ; until let] " !--i " >&3 ; do echo $i ; done >&3 )
972910105 }
973010106 function reread_TUNTIL { x=$((
973110107 i=10; until (( !--i )) >&3 ; do echo $i; done >&3
973210108 )|tr u x); }
973310109 function reread_TUNTIL {
9734- x=$(( i=10 ; until let " !--i " >&3 ; do echo $i ; done >&3 ) | tr u x )
10110+ x=$(( i=10 ; until let] " !--i " >&3 ; do echo $i ; done >&3 ) | tr u x )
973510111 }
973610112 inline_TCOPROC() {
973710113 cat * >&3 |& >&3 ls
@@ -9831,6 +10207,38 @@ expected-stdout:
983110207 2:ya x2,1,0.
983210208 3:ya,1,3.
983310209 ---
10210+name: valsub-1
10211+description:
10212+ Check that "value substitutions" work as advertised
10213+stdin:
10214+ x=1
10215+ y=2
10216+ z=3
10217+ REPLY=4
10218+ echo "before: x<$x> y<$y> z<$z> R<$REPLY>"
10219+ x=${|
10220+ local y
10221+ echo "begin: x<$x> y<$y> z<$z> R<$REPLY>"
10222+ x=5
10223+ y=6
10224+ z=7
10225+ REPLY=8
10226+ echo "end: x<$x> y<$y> z<$z> R<$REPLY>"
10227+ }
10228+ echo "after: x<$x> y<$y> z<$z> R<$REPLY>"
10229+ # ensure trailing newlines are kept
10230+ t=${|REPLY=$'foo\n\n';}
10231+ typeset -p t
10232+ echo -n this used to segfault
10233+ echo ${|true;}$(true).
10234+expected-stdout:
10235+ before: x<1> y<2> z<3> R<4>
10236+ begin: x<1> y<> z<3> R<>
10237+ end: x<5> y<6> z<7> R<8>
10238+ after: x<8> y<2> z<7> R<4>
10239+ typeset t=$'foo\n\n'
10240+ this used to segfault.
10241+---
983410242 name: test-stnze-1
983510243 description:
983610244 Check that the short form [ $x ] works
@@ -10156,7 +10564,7 @@ description:
1015610564 time-limit: 3
1015710565 stdin:
1015810566 baz() {
10159- typeset -n foo=foo
10567+ typeset -n foo=fnord fnord=foo
1016010568 foo[0]=bar
1016110569 }
1016210570 set -A foo bad
@@ -10165,7 +10573,9 @@ stdin:
1016510573 echo blah $foo .
1016610574 expected-stdout:
1016710575 sind bad .
10168- blah bar .
10576+ blah bad .
10577+expected-stderr-pattern:
10578+ /fnord: expression recurses on parameter/
1016910579 ---
1017010580 name: better-parens-1a
1017110581 description:
@@ -10743,3 +11153,19 @@ stdin:
1074311153 done
1074411154 Lb64decode $s >/dev/null
1074511155 ---
11156+name: xtrace-1
11157+description:
11158+ Check that "set -x" doesn't redirect too quickly
11159+stdin:
11160+ print '#!'"$__progname" >bash
11161+ cat >>bash <<'EOF'
11162+ echo 'GNU bash, version 2.05b.0(1)-release (i386-ecce-mirbsd10)
11163+ Copyright (C) 2002 Free Software Foundation, Inc.'
11164+ EOF
11165+ chmod +x bash
11166+ "$__progname" -xc 'foo=$(./bash --version 2>&1 | head -1); echo "=$foo="'
11167+expected-stdout:
11168+ =GNU bash, version 2.05b.0(1)-release (i386-ecce-mirbsd10)=
11169+expected-stderr-pattern:
11170+ /.*/
11171+---
--- a/src/dot.mkshrc
+++ b/src/dot.mkshrc
@@ -1,5 +1,5 @@
11 # $Id$
2-# $MirOS: src/bin/mksh/dot.mkshrc,v 1.77 2013/02/17 15:58:26 tg Exp $
2+# $MirOS: src/bin/mksh/dot.mkshrc,v 1.84 2013/08/10 13:43:50 tg Exp $
33 #-
44 # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
55 # 2011, 2012, 2013
@@ -22,35 +22,76 @@
2222 #-
2323 # ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells
2424
25+# catch non-mksh (including lksh) trying to shell this file
26+case $KSH_VERSION in
27+*MIRBSD\ KSH*) ;;
28+*) return 0 ;;
29+esac
30+
2531 PS1='#'; (( USER_ID )) && PS1='$'; [[ ${HOSTNAME:=$(ulimit -c 0; hostname -s \
2632 2>/dev/null)} = *([ ]|localhost) ]] && HOSTNAME=$(ulimit -c 0; hostname \
2733 2>/dev/null); : ${EDITOR:=/bin/ed} ${HOSTNAME:=nil} ${TERM:=vt100}
28-function precmd {
34+: ${MKSH:=$(whence -p mksh)}; PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
2935 local e=$?
3036
31- (( e )) && print -n "$e|"
32- # precmd is required to retain the errorlevel when ${ …;} is used
37+ (( e )) && REPLY+="$e|"
38+ REPLY+=${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?)}
39+ REPLY+=@${HOSTNAME%%.*}:
40+
41+ local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~}
42+ local m=${%d} n p=...; (( m > 0 )) || m=${#d}
43+ (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
44+ REPLY+=$p$d
45+
3346 return $e
34-}
35-PS1=$'\001\r''${ precmd;}${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?
36- )}@${HOSTNAME%%.*}:${ local e=$? d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || \
37- d=${d/#$p/~}; local m=${%d} n p=...; (( m > 0 )) || m=${#d}
38- (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || \
39- p=; print -nr -- "$p$d"; return $e;} '"$PS1 "
40-: ${MKSH:=$(whence -p mksh)}; export EDITOR HOSTNAME MKSH TERM USER
47+} '"$PS1 "; export EDITOR HOSTNAME MKSH TERM USER
4148 alias ls=ls
4249 unalias ls
4350 alias l='ls -F'
4451 alias la='l -a'
4552 alias ll='l -l'
4653 alias lo='l -alo'
54+alias doch='sudo mksh -c "$(fc -ln -1)"'
4755 whence -p rot13 >/dev/null || alias rot13='tr \
4856 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
4957 nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
50-whence -p hd >/dev/null || function hd {
51- hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \
52- -e '" |" "%_p"' -e '"|\n"' "$@"
53-}
58+if whence -p hd >/dev/null; then :; elif whence -p hexdump >/dev/null; then
59+ function hd {
60+ hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \
61+ -e '" |" "%_p"' -e '"|\n"' "$@"
62+ }
63+else
64+ function hd {
65+ local -Uui16 -Z11 pos=0
66+ local -Uui16 -Z5 hv=2147483647
67+ local dasc line i
68+
69+ cat "$@" | { set +U; if read -arN -1 line; then
70+ typeset -i1 line
71+ i=0
72+ while (( i < ${#line[*]} )); do
73+ hv=${line[i++]}
74+ if (( (pos & 15) == 0 )); then
75+ (( pos )) && print -r -- "$dasc|"
76+ print -n "${pos#16#} "
77+ dasc=' |'
78+ fi
79+ print -n "${hv#16#} "
80+ if (( (hv < 32) || (hv > 126) )); then
81+ dasc+=.
82+ else
83+ dasc+=${line[i-1]#1#}
84+ fi
85+ (( (pos++ & 15) == 7 )) && print -n -- '- '
86+ done
87+ while (( pos & 15 )); do
88+ print -n ' '
89+ (( (pos++ & 15) == 7 )) && print -n -- '- '
90+ done
91+ (( hv == 2147483647 )) || print -r -- "$dasc|"
92+ fi; }
93+ }
94+fi
5495
5596 # Berkeley C shell compatible dirs, popd, and pushd functions
5697 # Z shell compatible chpwd() hook, used to update DIRSTACK[0]
@@ -222,7 +263,7 @@ function Lb64decode {
222263 [[ -o utf8-mode ]]; local u=$?
223264 set +U
224265 local c s="$*" t=
225- [[ -n $s ]] || { s=$(cat;print x); s=${s%x}; }
266+ [[ -n $s ]] || { s=$(cat; print x); s=${s%x}; }
226267 local -i i=0 j=0 n=${#s} p=0 v x
227268 local -i16 o
228269
--- a/src/edit.c
+++ b/src/edit.c
@@ -1,4 +1,4 @@
1-/* $OpenBSD: edit.c,v 1.37 2013/01/21 10:13:24 halex Exp $ */
1+/* $OpenBSD: edit.c,v 1.38 2013/06/03 15:41:59 tedu Exp $ */
22 /* $OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $ */
33 /* $OpenBSD: emacs.c,v 1.44 2011/09/05 04:50:33 marco Exp $ */
44 /* $OpenBSD: vi.c,v 1.26 2009/06/29 22:50:19 martynas Exp $ */
@@ -28,7 +28,7 @@
2828
2929 #ifndef MKSH_NO_CMDLINE_EDITING
3030
31-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.265 2013/02/10 19:05:36 tg Exp $");
31+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.270 2013/08/14 20:26:17 tg Exp $");
3232
3333 /*
3434 * in later versions we might use libtermcap for this, but since external
@@ -66,7 +66,7 @@ static X_chars edchars;
6666 static char editmode;
6767 static int xx_cols; /* for Emacs mode */
6868 static int modified; /* buffer has been "modified" */
69-static char holdbuf[LINE]; /* place to hold last edit buffer */
69+static char *holdbufp; /* place to hold last edit buffer */
7070
7171 static int x_getc(void);
7272 static void x_putcf(int);
@@ -81,10 +81,10 @@ static char *x_glob_hlp_tilde_and_rem_qchar(char *, bool);
8181 static int x_basename(const char *, const char *);
8282 static void x_free_words(int, char **);
8383 static int x_escape(const char *, size_t, int (*)(const char *, size_t));
84-static int x_emacs(char *, size_t);
84+static int x_emacs(char *);
8585 static void x_init_prompt(void);
8686 #if !MKSH_S_NOVI
87-static int x_vi(char *, size_t);
87+static int x_vi(char *);
8888 #endif
8989
9090 #define x_flush() shf_flush(shl_out)
@@ -110,17 +110,17 @@ static int x_e_rebuildline(const char *);
110110 * read an edited command line
111111 */
112112 int
113-x_read(char *buf, size_t len)
113+x_read(char *buf)
114114 {
115115 int i;
116116
117117 x_mode(true);
118118 modified = 1;
119119 if (Flag(FEMACS) || Flag(FGMACS))
120- i = x_emacs(buf, len);
120+ i = x_emacs(buf);
121121 #if !MKSH_S_NOVI
122122 else if (Flag(FVI))
123- i = x_vi(buf, len);
123+ i = x_vi(buf);
124124 #endif
125125 else
126126 /* internal error */
@@ -919,7 +919,6 @@ static bool x_adj_ok;
919919 */
920920 static int x_adj_done; /* is incremented by x_adjust() */
921921
922-static int x_col;
923922 static int x_displen;
924923 static int x_arg; /* general purpose arg */
925924 static bool x_arg_defaulted; /* x_arg not explicitly set; defaulted to 1 */
@@ -944,9 +943,6 @@ static int x_curprefix;
944943 static char *macroptr; /* bind key macro active? */
945944 #endif
946945 #if !MKSH_S_NOVI
947-static int cur_col; /* current column on line */
948-static int pwidth; /* width of prompt */
949-static int prompt_trunc; /* how much of prompt to truncate */
950946 static int winwidth; /* width of window */
951947 static char *wbuf[2]; /* window buffers */
952948 static int wbuf_len; /* length of window buffers (x_cols - 3) */
@@ -955,13 +951,16 @@ static char morec; /* more character at right of window */
955951 static int lastref; /* argument to last refresh() */
956952 static int holdlen; /* length of holdbuf */
957953 #endif
958-static bool prompt_redraw; /* false if newline forced after prompt */
954+static int pwidth; /* width of prompt */
955+static int prompt_trunc; /* how much of prompt to truncate or -1 */
956+static int x_col; /* current column on line */
959957
960958 static int x_ins(const char *);
961959 static void x_delete(size_t, bool);
962960 static size_t x_bword(void);
963961 static size_t x_fword(bool);
964962 static void x_goto(char *);
963+static char *x_bs0(char *, char *);
965964 static void x_bs3(char **);
966965 static int x_size_str(char *);
967966 static int x_size2(char *, char **);
@@ -1170,30 +1169,25 @@ x_e_getmbc(char *sbuf)
11701169 static void
11711170 x_init_prompt(void)
11721171 {
1173- x_col = promptlen(prompt);
1174- x_adj_ok = true;
1175- prompt_redraw = true;
1176- if (x_col >= xx_cols)
1177- x_col %= xx_cols;
1178- x_displen = xx_cols - 2 - x_col;
1179- x_adj_done = 0;
1180-
1181- pprompt(prompt, 0);
1182- if (x_displen < 1) {
1183- x_col = 0;
1184- x_displen = xx_cols - 2;
1172+ prompt_trunc = pprompt(prompt, 0);
1173+ pwidth = prompt_trunc % x_cols;
1174+ prompt_trunc -= pwidth;
1175+ if ((mksh_uari_t)pwidth > ((mksh_uari_t)x_cols - 3 - MIN_EDIT_SPACE)) {
1176+ /* force newline after prompt */
1177+ prompt_trunc = -1;
1178+ pwidth = 0;
11851179 x_e_putc2('\n');
1186- prompt_redraw = false;
11871180 }
11881181 }
11891182
11901183 static int
1191-x_emacs(char *buf, size_t len)
1184+x_emacs(char *buf)
11921185 {
11931186 int c, i;
11941187 unsigned char f;
11951188
1196- xbp = xbuf = buf; xend = buf + len;
1189+ xbp = xbuf = buf;
1190+ xend = buf + LINE;
11971191 xlp = xcp = xep = buf;
11981192 *xcp = 0;
11991193 xlp_valid = true;
@@ -1202,8 +1196,10 @@ x_emacs(char *buf, size_t len)
12021196 x_histp = histptr + 1;
12031197 x_last_command = XFUNC_error;
12041198
1205- xx_cols = x_cols;
12061199 x_init_prompt();
1200+ x_displen = (xx_cols = x_cols) - 2 - (x_col = pwidth);
1201+ x_adj_done = 0;
1202+ x_adj_ok = true;
12071203
12081204 x_histncp = NULL;
12091205 if (x_nextcmd >= 0) {
@@ -1561,11 +1557,7 @@ x_fword(bool move)
15611557 static void
15621558 x_goto(char *cp)
15631559 {
1564- if (cp >= xep)
1565- cp = xep;
1566- else if (UTFMODE)
1567- while ((cp > xbuf) && ((*cp & 0xC0) == 0x80))
1568- --cp;
1560+ cp = cp >= xep ? xep : x_bs0(cp, xbuf);
15691561 if (cp < xbp || cp >= utf_skipcols(xbp, x_displen)) {
15701562 /* we are heading off screen */
15711563 xcp = cp;
@@ -1581,16 +1573,22 @@ x_goto(char *cp)
15811573 }
15821574 }
15831575
1576+static char *
1577+x_bs0(char *cp, char *lower_bound)
1578+{
1579+ if (UTFMODE)
1580+ while ((!lower_bound || (cp > lower_bound)) &&
1581+ ((*(unsigned char *)cp & 0xC0) == 0x80))
1582+ --cp;
1583+ return (cp);
1584+}
1585+
15841586 static void
15851587 x_bs3(char **p)
15861588 {
15871589 int i;
15881590
1589- (*p)--;
1590- if (UTFMODE)
1591- while (((unsigned char)**p & 0xC0) == 0x80)
1592- (*p)--;
1593-
1591+ *p = x_bs0((*p) - 1, NULL);
15941592 i = x_size2(*p, NULL);
15951593 while (i--)
15961594 x_e_putc2('\b');
@@ -1824,7 +1822,7 @@ x_load_hist(char **hp)
18241822 char *sp = NULL;
18251823
18261824 if (hp == histptr + 1) {
1827- sp = holdbuf;
1825+ sp = holdbufp;
18281826 modified = 0;
18291827 } else if (hp < history || hp > histptr) {
18301828 x_e_putc2(7);
@@ -1835,7 +1833,7 @@ x_load_hist(char **hp)
18351833 x_histp = hp;
18361834 oldsize = x_size_str(xbuf);
18371835 if (modified)
1838- strlcpy(holdbuf, xbuf, sizeof(holdbuf));
1836+ strlcpy(holdbufp, xbuf, LINE);
18391837 strlcpy(xbuf, sp, xend - xbuf);
18401838 xbp = xbuf;
18411839 xep = xcp = xbuf + strlen(xbuf);
@@ -2080,7 +2078,7 @@ x_cls(int c MKSH_A_UNUSED)
20802078 static void
20812079 x_redraw(int limit)
20822080 {
2083- int i, j, x_trunc = 0;
2081+ int i, j;
20842082 char *cp;
20852083
20862084 x_adj_ok = false;
@@ -2090,19 +2088,11 @@ x_redraw(int limit)
20902088 x_e_putc2('\r');
20912089 x_flush();
20922090 if (xbp == xbuf) {
2093- x_col = promptlen(prompt);
2094- if (x_col >= xx_cols)
2095- x_trunc = (x_col / xx_cols) * xx_cols;
2096- if (prompt_redraw)
2097- pprompt(prompt, x_trunc);
2098- }
2099- if (x_col >= xx_cols)
2100- x_col %= xx_cols;
2101- x_displen = xx_cols - 2 - x_col;
2102- if (x_displen < 1) {
2103- x_col = 0;
2104- x_displen = xx_cols - 2;
2091+ if (prompt_trunc != -1)
2092+ pprompt(prompt, prompt_trunc);
2093+ x_col = pwidth;
21052094 }
2095+ x_displen = xx_cols - 2 - x_col;
21062096 xlp_valid = false;
21072097 x_zots(xbp);
21082098 if (xbp != xbuf || xep > xlp)
@@ -2816,16 +2806,42 @@ do_complete(
28162806 static void
28172807 x_adjust(void)
28182808 {
2819- /* flag the fact that we were called. */
2809+ int col_left, n;
2810+
2811+ /* flag the fact that we were called */
28202812 x_adj_done++;
2813+
28212814 /*
2822- * we had a problem if the prompt length > xx_cols / 2
2815+ * calculate the amount of columns we need to "go back"
2816+ * from xcp to set xbp to (but never < xbuf) to 2/3 of
2817+ * the display width; take care of pwidth though
28232818 */
2824- if ((xbp = xcp - (x_displen / 2)) < xbuf)
2825- xbp = xbuf;
2826- if (UTFMODE)
2827- while ((xbp > xbuf) && ((*xbp & 0xC0) == 0x80))
2828- --xbp;
2819+ if ((col_left = xx_cols * 2 / 3) < MIN_EDIT_SPACE) {
2820+ /*
2821+ * cowardly refuse to do anything
2822+ * if the available space is too small;
2823+ * fall back to dumb pdksh code
2824+ */
2825+ if ((xbp = xcp - (x_displen / 2)) < xbuf)
2826+ xbp = xbuf;
2827+ /* elide UTF-8 fixup as penalty */
2828+ goto x_adjust_out;
2829+ }
2830+
2831+ /* fix up xbp to just past a character end first */
2832+ xbp = xcp >= xep ? xep : x_bs0(xcp, xbuf);
2833+ /* walk backwards */
2834+ while (xbp > xbuf && col_left > 0) {
2835+ xbp = x_bs0(xbp - 1, xbuf);
2836+ col_left -= (n = x_size2(xbp, NULL));
2837+ }
2838+ /* check if we hit the prompt */
2839+ if (xbp == xbuf && xcp != xbuf && col_left >= 0 && col_left < pwidth) {
2840+ /* so we did; force scrolling occurs */
2841+ xbp += utf_ptradj(xbp);
2842+ }
2843+
2844+ x_adjust_out:
28292845 xlp_valid = false;
28302846 x_redraw(xx_cols);
28312847 x_flush();
@@ -3345,9 +3361,9 @@ static void yank_range(int, int);
33453361 static int bracktype(int);
33463362 static void save_cbuf(void);
33473363 static void restore_cbuf(void);
3348-static int putbuf(const char *, ssize_t, int);
3364+static int putbuf(const char *, ssize_t, bool);
33493365 static void del_range(int, int);
3350-static int findch(int, int, int, int);
3366+static int findch(int, int, bool, bool);
33513367 static int forwword(int);
33523368 static int backword(int);
33533369 static int endword(int);
@@ -3411,11 +3427,11 @@ static const unsigned char classify[128] = {
34113427 /* 8 @ A B C D E F G */
34123428 vC|vX, vC, vM, vC, vC, vM, vM|vX, vC|vU|vZ,
34133429 /* 9 H I J K L M N O */
3414- 0, vC, 0, 0, 0, 0, vC|vU, 0,
3430+ 0, vC, 0, 0, 0, 0, vC|vU, vU,
34153431 /* A P Q R S T U V W */
34163432 vC, 0, vC, vC, vM|vX, vC, 0, vM,
34173433 /* B X Y Z [ \ ] ^ _ */
3418- vC, vC|vU, 0, 0, vC|vZ, 0, vM, vC|vZ,
3434+ vC, vC|vU, 0, vU, vC|vZ, 0, vM, vC|vZ,
34193435 /* C ` a b c d e f g */
34203436 0, vC, vM, vE, vE, vM, vM|vX, vC|vZ,
34213437 /* D h i j k l m n o */
@@ -3443,25 +3459,24 @@ static const unsigned char classify[128] = {
34433459 #define VLIT 8 /* ^V */
34443460 #define VSEARCH 9 /* /, ? */
34453461 #define VVERSION 10 /* <ESC> ^V */
3446-
3447-static char undocbuf[LINE];
3462+#define VPREFIX2 11 /* ^[[ and ^[O in insert mode */
34483463
34493464 static struct edstate *save_edstate(struct edstate *old);
34503465 static void restore_edstate(struct edstate *old, struct edstate *news);
34513466 static void free_edstate(struct edstate *old);
34523467
34533468 static struct edstate ebuf;
3454-static struct edstate undobuf = { undocbuf, 0, LINE, 0, 0 };
3469+static struct edstate undobuf;
34553470
3456-static struct edstate *es; /* current editor state */
3471+static struct edstate *es; /* current editor state */
34573472 static struct edstate *undo;
34583473
3459-static char ibuf[LINE]; /* input buffer */
3460-static int first_insert; /* set when starting in insert mode */
3474+static char *ibuf; /* input buffer */
3475+static bool first_insert; /* set when starting in insert mode */
34613476 static int saved_inslen; /* saved inslen for first insert */
34623477 static int inslen; /* length of input buffer */
34633478 static int srchlen; /* length of current search pattern */
3464-static char ybuf[LINE]; /* yank buffer */
3479+static char *ybuf; /* yank buffer */
34653480 static int yanklen; /* length of yank buffer */
34663481 static int fsavecmd = ' '; /* last find command */
34673482 static int fsavech; /* character to find */
@@ -3469,7 +3484,7 @@ static char lastcmd[MAXVICMD]; /* last non-move command */
34693484 static int lastac; /* argcnt for lastcmd */
34703485 static int lastsearch = ' '; /* last search command */
34713486 static char srchpat[SRCHLEN]; /* last search pattern */
3472-static int insert; /* non-zero in insert mode */
3487+static int insert; /* <>0 in insert mode */
34733488 static int hnum; /* position in history */
34743489 static int ohnum; /* history line copied (after mod) */
34753490 static int hlast; /* 1 past last position in history */
@@ -3495,7 +3510,7 @@ static enum expand_mode {
34953510 } expanded;
34963511
34973512 static int
3498-x_vi(char *buf, size_t len)
3513+x_vi(char *buf)
34993514 {
35003515 int c;
35013516
@@ -3503,36 +3518,29 @@ x_vi(char *buf, size_t len)
35033518 ohnum = hnum = hlast = histnum(-1) + 1;
35043519 insert = INSERT;
35053520 saved_inslen = inslen;
3506- first_insert = 1;
3521+ first_insert = true;
35073522 inslen = 0;
35083523 vi_macro_reset();
35093524
3525+ ebuf.cbuf = buf;
3526+ if (undobuf.cbuf == NULL) {
3527+ ibuf = alloc(LINE, AEDIT);
3528+ ybuf = alloc(LINE, AEDIT);
3529+ undobuf.cbuf = alloc(LINE, AEDIT);
3530+ }
3531+ undobuf.cbufsize = ebuf.cbufsize = LINE;
3532+ undobuf.linelen = ebuf.linelen = 0;
3533+ undobuf.cursor = ebuf.cursor = 0;
3534+ undobuf.winleft = ebuf.winleft = 0;
35103535 es = &ebuf;
3511- es->cbuf = buf;
35123536 undo = &undobuf;
3513- undo->cbufsize = es->cbufsize = len > LINE ? LINE : len;
3514-
3515- es->linelen = undo->linelen = 0;
3516- es->cursor = undo->cursor = 0;
3517- es->winleft = undo->winleft = 0;
35183537
3519- cur_col = promptlen(prompt);
3520- prompt_trunc = (cur_col / x_cols) * x_cols;
3521- cur_col -= prompt_trunc;
3522-
3523- pprompt(prompt, 0);
3524- if ((mksh_uari_t)cur_col > (mksh_uari_t)x_cols - 3 - MIN_EDIT_SPACE) {
3525- prompt_redraw = false;
3526- cur_col = 0;
3527- x_putc('\n');
3528- } else
3529- prompt_redraw = true;
3530- pwidth = cur_col;
3538+ x_init_prompt();
3539+ x_col = pwidth;
35313540
3532- if (!wbuf_len || wbuf_len != x_cols - 3) {
3533- wbuf_len = x_cols - 3;
3534- wbuf[0] = aresize(wbuf[0], wbuf_len, APERM);
3535- wbuf[1] = aresize(wbuf[1], wbuf_len, APERM);
3541+ if (wbuf_len != x_cols - 3 && ((wbuf_len = x_cols - 3))) {
3542+ wbuf[0] = aresize(wbuf[0], wbuf_len, AEDIT);
3543+ wbuf[1] = aresize(wbuf[1], wbuf_len, AEDIT);
35363544 }
35373545 if (wbuf_len) {
35383546 memset(wbuf[0], ' ', wbuf_len);
@@ -3589,11 +3597,11 @@ x_vi(char *buf, size_t len)
35893597 x_putc('\n');
35903598 x_flush();
35913599
3592- if (c == -1 || (ssize_t)len <= es->linelen)
3600+ if (c == -1 || (ssize_t)LINE <= es->linelen)
35933601 return (-1);
35943602
35953603 if (es->cbuf != buf)
3596- memmove(buf, es->cbuf, es->linelen);
3604+ memcpy(buf, es->cbuf, es->linelen);
35973605
35983606 buf[es->linelen++] = '\n';
35993607
@@ -3644,10 +3652,8 @@ vi_hook(int ch)
36443652 save_cbuf();
36453653 es->cursor = 0;
36463654 es->linelen = 0;
3647- if (ch == '/') {
3648- if (putbuf("/", 1, 0) != 0)
3649- return (-1);
3650- } else if (putbuf("?", 1, 0) != 0)
3655+ if (putbuf(ch == '/' ? "/" : "?", 1,
3656+ false) != 0)
36513657 return (-1);
36523658 refresh(0);
36533659 }
@@ -3656,7 +3662,7 @@ vi_hook(int ch)
36563662 es->cursor = 0;
36573663 es->linelen = 0;
36583664 putbuf(KSH_VERSION,
3659- strlen(KSH_VERSION), 0);
3665+ strlen(KSH_VERSION), false);
36603666 refresh(0);
36613667 }
36623668 }
@@ -3805,10 +3811,35 @@ vi_hook(int ch)
38053811 return (0);
38063812 }
38073813 break;
3814+
3815+ case VPREFIX2:
3816+ state = VFAIL;
3817+ switch (ch) {
3818+ case 'A':
3819+ /* the cursor may not be at the BOL */
3820+ if (!es->cursor)
3821+ break;
3822+ /* nor further in the line than we can search for */
3823+ if ((size_t)es->cursor >= sizeof(srchpat) - 1)
3824+ es->cursor = sizeof(srchpat) - 2;
3825+ /* anchor the search pattern */
3826+ srchpat[0] = '^';
3827+ /* take the current line up to the cursor */
3828+ memmove(srchpat + 1, es->cbuf, es->cursor);
3829+ srchpat[es->cursor + 1] = '\0';
3830+ /* set a magic flag */
3831+ argc1 = 2 + (int)es->cursor;
3832+ /* and emulate a backwards history search */
3833+ lastsearch = '/';
3834+ *curcmd = 'n';
3835+ goto pseudo_VCMD;
3836+ }
3837+ break;
38083838 }
38093839
38103840 switch (state) {
38113841 case VCMD:
3842+ pseudo_VCMD:
38123843 state = VNORMAL;
38133844 switch (vi_cmd(argc1, curcmd)) {
38143845 case -1:
@@ -3962,7 +3993,7 @@ vi_insert(int ch)
39623993 case Ctrl('['):
39633994 expanded = NONE;
39643995 if (first_insert) {
3965- first_insert = 0;
3996+ first_insert = false;
39663997 if (inslen == 0) {
39673998 inslen = saved_inslen;
39683999 return (redo_insert(0));
@@ -4074,12 +4105,12 @@ vi_cmd(int argcnt, const char *cmd)
40744105 * at this point, it's fairly reasonable that
40754106 * nlen + olen + 2 doesn't overflow
40764107 */
4077- nbuf = alloc(nlen + 1 + olen, APERM);
4108+ nbuf = alloc(nlen + 1 + olen, AEDIT);
40784109 memcpy(nbuf, ap->val.s, nlen);
40794110 nbuf[nlen++] = cmd[1];
40804111 if (macro.p) {
40814112 memcpy(nbuf + nlen, macro.p, olen);
4082- afree(macro.buf, APERM);
4113+ afree(macro.buf, AEDIT);
40834114 nlen += olen;
40844115 } else {
40854116 nbuf[nlen++] = '\0';
@@ -4164,7 +4195,8 @@ vi_cmd(int argcnt, const char *cmd)
41644195 hnum = hlast;
41654196 if (es->linelen != 0)
41664197 es->cursor++;
4167- while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
4198+ while (putbuf(ybuf, yanklen, false) == 0 &&
4199+ --argcnt > 0)
41684200 ;
41694201 if (es->cursor != 0)
41704202 es->cursor--;
@@ -4176,7 +4208,8 @@ vi_cmd(int argcnt, const char *cmd)
41764208 modified = 1;
41774209 hnum = hlast;
41784210 any = 0;
4179- while (putbuf(ybuf, yanklen, 0) == 0 && --argcnt > 0)
4211+ while (putbuf(ybuf, yanklen, false) == 0 &&
4212+ --argcnt > 0)
41804213 any = 1;
41814214 if (any && es->cursor != 0)
41824215 es->cursor--;
@@ -4378,6 +4411,11 @@ vi_cmd(int argcnt, const char *cmd)
43784411 hnum = c2;
43794412 ohnum = hnum;
43804413 }
4414+ if (argcnt >= 2) {
4415+ /* flag from cursor-up command */
4416+ es->cursor = argcnt - 2;
4417+ return (0);
4418+ }
43814419 break;
43824420 case '_':
43834421 {
@@ -4422,8 +4460,8 @@ vi_cmd(int argcnt, const char *cmd)
44224460 argcnt++;
44234461 p++;
44244462 }
4425- if (putbuf(" ", 1, 0) != 0 ||
4426- putbuf(sp, argcnt, 0) != 0) {
4463+ if (putbuf(" ", 1, false) != 0 ||
4464+ putbuf(sp, argcnt, false) != 0) {
44274465 if (es->cursor != 0)
44284466 es->cursor--;
44294467 return (-1);
@@ -4498,6 +4536,16 @@ vi_cmd(int argcnt, const char *cmd)
44984536 case Ctrl('x'):
44994537 expand_word(1);
45004538 break;
4539+
4540+
4541+ /* mksh: cursor movement */
4542+ case '[':
4543+ case 'O':
4544+ state = VPREFIX2;
4545+ if (es->linelen != 0)
4546+ es->cursor++;
4547+ insert = INSERT;
4548+ return (0);
45014549 }
45024550 if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
45034551 es->cursor--;
@@ -4556,7 +4604,8 @@ domove(int argcnt, const char *cmd, int sub)
45564604 t = fsavecmd > 'a';
45574605 if (*cmd == ',')
45584606 t = !t;
4559- if ((ncursor = findch(fsavech, argcnt, t, i)) < 0)
4607+ if ((ncursor = findch(fsavech, argcnt, tobool(t),
4608+ tobool(i))) < 0)
45604609 return (-1);
45614610 if (sub && t)
45624611 ncursor++;
@@ -4656,7 +4705,7 @@ static int
46564705 redo_insert(int count)
46574706 {
46584707 while (count-- > 0)
4659- if (putbuf(ibuf, inslen, insert == REPLACE) != 0)
4708+ if (putbuf(ibuf, inslen, tobool(insert == REPLACE)) != 0)
46604709 return (-1);
46614710 if (es->cursor > 0)
46624711 es->cursor--;
@@ -4707,9 +4756,9 @@ bracktype(int ch)
47074756 static void
47084757 save_cbuf(void)
47094758 {
4710- memmove(holdbuf, es->cbuf, es->linelen);
4759+ memmove(holdbufp, es->cbuf, es->linelen);
47114760 holdlen = es->linelen;
4712- holdbuf[holdlen] = '\0';
4761+ holdbufp[holdlen] = '\0';
47134762 }
47144763
47154764 static void
@@ -4717,7 +4766,7 @@ restore_cbuf(void)
47174766 {
47184767 es->cursor = 0;
47194768 es->linelen = holdlen;
4720- memmove(es->cbuf, holdbuf, holdlen);
4769+ memmove(es->cbuf, holdbufp, holdlen);
47214770 }
47224771
47234772 /* return a new edstate */
@@ -4726,8 +4775,8 @@ save_edstate(struct edstate *old)
47264775 {
47274776 struct edstate *news;
47284777
4729- news = alloc(sizeof(struct edstate), APERM);
4730- news->cbuf = alloc(old->cbufsize, APERM);
4778+ news = alloc(sizeof(struct edstate), AEDIT);
4779+ news->cbuf = alloc(old->cbufsize, AEDIT);
47314780 memcpy(news->cbuf, old->cbuf, old->linelen);
47324781 news->cbufsize = old->cbufsize;
47334782 news->linelen = old->linelen;
@@ -4749,8 +4798,8 @@ restore_edstate(struct edstate *news, struct edstate *old)
47494798 static void
47504799 free_edstate(struct edstate *old)
47514800 {
4752- afree(old->cbuf, APERM);
4753- afree(old, APERM);
4801+ afree(old->cbuf, AEDIT);
4802+ afree(old, AEDIT);
47544803 }
47554804
47564805 /*
@@ -4759,11 +4808,11 @@ free_edstate(struct edstate *old)
47594808 static int
47604809 x_vi_putbuf(const char *s, size_t len)
47614810 {
4762- return (putbuf(s, len, 0));
4811+ return (putbuf(s, len, false));
47634812 }
47644813
47654814 static int
4766-putbuf(const char *buf, ssize_t len, int repl)
4815+putbuf(const char *buf, ssize_t len, bool repl)
47674816 {
47684817 if (len == 0)
47694818 return (0);
@@ -4793,7 +4842,7 @@ del_range(int a, int b)
47934842 }
47944843
47954844 static int
4796-findch(int ch, int cnt, int forw, int incl)
4845+findch(int ch, int cnt, bool forw, bool incl)
47974846 {
47984847 int ncursor;
47994848
@@ -4989,8 +5038,8 @@ grabsearch(int save, int start, int fwd, const char *pat)
49895038 start--;
49905039 anchored = *pat == '^' ? (++pat, 1) : 0;
49915040 if ((hist = findhist(start, fwd, pat, anchored)) < 0) {
4992- /* (start != 0 && fwd && match(holdbuf, pat) >= 0) */
4993- if (start != 0 && fwd && strcmp(holdbuf, pat) >= 0) {
5041+ /* (start != 0 && fwd && match(holdbufp, pat) >= 0) */
5042+ if (start != 0 && fwd && strcmp(holdbufp, pat) >= 0) {
49945043 restore_cbuf();
49955044 return (0);
49965045 } else
@@ -5016,9 +5065,9 @@ redraw_line(bool newl)
50165065 x_putc('\r');
50175066 x_putc('\n');
50185067 }
5019- if (prompt_redraw)
5068+ if (prompt_trunc != -1)
50205069 pprompt(prompt, prompt_trunc);
5021- cur_col = pwidth;
5070+ x_col = pwidth;
50225071 morec = ' ';
50235072 }
50245073
@@ -5136,10 +5185,10 @@ display(char *wb1, char *wb2, int leftside)
51365185 twb2 = wb2;
51375186 while (cnt--) {
51385187 if (*twb1 != *twb2) {
5139- if (cur_col != col)
5188+ if (x_col != col)
51405189 ed_mov_opt(col, wb1);
51415190 x_putc(*twb1);
5142- cur_col++;
5191+ x_col++;
51435192 }
51445193 twb1++;
51455194 twb2++;
@@ -5160,34 +5209,34 @@ display(char *wb1, char *wb2, int leftside)
51605209 if (mc != morec) {
51615210 ed_mov_opt(pwidth + winwidth + 1, wb1);
51625211 x_putc(mc);
5163- cur_col++;
5212+ x_col++;
51645213 morec = mc;
51655214 }
5166- if (cur_col != ncol)
5215+ if (x_col != ncol)
51675216 ed_mov_opt(ncol, wb1);
51685217 }
51695218
51705219 static void
51715220 ed_mov_opt(int col, char *wb)
51725221 {
5173- if (col < cur_col) {
5174- if (col + 1 < cur_col - col) {
5222+ if (col < x_col) {
5223+ if (col + 1 < x_col - col) {
51755224 x_putc('\r');
5176- if (prompt_redraw)
5225+ if (prompt_trunc != -1)
51775226 pprompt(prompt, prompt_trunc);
5178- cur_col = pwidth;
5179- while (cur_col++ < col)
5227+ x_col = pwidth;
5228+ while (x_col++ < col)
51805229 x_putcf(*wb++);
51815230 } else {
5182- while (cur_col-- > col)
5231+ while (x_col-- > col)
51835232 x_putc('\b');
51845233 }
51855234 } else {
5186- wb = &wb[cur_col - pwidth];
5187- while (cur_col++ < col)
5235+ wb = &wb[x_col - pwidth];
5236+ while (x_col++ < col)
51885237 x_putcf(*wb++);
51895238 }
5190- cur_col = col;
5239+ x_col = col;
51915240 }
51925241
51935242
@@ -5229,7 +5278,7 @@ expand_word(int cmd)
52295278 rval = -1;
52305279 break;
52315280 }
5232- if (++i < nwords && putbuf(" ", 1, 0) != 0) {
5281+ if (++i < nwords && putbuf(" ", 1, false) != 0) {
52335282 rval = -1;
52345283 break;
52355284 }
@@ -5347,7 +5396,7 @@ complete_word(int cmd, int count)
53475396 */
53485397 if (match_len > 0 && match[match_len - 1] != '/' &&
53495398 !(flags & XCF_IS_NOSPACE))
5350- rval = putbuf(" ", 1, 0);
5399+ rval = putbuf(" ", 1, false);
53515400 }
53525401 x_free_words(nwords, words);
53535402
@@ -5404,7 +5453,7 @@ static void
54045453 vi_macro_reset(void)
54055454 {
54065455 if (macro.p) {
5407- afree(macro.buf, APERM);
5456+ afree(macro.buf, AEDIT);
54085457 memset((char *)&macro, 0, sizeof(macro));
54095458 }
54105459 }
@@ -5425,8 +5474,11 @@ x_init(void)
54255474 /* ^W */
54265475 edchars.werase = 027;
54275476
5428- /* initialise Emacs command line editing mode */
5477+ /* command line editing specific memory allocation */
54295478 ainit(AEDIT);
5479+ holdbufp = alloc(LINE, AEDIT);
5480+
5481+ /* initialise Emacs command line editing mode */
54305482 x_nextcmd = -1;
54315483
54325484 x_tab = alloc2(X_NTABS, sizeof(*x_tab), AEDIT);
--- a/src/eval.c
+++ b/src/eval.c
@@ -1,4 +1,4 @@
1-/* $OpenBSD: eval.c,v 1.37 2011/10/11 14:32:43 otto Exp $ */
1+/* $OpenBSD: eval.c,v 1.39 2013/07/01 17:25:27 jca Exp $ */
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -23,7 +23,7 @@
2323
2424 #include "sh.h"
2525
26-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.136 2013/02/10 23:43:59 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.142 2013/07/24 18:03:57 tg Exp $");
2727
2828 /*
2929 * string expansion
@@ -33,15 +33,21 @@ __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.136 2013/02/10 23:43:59 tg Exp $");
3333 */
3434
3535 /* expansion generator state */
36-typedef struct Expand {
37- /* int type; */ /* see expand() */
38- const char *str; /* string */
36+typedef struct {
37+ /* not including an "int type;" member, see expand() */
38+ /* string */
39+ const char *str;
40+ /* source */
3941 union {
40- const char **strv; /* string[] */
41- struct shf *shf; /* file */
42- } u; /* source */
43- struct tbl *var; /* variable in ${var..} */
44- bool split; /* split "$@" / call waitlast $() */
42+ /* string[] */
43+ const char **strv;
44+ /* file */
45+ struct shf *shf;
46+ } u;
47+ /* variable in ${var...} */
48+ struct tbl *var;
49+ /* split "$@" / call waitlast in $() */
50+ bool split;
4551 } Expand;
4652
4753 #define XBASE 0 /* scanning original */
@@ -59,7 +65,7 @@ typedef struct Expand {
5965
6066 static int varsub(Expand *, const char *, const char *, int *, int *);
6167 static int comsub(Expand *, const char *, int);
62-static void funsub(struct op *);
68+static char *valsub(struct op *, Area *);
6369 static char *trimsub(char *, char *, int);
6470 static void glob(char *, XPtrV *, bool);
6571 static void globit(XString *, char **, char *, XPtrV *, int);
@@ -198,33 +204,46 @@ typedef struct SubType {
198204 } SubType;
199205
200206 void
201-expand(const char *cp, /* input word */
202- XPtrV *wp, /* output words */
203- int f) /* DO* flags */
207+expand(
208+ /* input word */
209+ const char *ccp,
210+ /* output words */
211+ XPtrV *wp,
212+ /* DO* flags */
213+ int f)
204214 {
205215 int c = 0;
206- int type; /* expansion type */
207- int quote = 0; /* quoted */
208- XString ds; /* destination string */
209- char *dp; /* destination */
210- const char *sp; /* source */
211- int fdo, word; /* second pass flags; have word */
212- int doblank; /* field splitting of parameter/command subst */
216+ /* expansion type */
217+ int type;
218+ /* quoted */
219+ int quote = 0;
220+ /* destination string and live pointer */
221+ XString ds;
222+ char *dp;
223+ /* source */
224+ const char *sp;
225+ /* second pass flags */
226+ int fdo;
227+ /* have word */
228+ int word;
229+ /* field splitting of parameter/command substitution */
230+ int doblank;
231+ /* expansion variables */
213232 Expand x = {
214- /* expansion variables */
215233 NULL, { NULL }, NULL, 0
216234 };
217235 SubType st_head, *st;
218- /* For trailing newlines in COMSUB */
236+ /* record number of trailing newlines in COMSUB */
219237 int newlines = 0;
220238 bool saw_eq, make_magic;
221239 int tilde_ok;
222240 size_t len;
241+ char *cp;
223242
224- if (cp == NULL)
243+ if (ccp == NULL)
225244 internal_errorf("expand(NULL)");
226245 /* for alias, readonly, set, typeset commands */
227- if ((f & DOVACHECK) && is_wdvarassign(cp)) {
246+ if ((f & DOVACHECK) && is_wdvarassign(ccp)) {
228247 f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE);
229248 f |= DOASNTILDE;
230249 }
@@ -238,7 +257,7 @@ expand(const char *cp, /* input word */
238257 /* init destination string */
239258 Xinit(ds, dp, 128, ATEMP);
240259 type = XBASE;
241- sp = cp;
260+ sp = ccp;
242261 fdo = 0;
243262 saw_eq = false;
244263 /* must be 1/0 */
@@ -279,27 +298,26 @@ expand(const char *cp, /* input word */
279298 continue;
280299 case COMSUB:
281300 case FUNSUB:
301+ case VALSUB:
282302 tilde_ok = 0;
283303 if (f & DONTRUNCOMMAND) {
284304 word = IFS_WORD;
285305 *dp++ = '$';
286- if (c == FUNSUB) {
287- *dp++ = '{';
288- *dp++ = ' ';
289- } else
290- *dp++ = '(';
306+ *dp++ = c == COMSUB ? '(' : '{';
307+ if (c != COMSUB)
308+ *dp++ = c == FUNSUB ? ' ' : '|';
291309 while (*sp != '\0') {
292310 Xcheck(ds, dp);
293311 *dp++ = *sp++;
294312 }
295- if (c == FUNSUB) {
313+ if (c != COMSUB) {
296314 *dp++ = ';';
297315 *dp++ = '}';
298316 } else
299317 *dp++ = ')';
300318 } else {
301319 type = comsub(&x, sp, c);
302- if (type == XCOM && (f&DOBLANK))
320+ if (type != XBASE && (f & DOBLANK))
303321 doblank++;
304322 sp = strnul(sp) + 1;
305323 newlines = 0;
@@ -317,7 +335,6 @@ expand(const char *cp, /* input word */
317335 *dp++ = ')'; *dp++ = ')';
318336 } else {
319337 struct tbl v;
320- char *p;
321338
322339 v.flag = DEFINED|ISSET|INTEGER;
323340 /* not default */
@@ -326,9 +343,10 @@ expand(const char *cp, /* input word */
326343 v_evaluate(&v, substitute(sp, 0),
327344 KSH_UNWIND_ERROR, true);
328345 sp = strnul(sp) + 1;
329- for (p = str_val(&v); *p; ) {
346+ cp = str_val(&v);
347+ while (*cp) {
330348 Xcheck(ds, dp);
331- *dp++ = *p++;
349+ *dp++ = *cp++;
332350 }
333351 }
334352 continue;
@@ -394,8 +412,7 @@ expand(const char *cp, /* input word */
394412 if (stype)
395413 sp += slen;
396414 switch (stype & 0x17F) {
397- case 0x100 | '#':
398- {
415+ case 0x100 | '#': {
399416 char *beg, *end;
400417 mksh_ari_t seed;
401418 register uint32_t h;
@@ -416,8 +433,7 @@ expand(const char *cp, /* input word */
416433 (unsigned int)h);
417434 break;
418435 }
419- case 0x100 | 'Q':
420- {
436+ case 0x100 | 'Q': {
421437 struct shf shf;
422438
423439 shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
@@ -839,7 +855,10 @@ expand(const char *cp, /* input word */
839855 if (c == 0) {
840856 if (quote && !x.split)
841857 continue;
858+ /* this is so we don't terminate */
842859 c = ' ';
860+ /* now force-emit a word */
861+ goto emit_word;
843862 }
844863 if (quote && x.split) {
845864 /* terminate word for "$@" */
@@ -850,14 +869,19 @@ expand(const char *cp, /* input word */
850869 break;
851870
852871 case XCOM:
853- if (newlines) {
854- /* Spit out saved NLs */
872+ if (x.u.shf == NULL) {
873+ /* $(<...) failed */
874+ subst_exstat = 1;
875+ /* fake EOF */
876+ c = EOF;
877+ } else if (newlines) {
878+ /* spit out saved NLs */
855879 c = '\n';
856880 --newlines;
857881 } else {
858882 while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
859883 if (c == '\n')
860- /* Save newlines */
884+ /* save newlines */
861885 newlines++;
862886 if (newlines && c != EOF) {
863887 shf_ungetc(c, x.u.shf);
@@ -867,7 +891,8 @@ expand(const char *cp, /* input word */
867891 }
868892 if (c == EOF) {
869893 newlines = 0;
870- shf_close(x.u.shf);
894+ if (x.u.shf)
895+ shf_close(x.u.shf);
871896 if (x.split)
872897 subst_exstat = waitlast();
873898 type = XBASE;
@@ -895,21 +920,21 @@ expand(const char *cp, /* input word */
895920 */
896921 if (word == IFS_WORD ||
897922 (!ctype(c, C_IFSWS) && c && word == IFS_NWS)) {
898- char *p;
899-
923+ emit_word:
900924 *dp++ = '\0';
901- p = Xclose(ds, dp);
925+ cp = Xclose(ds, dp);
902926 if (fdo & DOBRACE)
903927 /* also does globbing */
904- alt_expand(wp, p, p,
905- p + Xlength(ds, (dp - 1)),
928+ alt_expand(wp, cp, cp,
929+ cp + Xlength(ds, (dp - 1)),
906930 fdo | (f & DOMARKDIRS));
907931 else if (fdo & DOGLOB)
908- glob(p, wp, tobool(f & DOMARKDIRS));
932+ glob(cp, wp, tobool(f & DOMARKDIRS));
909933 else if ((f & DOPAT) || !(fdo & DOMAGIC))
910- XPput(*wp, p);
934+ XPput(*wp, cp);
911935 else
912- XPput(*wp, debunk(p, p, strlen(p) + 1));
936+ XPput(*wp, debunk(cp, cp,
937+ strlen(cp) + 1));
913938 fdo = 0;
914939 saw_eq = false;
915940 tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
@@ -920,10 +945,8 @@ expand(const char *cp, /* input word */
920945 return;
921946 } else if (type == XSUB && ctype(c, C_IFS) &&
922947 !ctype(c, C_IFSWS) && Xlength(ds, dp) == 0) {
923- char *p;
924-
925- *(p = alloc(1, ATEMP)) = '\0';
926- XPput(*wp, p);
948+ *(cp = alloc(1, ATEMP)) = '\0';
949+ XPput(*wp, cp);
927950 type = XSUBMID;
928951 }
929952 if (word != IFS_NWS)
@@ -932,10 +955,8 @@ expand(const char *cp, /* input word */
932955 if (type == XSUB) {
933956 if (word == IFS_NWS &&
934957 Xlength(ds, dp) == 0) {
935- char *p;
936-
937- *(p = alloc(1, ATEMP)) = '\0';
938- XPput(*wp, p);
958+ *(cp = alloc(1, ATEMP)) = '\0';
959+ XPput(*wp, cp);
939960 }
940961 type = XSUBMID;
941962 }
@@ -1002,18 +1023,17 @@ expand(const char *cp, /* input word */
10021023 if (type == XBASE &&
10031024 (f & (DOTILDE|DOASNTILDE)) &&
10041025 (tilde_ok & 2)) {
1005- const char *p;
1006- char *dp_x;
1026+ const char *tcp;
1027+ char *tdp = dp;
10071028
1008- dp_x = dp;
1009- p = maybe_expand_tilde(sp,
1010- &ds, &dp_x,
1029+ tcp = maybe_expand_tilde(sp,
1030+ &ds, &tdp,
10111031 f & DOASNTILDE);
1012- if (p) {
1013- if (dp != dp_x)
1032+ if (tcp) {
1033+ if (dp != tdp)
10141034 word = IFS_WORD;
1015- dp = dp_x;
1016- sp = p;
1035+ dp = tdp;
1036+ sp = tcp;
10171037 continue;
10181038 }
10191039 }
@@ -1176,8 +1196,10 @@ varsub(Expand *xp, const char *sp, const char *word,
11761196 c = sp[0];
11771197 if (c == '*' || c == '@') {
11781198 switch (stype & 0x17F) {
1179- case '=': /* can't assign to a vector */
1180- case '%': /* can't trim a vector (yet) */
1199+ /* can't assign to a vector */
1200+ case '=':
1201+ /* can't trim a vector (yet) */
1202+ case '%':
11811203 case '#':
11821204 case '0':
11831205 case '/':
@@ -1204,8 +1226,10 @@ varsub(Expand *xp, const char *sp, const char *word,
12041226 XPtrV wv;
12051227
12061228 switch (stype & 0x17F) {
1207- case '=': /* can't assign to a vector */
1208- case '%': /* can't trim a vector (yet) */
1229+ /* can't assign to a vector */
1230+ case '=':
1231+ /* can't trim a vector (yet) */
1232+ case '%':
12091233 case '#':
12101234 case '?':
12111235 case '0':
@@ -1317,33 +1341,41 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
13171341 shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
13181342 SHF_MAPHI|SHF_CLEXEC);
13191343 if (shf == NULL)
1320- errorf("%s: %s %s", name, "can't open", "$() input");
1344+ warningf(!Flag(FTALKING), "%s: %s %s: %s", name,
1345+ "can't open", "$(<...) input", cstrerror(errno));
13211346 } else if (fn == FUNSUB) {
13221347 int ofd1;
13231348 struct temp *tf = NULL;
13241349
1325- /* create a temporary file, open for writing */
1350+ /*
1351+ * create a temporary file, open for reading and writing,
1352+ * with an shf open for reading (buffered) but yet unused
1353+ */
13261354 maketemp(ATEMP, TT_FUNSUB, &tf);
13271355 if (!tf->shf) {
13281356 errorf("can't %s temporary file %s: %s",
13291357 "create", tf->tffn, cstrerror(errno));
13301358 }
1331- /* save stdout and make the temporary file it */
1359+ /* extract shf from temporary file, unlink and free it */
1360+ shf = tf->shf;
1361+ unlink(tf->tffn);
1362+ afree(tf, ATEMP);
1363+ /* save stdout and let it point to the tempfile */
13321364 ofd1 = savefd(1);
1333- ksh_dup2(shf_fileno(tf->shf), 1, false);
1365+ ksh_dup2(shf_fileno(shf), 1, false);
13341366 /*
13351367 * run tree, with output thrown into the tempfile,
13361368 * in a new function block
13371369 */
1338- funsub(t);
1370+ valsub(t, NULL);
13391371 subst_exstat = exstat & 0xFF;
1340- /* close the tempfile and restore regular stdout */
1341- shf_close(tf->shf);
1372+ /* rewind the tempfile and restore regular stdout */
1373+ lseek(shf_fileno(shf), (off_t)0, SEEK_SET);
13421374 restfd(1, ofd1);
1343- /* now open, unlink and free the tempfile for reading */
1344- shf = shf_open(tf->tffn, O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
1345- unlink(tf->tffn);
1346- afree(tf, ATEMP);
1375+ } else if (fn == VALSUB) {
1376+ xp->str = valsub(t, ATEMP);
1377+ subst_exstat = exstat & 0xFF;
1378+ return (XSUB);
13471379 } else {
13481380 int ofd1, pv[2];
13491381
@@ -1495,11 +1527,11 @@ globit(XString *xs, /* dest string */
14951527 */
14961528 if ((check & GF_EXCHECK) ||
14971529 ((check & GF_MARKDIR) && (check & GF_GLOBBED))) {
1498-#define stat_check() (stat_done ? stat_done : \
1499- (stat_done = stat(Xstring(*xs, xp), &statb) < 0 \
1500- ? -1 : 1))
1530+#define stat_check() (stat_done ? stat_done : (stat_done = \
1531+ stat(Xstring(*xs, xp), &statb) < 0 ? -1 : 1))
15011532 struct stat lstatb, statb;
1502- int stat_done = 0; /* -1: failed, 1 ok */
1533+ /* -1: failed, 1 ok, 0 not yet done */
1534+ int stat_done = 0;
15031535
15041536 if (mksh_lstat(Xstring(*xs, xp), &lstatb) < 0)
15051537 return;
@@ -1801,12 +1833,21 @@ alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
18011833 }
18021834
18031835 /* helper function due to setjmp/longjmp woes */
1804-static void
1805-funsub(struct op *t)
1836+static char *
1837+valsub(struct op *t, Area *ap)
18061838 {
1839+ char * volatile cp = NULL;
1840+ struct tbl * volatile vp = NULL;
1841+
1842+ newenv(E_FUNC);
18071843 newblock();
1808- e->type = E_FUNC;
1844+ if (ap)
1845+ vp = local("REPLY", false);
18091846 if (!kshsetjmp(e->jbuf))
18101847 execute(t, XXCOM | XERROK, NULL);
1811- popblock();
1848+ if (vp)
1849+ strdupx(cp, str_val(vp), ap);
1850+ quitenv(NULL);
1851+
1852+ return (cp);
18121853 }
--- a/src/exec.c
+++ b/src/exec.c
@@ -1,4 +1,4 @@
1-/* $OpenBSD: exec.c,v 1.49 2009/01/29 23:27:26 jaredy Exp $ */
1+/* $OpenBSD: exec.c,v 1.50 2013/06/10 21:09:27 millert Exp $ */
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -23,7 +23,7 @@
2323
2424 #include "sh.h"
2525
26-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.116 2013/02/17 05:40:15 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.125 2013/07/21 20:44:44 tg Exp $");
2727
2828 #ifndef MKSH_DEFAULT_EXECSHELL
2929 #define MKSH_DEFAULT_EXECSHELL "/bin/sh"
@@ -106,7 +106,7 @@ execute(struct op * volatile t,
106106 /* set variable to its expanded value */
107107 z = strlen(cp) + 1;
108108 if (notoktomul(z, 2) || notoktoadd(z * 2, n))
109- internal_errorf(Toomem, (unsigned long)-1);
109+ internal_errorf(Toomem, (size_t)-1);
110110 dp = alloc(z * 2 + n, ATEMP);
111111 memcpy(dp, t->vars[0], n);
112112 t->vars[0] = dp;
@@ -138,14 +138,6 @@ execute(struct op * volatile t,
138138 /* Allow option parsing (bizarre, but POSIX) */
139139 timex_hook(t, &up);
140140 ap = (const char **)up;
141- if (Flag(FXTRACE) && ap[0]) {
142- shf_puts(substitute(str_val(global("PS4")), 0),
143- shl_out);
144- for (i = 0; ap[i]; i++)
145- shf_fprintf(shl_out, "%s%c", ap[i],
146- ap[i + 1] ? ' ' : '\n');
147- shf_flush(shl_out);
148- }
149141 if (ap[0])
150142 tp = findcom(ap[0], FC_BI|FC_FUNC);
151143 }
@@ -305,10 +297,12 @@ execute(struct op * volatile t,
305297 case TAND:
306298 rv = execute(t->left, XERROK, xerrok);
307299 if ((rv == 0) == (t->type == TAND))
308- rv = execute(t->right, XERROK, xerrok);
309- flags |= XERROK;
310- if (xerrok)
311- *xerrok = 1;
300+ rv = execute(t->right, flags & XERROK, xerrok);
301+ else {
302+ flags |= XERROK;
303+ if (xerrok)
304+ *xerrok = 1;
305+ }
312306 break;
313307
314308 case TBANG:
@@ -335,6 +329,7 @@ execute(struct op * volatile t,
335329 case TFOR:
336330 case TSELECT: {
337331 volatile bool is_first = true;
332+
338333 ap = (t->vars == NULL) ? e->loc->argv + 1 :
339334 (const char **)eval((const char **)t->vars,
340335 DOBLANK | DOGLOB | DOTILDE);
@@ -639,27 +634,44 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
639634 l_assign = e->loc;
640635 if (Flag(FEXPORT))
641636 type_flags |= EXPORT;
637+ if (Flag(FXTRACE))
638+ change_xtrace(2, false);
642639 for (i = 0; t->vars[i]; i++) {
643640 /* do NOT lookup in the new var/fn block just created */
644641 e->loc = l_expand;
645642 cp = evalstr(t->vars[i], DOASNTILDE);
646643 e->loc = l_assign;
647- /* but assign in there as usual */
648-
649644 if (Flag(FXTRACE)) {
650- if (i == 0)
651- shf_puts(substitute(str_val(global("PS4")), 0),
652- shl_out);
653- shf_fprintf(shl_out, "%s%c", cp,
654- t->vars[i + 1] ? ' ' : '\n');
655- if (!t->vars[i + 1])
656- shf_flush(shl_out);
645+ const char *ccp;
646+
647+ ccp = skip_varname(cp, true);
648+ if (*ccp == '+')
649+ ++ccp;
650+ if (*ccp == '=')
651+ ++ccp;
652+ shf_write(cp, ccp - cp, shl_xtrace);
653+ print_value_quoted(shl_xtrace, ccp);
654+ shf_putc(' ', shl_xtrace);
657655 }
656+ /* but assign in there as usual */
658657 typeset(cp, type_flags, 0, 0, 0);
659658 if (bourne_function_call && !(type_flags & EXPORT))
660659 typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
661660 }
662661
662+ if (Flag(FXTRACE)) {
663+ change_xtrace(2, false);
664+ if (ap[rv = 0]) {
665+ xtrace_ap_loop:
666+ print_value_quoted(shl_xtrace, ap[rv]);
667+ if (ap[++rv]) {
668+ shf_putc(' ', shl_xtrace);
669+ goto xtrace_ap_loop;
670+ }
671+ }
672+ change_xtrace(1, false);
673+ }
674+
663675 if ((cp = *ap) == NULL) {
664676 rv = subst_exstat;
665677 goto Leave;
@@ -700,10 +712,9 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
700712 break;
701713 }
702714 if (include(tp->u.fpath, 0, NULL, false) < 0) {
703- rv = errno;
704715 warningf(true, "%s: %s %s %s: %s", cp,
705716 "can't open", "function definition file",
706- tp->u.fpath, cstrerror(rv));
717+ tp->u.fpath, cstrerror(errno));
707718 rv = 127;
708719 break;
709720 }
@@ -740,9 +751,9 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
740751 getopts_reset(1);
741752 }
742753
743- old_xflag = Flag(FXTRACE);
744- Flag(FXTRACE) |= tp->flag & TRACE ? 1 : 0;
745-
754+ old_xflag = Flag(FXTRACE) ? 1 : 0;
755+ change_xtrace((Flag(FXTRACEREC) ? old_xflag : 0) |
756+ ((tp->flag & TRACE) ? 1 : 0), false);
746757 old_inuse = tp->flag & FINUSE;
747758 tp->flag |= FINUSE;
748759
@@ -751,9 +762,11 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
751762 execute(tp->val.t, flags & XERROK, NULL);
752763 i = LRETURN;
753764 }
765+
754766 kshname = old_kshname;
755- Flag(FXTRACE) = old_xflag;
767+ change_xtrace(old_xflag, false);
756768 tp->flag = (tp->flag & ~FINUSE) | old_inuse;
769+
757770 /*
758771 * Were we deleted while executing? If so, free the
759772 * execution tree. TODO: Unfortunately, the table entry
@@ -1033,25 +1046,23 @@ const char *
10331046 builtin(const char *name, int (*func) (const char **))
10341047 {
10351048 struct tbl *tp;
1036- uint32_t flag;
1049+ uint32_t flag = DEFINED;
10371050
10381051 /* see if any flags should be set for this builtin */
1039- for (flag = 0; ; name++) {
1052+ while (1) {
10401053 if (*name == '=')
10411054 /* command does variable assignment */
10421055 flag |= KEEPASN;
10431056 else if (*name == '*')
10441057 /* POSIX special builtin */
10451058 flag |= SPEC_BI;
1046- else if (*name == '+')
1047- /* POSIX regular builtin */
1048- flag |= REG_BI;
10491059 else
10501060 break;
1061+ name++;
10511062 }
10521063
10531064 tp = ktenter(&builtins, name, hash(name));
1054- tp->flag = DEFINED | flag;
1065+ tp->flag = flag;
10551066 tp->type = CSHELL;
10561067 tp->val.f = func;
10571068
@@ -1083,7 +1094,7 @@ findcom(const char *name, int flags)
10831094 tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL;
10841095 /*
10851096 * POSIX says special builtins first, then functions, then
1086- * POSIX regular builtins, then search path...
1097+ * regular builtins, then search path...
10871098 */
10881099 if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
10891100 tp = tbi;
@@ -1098,9 +1109,7 @@ findcom(const char *name, int flags)
10981109 &tp->u2.errnov);
10991110 }
11001111 }
1101- if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
1102- tp = tbi;
1103- if (!tp && (flags & FC_UNREGBI) && tbi)
1112+ if (!tp && (flags & FC_NORMBI) && tbi)
11041113 tp = tbi;
11051114 if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
11061115 tp = ktsearch(&taliases, name, h);
@@ -1298,10 +1307,11 @@ iosetup(struct ioword *iop, struct tbl *tp)
12981307 iotmp.name = (iotype == IOHERE) ? NULL : cp;
12991308 iotmp.flag |= IONAMEXP;
13001309
1301- if (Flag(FXTRACE))
1302- shellf("%s%s\n",
1303- substitute(str_val(global("PS4")), 0),
1304- snptreef(NULL, 32, "%R", &iotmp));
1310+ if (Flag(FXTRACE)) {
1311+ change_xtrace(2, false);
1312+ fptreef(shl_xtrace, 0, "%R", &iotmp);
1313+ change_xtrace(1, false);
1314+ }
13051315
13061316 switch (iotype) {
13071317 case IOREAD:
@@ -1345,8 +1355,11 @@ iosetup(struct ioword *iop, struct tbl *tp)
13451355 } else if ((u = check_fd(cp,
13461356 X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
13471357 &emsg)) < 0) {
1358+ char *sp;
1359+
13481360 warningf(true, "%s: %s",
1349- snptreef(NULL, 32, "%R", &iotmp), emsg);
1361+ (sp = snptreef(NULL, 32, "%R", &iotmp)), emsg);
1362+ afree(sp, ATEMP);
13501363 return (-1);
13511364 }
13521365 if (u == iop->unit)
@@ -1395,12 +1408,14 @@ iosetup(struct ioword *iop, struct tbl *tp)
13951408 else if (u != iop->unit) {
13961409 if (ksh_dup2(u, iop->unit, true) < 0) {
13971410 int eno;
1411+ char *sp;
13981412
13991413 eno = errno;
14001414 warningf(true, "%s %s %s",
14011415 "can't finish (dup) redirection",
1402- snptreef(NULL, 32, "%R", &iotmp),
1416+ (sp = snptreef(NULL, 32, "%R", &iotmp)),
14031417 cstrerror(eno));
1418+ afree(sp, ATEMP);
14041419 if (iotype != IODUP)
14051420 close(u);
14061421 return (-1);
@@ -1548,10 +1563,8 @@ do_selectargs(const char **ap, bool print_menu)
15481563 if (call_builtin(findcom("read", FC_BI), read_args, Tselect))
15491564 return (NULL);
15501565 s = str_val(global("REPLY"));
1551- if (*s) {
1552- getn(s, &i);
1566+ if (*s && getn(s, &i))
15531567 return ((i >= 1 && i <= argct) ? ap[i - 1] : null);
1554- }
15551568 print_menu = true;
15561569 }
15571570 }
--- a/src/expr.c
+++ b/src/expr.c
@@ -1,4 +1,4 @@
1-/* $OpenBSD: expr.c,v 1.21 2009/06/01 19:00:57 deraadt Exp $ */
1+/* $OpenBSD: expr.c,v 1.22 2013/03/28 08:39:28 nicm Exp $ */
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -23,23 +23,9 @@
2323
2424 #include "sh.h"
2525
26-__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.61 2013/02/15 18:36:48 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.72 2013/07/21 18:38:56 tg Exp $");
2727
28-#if !HAVE_SILENT_IDIVWRAPV
29-#if !defined(MKSH_LEGACY_MODE) || HAVE_LONG_32BIT
30-#define IDIVWRAPV_VL (mksh_uari_t)0x80000000UL
31-#define IDIVWRAPV_VR (mksh_uari_t)0xFFFFFFFFUL
32-#elif HAVE_LONG_64BIT
33-#define IDIVWRAPV_VL (mksh_uari_t)0x8000000000000000UL
34-#define IDIVWRAPV_VR (mksh_uari_t)0xFFFFFFFFFFFFFFFFUL
35-#else
36-# warning "cannot guarantee integer division wraparound"
37-#undef HAVE_SILENT_IDIVWRAPV
38-#define HAVE_SILENT_IDIVWRAPV 1
39-#endif
40-#endif
41-
42-/* The order of these enums is constrained by the order of opinfo[] */
28+/* the order of these enums is constrained by the order of opinfo[] */
4329 enum token {
4430 /* some (long) unary operators */
4531 O_PLUSPLUS = 0, O_MINUSMINUS,
@@ -47,7 +33,14 @@ enum token {
4733 O_EQ, O_NE,
4834 /* assignments are assumed to be in range O_ASN .. O_BORASN */
4935 O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
36+#ifndef MKSH_LEGACY_MODE
37+ O_ROLASN, O_RORASN,
38+#endif
5039 O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
40+ /* binary non-assignment operators */
41+#ifndef MKSH_LEGACY_MODE
42+ O_ROL, O_ROR,
43+#endif
5144 O_LSHIFT, O_RSHIFT,
5245 O_LE, O_GE, O_LT, O_GT,
5346 O_LAND,
@@ -67,14 +60,13 @@ enum token {
6760 /* things that don't appear in the opinfo[] table */
6861 VAR, LIT, END, BAD
6962 };
70-#define IS_BINOP(op) (((int)op) >= (int)O_EQ && ((int)op) <= (int)O_COMMA)
7163 #define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
7264
7365 /* precisions; used to be enum prec but we do arithmetics on it */
74-#define P_PRIMARY 0 /* VAR, LIT, (), ~ ! - + */
66+#define P_PRIMARY 0 /* VAR, LIT, (), ! ~ ++ -- */
7567 #define P_MULT 1 /* * / % */
7668 #define P_ADD 2 /* + - */
77-#define P_SHIFT 3 /* << >> */
69+#define P_SHIFT 3 /* <<< >>> << >> */
7870 #define P_RELATION 4 /* < <= > >= */
7971 #define P_EQUALITY 5 /* == != */
8072 #define P_BAND 6 /* & */
@@ -83,60 +75,72 @@ enum token {
8375 #define P_LAND 9 /* && */
8476 #define P_LOR 10 /* || */
8577 #define P_TERN 11 /* ?: */
86-#define P_ASSIGN 12 /* = *= /= %= += -= <<= >>= &= ^= |= */
78+ /* = += -= *= /= %= <<<= >>>= <<= >>= &= ^= |= */
79+#define P_ASSIGN 12
8780 #define P_COMMA 13 /* , */
8881 #define MAX_PREC P_COMMA
8982
9083 struct opinfo {
91- char name[4];
92- int len; /* name length */
93- int prec; /* precedence: lower is higher */
84+ char name[5];
85+ /* name length */
86+ uint8_t len;
87+ /* precedence: lower is higher */
88+ uint8_t prec;
9489 };
9590
96-/* Tokens in this table must be ordered so the longest are first
91+/*
92+ * Tokens in this table must be ordered so the longest are first
9793 * (eg, += before +). If you change something, change the order
9894 * of enum token too.
9995 */
10096 static const struct opinfo opinfo[] = {
101- { "++", 2, P_PRIMARY }, /* before + */
102- { "--", 2, P_PRIMARY }, /* before - */
103- { "==", 2, P_EQUALITY }, /* before = */
104- { "!=", 2, P_EQUALITY }, /* before ! */
105- { "=", 1, P_ASSIGN }, /* keep assigns in a block */
106- { "*=", 2, P_ASSIGN },
107- { "/=", 2, P_ASSIGN },
108- { "%=", 2, P_ASSIGN },
109- { "+=", 2, P_ASSIGN },
110- { "-=", 2, P_ASSIGN },
111- { "<<=", 3, P_ASSIGN },
112- { ">>=", 3, P_ASSIGN },
113- { "&=", 2, P_ASSIGN },
114- { "^=", 2, P_ASSIGN },
115- { "|=", 2, P_ASSIGN },
116- { "<<", 2, P_SHIFT },
117- { ">>", 2, P_SHIFT },
118- { "<=", 2, P_RELATION },
119- { ">=", 2, P_RELATION },
120- { "<", 1, P_RELATION },
121- { ">", 1, P_RELATION },
122- { "&&", 2, P_LAND },
123- { "||", 2, P_LOR },
124- { "*", 1, P_MULT },
125- { "/", 1, P_MULT },
126- { "%", 1, P_MULT },
127- { "+", 1, P_ADD },
128- { "-", 1, P_ADD },
129- { "&", 1, P_BAND },
130- { "^", 1, P_BXOR },
131- { "|", 1, P_BOR },
132- { "?", 1, P_TERN },
133- { ",", 1, P_COMMA },
134- { "~", 1, P_PRIMARY },
135- { "!", 1, P_PRIMARY },
136- { "(", 1, P_PRIMARY },
137- { ")", 1, P_PRIMARY },
138- { ":", 1, P_PRIMARY },
139- { "", 0, P_PRIMARY }
97+ { "++", 2, P_PRIMARY }, /* before + */
98+ { "--", 2, P_PRIMARY }, /* before - */
99+ { "==", 2, P_EQUALITY }, /* before = */
100+ { "!=", 2, P_EQUALITY }, /* before ! */
101+ { "=", 1, P_ASSIGN }, /* keep assigns in a block */
102+ { "*=", 2, P_ASSIGN },
103+ { "/=", 2, P_ASSIGN },
104+ { "%=", 2, P_ASSIGN },
105+ { "+=", 2, P_ASSIGN },
106+ { "-=", 2, P_ASSIGN },
107+#ifndef MKSH_LEGACY_MODE
108+ { "<<<=", 4, P_ASSIGN }, /* before <<< */
109+ { ">>>=", 4, P_ASSIGN }, /* before >>> */
110+#endif
111+ { "<<=", 3, P_ASSIGN },
112+ { ">>=", 3, P_ASSIGN },
113+ { "&=", 2, P_ASSIGN },
114+ { "^=", 2, P_ASSIGN },
115+ { "|=", 2, P_ASSIGN },
116+#ifndef MKSH_LEGACY_MODE
117+ { "<<<", 3, P_SHIFT }, /* before << */
118+ { ">>>", 3, P_SHIFT }, /* before >> */
119+#endif
120+ { "<<", 2, P_SHIFT },
121+ { ">>", 2, P_SHIFT },
122+ { "<=", 2, P_RELATION },
123+ { ">=", 2, P_RELATION },
124+ { "<", 1, P_RELATION },
125+ { ">", 1, P_RELATION },
126+ { "&&", 2, P_LAND },
127+ { "||", 2, P_LOR },
128+ { "*", 1, P_MULT },
129+ { "/", 1, P_MULT },
130+ { "%", 1, P_MULT },
131+ { "+", 1, P_ADD },
132+ { "-", 1, P_ADD },
133+ { "&", 1, P_BAND },
134+ { "^", 1, P_BXOR },
135+ { "|", 1, P_BOR },
136+ { "?", 1, P_TERN },
137+ { ",", 1, P_COMMA },
138+ { "~", 1, P_PRIMARY },
139+ { "!", 1, P_PRIMARY },
140+ { "(", 1, P_PRIMARY },
141+ { ")", 1, P_PRIMARY },
142+ { ":", 1, P_PRIMARY },
143+ { "", 0, P_PRIMARY }
140144 };
141145
142146 typedef struct expr_state {
@@ -151,18 +155,13 @@ typedef struct expr_state {
151155 /* token from token() */
152156 enum token tok;
153157 /* don't do assignments (for ?:, &&, ||) */
154- short noassign;
158+ uint8_t noassign;
155159 /* evaluating an $(()) expression? */
156160 bool arith;
157161 /* unsigned arithmetic calculation */
158162 bool natural;
159163 } Expr_state;
160164
161-#define bivui(x, op, y) (es->natural ? \
162- (mksh_uari_t)((x)->val.u op (y)->val.u) : \
163- (mksh_uari_t)((x)->val.i op (y)->val.i) \
164-)
165-
166165 enum error_type {
167166 ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
168167 ET_LVALUE, ET_RDONLY, ET_STR
@@ -170,7 +169,7 @@ enum error_type {
170169
171170 static void evalerr(Expr_state *, enum error_type, const char *)
172171 MKSH_A_NORETURN;
173-static struct tbl *evalexpr(Expr_state *, int);
172+static struct tbl *evalexpr(Expr_state *, unsigned int);
174173 static void exprtoken(Expr_state *);
175174 static struct tbl *do_ppmm(Expr_state *, enum token, struct tbl *, bool);
176175 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)
185184 struct tbl v;
186185 int ret;
187186
188- v.flag = DEFINED|INTEGER;
187+ v.flag = DEFINED | INTEGER;
189188 v.type = 0;
190189 ret = v_evaluate(&v, expr, error_ok, arith);
191190 *rval = v.val.i;
@@ -307,52 +306,103 @@ evalerr(Expr_state *es, enum error_type type, const char *str)
307306 unwind(LAEXPR);
308307 }
309308
309+/* do a ++ or -- operation */
310310 static struct tbl *
311-evalexpr(Expr_state *es, int prec)
311+do_ppmm(Expr_state *es, enum token op, struct tbl *vasn, bool is_prefix)
312+{
313+ struct tbl *vl;
314+ mksh_uari_t oval;
315+
316+ assign_check(es, op, vasn);
317+
318+ vl = intvar(es, vasn);
319+ oval = vl->val.u;
320+ if (op == O_PLUSPLUS)
321+ ++vl->val.u;
322+ else
323+ --vl->val.u;
324+ if (!es->noassign) {
325+ if (vasn->flag & INTEGER)
326+ setint_v(vasn, vl, es->arith);
327+ else
328+ setint(vasn, vl->val.i);
329+ }
330+ if (!is_prefix)
331+ /* undo the increment/decrement */
332+ vl->val.u = oval;
333+
334+ return (vl);
335+}
336+
337+static struct tbl *
338+evalexpr(Expr_state *es, unsigned int prec)
312339 {
313340 struct tbl *vl, *vr = NULL, *vasn;
314341 enum token op;
315- mksh_uari_t res = 0;
342+ mksh_uari_t res = 0, t1, t2, t3;
316343
317344 if (prec == P_PRIMARY) {
318- op = es->tok;
319- if (op == O_BNOT || op == O_LNOT || op == O_MINUS ||
320- op == O_PLUS) {
345+ switch ((int)(op = es->tok)) {
346+ case O_BNOT:
347+ case O_LNOT:
348+ case O_MINUS:
349+ case O_PLUS:
321350 exprtoken(es);
322351 vl = intvar(es, evalexpr(es, P_PRIMARY));
323- if (op == O_BNOT)
324- vl->val.i = ~vl->val.i;
325- else if (op == O_LNOT)
326- vl->val.i = !vl->val.i;
327- else if (op == O_MINUS)
328- vl->val.i = -vl->val.i;
329- /* op == O_PLUS is a no-op */
330- } else if (op == OPEN_PAREN) {
352+ switch ((int)op) {
353+ case O_BNOT:
354+ vl->val.u = ~vl->val.u;
355+ break;
356+ case O_LNOT:
357+ vl->val.u = !vl->val.u;
358+ break;
359+ case O_MINUS:
360+ vl->val.u = -vl->val.u;
361+ break;
362+ case O_PLUS:
363+ /* nop */
364+ break;
365+ }
366+ break;
367+
368+ case OPEN_PAREN:
331369 exprtoken(es);
332370 vl = evalexpr(es, MAX_PREC);
333371 if (es->tok != CLOSE_PAREN)
334372 evalerr(es, ET_STR, "missing )");
335373 exprtoken(es);
336- } else if (op == O_PLUSPLUS || op == O_MINUSMINUS) {
374+ break;
375+
376+ case O_PLUSPLUS:
377+ case O_MINUSMINUS:
337378 exprtoken(es);
338379 vl = do_ppmm(es, op, es->val, true);
339380 exprtoken(es);
340- } else if (op == VAR || op == LIT) {
381+ break;
382+
383+ case VAR:
384+ case LIT:
341385 vl = es->val;
342386 exprtoken(es);
343- } else {
387+ break;
388+
389+ default:
344390 evalerr(es, ET_UNEXPECTED, NULL);
345391 /* NOTREACHED */
346392 }
393+
347394 if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
348395 vl = do_ppmm(es, es->tok, vl, false);
349396 exprtoken(es);
350397 }
398+
351399 return (vl);
400+ /* prec == P_PRIMARY */
352401 }
402+
353403 vl = evalexpr(es, prec - 1);
354- for (op = es->tok; IS_BINOP(op) && opinfo[(int)op].prec == prec;
355- op = es->tok) {
404+ while ((int)(op = es->tok) >= (int)O_EQ && (int)op <= (int)O_COMMA &&
405+ opinfo[(int)op].prec == prec) {
356406 exprtoken(es);
357407 vasn = vl;
358408 if (op != O_ASN)
@@ -362,152 +412,204 @@ evalexpr(Expr_state *es, int prec)
362412 if (!es->noassign)
363413 assign_check(es, op, vasn);
364414 vr = intvar(es, evalexpr(es, P_ASSIGN));
365- } else if (op != O_TERN && op != O_LAND && op != O_LOR)
415+ } else if (op == O_TERN) {
416+ bool ev = vl->val.u != 0;
417+
418+ if (!ev)
419+ es->noassign++;
420+ vl = evalexpr(es, MAX_PREC);
421+ if (!ev)
422+ es->noassign--;
423+ if (es->tok != CTERN)
424+ evalerr(es, ET_STR, "missing :");
425+ exprtoken(es);
426+ if (ev)
427+ es->noassign++;
428+ vr = evalexpr(es, P_TERN);
429+ if (ev)
430+ es->noassign--;
431+ vl = ev ? vl : vr;
432+ continue;
433+ } else if (op != O_LAND && op != O_LOR)
366434 vr = intvar(es, evalexpr(es, prec - 1));
367- if ((op == O_DIV || op == O_MOD || op == O_DIVASN ||
368- op == O_MODASN) && vr->val.i == 0) {
369- if (es->noassign)
370- vr->val.i = 1;
371- else
372- evalerr(es, ET_STR, "zero divisor");
435+
436+ /* common ops setup */
437+ switch ((int)op) {
438+ case O_DIV:
439+ case O_DIVASN:
440+ case O_MOD:
441+ case O_MODASN:
442+ if (vr->val.u == 0) {
443+ if (!es->noassign)
444+ evalerr(es, ET_STR, "zero divisor");
445+ vr->val.u = 1;
446+ }
447+ /* calculate the absolute values */
448+ t1 = vl->val.i < 0 ? -vl->val.u : vl->val.u;
449+ t2 = vr->val.i < 0 ? -vr->val.u : vr->val.u;
450+ break;
451+#ifndef MKSH_LEGACY_MODE
452+ case O_LSHIFT:
453+ case O_LSHIFTASN:
454+ case O_RSHIFT:
455+ case O_RSHIFTASN:
456+ case O_ROL:
457+ case O_ROLASN:
458+ case O_ROR:
459+ case O_RORASN:
460+ t1 = vl->val.u;
461+ t2 = vr->val.u & 31;
462+ break;
463+#endif
464+ case O_LAND:
465+ case O_LOR:
466+ t1 = vl->val.u;
467+ t2 = 0; /* gcc */
468+ break;
469+ default:
470+ t1 = vl->val.u;
471+ t2 = vr->val.u;
472+ break;
373473 }
474+
475+#define cmpop(op) (es->natural ? \
476+ (mksh_uari_t)(vl->val.u op vr->val.u) : \
477+ (mksh_uari_t)(vl->val.i op vr->val.i) \
478+)
479+
480+ /* op calculation */
374481 switch ((int)op) {
375482 case O_TIMES:
376483 case O_TIMESASN:
377- res = bivui(vl, *, vr);
484+ res = t1 * t2;
378485 break;
486+ case O_MOD:
487+ case O_MODASN:
488+ if (es->natural) {
489+ res = vl->val.u % vr->val.u;
490+ break;
491+ }
492+ goto signed_division;
379493 case O_DIV:
380494 case O_DIVASN:
381-#if !HAVE_SILENT_IDIVWRAPV
495+ if (es->natural) {
496+ res = vl->val.u / vr->val.u;
497+ break;
498+ }
499+ signed_division:
382500 /*
383- * we are doing the comparisons here for the
384- * signed arithmetics (!es->natural) case,
385- * but the exact value checks and the bypass
386- * case assignments are done unsignedly as
387- * several compilers bitch around otherwise
501+ * a / b = abs(a) / abs(b) * sgn((u)a^(u)b)
388502 */
389- if (!es->natural &&
390- vl->val.u == IDIVWRAPV_VL &&
391- vr->val.u == IDIVWRAPV_VR) {
392- /* -2147483648 / -1 = 2147483648 */
393- /* this ^ is really (1 << 31) though */
394- res = IDIVWRAPV_VL;
395- } else
396-#endif
397- res = bivui(vl, /, vr);
398- break;
399- case O_MOD:
400- case O_MODASN:
401-#if !HAVE_SILENT_IDIVWRAPV
402- /* see O_DIV / O_DIVASN for the reason behind this */
403- if (!es->natural &&
404- vl->val.u == IDIVWRAPV_VL &&
405- vr->val.u == IDIVWRAPV_VR) {
406- /* -2147483648 % -1 = 0 */
407- res = 0;
408- } else
503+ t3 = t1 / t2;
504+#ifndef MKSH_LEGACY_MODE
505+ res = ((vl->val.u ^ vr->val.u) & 0x80000000) ? -t3 : t3;
506+#else
507+ res = ((t1 == vl->val.u ? 0 : 1) ^
508+ (t2 == vr->val.u ? 0 : 1)) ? -t3 : t3;
409509 #endif
410- res = bivui(vl, %, vr);
510+ if (op == O_MOD || op == O_MODASN) {
511+ /*
512+ * primitive modulo, to get the sign of
513+ * the result correct:
514+ * (a % b) = a - ((a / b) * b)
515+ * the subtraction and multiplication
516+ * are, amazingly enough, sign ignorant
517+ */
518+ res = vl->val.u - (res * vr->val.u);
519+ }
411520 break;
412521 case O_PLUS:
413522 case O_PLUSASN:
414- res = bivui(vl, +, vr);
523+ res = t1 + t2;
415524 break;
416525 case O_MINUS:
417526 case O_MINUSASN:
418- res = bivui(vl, -, vr);
527+ res = t1 - t2;
528+ break;
529+#ifndef MKSH_LEGACY_MODE
530+ case O_ROL:
531+ case O_ROLASN:
532+ res = (t1 << t2) | (t1 >> (32 - t2));
419533 break;
534+ case O_ROR:
535+ case O_RORASN:
536+ res = (t1 >> t2) | (t1 << (32 - t2));
537+ break;
538+#endif
420539 case O_LSHIFT:
421540 case O_LSHIFTASN:
422- res = bivui(vl, <<, vr);
541+ res = t1 << t2;
423542 break;
424543 case O_RSHIFT:
425544 case O_RSHIFTASN:
426- res = bivui(vl, >>, vr);
545+ res = es->natural || vl->val.i >= 0 ?
546+ t1 >> t2 :
547+ ~(~t1 >> t2);
427548 break;
428549 case O_LT:
429- res = bivui(vl, <, vr);
550+ res = cmpop(<);
430551 break;
431552 case O_LE:
432- res = bivui(vl, <=, vr);
553+ res = cmpop(<=);
433554 break;
434555 case O_GT:
435- res = bivui(vl, >, vr);
556+ res = cmpop(>);
436557 break;
437558 case O_GE:
438- res = bivui(vl, >=, vr);
559+ res = cmpop(>=);
439560 break;
440561 case O_EQ:
441- res = bivui(vl, ==, vr);
562+ res = t1 == t2;
442563 break;
443564 case O_NE:
444- res = bivui(vl, !=, vr);
565+ res = t1 != t2;
445566 break;
446567 case O_BAND:
447568 case O_BANDASN:
448- res = bivui(vl, &, vr);
569+ res = t1 & t2;
449570 break;
450571 case O_BXOR:
451572 case O_BXORASN:
452- res = bivui(vl, ^, vr);
573+ res = t1 ^ t2;
453574 break;
454575 case O_BOR:
455576 case O_BORASN:
456- res = bivui(vl, |, vr);
577+ res = t1 | t2;
457578 break;
458579 case O_LAND:
459- if (!vl->val.i)
580+ if (!t1)
460581 es->noassign++;
461582 vr = intvar(es, evalexpr(es, prec - 1));
462- res = bivui(vl, &&, vr);
463- if (!vl->val.i)
583+ res = t1 && vr->val.u;
584+ if (!t1)
464585 es->noassign--;
465586 break;
466587 case O_LOR:
467- if (vl->val.i)
588+ if (t1)
468589 es->noassign++;
469590 vr = intvar(es, evalexpr(es, prec - 1));
470- res = bivui(vl, ||, vr);
471- if (vl->val.i)
591+ res = t1 || vr->val.u;
592+ if (t1)
472593 es->noassign--;
473594 break;
474- case O_TERN:
475- {
476- bool ev = vl->val.i != 0;
477-
478- if (!ev)
479- es->noassign++;
480- vl = evalexpr(es, MAX_PREC);
481- if (!ev)
482- es->noassign--;
483- if (es->tok != CTERN)
484- evalerr(es, ET_STR, "missing :");
485- exprtoken(es);
486- if (ev)
487- es->noassign++;
488- vr = evalexpr(es, P_TERN);
489- if (ev)
490- es->noassign--;
491- vl = ev ? vl : vr;
492- }
493- break;
494595 case O_ASN:
495- res = vr->val.u;
496- break;
497596 case O_COMMA:
498- res = vr->val.u;
597+ res = t2;
499598 break;
500599 }
600+
601+#undef cmpop
602+
501603 if (IS_ASSIGNOP(op)) {
502604 vr->val.u = res;
503605 if (!es->noassign) {
504606 if (vasn->flag & INTEGER)
505607 setint_v(vasn, vr, es->arith);
506608 else
507- setint(vasn, (mksh_ari_t)res);
609+ setint(vasn, vr->val.i);
508610 }
509611 vl = vr;
510- } else if (op != O_TERN)
612+ } else
511613 vl->val.u = res;
512614 }
513615 return (vl);
@@ -520,13 +622,14 @@ exprtoken(Expr_state *es)
520622 int c;
521623 char *tvar;
522624
523- /* skip white space */
625+ /* skip whitespace */
524626 skip_spaces:
525627 while ((c = *cp), ksh_isspace(c))
526628 ++cp;
527629 if (es->tokp == es->expression && c == '#') {
528630 /* expression begins with # */
529- es->natural = true; /* switch to unsigned */
631+ /* switch to unsigned */
632+ es->natural = true;
530633 ++cp;
531634 goto skip_spaces;
532635 }
@@ -544,12 +647,6 @@ exprtoken(Expr_state *es)
544647 if (len == 0)
545648 evalerr(es, ET_STR, "missing ]");
546649 cp += len;
547- } else if (c == '(' /*)*/ ) {
548- /* todo: add math functions (all take single argument):
549- * abs acos asin atan cos cosh exp int log sin sinh sqrt
550- * tan tanh
551- */
552- ;
553650 }
554651 if (es->noassign) {
555652 es->val = tempvar();
@@ -610,39 +707,6 @@ exprtoken(Expr_state *es)
610707 es->tokp = cp;
611708 }
612709
613-/* Do a ++ or -- operation */
614-static struct tbl *
615-do_ppmm(Expr_state *es, enum token op, struct tbl *vasn, bool is_prefix)
616-{
617- struct tbl *vl;
618- mksh_ari_t oval;
619-
620- assign_check(es, op, vasn);
621-
622- vl = intvar(es, vasn);
623- oval = vl->val.i;
624- if (op == O_PLUSPLUS) {
625- if (es->natural)
626- ++vl->val.u;
627- else
628- ++vl->val.i;
629- } else {
630- if (es->natural)
631- --vl->val.u;
632- else
633- --vl->val.i;
634- }
635- if (vasn->flag & INTEGER)
636- setint_v(vasn, vl, es->arith);
637- else
638- setint(vasn, vl->val.i);
639- if (!is_prefix)
640- /* undo the increment/decrement */
641- vl->val.i = oval;
642-
643- return (vl);
644-}
645-
646710 static void
647711 assign_check(Expr_state *es, enum token op, struct tbl *vasn)
648712 {
@@ -833,129 +897,6 @@ utf_wctomb(char *dst, unsigned int wc)
833897 return ((char *)d - dst);
834898 }
835899
836-
837-#ifndef MKSH_mirbsd_wcwidth
838-/* --- begin of wcwidth.c excerpt --- */
839-/*-
840- * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
841- *
842- * Permission to use, copy, modify, and distribute this software
843- * for any purpose and without fee is hereby granted. The author
844- * disclaims all warranties with regard to this software.
845- */
846-
847-__RCSID("$miros: src/lib/libc/i18n/wcwidth.c,v 1.11 2012/09/01 23:46:43 tg Exp $");
848-
849-int
850-utf_wcwidth(unsigned int c)
851-{
852- static const struct cbset {
853- unsigned short first;
854- unsigned short last;
855- } comb[] = {
856- /* Unicode 6.1.0 BMP */
857- { 0x0300, 0x036F }, { 0x0483, 0x0489 }, { 0x0591, 0x05BD },
858- { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 },
859- { 0x05C7, 0x05C7 }, { 0x0600, 0x0604 }, { 0x0610, 0x061A },
860- { 0x064B, 0x065F }, { 0x0670, 0x0670 }, { 0x06D6, 0x06DD },
861- { 0x06DF, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
862- { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
863- { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0816, 0x0819 },
864- { 0x081B, 0x0823 }, { 0x0825, 0x0827 }, { 0x0829, 0x082D },
865- { 0x0859, 0x085B }, { 0x08E4, 0x08FE }, { 0x0900, 0x0902 },
866- { 0x093A, 0x093A }, { 0x093C, 0x093C }, { 0x0941, 0x0948 },
867- { 0x094D, 0x094D }, { 0x0951, 0x0957 }, { 0x0962, 0x0963 },
868- { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 },
869- { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 },
870- { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 },
871- { 0x0A4B, 0x0A4D }, { 0x0A51, 0x0A51 }, { 0x0A70, 0x0A71 },
872- { 0x0A75, 0x0A75 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
873- { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
874- { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
875- { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B44 }, { 0x0B4D, 0x0B4D },
876- { 0x0B56, 0x0B56 }, { 0x0B62, 0x0B63 }, { 0x0B82, 0x0B82 },
877- { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 },
878- { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 },
879- { 0x0C62, 0x0C63 }, { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF },
880- { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, { 0x0CE2, 0x0CE3 },
881- { 0x0D41, 0x0D44 }, { 0x0D4D, 0x0D4D }, { 0x0D62, 0x0D63 },
882- { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
883- { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
884- { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
885- { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
886- { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
887- { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F8D, 0x0F97 },
888- { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
889- { 0x1032, 0x1037 }, { 0x1039, 0x103A }, { 0x103D, 0x103E },
890- { 0x1058, 0x1059 }, { 0x105E, 0x1060 }, { 0x1071, 0x1074 },
891- { 0x1082, 0x1082 }, { 0x1085, 0x1086 }, { 0x108D, 0x108D },
892- { 0x109D, 0x109D }, { 0x1160, 0x11FF }, { 0x135D, 0x135F },
893- { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
894- { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
895- { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
896- { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
897- { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
898- { 0x1A17, 0x1A18 }, { 0x1A56, 0x1A56 }, { 0x1A58, 0x1A5E },
899- { 0x1A60, 0x1A60 }, { 0x1A62, 0x1A62 }, { 0x1A65, 0x1A6C },
900- { 0x1A73, 0x1A7C }, { 0x1A7F, 0x1A7F }, { 0x1B00, 0x1B03 },
901- { 0x1B34, 0x1B34 }, { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C },
902- { 0x1B42, 0x1B42 }, { 0x1B6B, 0x1B73 }, { 0x1B80, 0x1B81 },
903- { 0x1BA2, 0x1BA5 }, { 0x1BA8, 0x1BA9 }, { 0x1BAB, 0x1BAB },
904- { 0x1BE6, 0x1BE6 }, { 0x1BE8, 0x1BE9 }, { 0x1BED, 0x1BED },
905- { 0x1BEF, 0x1BF1 }, { 0x1C2C, 0x1C33 }, { 0x1C36, 0x1C37 },
906- { 0x1CD0, 0x1CD2 }, { 0x1CD4, 0x1CE0 }, { 0x1CE2, 0x1CE8 },
907- { 0x1CED, 0x1CED }, { 0x1CF4, 0x1CF4 }, { 0x1DC0, 0x1DE6 },
908- { 0x1DFC, 0x1DFF }, { 0x200B, 0x200F }, { 0x202A, 0x202E },
909- { 0x2060, 0x2064 }, { 0x206A, 0x206F }, { 0x20D0, 0x20F0 },
910- { 0x2CEF, 0x2CF1 }, { 0x2D7F, 0x2D7F }, { 0x2DE0, 0x2DFF },
911- { 0x302A, 0x302D }, { 0x3099, 0x309A }, { 0xA66F, 0xA672 },
912- { 0xA674, 0xA67D }, { 0xA69F, 0xA69F }, { 0xA6F0, 0xA6F1 },
913- { 0xA802, 0xA802 }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
914- { 0xA825, 0xA826 }, { 0xA8C4, 0xA8C4 }, { 0xA8E0, 0xA8F1 },
915- { 0xA926, 0xA92D }, { 0xA947, 0xA951 }, { 0xA980, 0xA982 },
916- { 0xA9B3, 0xA9B3 }, { 0xA9B6, 0xA9B9 }, { 0xA9BC, 0xA9BC },
917- { 0xAA29, 0xAA2E }, { 0xAA31, 0xAA32 }, { 0xAA35, 0xAA36 },
918- { 0xAA43, 0xAA43 }, { 0xAA4C, 0xAA4C }, { 0xAAB0, 0xAAB0 },
919- { 0xAAB2, 0xAAB4 }, { 0xAAB7, 0xAAB8 }, { 0xAABE, 0xAABF },
920- { 0xAAC1, 0xAAC1 }, { 0xAAEC, 0xAAED }, { 0xAAF6, 0xAAF6 },
921- { 0xABE5, 0xABE5 }, { 0xABE8, 0xABE8 }, { 0xABED, 0xABED },
922- { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE26 },
923- { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }
924- };
925- size_t min = 0, mid, max = NELEM(comb) - 1;
926-
927- /* test for 8-bit control characters */
928- if (c < 32 || (c >= 0x7F && c < 0xA0))
929- return (c ? -1 : 0);
930-
931- /* binary search in table of non-spacing characters */
932- if (c >= comb[0].first && c <= comb[max].last)
933- while (max >= min) {
934- mid = (min + max) / 2;
935- if (c > comb[mid].last)
936- min = mid + 1;
937- else if (c < comb[mid].first)
938- max = mid - 1;
939- else
940- return (0);
941- }
942-
943- /* if we arrive here, c is not a combining or C0/C1 control char */
944-
945- return ((c >= 0x1100 && (
946- c <= 0x115F || /* Hangul Jamo init. consonants */
947- c == 0x2329 || c == 0x232A ||
948- (c >= 0x2E80 && c <= 0xA4CF && c != 0x303F) || /* CJK ... Yi */
949- (c >= 0xAC00 && c <= 0xD7A3) || /* Hangul Syllables */
950- (c >= 0xF900 && c <= 0xFAFF) || /* CJK Compatibility Ideographs */
951- (c >= 0xFE10 && c <= 0xFE19) || /* Vertical forms */
952- (c >= 0xFE30 && c <= 0xFE6F) || /* CJK Compatibility Forms */
953- (c >= 0xFF00 && c <= 0xFF60) || /* Fullwidth Forms */
954- (c >= 0xFFE0 && c <= 0xFFE6))) ? 2 : 1);
955-}
956-/* --- end of wcwidth.c excerpt --- */
957-#endif
958-
959900 /*
960901 * Wrapper around access(2) because it says root can execute everything
961902 * on some operating systems. Does not set errno, no user needs it. Use
@@ -974,3 +915,277 @@ ksh_access(const char *fn, int mode)
974915
975916 return (rv);
976917 }
918+
919+#ifndef MKSH_mirbsd_wcwidth
920+/* From: X11/xc/programs/xterm/wcwidth.c,v 1.6 2013/05/31 23:27:09 tg Exp $ */
921+
922+struct mb_ucsrange {
923+ unsigned short beg;
924+ unsigned short end;
925+};
926+
927+static int mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems,
928+ unsigned int val);
929+
930+/*
931+ * Generated by MirOS: contrib/code/Snippets/eawparse,v 1.1 2013/05/31 23:27:16 tg Exp $
932+ * from Unicode 6.2.0
933+ */
934+
935+static const struct mb_ucsrange mb_ucs_combining[] = {
936+ { 0x0300, 0x036F },
937+ { 0x0483, 0x0489 },
938+ { 0x0591, 0x05BD },
939+ { 0x05BF, 0x05BF },
940+ { 0x05C1, 0x05C2 },
941+ { 0x05C4, 0x05C5 },
942+ { 0x05C7, 0x05C7 },
943+ { 0x0600, 0x0604 },
944+ { 0x0610, 0x061A },
945+ { 0x064B, 0x065F },
946+ { 0x0670, 0x0670 },
947+ { 0x06D6, 0x06DD },
948+ { 0x06DF, 0x06E4 },
949+ { 0x06E7, 0x06E8 },
950+ { 0x06EA, 0x06ED },
951+ { 0x070F, 0x070F },
952+ { 0x0711, 0x0711 },
953+ { 0x0730, 0x074A },
954+ { 0x07A6, 0x07B0 },
955+ { 0x07EB, 0x07F3 },
956+ { 0x0816, 0x0819 },
957+ { 0x081B, 0x0823 },
958+ { 0x0825, 0x0827 },
959+ { 0x0829, 0x082D },
960+ { 0x0859, 0x085B },
961+ { 0x08E4, 0x08FE },
962+ { 0x0900, 0x0902 },
963+ { 0x093A, 0x093A },
964+ { 0x093C, 0x093C },
965+ { 0x0941, 0x0948 },
966+ { 0x094D, 0x094D },
967+ { 0x0951, 0x0957 },
968+ { 0x0962, 0x0963 },
969+ { 0x0981, 0x0981 },
970+ { 0x09BC, 0x09BC },
971+ { 0x09C1, 0x09C4 },
972+ { 0x09CD, 0x09CD },
973+ { 0x09E2, 0x09E3 },
974+ { 0x0A01, 0x0A02 },
975+ { 0x0A3C, 0x0A3C },
976+ { 0x0A41, 0x0A42 },
977+ { 0x0A47, 0x0A48 },
978+ { 0x0A4B, 0x0A4D },
979+ { 0x0A51, 0x0A51 },
980+ { 0x0A70, 0x0A71 },
981+ { 0x0A75, 0x0A75 },
982+ { 0x0A81, 0x0A82 },
983+ { 0x0ABC, 0x0ABC },
984+ { 0x0AC1, 0x0AC5 },
985+ { 0x0AC7, 0x0AC8 },
986+ { 0x0ACD, 0x0ACD },
987+ { 0x0AE2, 0x0AE3 },
988+ { 0x0B01, 0x0B01 },
989+ { 0x0B3C, 0x0B3C },
990+ { 0x0B3F, 0x0B3F },
991+ { 0x0B41, 0x0B44 },
992+ { 0x0B4D, 0x0B4D },
993+ { 0x0B56, 0x0B56 },
994+ { 0x0B62, 0x0B63 },
995+ { 0x0B82, 0x0B82 },
996+ { 0x0BC0, 0x0BC0 },
997+ { 0x0BCD, 0x0BCD },
998+ { 0x0C3E, 0x0C40 },
999+ { 0x0C46, 0x0C48 },
1000+ { 0x0C4A, 0x0C4D },
1001+ { 0x0C55, 0x0C56 },
1002+ { 0x0C62, 0x0C63 },
1003+ { 0x0CBC, 0x0CBC },
1004+ { 0x0CBF, 0x0CBF },
1005+ { 0x0CC6, 0x0CC6 },
1006+ { 0x0CCC, 0x0CCD },
1007+ { 0x0CE2, 0x0CE3 },
1008+ { 0x0D41, 0x0D44 },
1009+ { 0x0D4D, 0x0D4D },
1010+ { 0x0D62, 0x0D63 },
1011+ { 0x0DCA, 0x0DCA },
1012+ { 0x0DD2, 0x0DD4 },
1013+ { 0x0DD6, 0x0DD6 },
1014+ { 0x0E31, 0x0E31 },
1015+ { 0x0E34, 0x0E3A },
1016+ { 0x0E47, 0x0E4E },
1017+ { 0x0EB1, 0x0EB1 },
1018+ { 0x0EB4, 0x0EB9 },
1019+ { 0x0EBB, 0x0EBC },
1020+ { 0x0EC8, 0x0ECD },
1021+ { 0x0F18, 0x0F19 },
1022+ { 0x0F35, 0x0F35 },
1023+ { 0x0F37, 0x0F37 },
1024+ { 0x0F39, 0x0F39 },
1025+ { 0x0F71, 0x0F7E },
1026+ { 0x0F80, 0x0F84 },
1027+ { 0x0F86, 0x0F87 },
1028+ { 0x0F8D, 0x0F97 },
1029+ { 0x0F99, 0x0FBC },
1030+ { 0x0FC6, 0x0FC6 },
1031+ { 0x102D, 0x1030 },
1032+ { 0x1032, 0x1037 },
1033+ { 0x1039, 0x103A },
1034+ { 0x103D, 0x103E },
1035+ { 0x1058, 0x1059 },
1036+ { 0x105E, 0x1060 },
1037+ { 0x1071, 0x1074 },
1038+ { 0x1082, 0x1082 },
1039+ { 0x1085, 0x1086 },
1040+ { 0x108D, 0x108D },
1041+ { 0x109D, 0x109D },
1042+ { 0x1160, 0x11FF },
1043+ { 0x135D, 0x135F },
1044+ { 0x1712, 0x1714 },
1045+ { 0x1732, 0x1734 },
1046+ { 0x1752, 0x1753 },
1047+ { 0x1772, 0x1773 },
1048+ { 0x17B4, 0x17B5 },
1049+ { 0x17B7, 0x17BD },
1050+ { 0x17C6, 0x17C6 },
1051+ { 0x17C9, 0x17D3 },
1052+ { 0x17DD, 0x17DD },
1053+ { 0x180B, 0x180D },
1054+ { 0x18A9, 0x18A9 },
1055+ { 0x1920, 0x1922 },
1056+ { 0x1927, 0x1928 },
1057+ { 0x1932, 0x1932 },
1058+ { 0x1939, 0x193B },
1059+ { 0x1A17, 0x1A18 },
1060+ { 0x1A56, 0x1A56 },
1061+ { 0x1A58, 0x1A5E },
1062+ { 0x1A60, 0x1A60 },
1063+ { 0x1A62, 0x1A62 },
1064+ { 0x1A65, 0x1A6C },
1065+ { 0x1A73, 0x1A7C },
1066+ { 0x1A7F, 0x1A7F },
1067+ { 0x1B00, 0x1B03 },
1068+ { 0x1B34, 0x1B34 },
1069+ { 0x1B36, 0x1B3A },
1070+ { 0x1B3C, 0x1B3C },
1071+ { 0x1B42, 0x1B42 },
1072+ { 0x1B6B, 0x1B73 },
1073+ { 0x1B80, 0x1B81 },
1074+ { 0x1BA2, 0x1BA5 },
1075+ { 0x1BA8, 0x1BA9 },
1076+ { 0x1BAB, 0x1BAB },
1077+ { 0x1BE6, 0x1BE6 },
1078+ { 0x1BE8, 0x1BE9 },
1079+ { 0x1BED, 0x1BED },
1080+ { 0x1BEF, 0x1BF1 },
1081+ { 0x1C2C, 0x1C33 },
1082+ { 0x1C36, 0x1C37 },
1083+ { 0x1CD0, 0x1CD2 },
1084+ { 0x1CD4, 0x1CE0 },
1085+ { 0x1CE2, 0x1CE8 },
1086+ { 0x1CED, 0x1CED },
1087+ { 0x1CF4, 0x1CF4 },
1088+ { 0x1DC0, 0x1DE6 },
1089+ { 0x1DFC, 0x1DFF },
1090+ { 0x200B, 0x200F },
1091+ { 0x202A, 0x202E },
1092+ { 0x2060, 0x2064 },
1093+ { 0x206A, 0x206F },
1094+ { 0x20D0, 0x20F0 },
1095+ { 0x2CEF, 0x2CF1 },
1096+ { 0x2D7F, 0x2D7F },
1097+ { 0x2DE0, 0x2DFF },
1098+ { 0x302A, 0x302D },
1099+ { 0x3099, 0x309A },
1100+ { 0xA66F, 0xA672 },
1101+ { 0xA674, 0xA67D },
1102+ { 0xA69F, 0xA69F },
1103+ { 0xA6F0, 0xA6F1 },
1104+ { 0xA802, 0xA802 },
1105+ { 0xA806, 0xA806 },
1106+ { 0xA80B, 0xA80B },
1107+ { 0xA825, 0xA826 },
1108+ { 0xA8C4, 0xA8C4 },
1109+ { 0xA8E0, 0xA8F1 },
1110+ { 0xA926, 0xA92D },
1111+ { 0xA947, 0xA951 },
1112+ { 0xA980, 0xA982 },
1113+ { 0xA9B3, 0xA9B3 },
1114+ { 0xA9B6, 0xA9B9 },
1115+ { 0xA9BC, 0xA9BC },
1116+ { 0xAA29, 0xAA2E },
1117+ { 0xAA31, 0xAA32 },
1118+ { 0xAA35, 0xAA36 },
1119+ { 0xAA43, 0xAA43 },
1120+ { 0xAA4C, 0xAA4C },
1121+ { 0xAAB0, 0xAAB0 },
1122+ { 0xAAB2, 0xAAB4 },
1123+ { 0xAAB7, 0xAAB8 },
1124+ { 0xAABE, 0xAABF },
1125+ { 0xAAC1, 0xAAC1 },
1126+ { 0xAAEC, 0xAAED },
1127+ { 0xAAF6, 0xAAF6 },
1128+ { 0xABE5, 0xABE5 },
1129+ { 0xABE8, 0xABE8 },
1130+ { 0xABED, 0xABED },
1131+ { 0xFB1E, 0xFB1E },
1132+ { 0xFE00, 0xFE0F },
1133+ { 0xFE20, 0xFE26 },
1134+ { 0xFEFF, 0xFEFF },
1135+ { 0xFFF9, 0xFFFB }
1136+};
1137+
1138+static const struct mb_ucsrange mb_ucs_fullwidth[] = {
1139+ { 0x1100, 0x115F },
1140+ { 0x2329, 0x232A },
1141+ { 0x2E80, 0x303E },
1142+ { 0x3040, 0xA4CF },
1143+ { 0xA960, 0xA97F },
1144+ { 0xAC00, 0xD7A3 },
1145+ { 0xF900, 0xFAFF },
1146+ { 0xFE10, 0xFE19 },
1147+ { 0xFE30, 0xFE6F },
1148+ { 0xFF00, 0xFF60 },
1149+ { 0xFFE0, 0xFFE6 }
1150+};
1151+
1152+/* simple binary search in ranges, with bounds optimisation */
1153+static int
1154+mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems, unsigned int val)
1155+{
1156+ size_t min = 0, mid, max = elems;
1157+
1158+ if (val < arr[min].beg || val > arr[max - 1].end)
1159+ return (0);
1160+
1161+ while (min < max) {
1162+ mid = (min + max) / 2;
1163+
1164+ if (val < arr[mid].beg)
1165+ max = mid;
1166+ else if (val > arr[mid].end)
1167+ min = mid + 1;
1168+ else
1169+ return (1);
1170+ }
1171+ return (0);
1172+}
1173+
1174+/* Unix column width of a wide character (Unicode code point, really) */
1175+int
1176+utf_wcwidth(unsigned int wc)
1177+{
1178+ /* except NUL, C0/C1 control characters and DEL yield -1 */
1179+ if (wc < 0x20 || (wc >= 0x7F && wc < 0xA0))
1180+ return (wc ? -1 : 0);
1181+
1182+ /* combining characters use 0 screen columns */
1183+ if (mb_ucsbsearch(mb_ucs_combining, NELEM(mb_ucs_combining), wc))
1184+ return (0);
1185+
1186+ /* all others use 1 or 2 screen columns */
1187+ if (mb_ucsbsearch(mb_ucs_fullwidth, NELEM(mb_ucs_fullwidth), wc))
1188+ return (2);
1189+ return (1);
1190+}
1191+#endif
--- a/src/funcs.c
+++ b/src/funcs.c
@@ -1,5 +1,5 @@
11 /* $OpenBSD: c_ksh.c,v 1.33 2009/02/07 14:03:24 kili Exp $ */
2-/* $OpenBSD: c_sh.c,v 1.41 2010/03/27 09:10:01 jmc Exp $ */
2+/* $OpenBSD: c_sh.c,v 1.43 2013/04/19 17:39:45 deraadt Exp $ */
33 /* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */
44 /* $OpenBSD: c_ulimit.c,v 1.17 2008/03/21 12:51:19 millert Exp $ */
55
@@ -38,7 +38,7 @@
3838 #endif
3939 #endif
4040
41-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.238 2013/02/18 22:47:32 tg Exp $");
41+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.244 2013/06/03 22:28:32 tg Exp $");
4242
4343 #if HAVE_KILLPG
4444 /*
@@ -84,70 +84,69 @@ c_false(const char **wp MKSH_A_UNUSED)
8484 }
8585
8686 /*
87- * A leading = means assignments before command are kept;
88- * a leading * means a POSIX special builtin;
89- * a leading + means a POSIX regular builtin
90- * (* and + should not be combined).
87+ * A leading = means assignments before command are kept.
88+ * A leading * means a POSIX special builtin.
9189 */
9290 const struct builtin mkshbuiltins[] = {
9391 {"*=.", c_dot},
9492 {"*=:", c_true},
9593 {"[", c_test},
94+ /* no =: AT&T manual wrong */
95+ {Talias, c_alias},
9696 {"*=break", c_brkcont},
9797 {Tgbuiltin, c_builtin},
98+ {"cat", c_cat},
99+ {"cd", c_cd},
100+ /* dash compatibility hack */
101+ {"chdir", c_cd},
102+ {"command", c_command},
98103 {"*=continue", c_brkcont},
104+ {"echo", c_print},
99105 {"*=eval", c_eval},
100106 {"*=exec", c_exec},
101107 {"*=exit", c_exitreturn},
102- {"+false", c_false},
103- {"*=return", c_exitreturn},
104- {Tsgset, c_set},
105- {"*=shift", c_shift},
106- {"=times", c_times},
107- {"*=trap", c_trap},
108- {"+=wait", c_wait},
109- {"+read", c_read},
110- {"test", c_test},
111- {"+true", c_true},
112- {"ulimit", c_ulimit},
113- {"+umask", c_umask},
114- {Tsgunset, c_unset},
115- /* no =: AT&T manual wrong */
116- {Tpalias, c_alias},
117- {"+cd", c_cd},
118- /* dash compatibility hack */
119- {"chdir", c_cd},
120- {"+command", c_command},
121- {"echo", c_print},
122108 {Tsgexport, c_typeset},
123- {"+fc", c_fc},
124- {"+getopts", c_getopts},
109+ {"false", c_false},
110+ {"fc", c_fc},
111+ {"getopts", c_getopts},
125112 {"=global", c_typeset},
126- {"+jobs", c_jobs},
127- {"+kill", c_kill},
113+ {"jobs", c_jobs},
114+ {"kill", c_kill},
128115 {"let", c_let},
116+ {"let]", c_let},
129117 {"print", c_print},
130-#ifdef MKSH_PRINTF_BUILTIN
131- {"printf", c_printf},
132-#endif
133118 {"pwd", c_pwd},
119+ {"read", c_read},
134120 {Tsgreadonly, c_typeset},
121+ {"realpath", c_realpath},
122+ {"rename", c_rename},
123+ {"*=return", c_exitreturn},
124+ {Tsgset, c_set},
125+ {"*=shift", c_shift},
126+ {"test", c_test},
127+ {"*=times", c_times},
128+ {"*=trap", c_trap},
129+ {"true", c_true},
135130 {T_typeset, c_typeset},
136- {Tpunalias, c_unalias},
131+ {"ulimit", c_ulimit},
132+ {"umask", c_umask},
133+ {Tunalias, c_unalias},
134+ {Tsgunset, c_unset},
135+ {"=wait", c_wait},
137136 {"whence", c_whence},
138137 #ifndef MKSH_UNEMPLOYED
139- {"+bg", c_fgbg},
140- {"+fg", c_fgbg},
138+ {"bg", c_fgbg},
139+ {"fg", c_fgbg},
141140 #endif
142141 #ifndef MKSH_NO_CMDLINE_EDITING
143142 {"bind", c_bind},
144143 #endif
145- {"cat", c_cat},
146144 #if HAVE_MKNOD
147145 {"mknod", c_mknod},
148146 #endif
149- {"realpath", c_realpath},
150- {"rename", c_rename},
147+#ifdef MKSH_PRINTF_BUILTIN
148+ {"printf", c_printf},
149+#endif
151150 #if HAVE_SELECT
152151 {"sleep", c_sleep},
153152 #endif
@@ -836,7 +835,7 @@ c_typeset(const char **wp)
836835 shf_putc('\n', shl_stdout);
837836 }
838837 } else if (!typeset(wp[i], fset, fclr, field, base)) {
839- bi_errorf("%s: %s", wp[i], "not identifier");
838+ bi_errorf("%s: %s", wp[i], "is not an identifier");
840839 goto errout;
841840 }
842841 }
@@ -2253,7 +2252,7 @@ c_trap(const char **wp)
22532252 wp += builtin_opt.optind;
22542253
22552254 if (*wp == NULL) {
2256- for (p = sigtraps, i = NSIG+1; --i >= 0; p++)
2255+ for (p = sigtraps, i = NSIG + 1; --i >= 0; p++)
22572256 if (p->trap != NULL) {
22582257 shf_puts("trap -- ", shl_stdout);
22592258 print_value_quoted(shl_stdout, p->trap);
@@ -2427,12 +2426,13 @@ c_set(const char **wp)
24272426 * which assumes the exit value set will be that of the $()
24282427 * (subst_exstat is cleared in execute() so that it will be 0
24292428 * if there are no command substitutions).
2430- * Switched ksh (!posix !sh) to POSIX in mksh R39b.
24312429 */
24322430 #ifdef MKSH_LEGACY_MODE
2433- return (subst_exstat);
2431+ /* traditional behaviour, unless set -o posix */
2432+ return (Flag(FPOSIX) ? 0 : subst_exstat);
24342433 #else
2435- return (Flag(FSH) ? subst_exstat : 0);
2434+ /* conformant behaviour, unless set -o sh +o posix */
2435+ return (Flag(FSH) && !Flag(FPOSIX) ? subst_exstat : 0);
24362436 #endif
24372437 }
24382438
@@ -3726,7 +3726,7 @@ c_cat(const char **wp)
37263726 rv = 0;
37273727
37283728 if ((buf = malloc_osfunc(MKSH_CAT_BUFSIZ)) == NULL) {
3729- bi_errorf(Toomem, (unsigned long)MKSH_CAT_BUFSIZ);
3729+ bi_errorf(Toomem, (size_t)MKSH_CAT_BUFSIZ);
37303730 return (1);
37313731 }
37323732
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -1,7 +1,8 @@
1-/* $OpenBSD: jobs.c,v 1.38 2009/12/12 04:28:44 deraadt Exp $ */
1+/* $OpenBSD: jobs.c,v 1.39 2009/12/13 04:36:48 deraadt Exp $ */
22
33 /*-
4- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012
4+ * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
5+ * 2012, 2013
56 * Thorsten Glaser <tg@mirbsd.org>
67 *
78 * Provided that these terms and disclaimer and all copyright notices
@@ -22,7 +23,7 @@
2223
2324 #include "sh.h"
2425
25-__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.94 2012/12/28 02:28:36 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.100 2013/07/26 20:33:23 tg Exp $");
2627
2728 #if HAVE_KILLPG
2829 #define mksh_killpg killpg
@@ -44,12 +45,11 @@ struct proc {
4445 int state;
4546 int status; /* wait status */
4647 /* process command string from vistree */
47- char command[64 - (ALLOC_SIZE + sizeof(Proc *) + sizeof(pid_t) +
48+ char command[256 - (ALLOC_SIZE + sizeof(Proc *) + sizeof(pid_t) +
4849 2 * sizeof(int))];
4950 };
5051
5152 /* Notify/print flag - j_print() argument */
52-#define JP_NONE 0 /* don't print anything */
5353 #define JP_SHORT 1 /* print signals processes were killed by */
5454 #define JP_MEDIUM 2 /* print [job-num] -/+ command */
5555 #define JP_LONG 3 /* print [job-num] -/+ pid command */
@@ -102,17 +102,14 @@ struct job {
102102 #define JW_PIPEST 0x08 /* want PIPESTATUS */
103103
104104 /* Error codes for j_lookup() */
105-#define JL_OK 0
106-#define JL_NOSUCH 1 /* no such job */
107-#define JL_AMBIG 2 /* %foo or %?foo is ambiguous */
108-#define JL_INVALID 3 /* non-pid, non-% job id */
105+#define JL_NOSUCH 0 /* no such job */
106+#define JL_AMBIG 1 /* %foo or %?foo is ambiguous */
107+#define JL_INVALID 2 /* non-pid, non-% job id */
109108
110109 static const char * const lookup_msgs[] = {
111- null,
112110 "no such job",
113111 "ambiguous",
114- "argument must be %job or process id",
115- NULL
112+ "argument must be %job or process id"
116113 };
117114
118115 static Job *job_list; /* job list */
@@ -463,7 +460,7 @@ exchild(struct op *t, int flags,
463460 forksleep <<= 1;
464461 }
465462 /* ensure $RANDOM changes between parent and child */
466- rndset((long)cldpid);
463+ rndset((unsigned long)cldpid);
467464 /* fork failed? */
468465 if (cldpid < 0) {
469466 kill_job(j, SIGKILL);
@@ -506,9 +503,6 @@ exchild(struct op *t, int flags,
506503 /* Do this before restoring signal */
507504 if (flags & XCOPROC)
508505 coproc_cleanup(false);
509-#ifndef MKSH_NOPROSPECTOFWORK
510- sigprocmask(SIG_SETMASK, &omask, NULL);
511-#endif
512506 cleanup_parents_env();
513507 #ifndef MKSH_UNEMPLOYED
514508 /*
@@ -543,6 +537,10 @@ exchild(struct op *t, int flags,
543537 }
544538 /* in case of $(jobs) command */
545539 remove_job(j, "child");
540+#ifndef MKSH_NOPROSPECTOFWORK
541+ /* remove_job needs SIGCHLD blocked still */
542+ sigprocmask(SIG_SETMASK, &omask, NULL);
543+#endif
546544 nzombie = 0;
547545 #ifndef MKSH_UNEMPLOYED
548546 ttypgrp_ok = false;
@@ -906,7 +904,7 @@ j_jobs(const char *cp, int slp,
906904 zflag = 1;
907905 }
908906 if (cp) {
909- int ecode;
907+ int ecode;
910908
911909 if ((j = j_lookup(cp, &ecode)) == NULL) {
912910 #ifndef MKSH_NOPROSPECTOFWORK
@@ -1220,6 +1218,8 @@ j_waitj(Job *j,
12201218 ARRAY | INT_U | AINDEX;
12211219 got_array:
12221220 vp->val.i = proc_errorlevel(p);
1221+ if (Flag(FPIPEFAIL) && vp->val.i)
1222+ rv = vp->val.i;
12231223 p = p->next;
12241224 }
12251225 }
@@ -1251,8 +1251,7 @@ j_waitj(Job *j,
12511251 static void
12521252 j_sigchld(int sig MKSH_A_UNUSED)
12531253 {
1254- /* this runs inside interrupt context, with errno saved */
1255-
1254+ int saved_errno = errno;
12561255 Job *j;
12571256 Proc *p = NULL;
12581257 pid_t pid;
@@ -1340,7 +1339,7 @@ j_sigchld(int sig MKSH_A_UNUSED)
13401339 #ifdef MKSH_NO_SIGSUSPEND
13411340 sigprocmask(SIG_SETMASK, &omask, NULL);
13421341 #endif
1343- /* nothing */;
1342+ errno = saved_errno;
13441343 }
13451344
13461345 /*
--- a/src/lalloc.c
+++ b/src/lalloc.c
@@ -1,5 +1,5 @@
11 /*-
2- * Copyright (c) 2009, 2010, 2011
2+ * Copyright (c) 2009, 2010, 2011, 2013
33 * Thorsten Glaser <tg@mirbsd.org>
44 *
55 * Provided that these terms and disclaimer and all copyright notices
@@ -20,7 +20,7 @@
2020
2121 #include "sh.h"
2222
23-__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.19 2011/09/07 15:24:16 tg Exp $");
23+__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.20 2013/06/03 22:28:33 tg Exp $");
2424
2525 /* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */
2626 #if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0)
@@ -100,7 +100,7 @@ aresize(void *ptr, size_t numb, Area *ap)
100100 || ALLOC_ISUNALIGNED(lp)
101101 #endif
102102 )
103- internal_errorf(Toomem, (unsigned long)numb);
103+ internal_errorf(Toomem, numb);
104104 /* this only works because Area is an ALLOC_ITEM */
105105 lp->next = ap->next;
106106 ap->next = lp;
--- a/src/lex.c
+++ b/src/lex.c
@@ -1,4 +1,4 @@
1-/* $OpenBSD: lex.c,v 1.46 2013/01/20 14:47:46 stsp Exp $ */
1+/* $OpenBSD: lex.c,v 1.47 2013/03/03 19:11:34 guenther Exp $ */
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -23,7 +23,7 @@
2323
2424 #include "sh.h"
2525
26-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.182 2013/02/19 18:45:20 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.188 2013/08/10 13:44:31 tg Exp $");
2727
2828 /*
2929 * states while lexing word
@@ -102,8 +102,6 @@ static void gethere(bool);
102102 static Lex_state *push_state_i(State_info *, Lex_state *);
103103 static Lex_state *pop_state_i(State_info *, Lex_state *);
104104
105-static int dopprompt(const char *, int, bool);
106-
107105 static int backslash_skip;
108106 static int ignore_backslash_newline;
109107
@@ -338,7 +336,9 @@ yylex(int cf)
338336 }
339337 break;
340338 case '\'':
341- open_ssquote:
339+ open_ssquote_unless_heredoc:
340+ if ((cf & HEREDOC))
341+ goto store_char;
342342 *wp++ = OQUOTE;
343343 ignore_backslash_newline++;
344344 PUSH_STATE(SSQUOTE);
@@ -421,8 +421,14 @@ yylex(int cf)
421421 wp += cz;
422422 }
423423 } else if (c == '{') /*}*/ {
424- c = getsc();
425- if (ctype(c, C_IFSWS)) {
424+ if ((c = getsc()) == '|') {
425+ /*
426+ * non-subenvironment
427+ * value substitution
428+ */
429+ c = VALSUB;
430+ goto subst_command2;
431+ } else if (ctype(c, C_IFSWS)) {
426432 /*
427433 * non-subenvironment
428434 * "command" substitution
@@ -495,7 +501,8 @@ yylex(int cf)
495501 PUSH_STATE(STBRACEKORN);
496502 } else {
497503 ungetsc(c);
498- if (state == SDQUOTE)
504+ if (state == SDQUOTE ||
505+ state == SQBRACE)
499506 PUSH_STATE(SQBRACE);
500507 else
501508 PUSH_STATE(SBRACE);
@@ -616,6 +623,8 @@ yylex(int cf)
616623 case SSQUOTE:
617624 if (c == '\'') {
618625 POP_STATE();
626+ if ((cf & HEREDOC) || state == SQBRACE)
627+ goto store_char;
619628 *wp++ = CQUOTE;
620629 ignore_backslash_newline--;
621630 } else {
@@ -693,7 +702,7 @@ yylex(int cf)
693702
694703 case SBRACE:
695704 if (c == '\'')
696- goto open_ssquote;
705+ goto open_ssquote_unless_heredoc;
697706 else if (c == '\\')
698707 goto getsc_qchar;
699708 common_SQBRACE:
@@ -812,7 +821,7 @@ yylex(int cf)
812821 }
813822 break;
814823 case '\'':
815- goto open_ssquote;
824+ goto open_ssquote_unless_heredoc;
816825 case '$':
817826 if ((c2 = getsc()) == '\'') {
818827 open_sequote:
@@ -898,7 +907,11 @@ yylex(int cf)
898907 state = SBASE;
899908
900909 dp = Xstring(ws, wp);
901- if ((c == '<' || c == '>' || c == '&') && state == SBASE) {
910+ if (state == SBASE && (
911+#ifndef MKSH_LEGACY_MODE
912+ (c == '&' && !Flag(FSH) && !Flag(FPOSIX)) ||
913+#endif
914+ c == '<' || c == '>')) {
902915 struct ioword *iop = alloc(sizeof(struct ioword), ATEMP);
903916
904917 if (Xlength(ws, wp) == 0)
@@ -1374,7 +1387,7 @@ getsc_line(Source *s)
13741387 Flag(FEMACS) || Flag(FGMACS))) {
13751388 int nread;
13761389
1377- nread = x_read(xp, LINE);
1390+ nread = x_read(xp);
13781391 if (nread < 0)
13791392 /* read error */
13801393 nread = 0;
@@ -1505,8 +1518,8 @@ set_prompt(int to, Source *s)
15051518 }
15061519 }
15071520
1508-static int
1509-dopprompt(const char *cp, int ntruncate, bool doprint)
1521+int
1522+pprompt(const char *cp, int ntruncate)
15101523 {
15111524 int columns = 0, lines = 0;
15121525 bool indelimit = false;
@@ -1539,35 +1552,21 @@ dopprompt(const char *cp, int ntruncate, bool doprint)
15391552 else if (UTFMODE && ((unsigned char)*cp > 0x7F)) {
15401553 const char *cp2;
15411554 columns += utf_widthadj(cp, &cp2);
1542- if (doprint && (indelimit ||
1543- (ntruncate < (x_cols * lines + columns))))
1555+ if (indelimit ||
1556+ (ntruncate < (x_cols * lines + columns)))
15441557 shf_write(cp, cp2 - cp, shl_out);
15451558 cp = cp2 - /* loop increment */ 1;
15461559 continue;
15471560 } else
15481561 columns++;
1549- if (doprint && (*cp != delimiter) &&
1562+ if ((*cp != delimiter) &&
15501563 (indelimit || (ntruncate < (x_cols * lines + columns))))
15511564 shf_putc(*cp, shl_out);
15521565 }
1553- if (doprint)
1554- shf_flush(shl_out);
1566+ shf_flush(shl_out);
15551567 return (x_cols * lines + columns);
15561568 }
15571569
1558-
1559-void
1560-pprompt(const char *cp, int ntruncate)
1561-{
1562- dopprompt(cp, ntruncate, true);
1563-}
1564-
1565-int
1566-promptlen(const char *cp)
1567-{
1568- return (dopprompt(cp, 0, false));
1569-}
1570-
15711570 /*
15721571 * Read the variable part of a ${...} expression (i.e. up to but not
15731572 * including the :[-+?=#%] or close-brace).
--- /dev/null
+++ b/src/lksh.1
@@ -0,0 +1,297 @@
1+.\" $MirOS: src/bin/mksh/lksh.1,v 1.5 2013/05/22 18:18:06 tg Exp $
2+.\"-
3+.\" Copyright (c) 2008, 2009, 2010, 2012, 2013
4+.\" Thorsten “mirabilos” Glaser <tg@mirbsd.org>
5+.\"
6+.\" Provided that these terms and disclaimer and all copyright notices
7+.\" are retained or reproduced in an accompanying document, permission
8+.\" is granted to deal in this work without restriction, including un‐
9+.\" limited rights to use, publicly perform, distribute, sell, modify,
10+.\" merge, give away, or sublicence.
11+.\"
12+.\" This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
13+.\" the utmost extent permitted by applicable law, neither express nor
14+.\" implied; without malicious intent or gross negligence. In no event
15+.\" may a licensor, author or contributor be held liable for indirect,
16+.\" direct, other damage, loss, or other issues arising in any way out
17+.\" of dealing in the work, even if advised of the possibility of such
18+.\" damage or existence of a defect, except proven that it results out
19+.\" of said person’s immediate fault when using the work as intended.
20+.\"-
21+.\" Try to make GNU groff and AT&T nroff more compatible
22+.\" * ` generates ‘ in gnroff, so use \`
23+.\" * ' generates ’ in gnroff, \' generates ´, so use \*(aq
24+.\" * - generates ‐ in gnroff, \- generates −, so .tr it to -
25+.\" thus use - for hyphens and \- for minus signs and option dashes
26+.\" * ~ is size-reduced and placed atop in groff, so use \*(TI
27+.\" * ^ is size-reduced and placed atop in groff, so use \*(ha
28+.\" * \(en does not work in nroff, so use \*(en
29+.\" * <>| are problematic, so redefine and use \*(Lt\*(Gt\*(Ba
30+.\" Also make sure to use \& especially with two-letter words.
31+.\" The section after the "doc" macropackage has been loaded contains
32+.\" additional code to convene between the UCB mdoc macropackage (and
33+.\" its variant as BSD mdoc in groff) and the GNU mdoc macropackage.
34+.\"
35+.ie \n(.g \{\
36+. if \*[.T]ascii .tr \-\N'45'
37+. if \*[.T]latin1 .tr \-\N'45'
38+. if \*[.T]utf8 .tr \-\N'45'
39+. ds <= \[<=]
40+. ds >= \[>=]
41+. ds Rq \[rq]
42+. ds Lq \[lq]
43+. ds sL \(aq
44+. ds sR \(aq
45+. if \*[.T]utf8 .ds sL `
46+. if \*[.T]ps .ds sL `
47+. if \*[.T]utf8 .ds sR '
48+. if \*[.T]ps .ds sR '
49+. ds aq \(aq
50+. ds TI \(ti
51+. ds ha \(ha
52+. ds en \(en
53+.\}
54+.el \{\
55+. ds aq '
56+. ds TI ~
57+. ds ha ^
58+. ds en \(em
59+.\}
60+.\"
61+.\" Implement .Dd with the Mdocdate RCS keyword
62+.\"
63+.rn Dd xD
64+.de Dd
65+.ie \\$1$Mdocdate: \{\
66+. xD \\$2 \\$3, \\$4
67+.\}
68+.el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
69+..
70+.\"
71+.\" .Dd must come before definition of .Mx, because when called
72+.\" with -mandoc, it might implement .Mx itself, but we want to
73+.\" use our own definition. And .Dd must come *first*, always.
74+.\"
75+.Dd $Mdocdate: May 22 2013 $
76+.\"
77+.\" Check which macro package we use, and do other -mdoc setup.
78+.\"
79+.ie \n(.g \{\
80+. if \*[.T]utf8 .tr \[la]\*(Lt
81+. if \*[.T]utf8 .tr \[ra]\*(Gt
82+. ie d volume-ds-1 .ds tT gnu
83+. el .ds tT bsd
84+.\}
85+.el .ds tT ucb
86+.\"
87+.\" Implement .Mx (MirBSD)
88+.\"
89+.ie "\*(tT"gnu" \{\
90+. eo
91+. de Mx
92+. nr curr-font \n[.f]
93+. nr curr-size \n[.ps]
94+. ds str-Mx \f[\n[curr-font]]\s[\n[curr-size]u]
95+. ds str-Mx1 \*[Tn-font-size]\%MirOS\*[str-Mx]
96+. if !\n[arg-limit] \
97+. if \n[.$] \{\
98+. ds macro-name Mx
99+. parse-args \$@
100+. \}
101+. if (\n[arg-limit] > \n[arg-ptr]) \{\
102+. nr arg-ptr +1
103+. ie (\n[type\n[arg-ptr]] == 2) \
104+. as str-Mx1 \~\*[arg\n[arg-ptr]]
105+. el \
106+. nr arg-ptr -1
107+. \}
108+. ds arg\n[arg-ptr] "\*[str-Mx1]
109+. nr type\n[arg-ptr] 2
110+. ds space\n[arg-ptr] "\*[space]
111+. nr num-args (\n[arg-limit] - \n[arg-ptr])
112+. nr arg-limit \n[arg-ptr]
113+. if \n[num-args] \
114+. parse-space-vector
115+. print-recursive
116+..
117+. ec
118+. ds sP \s0
119+. ds tN \*[Tn-font-size]
120+.\}
121+.el \{\
122+. de Mx
123+. nr cF \\n(.f
124+. nr cZ \\n(.s
125+. ds aa \&\f\\n(cF\s\\n(cZ
126+. if \\n(aC==0 \{\
127+. ie \\n(.$==0 \&MirOS\\*(aa
128+. el .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
129+. \}
130+. if \\n(aC>\\n(aP \{\
131+. nr aP \\n(aP+1
132+. ie \\n(C\\n(aP==2 \{\
133+. as b1 \&MirOS\ #\&\\*(A\\n(aP\\*(aa
134+. ie \\n(aC>\\n(aP \{\
135+. nr aP \\n(aP+1
136+. nR
137+. \}
138+. el .aZ
139+. \}
140+. el \{\
141+. as b1 \&MirOS\\*(aa
142+. nR
143+. \}
144+. \}
145+..
146+.\}
147+.\"-
148+.Dt LKSH 1
149+.Os MirBSD
150+.Sh NAME
151+.Nm lksh
152+.Nd Legacy Korn shell built on mksh
153+.Sh SYNOPSIS
154+.Nm
155+.Bk -words
156+.Op Fl +abCefhiklmnprUuvXx
157+.Op Fl +o Ar opt
158+.Oo
159+.Fl c Ar string \*(Ba
160+.Fl s \*(Ba
161+.Ar file
162+.Op Ar args ...
163+.Oc
164+.Ek
165+.Sh DESCRIPTION
166+.Nm
167+is a command interpreter intended exclusively for running legacy
168+shell scripts.
169+It is built on
170+.Nm mksh ;
171+refer to its manual page for details on the scripting language.
172+It is recommended to port scripts to
173+.Nm mksh
174+instead of relying on legacy or idiotic POSIX-mandated behaviour,
175+since the MirBSD Korn Shell scripting language is much more consistent.
176+.Sh LEGACY MODE
177+.Nm
178+has the following differences from
179+.Nm mksh :
180+.Bl -bullet
181+.It
182+There is no explicit support for interactive use,
183+nor any command line editing or history code.
184+Hence,
185+.Nm
186+is not suitable as a user's login shell, either; use
187+.Nm mksh
188+instead.
189+.It
190+The
191+.Ev KSH_VERSION
192+string identifies
193+.Nm
194+as
195+.Dq LEGACY KSH
196+instead of
197+.Dq MIRBSD KSH .
198+.It
199+.Nm
200+only offers the traditional ten file descriptors to scripts.
201+.It
202+.Nm
203+uses
204+.Tn POSIX
205+arithmetics, which has quite a few implications:
206+The data type for arithmetics is the host ISO C
207+.Vt long
208+data type.
209+Signed integer wraparound is Undefined Behaviour.
210+The sign of the result of a modulo operation with at least one
211+negative operand is unspecified.
212+Shift operations on negative numbers are unspecified.
213+Division of the largest negative number by \-1 is Undefined Behaviour.
214+The compiler is permitted to delete all data and crash the system
215+if Undefined Behaviour occurs.
216+.It
217+The rotation arithmetic operators are not available.
218+.It
219+The shift arithmetic operators take all bits of the second operand into
220+account; if they exceed permitted precision, the result is unspecified.
221+.It
222+The
223+.Tn GNU
224+.Nm bash
225+extension &\*(Gt to redirect stdout and stderr in one go is not parsed.
226+.It
227+The
228+.Nm mksh
229+command line option
230+.Fl T
231+is not available.
232+.It
233+Unless
234+.Ic set -o posix
235+is active,
236+.Nm
237+always uses traditional mode for constructs like:
238+.Bd -literal -offset indent
239+$ set -- $(getopt ab:c "$@")
240+$ echo $?
241+.Ed
242+.Pp
243+POSIX mandates this to show 0, but traditional mode
244+passes through the errorlevel from the
245+.Xr getopt 1
246+command.
247+.It
248+.Nm lksh ,
249+unlike
250+.At
251+.Nm ksh ,
252+does not keep file descriptors \*(Gt 2 private.
253+.El
254+.Sh SEE ALSO
255+.Xr mksh 1
256+.Pp
257+.Pa https://www.mirbsd.org/mksh.htm
258+.Pp
259+.Pa https://www.mirbsd.org/ksh\-chan.htm
260+.Sh CAVEATS
261+To use
262+.Nm
263+as
264+.Pa /bin/sh ,
265+compilation to enable
266+.Ic set -o posix
267+by default is highly recommended for better standards compliance.
268+.Pp
269+.Nm
270+tries to make a cross between a legacy bourne/posix compatibl-ish
271+shell and a legacy pdksh-alike but
272+.Dq legacy
273+is not exactly specified.
274+.Pp
275+The
276+.Ic set
277+built-in command does not have all options one would expect
278+from a full-blown
279+.Nm mksh
280+or
281+.Nm pdksh .
282+.Pp
283+Talk to the
284+.Mx
285+development team using the mailing list at
286+.Aq miros\-mksh@mirbsd.org
287+or the
288+.Li \&#\&!/bin/mksh
289+.Pq or Li \&#ksh
290+IRC channel at
291+.Pa irc.freenode.net
292+.Pq Port 6697 SSL, 6667 unencrypted
293+if you need any further quirks or assistance,
294+and consider migrating your legacy scripts to work with
295+.Nm mksh
296+instead of requiring
297+.Nm .
--- a/src/main.c
+++ b/src/main.c
@@ -1,4 +1,4 @@
1-/* $OpenBSD: main.c,v 1.51 2012/09/10 01:25:30 tedu Exp $ */
1+/* $OpenBSD: main.c,v 1.52 2013/06/15 17:25:19 millert Exp $ */
22 /* $OpenBSD: tty.c,v 1.9 2006/03/14 22:08:01 deraadt Exp $ */
33 /* $OpenBSD: io.c,v 1.22 2006/03/17 16:30:13 millert Exp $ */
44 /* $OpenBSD: table.c,v 1.15 2012/02/19 07:52:30 otto Exp $ */
@@ -34,7 +34,7 @@
3434 #include <locale.h>
3535 #endif
3636
37-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.260 2013/02/10 21:42:16 tg Exp $");
37+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.269 2013/07/25 18:07:46 tg Exp $");
3838
3939 extern char **environ;
4040
@@ -48,6 +48,7 @@ extern char **environ;
4848
4949 static uint8_t isuc(const char *);
5050 static int main_init(int, const char *[], Source **, struct block **);
51+uint32_t chvt_rndsetup(const void *, size_t);
5152 void chvt_reinit(void);
5253 static void reclaim(void);
5354 static void remove_temps(struct temp *);
@@ -137,15 +138,25 @@ rndsetup(void)
137138 /* introduce variation (and yes, second arg MBZ for portability) */
138139 mksh_TIME(bufptr->tv);
139140
141+ h = chvt_rndsetup(bufptr, sizeof(*bufptr));
142+
143+ afree(cp, APERM);
144+ return ((mksh_uari_t)h);
145+}
146+
147+uint32_t
148+chvt_rndsetup(const void *bp, size_t sz)
149+{
150+ register uint32_t h;
151+
140152 NZATInit(h);
141153 /* variation through pid, ppid, and the works */
142154 NZATUpdateMem(h, &rndsetupstate, sizeof(rndsetupstate));
143155 /* some variation, some possibly entropy, depending on OE */
144- NZATUpdateMem(h, bufptr, sizeof(*bufptr));
156+ NZATUpdateMem(h, bp, sz);
145157 NZAATFinish(h);
146158
147- afree(cp, APERM);
148- return ((mksh_uari_t)h);
159+ return (h);
149160 }
150161
151162 void
@@ -238,7 +249,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
238249
239250 /* define built-in commands and see if we were called as one */
240251 ktinit(APERM, &builtins,
241- /* currently up to 50 builtins: 75% of 128 = 2^7 */
252+ /* currently up to 51 builtins: 75% of 128 = 2^7 */
242253 7);
243254 for (i = 0; mkshbuiltins[i].name != NULL; i++)
244255 if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
@@ -251,11 +262,20 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
251262 if (argi < 0)
252263 return (1);
253264
265+#if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED)
266+ /* are we called as -sh or /bin/sh or so? */
267+ if (!strcmp(ccp, "sh")) {
268+ /* either also turns off braceexpand */
269+#ifdef MKSH_BINSHPOSIX
270+ /* enable better POSIX conformance */
271+ change_flag(FPOSIX, OF_FIRSTTIME, true);
272+#endif
254273 #ifdef MKSH_BINSHREDUCED
255- /* set FSH if we're called as -sh or /bin/sh or so */
256- if (!strcmp(ccp, "sh"))
274+ /* enable kludge/compat mode */
257275 change_flag(FSH, OF_FIRSTTIME, true);
258276 #endif
277+ }
278+#endif
259279 }
260280
261281 initvar();
@@ -323,6 +343,11 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
323343 */
324344 Flag(FBRACEEXPAND) = 1;
325345
346+ /*
347+ * Turn on "set -x" inheritance by default.
348+ */
349+ Flag(FXTRACEREC) = 1;
350+
326351 #ifndef MKSH_NO_CMDLINE_EDITING
327352 /*
328353 * 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)
411436 return (1);
412437 }
413438
414-#ifdef DEBUG
439+#if defined(DEBUG) && !defined(MKSH_LEGACY_MODE)
415440 /* test wraparound of arithmetic types */
416441 {
417442 volatile long xl;
@@ -442,7 +467,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
442467 xc = 0;
443468 --xc;
444469 if ((xua2 != 2147483648UL) ||
445- (xl != -2147483648L) || (xul != 2147483648UL) ||
470+ (xl != (-2147483647L-1)) || (xul != 2147483648UL) ||
446471 (xi != -1) || (xui != 4294967295U) ||
447472 (xa != 0) || (xua != 0) || (xc != 255))
448473 errorf("integer wraparound test failed");
@@ -889,8 +914,9 @@ unwind(int i)
889914 }
890915
891916 /* ordering for EXIT vs ERR is a bit odd (this is what AT&T ksh does) */
892- if (i == LEXIT ||
893- ((i == LERROR || i == LINTR) && sigtraps[ksh_SIGEXIT].trap)) {
917+ if (i == LEXIT || ((i == LERROR || i == LINTR) &&
918+ sigtraps[ksh_SIGEXIT].trap &&
919+ (!Flag(FTALKING) || Flag(FERREXIT)))) {
894920 ++trap_nested;
895921 runtrap(&sigtraps[ksh_SIGEXIT], trap_nested == 1);
896922 --trap_nested;
@@ -1006,6 +1032,10 @@ quitenv(struct shf *shf)
10061032 #ifndef MKSH_NO_CMDLINE_EDITING
10071033 x_done();
10081034 #endif
1035+#ifndef MKSH_NOPROSPECTOFWORK
1036+ /* block at least SIGCHLD during/after afreeall */
1037+ sigprocmask(SIG_BLOCK, &sm_sigchld, NULL);
1038+#endif
10091039 afreeall(APERM);
10101040 for (fd = 3; fd < NUFILE; fd++)
10111041 if ((i = fcntl(fd, F_GETFD, 0)) != -1 &&
@@ -1364,7 +1394,7 @@ initio(void)
13641394 /* force buffer allocation */
13651395 shf_fdopen(1, SHF_WR, shl_stdout);
13661396 shf_fdopen(2, SHF_WR, shl_out);
1367- shf_fdopen(2, SHF_WR, shl_spare);
1397+ shf_fdopen(2, SHF_WR, shl_xtrace);
13681398 #ifdef DF
13691399 if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
13701400 if ((lfp = getenv("HOME")) == NULL || *lfp != '/')
@@ -1594,7 +1624,7 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist)
15941624 {
15951625 char *cp;
15961626 size_t len;
1597- int i;
1627+ int i, j;
15981628 struct temp *tp;
15991629 const char *dir;
16001630 struct stat sb;
@@ -1644,17 +1674,19 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist)
16441674 }
16451675
16461676 if (type == TT_FUNSUB) {
1647- int nfd;
1648-
16491677 /* map us high and mark as close-on-exec */
1650- if ((nfd = savefd(i)) != i) {
1678+ if ((j = savefd(i)) != i) {
16511679 close(i);
1652- i = nfd;
1680+ i = j;
16531681 }
1654- }
1682+
1683+ /* operation mode for the shf */
1684+ j = SHF_RD;
1685+ } else
1686+ j = SHF_WR;
16551687
16561688 /* shf_fdopen cannot fail, so no fd leak */
1657- tp->shf = shf_fdopen(i, SHF_WR, NULL);
1689+ tp->shf = shf_fdopen(i, j, NULL);
16581690
16591691 maketemp_out:
16601692 tp->next = *tlist;
--- a/src/misc.c
+++ b/src/misc.c
@@ -3,7 +3,7 @@
33
44 /*-
55 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
6- * 2011, 2012
6+ * 2011, 2012, 2013
77 * Thorsten Glaser <tg@mirbsd.org>
88 *
99 * Provided that these terms and disclaimer and all copyright notices
@@ -30,7 +30,7 @@
3030 #include <grp.h>
3131 #endif
3232
33-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.205 2012/12/17 23:18:08 tg Exp $");
33+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.214 2013/08/11 14:57:09 tg Exp $");
3434
3535 #define KSH_CHVT_FLAG
3636 #ifdef MKSH_SMALL
@@ -54,7 +54,7 @@ static int do_gmatch(const unsigned char *, const unsigned char *,
5454 const unsigned char *, const unsigned char *);
5555 static const unsigned char *cclass(const unsigned char *, unsigned char);
5656 #ifdef KSH_CHVT_CODE
57-static void chvt(const char *);
57+static void chvt(const Getopt *);
5858 #endif
5959
6060 /*XXX this should go away */
@@ -123,10 +123,15 @@ Xcheck_grow(XString *xsp, const char *xp, size_t more)
123123 return (xsp->beg + (xp - old_beg));
124124 }
125125
126+
126127 #define SHFLAGS_DEFNS
127128 #include "sh_flags.h"
128129
129-const struct shoption options[] = {
130+#define OFC(i) (options[i][-2])
131+#define OFF(i) (((const unsigned char *)options[i])[-1])
132+#define OFN(i) (options[i])
133+
134+const char * const options[] = {
130135 #define SHFLAGS_ITEMS
131136 #include "sh_flags.h"
132137 };
@@ -137,15 +142,20 @@ const struct shoption options[] = {
137142 size_t
138143 option(const char *n)
139144 {
140- size_t i;
145+ size_t i = 0;
141146
142- if ((n[0] == '-' || n[0] == '+') && n[1] && !n[2]) {
143- for (i = 0; i < NELEM(options); i++)
144- if (options[i].c == n[1])
147+ if ((n[0] == '-' || n[0] == '+') && n[1] && !n[2])
148+ while (i < NELEM(options)) {
149+ if (OFC(i) == n[1])
150+ return (i);
151+ ++i;
152+ }
153+ else
154+ while (i < NELEM(options)) {
155+ if (!strcmp(OFN(i), n))
145156 return (i);
146- } else for (i = 0; i < NELEM(options); i++)
147- if (options[i].name && strcmp(options[i].name, n) == 0)
148- return (i);
157+ ++i;
158+ }
149159
150160 return ((size_t)-1);
151161 }
@@ -165,7 +175,7 @@ options_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
165175 const struct options_info *oi = (const struct options_info *)arg;
166176
167177 shf_snprintf(buf, buflen, "%-*s %s",
168- oi->opt_width, options[oi->opts[i]].name,
178+ oi->opt_width, OFN(oi->opts[i]),
169179 Flag(oi->opts[i]) ? "on" : "off");
170180 return (buf);
171181 }
@@ -184,12 +194,11 @@ printoptions(bool verbose)
184194
185195 oi.opt_width = 0;
186196 while (i < NELEM(options)) {
187- if (options[i].name) {
197+ if ((len = strlen(OFN(i)))) {
188198 oi.opts[n++] = i;
189- len = strlen(options[i].name);
190199 if (len > octs)
191200 octs = len;
192- len = utf_mbswidth(options[i].name);
201+ len = utf_mbswidth(OFN(i));
193202 if ((int)len > oi.opt_width)
194203 oi.opt_width = (int)len;
195204 }
@@ -200,10 +209,9 @@ printoptions(bool verbose)
200209 } else {
201210 /* short version like AT&T ksh93 */
202211 shf_puts(Tset, shl_stdout);
203- while (i < (int)NELEM(options)) {
204- if (Flag(i) && options[i].name)
205- shprintf("%s %s %s", null, "-o",
206- options[i].name);
212+ while (i < NELEM(options)) {
213+ if (Flag(i) && OFN(i)[0])
214+ shprintf(" -o %s", OFN(i));
207215 ++i;
208216 }
209217 shf_putc('\n', shl_stdout);
@@ -213,13 +221,15 @@ printoptions(bool verbose)
213221 char *
214222 getoptions(void)
215223 {
216- size_t i;
217- char m[(int)FNFLAGS + 1];
224+ size_t i = 0;
225+ char c, m[(int)FNFLAGS + 1];
218226 char *cp = m;
219227
220- for (i = 0; i < NELEM(options); i++)
221- if (options[i].c && Flag(i))
222- *cp++ = options[i].c;
228+ while (i < NELEM(options)) {
229+ if ((c = OFC(i)) && Flag(i))
230+ *cp++ = c;
231+ ++i;
232+ }
223233 strndupx(cp, m, cp - m, ATEMP);
224234 return (cp);
225235 }
@@ -229,8 +239,12 @@ void
229239 change_flag(enum sh_flag f, int what, bool newset)
230240 {
231241 unsigned char oldval;
232- unsigned char newval;
242+ unsigned char newval = (newset ? 1 : 0);
233243
244+ if (f == FXTRACE) {
245+ change_xtrace(newval, true);
246+ return;
247+ }
234248 oldval = Flag(f);
235249 Flag(f) = newval = (newset ? 1 : 0);
236250 #ifndef MKSH_UNEMPLOYED
@@ -277,16 +291,46 @@ change_flag(enum sh_flag f, int what, bool newset)
277291 setgid(kshegid);
278292 #endif
279293 } else if ((f == FPOSIX || f == FSH) && newval) {
280- Flag(FPOSIX) = Flag(FSH) = Flag(FBRACEEXPAND) = 0;
281- Flag(f) = newval;
282- }
283- /* Changing interactive flag? */
284- if (f == FTALKING) {
294+ /* Turning on -o posix or -o sh? */
295+ Flag(FBRACEEXPAND) = 0;
296+ } else if (f == FTALKING) {
297+ /* Changing interactive flag? */
285298 if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid)
286299 Flag(FTALKING_I) = newval;
287300 }
288301 }
289302
303+void
304+change_xtrace(unsigned char newval, bool dosnapshot)
305+{
306+ if (!dosnapshot && newval == Flag(FXTRACE))
307+ return;
308+
309+ if (Flag(FXTRACE) == 2) {
310+ shf_putc('\n', shl_xtrace);
311+ Flag(FXTRACE) = 1;
312+ shf_flush(shl_xtrace);
313+ }
314+
315+ if (!dosnapshot && Flag(FXTRACE) == 1)
316+ switch (newval) {
317+ case 1:
318+ return;
319+ case 2:
320+ goto changed_xtrace;
321+ }
322+
323+ shf_flush(shl_xtrace);
324+ if (shl_xtrace->fd != 2)
325+ close(shl_xtrace->fd);
326+ if (!newval || (shl_xtrace->fd = savefd(2)) == -1)
327+ shl_xtrace->fd = 2;
328+
329+ changed_xtrace:
330+ if ((Flag(FXTRACE) = newval) == 2)
331+ shf_puts(substitute(str_val(global("PS4")), 0), shl_xtrace);
332+}
333+
290334 /*
291335 * Parse command line and set command arguments. Returns the index of
292336 * non-option arguments, -1 if there is an error.
@@ -306,10 +350,11 @@ parse_args(const char **argv,
306350 size_t i;
307351 int optc, arrayset = 0;
308352 bool sortargs = false;
353+ bool fcompatseen = false;
309354
310355 /* First call? Build option strings... */
311356 if (cmd_opts[0] == '\0') {
312- char *p = cmd_opts, *q = set_opts;
357+ char ch, *p = cmd_opts, *q = set_opts;
313358
314359 /* see cmd_opts[] declaration */
315360 *p++ = 'o';
@@ -326,11 +371,11 @@ parse_args(const char **argv,
326371 *q++ = 's';
327372
328373 for (i = 0; i < NELEM(options); i++) {
329- if (options[i].c) {
330- if (options[i].flags & OF_CMDLINE)
331- *p++ = options[i].c;
332- if (options[i].flags & OF_SET)
333- *q++ = options[i].c;
374+ if ((ch = OFC(i))) {
375+ if (OFF(i) & OF_CMDLINE)
376+ *p++ = ch;
377+ if (OFF(i) & OF_SET)
378+ *q++ = ch;
334379 }
335380 }
336381 *p = '\0';
@@ -379,6 +424,17 @@ parse_args(const char **argv,
379424 break;
380425 }
381426 i = option(go.optarg);
427+ if ((i == FPOSIX || i == FSH) && set && !fcompatseen) {
428+ /*
429+ * If running 'set -o posix' or
430+ * 'set -o sh', turn off the other;
431+ * if running 'set -o posix -o sh'
432+ * allow both to be set though.
433+ */
434+ Flag(FPOSIX) = 0;
435+ Flag(FSH) = 0;
436+ fcompatseen = true;
437+ }
382438 if ((i != (size_t)-1) && (set ? 1U : 0U) == Flag(i))
383439 /*
384440 * Don't check the context if the flag
@@ -387,7 +443,7 @@ parse_args(const char **argv,
387443 * if the output of "set +o" is to be used.
388444 */
389445 ;
390- else if ((i != (size_t)-1) && (options[i].flags & what))
446+ else if ((i != (size_t)-1) && (OFF(i) & what))
391447 change_flag((enum sh_flag)i, what, set);
392448 else {
393449 bi_errorf("%s: %s", go.optarg, "bad option");
@@ -403,7 +459,7 @@ parse_args(const char **argv,
403459 errorf("no TIOCSCTTY ioctl");
404460 #else
405461 change_flag(FTALKING, OF_CMDLINE, true);
406- chvt(go.optarg);
462+ chvt(&go);
407463 break;
408464 #endif
409465 #endif
@@ -420,8 +476,8 @@ parse_args(const char **argv,
420476 break;
421477 }
422478 for (i = 0; i < NELEM(options); i++)
423- if (optc == options[i].c &&
424- (what & options[i].flags)) {
479+ if (optc == OFC(i) &&
480+ (what & OFF(i))) {
425481 change_flag((enum sh_flag)i, what, set);
426482 break;
427483 }
@@ -433,8 +489,10 @@ parse_args(const char **argv,
433489 (argv[go.optind][0] == '-' || argv[go.optind][0] == '+') &&
434490 argv[go.optind][1] == '\0') {
435491 /* lone - clears -v and -x flags */
436- if (argv[go.optind][0] == '-')
437- Flag(FVERBOSE) = Flag(FXTRACE) = 0;
492+ if (argv[go.optind][0] == '-') {
493+ Flag(FVERBOSE) = 0;
494+ change_xtrace(0, false);
495+ }
438496 /* set skips lone - or + option */
439497 go.optind++;
440498 }
@@ -472,9 +530,11 @@ int
472530 getn(const char *s, int *ai)
473531 {
474532 char c;
475- unsigned int i = 0;
533+ mksh_ari_u num;
476534 bool neg = false;
477535
536+ num.u = 0;
537+
478538 do {
479539 c = *s++;
480540 } while (ksh_isspace(c));
@@ -492,18 +552,20 @@ getn(const char *s, int *ai)
492552 if (!ksh_isdigit(c))
493553 /* not numeric */
494554 return (0);
495- if (i > 214748364U)
555+ if (num.u > 214748364U)
496556 /* overflow on multiplication */
497557 return (0);
498- i = i * 10U + (unsigned int)(c - '0');
499- /* now: i <= 2147483649U */
558+ num.u = num.u * 10U + (unsigned int)(c - '0');
559+ /* now: num.u <= 2147483649U */
500560 } while ((c = *s++));
501561
502- if (i > (neg ? 2147483648U : 2147483647U))
562+ if (num.u > (neg ? 2147483648U : 2147483647U))
503563 /* overflow for signed 32-bit int */
504564 return (0);
505565
506- *ai = neg ? -(int)i : (int)i;
566+ if (neg)
567+ num.u = -num.u;
568+ *ai = num.i;
507569 return (1);
508570 }
509571
@@ -1206,20 +1268,19 @@ print_columns(struct shf *shf, unsigned int n,
12061268 /* if we can only print one column anyway, skip the goo */
12071269 if (cols < 2) {
12081270 for (i = 0; i < n; ++i)
1209- shf_fprintf(shf, "%s \n",
1271+ shf_fprintf(shf, "%s\n",
12101272 (*func)(str, max_oct, i, arg));
12111273 goto out;
12121274 }
12131275
12141276 rows = (n + cols - 1) / cols;
12151277 if (prefcol && cols > rows) {
1216- i = rows;
1217- rows = cols > n ? n : cols;
1218- cols = i;
1278+ cols = rows;
1279+ rows = (n + cols - 1) / cols;
12191280 }
12201281
1282+ nspace = (x_cols - max_col * cols) / cols;
12211283 max_col = -max_col;
1222- nspace = (x_cols + max_col * cols) / cols;
12231284 if (nspace <= 0)
12241285 nspace = 1;
12251286 for (r = 0; r < rows; r++) {
@@ -1911,59 +1972,69 @@ c_cd(const char **wp)
19111972
19121973
19131974 #ifdef KSH_CHVT_CODE
1975+extern uint32_t chvt_rndsetup(const void *, size_t);
19141976 extern void chvt_reinit(void);
19151977
19161978 static void
1917-chvt(const char *fn)
1979+chvt(const Getopt *go)
19181980 {
1919- char dv[20];
1920- struct stat sb;
1981+ const char *dv = go->optarg;
1982+ char *cp = NULL;
19211983 int fd;
19221984
1923- if (*fn == '-') {
1924- memcpy(dv, "-/dev/null", sizeof("-/dev/null"));
1925- fn = dv + 1;
1926- } else {
1927- if (stat(fn, &sb)) {
1928- memcpy(dv, "/dev/ttyC", 9);
1929- strlcpy(dv + 9, fn, sizeof(dv) - 9);
1985+ switch (*dv) {
1986+ case '-':
1987+ dv = "/dev/null";
1988+ break;
1989+ case '!':
1990+ ++dv;
1991+ /* FALLTHROUGH */
1992+ default: {
1993+ struct stat sb;
1994+
1995+ if (stat(dv, &sb)) {
1996+ cp = shf_smprintf("/dev/ttyC%s", dv);
1997+ dv = cp;
19301998 if (stat(dv, &sb)) {
1931- strlcpy(dv + 8, fn, sizeof(dv) - 8);
1932- if (stat(dv, &sb))
1933- errorf("%s: %s %s", "chvt",
1934- "can't find tty", fn);
1999+ memmove(cp + 1, cp, /* /dev/tty */ 8);
2000+ dv = cp + 1;
2001+ if (stat(dv, &sb)) {
2002+ errorf("%s: %s: %s", "chvt",
2003+ "can't find tty", go->optarg);
2004+ }
19352005 }
1936- fn = dv;
19372006 }
19382007 if (!(sb.st_mode & S_IFCHR))
1939- errorf("%s %s %s", "chvt: not a char", "device", fn);
1940- if ((sb.st_uid != 0) && chown(fn, 0, 0))
1941- warningf(false, "%s: %s %s", "chvt", "can't chown root", fn);
1942- if (((sb.st_mode & 07777) != 0600) && chmod(fn, (mode_t)0600))
1943- warningf(false, "%s: %s %s", "chvt", "can't chmod 0600", fn);
2008+ errorf("%s: %s: %s", "chvt", "not a char device", dv);
2009+#ifndef MKSH_DISABLE_REVOKE_WARNING
19442010 #if HAVE_REVOKE
1945- if (revoke(fn))
2011+ if (revoke(dv))
19462012 #endif
19472013 warningf(false, "%s: %s %s", "chvt",
19482014 "new shell is potentially insecure, can't revoke",
1949- fn);
2015+ dv);
2016+#endif
2017+ }
19502018 }
1951- if ((fd = open(fn, O_RDWR)) < 0) {
2019+ if ((fd = open(dv, O_RDWR)) < 0) {
19522020 sleep(1);
1953- if ((fd = open(fn, O_RDWR)) < 0)
1954- errorf("%s: %s %s", "chvt", "can't open", fn);
2021+ if ((fd = open(dv, O_RDWR)) < 0) {
2022+ errorf("%s: %s %s", "chvt", "can't open", dv);
2023+ }
19552024 }
1956- switch (fork()) {
1957- case -1:
1958- errorf("%s: %s %s", "chvt", "fork", "failed");
1959- case 0:
1960- break;
1961- default:
1962- exit(0);
2025+ if (go->optarg[0] != '!') {
2026+ switch (fork()) {
2027+ case -1:
2028+ errorf("%s: %s %s", "chvt", "fork", "failed");
2029+ case 0:
2030+ break;
2031+ default:
2032+ exit(0);
2033+ }
19632034 }
19642035 if (setsid() == -1)
19652036 errorf("%s: %s %s", "chvt", "setsid", "failed");
1966- if (fn != dv + 1) {
2037+ if (go->optarg[0] != '-') {
19672038 if (ioctl(fd, TIOCSCTTY, NULL) == -1)
19682039 errorf("%s: %s %s", "chvt", "TIOCSCTTY", "failed");
19692040 if (tcflush(fd, TCIOFLUSH))
@@ -1974,14 +2045,7 @@ chvt(const char *fn)
19742045 ksh_dup2(fd, 2, false);
19752046 if (fd > 2)
19762047 close(fd);
1977- {
1978- register uint32_t h;
1979-
1980- NZATInit(h);
1981- NZATUpdateMem(h, &rndsetupstate, sizeof(rndsetupstate));
1982- NZAATFinish(h);
1983- rndset((long)h);
1984- }
2048+ rndset((unsigned long)chvt_rndsetup(go, sizeof(Getopt)));
19852049 chvt_reinit();
19862050 }
19872051 #endif
--- a/src/mksh.1
+++ b/src/mksh.1
@@ -1,5 +1,5 @@
1-.\" $MirOS: src/bin/mksh/mksh.1,v 1.305 2013/02/19 18:45:20 tg Exp $
2-.\" $OpenBSD: ksh.1,v 1.145 2013/01/17 21:20:25 jmc Exp $
1+.\" $MirOS: src/bin/mksh/mksh.1,v 1.320 2013/08/10 14:11:39 tg Exp $
2+.\" $OpenBSD: ksh.1,v 1.147 2013/06/13 19:43:09 millert Exp $
33 .\"-
44 .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
55 .\" 2010, 2011, 2012, 2013
@@ -74,7 +74,7 @@
7474 .\" with -mandoc, it might implement .Mx itself, but we want to
7575 .\" use our own definition. And .Dd must come *first*, always.
7676 .\"
77-.Dd $Mdocdate: February 19 2013 $
77+.Dd $Mdocdate: August 10 2013 $
7878 .\"
7979 .\" Check which macro package we use, and do other -mdoc setup.
8080 .\"
@@ -157,7 +157,11 @@
157157 .Nm
158158 .Bk -words
159159 .Op Fl +abCefhiklmnprUuvXx
160-.Op Fl T Ar /dev/ttyCn \*(Ba \-
160+.Oo
161+.Fl T Oo Ar \&! Oc Ns Ar tty
162+\*(Ba
163+.Ar \&\-
164+.Oc
161165 .Op Fl +o Ar option
162166 .Oo
163167 .Fl c Ar string \*(Ba
@@ -295,16 +299,28 @@ Redirections that create files can't be used (i.e.\&
295299 .It Fl s
296300 The shell reads commands from standard input; all non-option arguments
297301 are positional parameters.
298-.It Fl T Ar tty
302+.It Fl T Ar name
299303 Spawn
300304 .Nm
301305 on the
302306 .Xr tty 4
303307 device given.
304-Superuser only.
308+The paths
309+.Ar name ,
310+.Pa /dev/ttyC Ns Ar name
311+and
312+.Pa /dev/tty Ns Ar name
313+are attempted in order.
314+Unless
315+.Ar name
316+begins with an exclamation mark
317+.Pq Sq \&! ,
318+this is done in a subshell and returns immediately.
305319 If
306-.Ar tty
307-is a dash, detach from controlling terminal (daemonise) instead.
320+.Ar name
321+is a dash
322+.Pq Sq \&\- ,
323+detach from controlling terminal (daemonise) instead.
308324 .El
309325 .Pp
310326 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
514530 last is piped (see
515531 .Xr pipe 2 )
516532 to the standard input of the following command.
517-The exit status of a pipeline is that of its last command.
533+The exit status of a pipeline is that of its last command, unless the
534+.Ic pipefail
535+option is set (see there).
518536 All commands of a pipeline are executed in separate subshells;
519537 this is allowed by POSIX but differs from both variants of
520538 .At
@@ -1180,6 +1198,15 @@ work, and in that
11801198 .Ic exit
11811199 terminates the parent shell.
11821200 .Pp
1201+Another variant of substitution are the valsubs (value substitutions)
1202+.Pf ${\*(Ba\& Ns Ar command Ns \&;}
1203+which are also executed in the current environment, like funsubs, but
1204+share their I/O with the parent; instead, they evaluate to whatever
1205+the, initially empty, expression-local variable
1206+.Ev REPLY
1207+is set to within the
1208+.Ar command Ns No s .
1209+.Pp
11831210 If a substitution appears outside of double quotes, the results of the
11841211 substitution are generally subject to word or field splitting according to
11851212 the current value of the
@@ -2037,6 +2064,9 @@ Parameter, command, and arithmetic substitutions are performed
20372064 before it is printed.
20382065 The default is
20392066 .Sq +\ \& .
2067+You may want to set it to
2068+.Sq \&[$EPOCHREALTIME]\ \&
2069+instead, to include timestamps.
20402070 .It Ev PWD
20412071 The current working directory.
20422072 May be unset or
@@ -2431,6 +2461,13 @@ in
24312461 .Nm
24322462 but a syntax error in GNU
24332463 .Nm bash .
2464+Setting the
2465+.Fl o Ar posix
2466+or
2467+.Fl o Ar sh
2468+shell options disable parsing of this redirection;
2469+it's a compatibility feature to legacy scripts, to
2470+not be used when writing new shell code.
24342471 .It Xo
24352472 .No &\*(Gt\*(Ba Ar file ,
24362473 .No &\*(Gt\*(Gt Ar file ,
@@ -2515,15 +2552,15 @@ Unary operators:
25152552 Binary operators:
25162553 .Bd -literal -offset indent
25172554 ,
2518-= *= /= %= += \-= \*(Lt\*(Lt= \*(Gt\*(Gt= &= \*(ha= \*(Ba=
2555+= += \-= *= /= %= \*(Lt\*(Lt\*(Lt= \*(Gt\*(Gt\*(Gt= \*(Lt\*(Lt= \*(Gt\*(Gt= &= \*(ha= \*(Ba=
25192556 \*(Ba\*(Ba
25202557 &&
25212558 \*(Ba
25222559 \*(ha
25232560 &
25242561 == !=
2525-\*(Lt \*(Lt= \*(Gt= \*(Gt
2526-\*(Lt\*(Lt \*(Gt\*(Gt
2562+\*(Lt \*(Lt= \*(Gt \*(Gt=
2563+\*(Lt\*(Lt\*(Lt \*(Gt\*(Gt\*(Gt \*(Lt\*(Lt \*(Gt\*(Gt
25272564 + \-
25282565 * / %
25292566 .Ed
@@ -2553,9 +2590,14 @@ Additionally, base-16 integers may be specified by prefixing them with
25532590 in all forms of arithmetic expressions, except as numeric arguments to the
25542591 .Ic test
25552592 built-in command.
2556-It is discouraged to prefix numbers with a sole zero
2557-.Pq Sq 0 ,
2558-because some shells may interpret them as base-8 integers.
2593+Prefixing numbers with a sole digit zero
2594+.Pq Sq 0
2595+leads to the shell interpreting it as base-8 integer in
2596+.Ic posix
2597+mode
2598+.Em only ;
2599+historically, (pd)ksh has never done so either anyway,
2600+and it's unsafe to do that, but POSIX demands it nowadays.
25592601 As a special
25602602 .Nm mksh
25612603 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.
26092651 .It =
26102652 Assignment; the variable on the left is set to the value on the right.
26112653 .It Xo
2612-.No *= /= += \-= \*(Lt\*(Lt=
2613-.No \*(Gt\*(Gt= &= \*(ha= \*(Ba=
2654+.No += \-= *= /= %= \*(Lt\*(Lt\*(Lt= \*(Gt\*(Gt\*(Gt=
2655+.No \*(Lt\*(Lt= \*(Gt\*(Gt= &= \*(ha= \*(Ba=
26142656 .Xc
26152657 Assignment operators.
26162658 .Sm off
@@ -2656,10 +2698,15 @@ Not equal; the result is 0 if both arguments are equal, 1 if not.
26562698 .It \*(Lt
26572699 Less than; the result is 1 if the left argument is less than the right, 0 if
26582700 not.
2659-.It \*(Lt= \*(Gt= \*(Gt
2701+.It \*(Lt= \*(Gt \*(Gt=
26602702 Less than or equal, greater than or equal, greater than.
26612703 See
26622704 .Ic \*(Lt .
2705+.It \*(Lt\*(Lt\*(Lt \*(Gt\*(Gt\*(Gt
2706+Rotate left (right); the result is similar to shift (see
2707+.Ic \*(Lt\*(Lt )
2708+except that the bits shifted out at one end are shifted in
2709+at the other end, instead of zero or sign bits.
26632710 .It \*(Lt\*(Lt \*(Gt\*(Gt
26642711 Shift left (right); the result is the left argument with its bits shifted left
26652712 (right) by the amount given in the right argument.
@@ -2668,7 +2715,6 @@ Addition, subtraction, multiplication, and division.
26682715 .It %
26692716 Remainder; the result is the remainder of the division of the left argument by
26702717 the right.
2671-The sign of the result is unspecified if either argument is negative.
26722718 .It Xo
26732719 .Sm off
26742720 .Aq Ar arg1 ?
@@ -2682,6 +2728,7 @@ is non-zero, the result is
26822728 .Aq Ar arg2 ;
26832729 otherwise the result is
26842730 .Aq Ar arg3 .
2731+The non-result argument is not evaluated.
26852732 .El
26862733 .Ss Co-processes
26872734 A co-process (which is a pipeline created with the
@@ -2753,8 +2800,7 @@ However, unlike
27532800 shell arguments (i.e. positional parameters $1, $2, etc.)\&
27542801 are never visible inside them.
27552802 When the shell is determining the location of a command, functions
2756-are searched after special built-in commands, before regular and
2757-non-regular built-ins, and before the
2803+are searched after special built-in commands, before builtins and the
27582804 .Ev PATH
27592805 is searched.
27602806 .Pp
@@ -2868,8 +2914,8 @@ returns.
28682914 .El
28692915 .Ss Command execution
28702916 After evaluation of command-line arguments, redirections, and parameter
2871-assignments, the type of command is determined: a special built-in, a
2872-function, a regular built-in, or the name of a file to execute found using the
2917+assignments, the type of command is determined: a special built-in command,
2918+a function, a normal builtin, or the name of a file to execute found using the
28732919 .Ev PATH
28742920 parameter.
28752921 The checks are made in the above order.
@@ -2885,46 +2931,30 @@ parameter is not used to find them.
28852931 The original
28862932 .Nm ksh
28872933 and POSIX differ somewhat in which commands are considered
2888-special or regular:
2934+special or regular.
28892935 .Pp
2890-POSIX special commands
2936+POSIX special built-in utilities:
28912937 .Pp
28922938 .Ic \&. , \&: , break , continue ,
28932939 .Ic eval , exec , exit , export ,
28942940 .Ic readonly , return , set , shift ,
2895-.Ic trap , unset , wait
2941+.Ic times , trap , unset
28962942 .Pp
28972943 Additional
28982944 .Nm
2899-special commands
2900-.Pp
2901-.Ic builtin , global , times , typeset
2902-.Pp
2903-Very special commands
2904-.Pq non-POSIX
2945+commands keeping assignments:
29052946 .Pp
2906-.Ic alias , readonly , set , typeset
2947+.Ic builtin , global , typeset , wait
29072948 .Pp
2908-POSIX regular commands
2949+Builtins that are not special:
29092950 .Pp
2910-.Ic alias , bg , cd , command ,
2951+.Ic [ , alias , bg , bind ,
2952+.Ic cat , cd , command , echo ,
29112953 .Ic false , fc , fg , getopts ,
2912-.Ic jobs , kill , read , true ,
2913-.Ic umask , unalias
2914-.Pp
2915-Additional
2916-.Nm
2917-regular commands
2918-.Pp
2919-.Ic \&[ , chdir , bind , cat ,
2920-.Ic echo , let , mknod , print ,
2921-.Ic pwd , realpath , rename , sleep ,
2922-.Ic test , ulimit , whence
2923-.Pp
2924-In the future, the additional
2925-.Nm
2926-special and regular commands may be treated
2927-differently from the POSIX special and regular commands.
2954+.Ic jobs , kill , let , mknod ,
2955+.Ic print , pwd , read , realpath ,
2956+.Ic rename , sleep , test , true ,
2957+.Ic ulimit , umask , unalias , whence
29282958 .Pp
29292959 Once the type of command has been determined, any command-line parameter
29302960 assignments are performed and exported for the duration of the command.
@@ -2952,6 +2982,10 @@ those of the environment the command is used in.
29522982 The null command.
29532983 Exit status is set to zero.
29542984 .Pp
2985+.It Ic \&[ Ar expression Ic \&]
2986+See
2987+.Ic test .
2988+.Pp
29552989 .It Xo Ic alias
29562990 .Oo Fl d \*(Ba t Oo Fl r Oc \*(Ba
29572991 .Cm +\-x Oc
@@ -3506,6 +3540,10 @@ resetting
35063540 .Ev OPTIND ,
35073541 may lead to unexpected results.
35083542 .Pp
3543+.It global Ar ...
3544+See
3545+.Ic typeset .
3546+.Pp
35093547 .It Xo
35103548 .Ic hash
35113549 .Op Fl r
@@ -3585,6 +3623,10 @@ Since expressions may need to be quoted,
35853623 is syntactic sugar for
35863624 .No let \&" Ns Ar expr Ns \&" .
35873625 .Pp
3626+.It let]
3627+Internally used alias for
3628+.Ic let .
3629+.Pp
35883630 .It Xo
35893631 .Ic mknod
35903632 .Op Fl m Ar mode
@@ -4004,11 +4046,14 @@ explicitly tested by a shell construct such as
40044046 .Ic if ,
40054047 .Ic until ,
40064048 .Ic while ,
4007-.Ic && ,
4008-.Ic \*(Ba\*(Ba ,
40094049 or
40104050 .Ic !\&
40114051 statements.
4052+For
4053+.Ic &&
4054+or
4055+.Ic \*(Ba\*(Ba ,
4056+only the status of the last command is tested.
40124057 .It Fl f \*(Ba Fl o Ic noglob
40134058 Do not expand file name patterns.
40144059 .It Fl h \*(Ba Fl o Ic trackall
@@ -4097,7 +4142,7 @@ Mark directories with a trailing
40974142 .Ql /
40984143 during file name generation.
40994144 .It Fl x \*(Ba Fl o Ic xtrace
4100-Print commands and parameter assignments when they are executed, preceded by
4145+Print command trees when they are executed, preceded by
41014146 the value of
41024147 .Ev PS4 .
41034148 .It Fl o Ic bgnice
@@ -4120,6 +4165,11 @@ must be used.
41204165 To avoid infinite loops, the shell will exit if
41214166 .Dv EOF
41224167 is read 13 times in a row.
4168+.It Fl o Ic inherit\-xtrace
4169+Do not reset
4170+.Fl o Ic xtrace
4171+upon entering functions.
4172+This is enabled by default.
41234173 .It Fl o Ic nohup
41244174 Do not kill running jobs with a
41254175 .Dv SIGHUP
@@ -4162,6 +4212,9 @@ See the
41624212 and
41634213 .Ic pwd
41644214 commands above for more details.
4215+.It Fl o Ic pipefail
4216+Make the exit status of a pipeline (before logically complementing) the
4217+rightmost non-zero errorlevel, or zero if all commands exited with zero.
41654218 .It Fl o Ic posix
41664219 Enable a somewhat more
41674220 .Px
@@ -6020,6 +6073,11 @@ Search for the
60206073 .Ar n Ns th
60216074 occurrence of the last search string;
60226075 the direction of the search is the opposite of the last search.
6076+.It Ar ANSI-CurUp
6077+Take the characters from the beginning of the line to the current
6078+cursor position as search string and do a backwards history search
6079+for lines beginning with this string; keep the cursor position.
6080+This works only in insert mode and keeps it enabled.
60236081 .El
60246082 .Pp
60256083 Edit commands
@@ -6309,21 +6367,53 @@ all contributors, such as the Debian and OpenBSD projects.
63096367 .\" Open Source licence.
63106368 .\"
63116369 See the documentation, CVS, and web site for details.
6370+.Pp
6371+The BSD daemon is Copyright \(co Marshall Kirk McKusick.
6372+The complete legalese is at:
6373+.Pa https://www.mirbsd.org/TaC\-mksh.txt
6374+.\"
6375+.\" This boils down to: feel free to use mksh.ico as application icon
6376+.\" or shortcut for mksh or mksh/Win32; distro patches are ok (but we
6377+.\" request they amend $KSH_VERSION when modifying mksh). Authors are
6378+.\" Marshall Kirk McKusick (UCB), Rick Collette (ekkoBSD), Thorsten
6379+.\" Glaser, Benny Siegert (MirBSD), Michael Langguth (mksh/Win32).
6380+.\"
6381+.\" As far as MirBSD is concerned, the files themselves are free
6382+.\" to modification and distribution under BSD/MirOS Licence, the
6383+.\" restriction on use stems only from trademark law's requirement
6384+.\" to protect it or lose it, which McKusick almost did.
6385+.\"
63126386 .Sh CAVEATS
63136387 .Nm
63146388 only supports the Unicode BMP (Basic Multilingual Plane).
6315-It has a different scope model from
6389+.Pp
6390+.Nm
6391+has a different scope model from
63166392 .At
63176393 .Nm ksh ,
63186394 which leads to subtile differences in semantics for identical builtins.
6395+This can cause issues with a
6396+.Ic nameref
6397+to suddenly point to a local variable by accident; fixing this is hard.
63196398 .Pp
63206399 The parts of a pipeline, like below, are executed in subshells.
6321-Thus, variable assignments inside them fail.
6400+Thus, variable assignments inside them are not visible in the
6401+surrounding execution environment.
63226402 Use co-processes instead.
63236403 .Bd -literal -offset indent
63246404 foo \*(Ba bar \*(Ba read baz # will not change $baz
63256405 foo \*(Ba bar \*(Ba& read \-p baz # will, however, do so
63266406 .Ed
6407+.Pp
6408+.Nm mksh
6409+provides a consistent set of 32-bit integer arithmetics, both signed
6410+and unsigned, with defined wraparound and sign of the result of a modulo
6411+operation, even (defying POSIX) on 64-bit systems.
6412+If you require 64-bit integer arithmetics, use
6413+.Nm lksh Pq legacy mksh
6414+instead, but be aware that, in POSIX, it's legal for the OS to make
6415+.Li print $((2147483647 + 1))
6416+delete all files on your system, as it's Undefined Behaviour.
63276417 .Sh BUGS
63286418 Suspending (using \*(haZ) pipelines like the one below will only suspend
63296419 the currently running part of the pipeline; in this example,
@@ -6335,7 +6425,7 @@ $ /bin/sleep 666 && echo fubar
63356425 .Ed
63366426 .Pp
63376427 This document attempts to describe
6338-.Nm mksh\ R43
6428+.Nm mksh\ R48
63396429 and up,
63406430 compiled without any options impacting functionality, such as
63416431 .Dv MKSH_SMALL ,
Binary files /dev/null and b/src/mksh.ico differ
--- a/src/sh.h
+++ b/src/sh.h
@@ -3,7 +3,7 @@
33 /* $OpenBSD: table.h,v 1.8 2012/02/19 07:52:30 otto Exp $ */
44 /* $OpenBSD: tree.h,v 1.10 2005/03/28 21:28:22 deraadt Exp $ */
55 /* $OpenBSD: expand.h,v 1.6 2005/03/30 17:16:37 deraadt Exp $ */
6-/* $OpenBSD: lex.h,v 1.12 2013/01/20 14:47:46 stsp Exp $ */
6+/* $OpenBSD: lex.h,v 1.13 2013/03/03 19:11:34 guenther Exp $ */
77 /* $OpenBSD: proto.h,v 1.34 2012/06/27 07:17:19 otto Exp $ */
88 /* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */
99 /* $OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $ */
@@ -164,9 +164,9 @@
164164 #endif
165165
166166 #ifdef EXTERN
167-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.639 2013/02/19 18:45:22 tg Exp $");
167+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.667 2013/08/14 20:26:19 tg Exp $");
168168 #endif
169-#define MKSH_VERSION "R43 2013/02/19"
169+#define MKSH_VERSION "R48 2013/08/14"
170170
171171 /* arithmetic types: C implementation */
172172 #if !HAVE_CAN_INTTYPES
@@ -370,6 +370,7 @@ extern int revoke(const char *);
370370 #endif
371371
372372 #if defined(DEBUG) || !HAVE_STRERROR
373+#undef strerror
373374 #define strerror /* poisoned */ dontuse_strerror
374375 #define cstrerror /* replaced */ cstrerror
375376 extern const char *cstrerror(int);
@@ -415,7 +416,7 @@ extern int __cdecl setegid(gid_t);
415416
416417 /* remove redundancies */
417418
418-#if defined(MirBSD) && (MirBSD >= 0x08A8) && !defined(MKSH_OPTSTATIC)
419+#if defined(MirBSD) && (MirBSD >= 0x0AB3) && !defined(MKSH_OPTSTATIC)
419420 #define MKSH_mirbsd_wcwidth
420421 #define utf_wcwidth(i) wcwidth((__WCHAR_TYPE__)i)
421422 extern int wcwidth(__WCHAR_TYPE__);
@@ -443,8 +444,6 @@ extern int wcwidth(__WCHAR_TYPE__);
443444 #define MAGIC (7) /* prefix for *?[!{,} during expand */
444445 #define ISMAGIC(c) ((unsigned char)(c) == MAGIC)
445446
446-#define LINE 4096 /* input line size */
447-
448447 EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
449448
450449 #ifdef MKSH_LEGACY_MODE
@@ -471,6 +470,14 @@ union mksh_ccphack {
471470 const char **ro;
472471 };
473472
473+/*
474+ * Evil hack since casting uint to sint is implementation-defined
475+ */
476+typedef union {
477+ mksh_ari_t i;
478+ mksh_uari_t u;
479+} mksh_ari_u;
480+
474481 /* for const debugging */
475482 #if defined(DEBUG) && defined(__GNUC__) && !defined(__ICC) && \
476483 !defined(__INTEL_COMPILER) && !defined(__SUNPRO_C)
@@ -511,8 +518,9 @@ char *ucstrstr(char *, const char *);
511518 #define mkssert(e) do { } while (/* CONSTCOND */ 0)
512519 #endif
513520
514-#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 431)
521+#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 481)
515522 #error Must run Build.sh to compile this.
523+extern void thiswillneverbedefinedIhope(void);
516524 int
517525 im_sorry_dave(void)
518526 {
@@ -763,18 +771,11 @@ EXTERN struct {
763771 #define OF_FIRSTTIME 0x10 /* as early as possible, once */
764772 #define OF_ANY (OF_CMDLINE | OF_SET | OF_SPECIAL | OF_INTERNAL)
765773
766-struct shoption {
767- const char *name; /* long name of option */
768- char c; /* character flag (if any) */
769- unsigned char flags; /* OF_* */
770-};
771-extern const struct shoption options[];
772-
773774 /* null value for variable; comparison pointer for unset */
774775 EXTERN char null[] E_INIT("");
775776 /* helpers for string pooling */
776777 EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented");
777-EXTERN const char Toomem[] E_INIT("can't allocate %lu data bytes");
778+EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes");
778779 #if defined(__GNUC__)
779780 /* trust this to have string pooling; -Wformat bitches otherwise */
780781 #define Tsynerr "syntax error"
@@ -788,10 +789,8 @@ EXTERN const char Tr_fc_e_dash[] E_INIT("r=fc -e -");
788789 EXTERN const char Tlocal_typeset[] E_INIT("local=typeset");
789790 #define T_typeset (Tlocal_typeset + 5) /* "=typeset" */
790791 #define Ttypeset (Tlocal_typeset + 6) /* "typeset" */
791-EXTERN const char Tpalias[] E_INIT("+alias");
792-#define Talias (Tpalias + 1) /* "alias" */
793-EXTERN const char Tpunalias[] E_INIT("+unalias");
794-#define Tunalias (Tpunalias + 1) /* "unalias" */
792+EXTERN const char Talias[] E_INIT("alias");
793+EXTERN const char Tunalias[] E_INIT("unalias");
795794 EXTERN const char Tsgset[] E_INIT("*=set");
796795 #define Tset (Tsgset + 2) /* "set" */
797796 EXTERN const char Tsgunset[] E_INIT("*=unset");
@@ -830,7 +829,7 @@ struct temp {
830829 * stdio and our IO routines
831830 */
832831
833-#define shl_spare (&shf_iob[0]) /* for c_read()/c_print() */
832+#define shl_xtrace (&shf_iob[0]) /* for set -x */
834833 #define shl_stdout (&shf_iob[1])
835834 #define shl_out (&shf_iob[2])
836835 #ifdef DF
@@ -984,6 +983,8 @@ EXTERN uint32_t builtin_flag;
984983 /* current working directory */
985984 EXTERN char *current_wd;
986985
986+/* input line size */
987+#define LINE (4096 - ALLOC_SIZE)
987988 /*
988989 * Minimum required space to work with on a line - if the prompt leaves
989990 * less space than this on a line, the prompt is truncated.
@@ -1151,7 +1152,6 @@ EXTERN struct tbl vtemp;
11511152 #define FDELETE BIT(10) /* function deleted while it was executing */
11521153 #define FKSH BIT(11) /* function defined with function x (vs x()) */
11531154 #define SPEC_BI BIT(12) /* a POSIX special builtin */
1154-#define REG_BI BIT(13) /* a POSIX regular builtin */
11551155 /*
11561156 * Attributes that can be set by the user (used to decide if an unset
11571157 * param should be repoted by set/typeset). Does not include ARRAY or
@@ -1180,12 +1180,11 @@ EXTERN enum {
11801180
11811181 /* Flags for findcom()/comexec() */
11821182 #define FC_SPECBI BIT(0) /* special builtin */
1183-#define FC_FUNC BIT(1) /* function builtin */
1184-#define FC_REGBI BIT(2) /* regular builtin */
1185-#define FC_UNREGBI BIT(3) /* un-regular builtin (!special,!regular) */
1186-#define FC_BI (FC_SPECBI|FC_REGBI|FC_UNREGBI)
1187-#define FC_PATH BIT(4) /* do path search */
1188-#define FC_DEFPATH BIT(5) /* use default path in path search */
1183+#define FC_FUNC BIT(1) /* function */
1184+#define FC_NORMBI BIT(2) /* not special builtin */
1185+#define FC_BI (FC_SPECBI | FC_NORMBI)
1186+#define FC_PATH BIT(3) /* do path search */
1187+#define FC_DEFPATH BIT(4) /* use default path in path search */
11891188
11901189
11911190 #define AF_ARGV_ALLOC 0x1 /* argv[] array allocated */
@@ -1254,10 +1253,6 @@ EXTERN const char *prompt;
12541253 EXTERN int cur_prompt; /* PS1 or PS2 */
12551254 EXTERN int current_lineno; /* LINENO value */
12561255
1257-#define NOBLOCK ((struct op *)NULL)
1258-#define NOWORD ((char *)NULL)
1259-#define NOWORDS ((char **)NULL)
1260-
12611256 /*
12621257 * Description of a command or an operation on commands.
12631258 */
@@ -1326,6 +1321,7 @@ struct op {
13261321 #define CPAT 11 /* close pattern: ) */
13271322 #define ADELIM 12 /* arbitrary delimiter: ${foo:2:3} ${foo/bar/baz} */
13281323 #define FUNSUB 14 /* ${ foo;} substitution (NUL terminated) */
1324+#define VALSUB 15 /* ${|foo;} substitution (NUL terminated) */
13291325
13301326 /*
13311327 * IO redirection
@@ -1680,7 +1676,7 @@ void x_init(void);
16801676 #ifdef DEBUG_LEAKS
16811677 void x_done(void);
16821678 #endif
1683-int x_read(char *, size_t);
1679+int x_read(char *);
16841680 #endif
16851681 void x_mkraw(int, mksh_ttyst *, bool);
16861682 /* eval.c */
@@ -1834,8 +1830,7 @@ void yyerror(const char *, ...)
18341830 MKSH_A_FORMAT(__printf__, 1, 2);
18351831 Source *pushs(int, Area *);
18361832 void set_prompt(int, Source *);
1837-void pprompt(const char *, int);
1838-int promptlen(const char *);
1833+int pprompt(const char *, int);
18391834 /* main.c */
18401835 int include(const char *, int, const char **, bool);
18411836 int command(const char *, int);
@@ -1903,6 +1898,7 @@ void initctypes(void);
19031898 size_t option(const char *);
19041899 char *getoptions(void);
19051900 void change_flag(enum sh_flag, int, bool);
1901+void change_xtrace(unsigned char, bool);
19061902 int parse_args(const char **, int, bool *);
19071903 int getn(const char *, int *);
19081904 int gmatchx(const char *, const char *, bool);
@@ -2011,7 +2007,7 @@ char *arrayname(const char *);
20112007 mksh_uari_t set_array(const char *, bool, const char **);
20122008 uint32_t hash(const void *);
20132009 mksh_ari_t rndget(void);
2014-void rndset(long);
2010+void rndset(unsigned long);
20152011
20162012 enum Test_op {
20172013 /* non-operator */
--- a/src/sh_flags.h
+++ b/src/sh_flags.h
@@ -1,11 +1,22 @@
11 #if defined(SHFLAGS_DEFNS)
2-__RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.12 2012/06/28 20:14:17 tg Exp $");
3-#define FN(sname,cname,ochar,flags) /* nothing */
2+__RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.16 2013/08/11 14:57:11 tg Exp $");
3+#define FN(sname,cname,ochar,flags) \
4+ static const struct { \
5+ /* character flag (if any) */ \
6+ char c; \
7+ /* OF_* */ \
8+ unsigned char optflags; \
9+ /* long name of option */ \
10+ char name[sizeof(sname)]; \
11+ } shoptione_ ## cname = { \
12+ ochar, flags, sname \
13+ };
414 #elif defined(SHFLAGS_ENUMS)
515 #define FN(sname,cname,ochar,flags) cname,
616 #define F0(sname,cname,ochar,flags) cname = 0,
717 #elif defined(SHFLAGS_ITEMS)
8-#define FN(sname,cname,ochar,flags) { sname, ochar, flags },
18+#define FN(sname,cname,ochar,flags) \
19+ ((const char *)(&shoptione_ ## cname)) + 2,
920 #endif
1021
1122 #ifndef F0
@@ -45,6 +56,9 @@ FN("gmacs", FGMACS, 0, OF_ANY)
4556 /* ./. reading EOF does not exit */
4657 FN("ignoreeof", FIGNOREEOF, 0, OF_ANY)
4758
59+/* ./. inherit -x flag */
60+FN("inherit-xtrace", FXTRACEREC, 0, OF_ANY)
61+
4862 /* -i interactive shell */
4963 FN("interactive", FTALKING, 'i', OF_CMDLINE)
5064
@@ -88,7 +102,10 @@ FN("nounset", FNOUNSET, 'u', OF_ANY)
88102 /* ./. don't do logical cds/pwds (non-standard) */
89103 FN("physical", FPHYSICAL, 0, OF_ANY)
90104
91-/* ./. pdksh compat: somewhat more POSIXish mode (non-standard) */
105+/* ./. errorlevel of a pipeline is the rightmost nonzero value */
106+FN("pipefail", FPIPEFAIL, 0, OF_ANY)
107+
108+/* ./. adhere more closely to POSIX even when undesirable */
92109 FN("posix", FPOSIX, 0, OF_ANY)
93110
94111 /* -p use suid_profile; privileged shell */
@@ -97,7 +114,7 @@ FN("privileged", FPRIVILEGED, 'p', OF_ANY)
97114 /* -r restricted shell */
98115 FN("restricted", FRESTRICTED, 'r', OF_CMDLINE)
99116
100-/* ./. pdksh compat: called as sh not mksh; kludge mode (non-standard) */
117+/* ./. kludge mode for better compat with traditional sh (OS-specific) */
101118 FN("sh", FSH, 0, OF_ANY)
102119
103120 /* -s (invocation) parse stdin (pseudo non-standard) */
@@ -130,17 +147,17 @@ FN("viraw", FVIRAW, 0, OF_ANY)
130147 FN("xtrace", FXTRACE, 'x', OF_ANY)
131148
132149 /* -c (invocation) execute specified command */
133-FN(NULL, FCOMMAND, 'c', OF_CMDLINE)
150+FN("", FCOMMAND, 'c', OF_CMDLINE)
134151
135152 /*
136153 * anonymous flags: used internally by shell only (not visible to user)
137154 */
138155
139156 /* ./. direct builtin call (divined from argv[0] multi-call binary) */
140-FN(NULL, FAS_BUILTIN, 0, OF_INTERNAL)
157+FN("", FAS_BUILTIN, 0, OF_INTERNAL)
141158
142159 /* ./. (internal) initial shell was interactive */
143-FN(NULL, FTALKING_I, 0, OF_INTERNAL)
160+FN("", FTALKING_I, 0, OF_INTERNAL)
144161
145162 #undef FN
146163 #undef F0
--- a/src/shf.c
+++ b/src/shf.c
@@ -1,7 +1,8 @@
1-/* $OpenBSD: shf.c,v 1.15 2006/04/02 00:48:33 deraadt Exp $ */
1+/* $OpenBSD: shf.c,v 1.16 2013/04/19 17:36:09 millert Exp $ */
22
33 /*-
4- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012
4+ * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
5+ * 2012, 2013
56 * Thorsten Glaser <tg@mirbsd.org>
67 *
78 * Provided that these terms and disclaimer and all copyright notices
@@ -24,7 +25,7 @@
2425
2526 #include "sh.h"
2627
27-__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.56 2013/01/01 03:32:44 tg Exp $");
28+__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.61 2013/07/21 18:36:03 tg Exp $");
2829
2930 /* flags to shf_emptybuf() */
3031 #define EB_READSW 0x01 /* about to switch to reading */
@@ -51,7 +52,7 @@ shf_open(const char *name, int oflags, int mode, int sflags)
5152 ssize_t bsize =
5253 /* at most 512 */
5354 sflags & SHF_UNBUF ? (sflags & SHF_RD ? 1 : 0) : SHF_BSIZE;
54- int fd;
55+ int fd, eno;
5556
5657 /* Done before open so if alloca fails, fd won't be lost. */
5758 shf = alloc(sizeof(struct shf) + bsize, ATEMP);
@@ -63,16 +64,20 @@ shf_open(const char *name, int oflags, int mode, int sflags)
6364
6465 fd = open(name, oflags, mode);
6566 if (fd < 0) {
67+ eno = errno;
6668 afree(shf, shf->areap);
69+ errno = eno;
6770 return (NULL);
6871 }
6972 if ((sflags & SHF_MAPHI) && fd < FDBASE) {
7073 int nfd;
7174
7275 nfd = fcntl(fd, F_DUPFD, FDBASE);
76+ eno = errno;
7377 close(fd);
7478 if (nfd < 0) {
7579 afree(shf, shf->areap);
80+ errno = eno;
7681 return (NULL);
7782 }
7883 fd = nfd;
@@ -740,8 +745,6 @@ shf_smprintf(const char *fmt, ...)
740745 return (shf_sclose(&shf));
741746 }
742747
743-#define BUF_SIZE 128
744-
745748 #define FL_HASH 0x001 /* '#' seen */
746749 #define FL_PLUS 0x002 /* '+' seen */
747750 #define FL_RIGHT 0x004 /* '-' seen */
@@ -985,6 +988,10 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
985988 case 's':
986989 if ((s = VA(const char *)) == NULL)
987990 s = "(null)";
991+ else if (flags & FL_HASH) {
992+ print_value_quoted(shf, s);
993+ continue;
994+ }
988995 len = utf_mbswidth(s);
989996 break;
990997
--- a/src/syn.c
+++ b/src/syn.c
@@ -1,8 +1,8 @@
1-/* $OpenBSD: syn.c,v 1.28 2008/07/23 16:34:38 jaredy Exp $ */
1+/* $OpenBSD: syn.c,v 1.29 2013/06/03 18:40:05 jca Exp $ */
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
5- * 2011, 2012
5+ * 2011, 2012, 2013
66 * Thorsten Glaser <tg@mirbsd.org>
77 *
88 * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
2323
2424 #include "sh.h"
2525
26-__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.88 2012/12/28 02:28:39 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.92 2013/06/03 22:28:17 tg Exp $");
2727
2828 struct nesting_state {
2929 int start_token; /* token than began nesting (eg, FOR) */
@@ -53,7 +53,7 @@ static struct op *caselist(void);
5353 static struct op *casepart(int);
5454 static struct op *function_body(char *, bool);
5555 static char **wordlist(void);
56-static struct op *block(int, struct op *, struct op *, char **);
56+static struct op *block(int, struct op *, struct op *);
5757 static struct op *newtp(int);
5858 static void syntaxerr(const char *) MKSH_A_NORETURN;
5959 static void nesting_push(struct nesting_state *, int);
@@ -108,9 +108,9 @@ pipeline(int cf)
108108 if ((p = get_command(CONTIN)) == NULL)
109109 syntaxerr(NULL);
110110 if (tl == NULL)
111- t = tl = block(TPIPE, t, p, NOWORDS);
111+ t = tl = block(TPIPE, t, p);
112112 else
113- tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
113+ tl = tl->right = block(TPIPE, tl->right, p);
114114 }
115115 REJECT;
116116 }
@@ -128,7 +128,7 @@ andor(void)
128128 while ((c = token(0)) == LOGAND || c == LOGOR) {
129129 if ((p = pipeline(CONTIN)) == NULL)
130130 syntaxerr(NULL);
131- t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
131+ t = block(c == LOGAND? TAND: TOR, t, p);
132132 }
133133 REJECT;
134134 }
@@ -157,16 +157,15 @@ c_list(bool multi)
157157 } else if (!p)
158158 break;
159159 else if (c == '&' || c == COPROC)
160- p = block(c == '&' ? TASYNC : TCOPROC,
161- p, NOBLOCK, NOWORDS);
160+ p = block(c == '&' ? TASYNC : TCOPROC, p, NULL);
162161 else if (c != ';')
163162 have_sep = false;
164163 if (!t)
165164 t = p;
166165 else if (!tl)
167- t = tl = block(TLIST, t, p, NOWORDS);
166+ t = tl = block(TLIST, t, p);
168167 else
169- tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
168+ tl = tl->right = block(TLIST, tl->right, p);
170169 if (!have_sep)
171170 break;
172171 }
@@ -240,11 +239,11 @@ nested(int type, int smark, int emark)
240239 t = c_list(true);
241240 musthave(emark, KEYWORD|sALIAS);
242241 nesting_pop(&old_nesting);
243- return (block(type, t, NOBLOCK, NOWORDS));
242+ return (block(type, t, NULL));
244243 }
245244
246245 static const char let_cmd[] = {
247- CHAR, 'l', CHAR, 'e', CHAR, 't', EOS
246+ CHAR, 'l', CHAR, 'e', CHAR, 't', CHAR, ']', EOS
248247 };
249248 static const char setA_cmd0[] = {
250249 CHAR, 's', CHAR, 'e', CHAR, 't', EOS
@@ -465,7 +464,7 @@ get_command(int cf)
465464 t = pipeline(0);
466465 if (t == NULL)
467466 syntaxerr(NULL);
468- t = block(TBANG, NOBLOCK, t, NOWORDS);
467+ t = block(TBANG, NULL, t);
469468 break;
470469
471470 case TIME:
@@ -477,7 +476,7 @@ get_command(int cf)
477476 t->str[0] = '\0';
478477 t->str[1] = '\0';
479478 }
480- t = block(TTIME, t, NOBLOCK, NOWORDS);
479+ t = block(TTIME, t, NULL);
481480 break;
482481
483482 case FUNCTION:
@@ -505,7 +504,7 @@ get_command(int cf)
505504 XPput(args, NULL);
506505 t->args = (const char **)XPclose(args);
507506 XPput(vars, NULL);
508- t->vars = (char **) XPclose(vars);
507+ t->vars = (char **)XPclose(vars);
509508 } else {
510509 XPfree(args);
511510 XPfree(vars);
@@ -632,7 +631,7 @@ casepart(int endtok)
632631 } while (token(0) == '|');
633632 REJECT;
634633 XPput(ptns, NULL);
635- t->vars = (char **) XPclose(ptns);
634+ t->vars = (char **)XPclose(ptns);
636635 musthave(')', 0);
637636
638637 t->left = c_list(true);
@@ -743,13 +742,8 @@ wordlist(void)
743742 XPput(args, yylval.cp);
744743 if (c != '\n' && c != ';')
745744 syntaxerr(NULL);
746- if (XPsize(args) == 0) {
747- XPfree(args);
748- return (NULL);
749- } else {
750- XPput(args, NULL);
751- return ((char **)XPclose(args));
752- }
745+ XPput(args, NULL);
746+ return ((char **)XPclose(args));
753747 }
754748
755749 /*
@@ -757,14 +751,13 @@ wordlist(void)
757751 */
758752
759753 static struct op *
760-block(int type, struct op *t1, struct op *t2, char **wp)
754+block(int type, struct op *t1, struct op *t2)
761755 {
762756 struct op *t;
763757
764758 t = newtp(type);
765759 t->left = t1;
766760 t->right = t2;
767- t->vars = wp;
768761 return (t);
769762 }
770763
@@ -1131,7 +1124,7 @@ yyrecursive(int subtype MKSH_A_UNUSED)
11311124 struct yyrecursive_state *ys;
11321125 int stok, etok;
11331126
1134- if (subtype == FUNSUB) {
1127+ if (subtype != COMSUB) {
11351128 stok = '{';
11361129 etok = '}';
11371130 } else {
--- a/src/tree.c
+++ b/src/tree.c
@@ -2,7 +2,7 @@
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5- * 2011, 2012
5+ * 2011, 2012, 2013
66 * Thorsten Glaser <tg@mirbsd.org>
77 *
88 * Provided that these terms and disclaimer and all copyright notices
@@ -23,12 +23,12 @@
2323
2424 #include "sh.h"
2525
26-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.67 2012/12/04 01:10:35 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.71 2013/07/26 20:33:24 tg Exp $");
2727
2828 #define INDENT 8
2929
3030 static void ptree(struct op *, int, struct shf *);
31-static void pioact(struct shf *, int, struct ioword *);
31+static void pioact(struct shf *, struct ioword *);
3232 static const char *wdvarput(struct shf *, const char *, int, int);
3333 static void vfptreef(struct shf *, int, const char *, va_list);
3434 static struct ioword **iocopy(struct ioword **, Area *);
@@ -214,7 +214,7 @@ ptree(struct op *t, int indent, struct shf *shf)
214214 bool need_nl = false;
215215
216216 while (*ioact != NULL)
217- pioact(shf, indent, *ioact++);
217+ pioact(shf, *ioact++);
218218 /* Print here documents after everything else... */
219219 ioact = t->ioact;
220220 while (*ioact != NULL) {
@@ -244,7 +244,7 @@ ptree(struct op *t, int indent, struct shf *shf)
244244 }
245245
246246 static void
247-pioact(struct shf *shf, int indent, struct ioword *iop)
247+pioact(struct shf *shf, struct ioword *iop)
248248 {
249249 int flag = iop->flag;
250250 int type = flag & IOTYPE;
@@ -259,16 +259,20 @@ pioact(struct shf *shf, int indent, struct ioword *iop)
259259
260260 switch (type) {
261261 case IOREAD:
262- shf_puts("<", shf);
262+ shf_putc('<', shf);
263263 break;
264264 case IOHERE:
265- shf_puts(flag & IOSKIP ? "<<-" : "<<", shf);
265+ shf_puts("<<", shf);
266+ if (flag & IOSKIP)
267+ shf_putc('-', shf);
266268 break;
267269 case IOCAT:
268270 shf_puts(">>", shf);
269271 break;
270272 case IOWRITE:
271- shf_puts(flag & IOCLOB ? ">|" : ">", shf);
273+ shf_putc('>', shf);
274+ if (flag & IOCLOB)
275+ shf_putc('|', shf);
272276 break;
273277 case IORDWR:
274278 shf_puts("<>", shf);
@@ -283,9 +287,13 @@ pioact(struct shf *shf, int indent, struct ioword *iop)
283287 wdvarput(shf, iop->delim, 0, WDS_TPUTS);
284288 if (iop->flag & IOHERESTR)
285289 shf_putc(' ', shf);
286- } else if (iop->name)
287- fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
288- iop->name);
290+ } else if (iop->name) {
291+ if (iop->flag & IONAMEXP)
292+ print_value_quoted(shf, iop->name);
293+ else
294+ wdvarput(shf, iop->name, 0, WDS_TPUTS);
295+ shf_putc(' ', shf);
296+ }
289297 prevent_semicolon = false;
290298 }
291299
@@ -345,7 +353,14 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
345353 shf_puts(cs, shf);
346354 break;
347355 case FUNSUB:
348- shf_puts("${ ", shf);
356+ c = ' ';
357+ if (0)
358+ /* FALLTHROUGH */
359+ case VALSUB:
360+ c = '|';
361+ shf_putc('$', shf);
362+ shf_putc('{', shf);
363+ shf_putc(c, shf);
349364 cs = ";}";
350365 goto pSUB;
351366 case EXPRSUB:
@@ -485,7 +500,7 @@ vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
485500 break;
486501 case 'R':
487502 /* I/O redirection */
488- pioact(shf, indent, va_arg(va, struct ioword *));
503+ pioact(shf, va_arg(va, struct ioword *));
489504 break;
490505 default:
491506 shf_putc(c, shf);
@@ -588,6 +603,7 @@ wdscan(const char *wp, int c)
588603 break;
589604 case COMSUB:
590605 case FUNSUB:
606+ case VALSUB:
591607 case EXPRSUB:
592608 while (*wp++ != 0)
593609 ;
@@ -745,8 +761,8 @@ vistree(char *dst, size_t sz, struct op *t)
745761 char *cp, *buf;
746762 size_t n;
747763
748- buf = alloc(sz + 8, ATEMP);
749- snptreef(buf, sz + 8, "%T", t);
764+ buf = alloc(sz + 16, ATEMP);
765+ snptreef(buf, sz + 16, "%T", t);
750766 cp = buf;
751767 vist_loop:
752768 if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
@@ -830,6 +846,9 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
830846 case FUNSUB:
831847 shf_puts("FUNSUB<", shf);
832848 goto dumpsub;
849+ case VALSUB:
850+ shf_puts("VALSUB<", shf);
851+ goto dumpsub;
833852 case EXPRSUB:
834853 shf_puts("EXPRSUB<", shf);
835854 goto dumpsub;
--- a/src/var.c
+++ b/src/var.c
@@ -1,4 +1,4 @@
1-/* $OpenBSD: var.c,v 1.34 2007/10/15 02:16:35 deraadt Exp $ */
1+/* $OpenBSD: var.c,v 1.35 2013/04/05 01:31:30 tedu Exp $ */
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -27,7 +27,7 @@
2727 #include <sys/sysctl.h>
2828 #endif
2929
30-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.166 2013/02/18 22:24:52 tg Exp $");
30+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.173 2013/05/31 22:47:14 tg Exp $");
3131
3232 /*-
3333 * Variables
@@ -49,7 +49,7 @@ static void unspecial(const char *);
4949 static void getspec(struct tbl *);
5050 static void setspec(struct tbl *);
5151 static void unsetspec(struct tbl *);
52-static int getint(struct tbl *, mksh_ari_t *, bool);
52+static int getint(struct tbl *, mksh_ari_u *, bool);
5353 static const char *array_index_calc(const char *, bool *, uint32_t *);
5454
5555 /*
@@ -347,7 +347,7 @@ str_val(struct tbl *vp)
347347 else {
348348 /* integer source */
349349 mksh_uari_t n;
350- int base;
350+ unsigned int base;
351351 /**
352352 * worst case number length is when base == 2:
353353 * 1 (minus) + 2 (base, up to 36) + 1 ('#') +
@@ -361,8 +361,8 @@ str_val(struct tbl *vp)
361361 if (vp->flag & INT_U)
362362 n = vp->val.u;
363363 else
364- n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
365- base = (vp->type == 0) ? 10 : vp->type;
364+ n = (vp->val.i < 0) ? -vp->val.u : vp->val.u;
365+ base = (vp->type == 0) ? 10U : (unsigned int)vp->type;
366366
367367 if (base == 1 && n == 0)
368368 base = 2;
@@ -471,48 +471,43 @@ setint(struct tbl *vq, mksh_ari_t n)
471471 }
472472
473473 static int
474-getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
474+getint(struct tbl *vp, mksh_ari_u *nump, bool arith)
475475 {
476- int c, base, neg;
477- mksh_uari_t num;
476+ mksh_uari_t c, num, base;
478477 const char *s;
479- bool have_base = false;
478+ bool have_base = false, neg = false;
480479
481480 if (vp->flag&SPECIAL)
482481 getspec(vp);
483- /* XXX is it possible for ISSET to be set and val.s to be 0? */
482+ /* XXX is it possible for ISSET to be set and val.s to be NULL? */
484483 if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
485484 return (-1);
486485 if (vp->flag&INTEGER) {
487- *nump = vp->val.i;
486+ nump->i = vp->val.i;
488487 return (vp->type);
489488 }
490489 s = vp->val.s + vp->type;
491490 base = 10;
492491 num = 0;
493- neg = 0;
494492 if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') {
495493 s += 2;
496494 base = 16;
497495 have_base = true;
498496 }
499-#ifdef MKSH_LEGACY_MODE
500- if (arith && s[0] == '0' && ksh_isdigit(s[1]) &&
497+ if (Flag(FPOSIX) && arith && s[0] == '0' && ksh_isdigit(s[1]) &&
501498 !(vp->flag & ZEROFIL)) {
502499 /* interpret as octal (deprecated) */
503500 base = 8;
504501 have_base = true;
505502 }
506-#endif
507503 while ((c = *s++)) {
508504 if (c == '-') {
509- neg++;
505+ neg = true;
510506 continue;
511507 } else if (c == '#') {
512508 if (have_base || num < 1 || num > 36)
513509 return (-1);
514- base = (int)num;
515- if (base == 1) {
510+ if ((base = num) == 1) {
516511 unsigned int wc;
517512
518513 if (!UTFMODE)
@@ -525,7 +520,7 @@ getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
525520 * not round-tripping correctly XXX)
526521 */
527522 wc = 0xEF00 + *(const unsigned char *)s;
528- *nump = (mksh_ari_t)wc;
523+ nump->u = (mksh_uari_t)wc;
529524 return (1);
530525 }
531526 num = 0;
@@ -539,11 +534,13 @@ getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
539534 c -= 'A' - 10;
540535 else
541536 return (-1);
542- if (c < 0 || c >= base)
537+ if (c >= base)
543538 return (-1);
544539 num = num * base + c;
545540 }
546- *nump = neg ? -((mksh_ari_t)num) : (mksh_ari_t)num;
541+ if (neg)
542+ num = -num;
543+ nump->u = num;
547544 return (base);
548545 }
549546
@@ -555,11 +552,11 @@ struct tbl *
555552 setint_v(struct tbl *vq, struct tbl *vp, bool arith)
556553 {
557554 int base;
558- mksh_ari_t num;
555+ mksh_ari_u num;
559556
560557 if ((base = getint(vp, &num, arith)) == -1)
561558 return (NULL);
562- setint_n(vq, num, 0);
559+ setint_n(vq, num.i, 0);
563560 if (vq->type == 0)
564561 /* default base */
565562 vq->type = base;
@@ -708,6 +705,10 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
708705
709706 /* check for valid variable name, search for value */
710707 val = skip_varname(var, false);
708+ if (val == var) {
709+ /* no variable name given */
710+ return (NULL);
711+ }
711712 if (*val == '[') {
712713 if (set_refflag != SRF_NOP)
713714 errorf("%s: %s", var,
@@ -742,7 +743,6 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
742743 * must have a = when setting a variable by importing
743744 * the original environment, otherwise be empty; we
744745 * also end up here when a variable name was invalid
745- * or none given
746746 */
747747 return (NULL);
748748 } else {
@@ -768,10 +768,15 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
768768 if (vp != NULL)
769769 qval = str_val(vp);
770770 }
771- /* silently ignore 'nameref foo=foo' */
772- if (qval != NULL && !strcmp(qval, tvar)) {
773- afree(tvar, ATEMP);
774- return (&vtemp);
771+ /* prevent nameref loops */
772+ while (qval) {
773+ if (!strcmp(qval, tvar))
774+ errorf("%s: %s", qval,
775+ "expression recurses on parameter");
776+ varsearch(e->loc, &vp, qval, hash(qval));
777+ qval = NULL;
778+ if (vp && ((vp->flag & (ARRAY|ASSOC)) == ASSOC))
779+ qval = str_val(vp);
775780 }
776781 }
777782
@@ -1094,7 +1099,7 @@ static int user_lineno; /* what user set $LINENO to */
10941099 static void
10951100 getspec(struct tbl *vp)
10961101 {
1097- register mksh_ari_t i;
1102+ mksh_ari_u num;
10981103 int st;
10991104 struct timeval tv;
11001105
@@ -1114,19 +1119,19 @@ getspec(struct tbl *vp)
11141119 }
11151120 switch (st) {
11161121 case V_BASHPID:
1117- i = (mksh_ari_t)procpid;
1122+ num.u = (mksh_uari_t)procpid;
11181123 break;
11191124 case V_COLUMNS:
1120- i = x_cols;
1125+ num.i = x_cols;
11211126 break;
11221127 case V_HISTSIZE:
1123- i = histsize;
1128+ num.i = histsize;
11241129 break;
11251130 case V_LINENO:
1126- i = current_lineno + user_lineno;
1131+ num.i = current_lineno + user_lineno;
11271132 break;
11281133 case V_LINES:
1129- i = x_lins;
1134+ num.i = x_lins;
11301135 break;
11311136 case V_EPOCHREALTIME: {
11321137 /* 10(%u) + 1(.) + 6 + NUL */
@@ -1141,10 +1146,10 @@ getspec(struct tbl *vp)
11411146 return;
11421147 }
11431148 case V_OPTIND:
1144- i = user_opt.uoptind;
1149+ num.i = user_opt.uoptind;
11451150 break;
11461151 case V_RANDOM:
1147- i = rndget();
1152+ num.i = rndget();
11481153 break;
11491154 case V_SECONDS:
11501155 /*
@@ -1154,7 +1159,7 @@ getspec(struct tbl *vp)
11541159 */
11551160 if (vp->flag & ISSET) {
11561161 mksh_TIME(tv);
1157- i = tv.tv_sec - seconds;
1162+ num.i = tv.tv_sec - seconds;
11581163 } else
11591164 return;
11601165 break;
@@ -1163,14 +1168,14 @@ getspec(struct tbl *vp)
11631168 return;
11641169 }
11651170 vp->flag &= ~SPECIAL;
1166- setint_n(vp, i, 0);
1171+ setint_n(vp, num.i, 0);
11671172 vp->flag |= SPECIAL;
11681173 }
11691174
11701175 static void
11711176 setspec(struct tbl *vp)
11721177 {
1173- mksh_ari_t i;
1178+ mksh_ari_u num;
11741179 char *s;
11751180 int st;
11761181
@@ -1228,11 +1233,11 @@ setspec(struct tbl *vp)
12281233 case V_SECONDS:
12291234 case V_TMOUT:
12301235 vp->flag &= ~SPECIAL;
1231- if (getint(vp, &i, false) == -1) {
1236+ if (getint(vp, &num, false) == -1) {
12321237 s = str_val(vp);
12331238 if (st != V_RANDOM)
12341239 errorf("%s: %s: %s", vp->name, "bad number", s);
1235- i = hash(s);
1240+ num.u = hash(s);
12361241 }
12371242 vp->flag |= SPECIAL;
12381243 break;
@@ -1245,40 +1250,40 @@ setspec(struct tbl *vp)
12451250
12461251 switch (st) {
12471252 case V_COLUMNS:
1248- if (i >= MIN_COLS)
1249- x_cols = i;
1253+ if (num.i >= MIN_COLS)
1254+ x_cols = num.i;
12501255 break;
12511256 case V_HISTSIZE:
1252- sethistsize(i);
1257+ sethistsize(num.i);
12531258 break;
12541259 case V_LINENO:
12551260 /* The -1 is because line numbering starts at 1. */
1256- user_lineno = (unsigned int)i - current_lineno - 1;
1261+ user_lineno = num.u - current_lineno - 1;
12571262 break;
12581263 case V_LINES:
1259- if (i >= MIN_LINS)
1260- x_lins = i;
1264+ if (num.i >= MIN_LINS)
1265+ x_lins = num.i;
12611266 break;
12621267 case V_OPTIND:
1263- getopts_reset((int)i);
1268+ getopts_reset((int)num.i);
12641269 break;
12651270 case V_RANDOM:
12661271 /*
12671272 * mksh R39d+ no longer has the traditional repeatability
12681273 * of $RANDOM sequences, but always retains state
12691274 */
1270- rndset((long)i);
1275+ rndset((unsigned long)num.u);
12711276 break;
12721277 case V_SECONDS:
12731278 {
12741279 struct timeval tv;
12751280
12761281 mksh_TIME(tv);
1277- seconds = tv.tv_sec - i;
1282+ seconds = tv.tv_sec - num.i;
12781283 }
12791284 break;
12801285 case V_TMOUT:
1281- ksh_tmout = i >= 0 ? i : 0;
1286+ ksh_tmout = num.i >= 0 ? num.i : 0;
12821287 break;
12831288 }
12841289 }
@@ -1534,7 +1539,7 @@ rndget(void)
15341539 }
15351540
15361541 void
1537-rndset(long v)
1542+rndset(unsigned long v)
15381543 {
15391544 register uint32_t h;
15401545
Show on old repository browser