Update to mksh R48
Change-Id: I4d1bef9bf8ddc7899cfb32a6f2fa9e6f632bc53f
This commit is contained in:
parent
f8c396c4d4
commit
811a575c0f
26 changed files with 2713 additions and 1377 deletions
|
@ -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)
|
||||
|
|
15
mkmf.sh
15
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
|
||||
|
|
40
mkshrc
40
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 {
|
||||
|
|
385
src/Build.sh
385
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
|
||||
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
|
||||
;;
|
||||
kencc)
|
||||
save_NOWARN=
|
||||
DOWARN=
|
||||
;;
|
||||
mipspro)
|
||||
save_NOWARN=
|
||||
DOWARN="-diag_error 1-10000"
|
||||
;;
|
||||
msc)
|
||||
save_NOWARN="${ccpc}/w"
|
||||
DOWARN="${ccpc}/WX"
|
||||
;;
|
||||
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"
|
||||
elif test $ct = hpcc; then
|
||||
save_NOWARN=
|
||||
DOWARN=+We
|
||||
elif test $ct = mipspro; then
|
||||
save_NOWARN=
|
||||
DOWARN="-diag_error 1-10000"
|
||||
elif test $ct = msc; then
|
||||
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
|
||||
;;
|
||||
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
|
||||
|
@ -1956,71 +2014,6 @@ EOF
|
|||
esac
|
||||
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)
|
||||
#
|
||||
|
@ -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
|
||||
|
|
38
src/check.pl
38
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;
|
||||
|
|
622
src/check.t
622
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:
|
||||
/.*/
|
||||
---
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
338
src/edit.c
338
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 (prompt_trunc != -1)
|
||||
pprompt(prompt, prompt_trunc);
|
||||
x_col = pwidth;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
x_init_prompt();
|
||||
x_col = pwidth;
|
||||
|
||||
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;
|
||||
|
||||
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 *)¯o, 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);
|
||||
|
|
225
src/eval.c
225
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);
|
||||
}
|
||||
|
|
111
src/exec.c
111
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;
|
||||
}
|
||||
}
|
||||
|
|
885
src/expr.c
885
src/expr.c
File diff suppressed because it is too large
Load diff
94
src/funcs.c
94
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},
|
||||
{Tsgexport, c_typeset},
|
||||
{"false", c_false},
|
||||
{"fc", c_fc},
|
||||
{"getopts", c_getopts},
|
||||
{"=global", c_typeset},
|
||||
{"jobs", c_jobs},
|
||||
{"kill", c_kill},
|
||||
{"let", c_let},
|
||||
{"let]", c_let},
|
||||
{"print", c_print},
|
||||
{"pwd", c_pwd},
|
||||
{"read", c_read},
|
||||
{Tsgreadonly, c_typeset},
|
||||
{"realpath", c_realpath},
|
||||
{"rename", c_rename},
|
||||
{"*=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},
|
||||
{"=global", c_typeset},
|
||||
{"+jobs", c_jobs},
|
||||
{"+kill", c_kill},
|
||||
{"let", c_let},
|
||||
{"print", c_print},
|
||||
#ifdef MKSH_PRINTF_BUILTIN
|
||||
{"printf", c_printf},
|
||||
#endif
|
||||
{"pwd", c_pwd},
|
||||
{Tsgreadonly, c_typeset},
|
||||
{"*=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);
|
||||
}
|
||||
|
||||
|
|
39
src/jobs.c
39
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
63
src/lex.c
63
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).
|
||||
|
|
297
src/lksh.1
Normal file
297
src/lksh.1
Normal file
|
@ -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 .
|
72
src/main.c
72
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,10 +262,19 @@ 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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -1005,6 +1031,10 @@ quitenv(struct shf *shf)
|
|||
#ifdef DEBUG_LEAKS
|
||||
#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++)
|
||||
|
@ -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;
|
||||
|
|
252
src/misc.c
252
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);
|
||||
} else for (i = 0; i < NELEM(options); i++)
|
||||
if (options[i].name && strcmp(options[i].name, n) == 0)
|
||||
return (i);
|
||||
++i;
|
||||
}
|
||||
else
|
||||
while (i < NELEM(options)) {
|
||||
if (!strcmp(OFN(i), n))
|
||||
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
|
||||
|
|
204
src/mksh.1
204
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
|
||||
commands keeping assignments:
|
||||
.Pp
|
||||
.Ic builtin , global , times , typeset
|
||||
.Ic builtin , global , typeset , wait
|
||||
.Pp
|
||||
Very special commands
|
||||
.Pq non-POSIX
|
||||
Builtins that are not special:
|
||||
.Pp
|
||||
.Ic alias , readonly , set , typeset
|
||||
.Pp
|
||||
POSIX regular commands
|
||||
.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 ,
|
||||
|
|
BIN
src/mksh.ico
Normal file
BIN
src/mksh.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
66
src/sh.h
66
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 */
|
||||
|
|
|
@ -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
|
||||
|
|
19
src/shf.c
19
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;
|
||||
|
||||
|
|
47
src/syn.c
47
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 {
|
||||
|
|
49
src/tree.c
49
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;
|
||||
|
|
111
src/var.c
111
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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue