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