Update to mksh R48

Change-Id: I4d1bef9bf8ddc7899cfb32a6f2fa9e6f632bc53f
This commit is contained in:
Thorsten Glaser 2013-07-25 14:24:45 +00:00
parent f8c396c4d4
commit 811a575c0f
26 changed files with 2713 additions and 1377 deletions

View file

@ -37,6 +37,7 @@ LOCAL_C_INCLUDES:= $(LOCAL_PATH)/src
LOCAL_CFLAGS:= -DMKSHRC_PATH=\"/system/etc/mkshrc\" \
-DMKSH_DEFAULT_EXECSHELL=\"/system/bin/sh\" \
-DMKSH_DEFAULT_TMPDIR=\"/data/local\" \
-Wno-deprecated-declarations \
-fno-asynchronous-unwind-tables -fwrapv \
-DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_CONSERVATIVE_FDS \
-DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH \
@ -62,9 +63,8 @@ LOCAL_CFLAGS:= -DMKSHRC_PATH=\"/system/etc/mkshrc\" \
-DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 \
-DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \
-DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 \
-DHAVE_PERSISTENT_HISTORY=0 -DHAVE_SILENT_IDIVWRAPV=0 \
-DMKSH_BUILD_R=431
-DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=481
# check categories: shell:legacy-no int:32 android convfds no-histfile
# check_categories= shell:legacy-no int:32 android convfds no-histfile
include $(BUILD_EXECUTABLE)

15
mkmf.sh
View file

@ -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
View file

@ -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 {

View file

@ -1,5 +1,5 @@
#!/bin/sh
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.622 2013/02/19 18:45:15 tg Exp $'
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.645 2013/08/10 13:44:25 tg Exp $'
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013
@ -28,6 +28,9 @@ srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.622 2013/02/19 18:45:15 tg Exp $'
LC_ALL=C
export LC_ALL
echo "For the build logs, demonstrate that /dev/null and /dev/tty exist:"
ls -l /dev/null /dev/tty
case $ZSH_VERSION:$VERSION in
:zsh*) ZSH_VERSION=2 ;;
esac
@ -63,7 +66,7 @@ vq() {
rmf() {
for _f in "$@"; do
case $_f in
Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|mksh.1) ;;
Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|*.ico|*.1) ;;
*) rm -f "$_f" ;;
esac
done
@ -190,6 +193,7 @@ ac_testn() {
ac_ifcpp() {
expr=$1; shift
ac_testn "$@" <<-EOF
extern int thiswillneverbedefinedIhope(void);
int main(void) { return (
#$expr
0
@ -458,7 +462,7 @@ oswarn=
ccpc=-Wc,
ccpl=-Wl,
tsts=
ccpr='|| for _f in ${tcfn}*; do case $_f in Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|mksh.1) ;; *) rm -f "$_f" ;; esac; done'
ccpr='|| for _f in ${tcfn}*; do case $_f in Build.sh|check.pl|check.t|dot.mkshrc|*.c|*.h|*.ico|*.1) ;; *) rm -f "$_f" ;; esac; done'
# Evil hack
if test x"$TARGET_OS" = x"Android"; then
@ -686,8 +690,11 @@ Plan9)
add_cppflags -D_SUSV2_SOURCE
add_cppflags -DMKSH_ASSUME_UTF8; HAVE_ISSET_MKSH_ASSUME_UTF8=1
add_cppflags -DMKSH_NO_CMDLINE_EDITING
add_cppflags -DMKSH__NO_SETEUGID
oswarn=' and will currently not work'
add_cppflags -DMKSH_UNEMPLOYED
# this is for detecting kencc
add_cppflags -DMKSH_MAYBE_KENCC
;;
PW32*)
HAVE_SIG_T=0 # incompatible
@ -766,7 +773,7 @@ esac
: ${HAVE_MKNOD=0}
: ${AWK=awk} ${CC=cc} ${NROFF=nroff}
: ${AWK=awk} ${CC=cc} ${NROFF=nroff} ${SIZE=size}
test 0 = $r && echo | $NROFF -v 2>&1 | grep GNU >/dev/null 2>&1 && \
NROFF="$NROFF -c"
@ -876,6 +883,9 @@ ct="ucode"
ct="uslc"
#elif defined(__LCC__)
ct="lcc"
#elif defined(MKSH_MAYBE_KENCC)
/* and none of the above matches */
ct="kencc"
#else
ct="unknown"
#endif
@ -952,6 +962,9 @@ iar)
icc)
vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN $LIBS -V"
;;
kencc)
vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN -v conftest.c $LIBS"
;;
lcc)
vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN -v conftest.c $LIBS"
add_cppflags -D__inline__=__inline
@ -1074,19 +1087,23 @@ if ac_ifcpp 'if 0' compiler_fails '' \
'if the compiler does not fail correctly'; then
save_CFLAGS=$CFLAGS
: ${HAVE_CAN_DELEXE=x}
if test $ct = dmc; then
CFLAGS="$CFLAGS ${ccpl}/DELEXECUTABLE"
ac_testn can_delexe compiler_fails 0 'for the /DELEXECUTABLE linker option' <<-EOF
int main(void) { return (0); }
EOF
elif test $ct = dec; then
case $ct in
dec)
CFLAGS="$CFLAGS ${ccpl}-non_shared"
ac_testn can_delexe compiler_fails 0 'for the -non_shared linker option' <<-EOF
int main(void) { return (0); }
EOF
else
;;
dmc)
CFLAGS="$CFLAGS ${ccpl}/DELEXECUTABLE"
ac_testn can_delexe compiler_fails 0 'for the /DELEXECUTABLE linker option' <<-EOF
int main(void) { return (0); }
EOF
;;
*)
exit 1
fi
;;
esac
test 1 = $HAVE_CAN_DELEXE || CFLAGS=$save_CFLAGS
ac_testn compiler_still_fails '' 'if the compiler still does not fail correctly' <<-EOF
EOF
@ -1099,49 +1116,65 @@ if ac_ifcpp 'ifdef __TINYC__' couldbe_tcc '!' compiler_known 0 \
HAVE_COMPILER_KNOWN=1
fi
if test $ct = sunpro; then
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

View file

@ -1,7 +1,8 @@
# $MirOS: src/bin/mksh/check.pl,v 1.31 2012/04/06 12:22:14 tg Exp $
# $OpenBSD: th,v 1.13 2006/05/18 21:27:23 miod Exp $
# $MirOS: src/bin/mksh/check.pl,v 1.32 2013/07/21 18:35:56 tg Exp $
# $OpenBSD: th,v 1.16 2013/06/14 20:52:08 millert Exp $
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
# 2012, 2013
# Thorsten Glaser <tg@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
@ -171,13 +172,15 @@ BEGIN {
use Getopt::Std;
use Config;
use File::Temp qw/ :mktemp /;
$os = defined $^O ? $^O : 'unknown';
($prog = $0) =~ s#.*/##;
$Usage = <<EOF ;
Usage: $prog [-Pv] [-C cat] [-e e=v] [-p prog] [-s fn] [-t tmo] name ...
Usage: $prog [-Pv] [-C cat] [-e e=v] [-p prog] [-s fn] [-T dir] \
[-t tmo] name ...
-C c Specify the comma separated list of categories the program
belongs to (see category field).
-e e=v Set the environment variable e to v for all tests
@ -188,6 +191,7 @@ Usage: $prog [-Pv] [-C cat] [-e e=v] [-p prog] [-s fn] [-t tmo] name ...
-p p Use p as the program to test
-s s Read tests from file s; if s is a directory, it is recursively
scaned for test files (which end in .t).
-T dir Use dir instead of /tmp to hold temporary files
-t t Use t as default time limit for tests (default is unlimited)
-v Verbose mode: print reason test failed.
name specifies the name of the test(s) to run; if none are
@ -229,12 +233,6 @@ EOF
"os:$os", '1'
);
$temps = "/tmp/rts$$";
$tempi = "/tmp/rti$$";
$tempo = "/tmp/rto$$";
$tempe = "/tmp/rte$$";
$tempdir = "/tmp/rtd$$";
$nfailed = 0;
$nifailed = 0;
$nxfailed = 0;
@ -243,7 +241,7 @@ $nxpassed = 0;
%known_tests = ();
if (!getopts('C:e:Pp:s:t:v')) {
if (!getopts('C:e:Pp:s:T:t:v')) {
print STDERR $Usage;
exit 1;
}
@ -253,6 +251,7 @@ die "$prog: no test set specified (use -s)\n" if !defined $opt_s;
$test_prog = $opt_p;
$verbose = defined $opt_v && $opt_v;
$test_set = $opt_s;
$temp_dir = $opt_T || "/tmp";
if (defined $opt_t) {
die "$prog: bad -t argument (should be number > 0): $opt_t\n"
if $opt_t !~ /^\d+$/ || $opt_t <= 0;
@ -297,8 +296,6 @@ if (defined $opt_e) {
}
%old_env = %ENV;
die "$prog: couldn't make directory $tempdir - $!\n" if !mkdir($tempdir, 0777);
chop($pwd = `pwd 2>/dev/null`);
die "$prog: couldn't get current working directory\n" if $pwd eq '';
die "$prog: couldn't cd to $pwd - $!\n" if !chdir($pwd);
@ -316,6 +313,17 @@ $SIG{'ALRM'} = 'catch_sigalrm';
$| = 1;
# Create temp files
($fh, $temps) = mkstemp("${temp_dir}/rts.XXXXXXXX");
close($fh);
($fh, $tempi) = mkstemp("${temp_dir}/rti.XXXXXXXX");
close($fh);
($fh, $tempo) = mkstemp("${temp_dir}/rto.XXXXXXXX");
close($fh);
($fh, $tempe) = mkstemp("${temp_dir}/rte.XXXXXXXX");
close($fh);
$tempdir = mkdtemp("${temp_dir}/rtd.XXXXXXXX");
if (-d $test_set) {
$file_prefix_skip = length($test_set) + 1;
$ret = &process_test_dir($test_set);
@ -433,6 +441,8 @@ run_test
local(*test) = @_;
local($name) = $test{':full-name'};
return undef if !&scrub_dir($tempdir);
if (defined $test{'stdin'}) {
return undef if !&write_file($tempi, $test{'stdin'});
$ifile = $tempi;
@ -444,8 +454,6 @@ run_test
return undef if !&write_file($temps, $test{'script'});
}
return undef if !&scrub_dir($tempdir);
if (!chdir($tempdir)) {
print STDERR "$prog: couldn't cd to $tempdir - $!\n";
return undef;

View file

@ -1,7 +1,9 @@
# $MirOS: src/bin/mksh/check.t,v 1.597 2013/02/19 18:45:17 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.629 2013/08/14 20:26:15 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
# $OpenBSD: regress.t,v 1.15 2013/07/01 17:25:27 jca Exp $
# $OpenBSD: obsd-regress.t,v 1.5 2013/07/01 17:25:27 jca Exp $
#-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013
@ -29,7 +31,7 @@
# http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD
expected-stdout:
@(#)MIRBSD KSH R43 2013/02/19
@(#)MIRBSD KSH R48 2013/08/14
description:
Check version of shell.
stdin:
@ -38,7 +40,7 @@ name: KSH_VERSION
category: shell:legacy-no
---
expected-stdout:
@(#)LEGACY KSH R43 2013/02/19
@(#)LEGACY KSH R48 2013/08/14
description:
Check version of legacy shell.
stdin:
@ -290,6 +292,22 @@ stdin:
expected-stdout:
= 4 2 =
---
name: arith-lazy-4
description:
Check that preun/postun not done on non-evaluated side of ternary
operator
stdin:
(( m = n = 0, 1 ? n++ : m++ ? 2 : 3 ))
echo "($n, $m)"
m=0; echo $(( 0 ? ++m : 2 )); echo $m
m=0; echo $(( 0 ? m++ : 2 )); echo $m
expected-stdout:
(1, 0)
2
0
2
0
---
name: arith-ternary-prec-1
description:
Check precedence of ternary operator vs assignment
@ -363,30 +381,35 @@ expected-stdout:
---
name: arith-mandatory
description:
If MKSH_GCC55009 is set when compiling, passing of
this test is *mandatory* for a valid mksh executable!
Passing of this test is *mandatory* for a valid mksh executable!
category: shell:legacy-no
stdin:
typeset -i sari=0
typeset -Ui uari=0
typeset -i x=0
print -r -- $((x++)):$sari=$uari.
print -r -- $((x++)):$sari=$uari. #0
let --sari --uari
print -r -- $((x++)):$sari=$uari.
print -r -- $((x++)):$sari=$uari. #1
sari=2147483647 uari=2147483647
print -r -- $((x++)):$sari=$uari.
print -r -- $((x++)):$sari=$uari. #2
let ++sari ++uari
print -r -- $((x++)):$sari=$uari.
print -r -- $((x++)):$sari=$uari. #3
let --sari --uari
let 'sari *= 2' 'uari *= 2'
let ++sari ++uari
print -r -- $((x++)):$sari=$uari.
print -r -- $((x++)):$sari=$uari. #4
let ++sari ++uari
print -r -- $((x++)):$sari=$uari.
print -r -- $((x++)):$sari=$uari. #5
sari=-2147483648 uari=-2147483648
print -r -- $((x++)):$sari=$uari.
print -r -- $((x++)):$sari=$uari. #6
let --sari --uari
print -r -- $((x++)):$sari=$uari.
print -r -- $((x++)):$sari=$uari. #7
(( sari = -5 >> 1 ))
((# uari = -5 >> 1 ))
print -r -- $((x++)):$sari=$uari. #8
(( sari = -2 ))
((# uari = sari ))
print -r -- $((x++)):$sari=$uari. #9
expected-stdout:
0:0=0.
1:-1=4294967295.
@ -396,6 +419,8 @@ expected-stdout:
5:0=0.
6:-2147483648=2147483648.
7:2147483647=2147483647.
8:-3=2147483645.
9:-2=4294967294.
---
name: arith-unsigned-1
description:
@ -2530,30 +2555,6 @@ expected-stdout:
\END
end
---
name: heredoc-quoting-unsubst
description:
Check for correct handling of quoted characters in
here documents without substitution (marker is quoted).
stdin:
foo=bar
cat <<-'EOF'
x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
EOF
expected-stdout:
x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
---
name: heredoc-quoting-subst
description:
Check for correct handling of quoted characters in
here documents with substitution (marker is not quoted).
stdin:
foo=bar
cat <<-EOF
x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
EOF
expected-stdout:
x " \" \ \ $ $ baz `echo baz` bar $foo x
---
name: heredoc-tmpfile-1
description:
Check that heredoc temp files aren't removed too soon or too late.
@ -2736,6 +2737,131 @@ expected-stdout:
hi
Left overs: *
---
name: heredoc-quoting-unsubst
description:
Check for correct handling of quoted characters in
here documents without substitution (marker is quoted).
stdin:
foo=bar
cat <<-'EOF'
x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
EOF
expected-stdout:
x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
---
name: heredoc-quoting-subst
description:
Check for correct handling of quoted characters in
here documents with substitution (marker is not quoted).
stdin:
foo=bar
cat <<-EOF
x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
EOF
expected-stdout:
x " \" \ \ $ $ baz `echo baz` bar $foo x
---
name: single-quotes-in-braces
description:
Check that single quotes inside unquoted {} are treated as quotes
stdin:
foo=1
echo ${foo:+'blah $foo'}
expected-stdout:
blah $foo
---
name: single-quotes-in-quoted-braces
description:
Check that single quotes inside quoted {} are treated as
normal char
stdin:
foo=1
echo "${foo:+'blah $foo'}"
expected-stdout:
'blah 1'
---
name: single-quotes-in-braces-nested
description:
Check that single quotes inside unquoted {} are treated as quotes,
even if that's inside a double-quoted command expansion
stdin:
foo=1
echo "$( echo ${foo:+'blah $foo'})"
expected-stdout:
blah $foo
---
name: single-quotes-in-brace-pattern
description:
Check that single quotes inside {} pattern are treated as quotes
stdin:
foo=1234
echo ${foo%'2'*} "${foo%'2'*}" ${foo%2'*'} "${foo%2'*'}"
expected-stdout:
1 1 1234 1234
---
name: single-quotes-in-heredoc-braces
description:
Check that single quotes inside {} in heredoc are treated
as normal char
stdin:
foo=1
cat <<EOM
${foo:+'blah $foo'}
EOM
expected-stdout:
'blah 1'
---
name: single-quotes-in-nested-braces
description:
Check that single quotes inside nested unquoted {} are
treated as quotes
stdin:
foo=1
echo ${foo:+${foo:+'blah $foo'}}
expected-stdout:
blah $foo
---
name: single-quotes-in-nested-quoted-braces
description:
Check that single quotes inside nested quoted {} are treated
as normal char
stdin:
foo=1
echo "${foo:+${foo:+'blah $foo'}}"
expected-stdout:
'blah 1'
---
name: single-quotes-in-nested-braces-nested
description:
Check that single quotes inside nested unquoted {} are treated
as quotes, even if that's inside a double-quoted command expansion
stdin:
foo=1
echo "$( echo ${foo:+${foo:+'blah $foo'}})"
expected-stdout:
blah $foo
---
name: single-quotes-in-nested-brace-pattern
description:
Check that single quotes inside nested {} pattern are treated as quotes
stdin:
foo=1234
echo ${foo:+${foo%'2'*}} "${foo:+${foo%'2'*}}" ${foo:+${foo%2'*'}} "${foo:+${foo%2'*'}}"
expected-stdout:
1 1 1234 1234
---
name: single-quotes-in-heredoc-nested-braces
description:
Check that single quotes inside nested {} in heredoc are treated
as normal char
stdin:
foo=1
cat <<EOM
${foo:+${foo:+'blah $foo'}}
EOM
expected-stdout:
'blah 1'
---
name: history-basic
description:
See if we can test history at all
@ -3466,10 +3592,10 @@ stdin:
showargs 3 $@
showargs 4 "$@"
expected-stdout:
<1> <A B C>
<1> <A> <B> <C>
<2> <ABC>
<3> <A B C>
<4> <A B C>
<3> <A> <B> <C>
<4> <A> <B> <C>
---
name: IFS-space-colon-1
description:
@ -3772,22 +3898,17 @@ expected-stdout:
---
name: integer-base-check-flat
description:
Check behaviour does not match POSuX, because a not type-safe
scripting language has *no* business interpreting "010" as octal
category: shell:legacy-no
Check behaviour does not match POSuX (except if set -o posix),
because a not type-safe scripting language has *no* business
interpreting the string "010" as octal numer eight (dangerous).
stdin:
echo :$((10)).$((010)).$((0x10)).
echo 1 "$("$__progname" -c 'echo :$((10))/$((010)),$((0x10)):')" .
echo 2 "$("$__progname" -o posix -c 'echo :$((10))/$((010)),$((0x10)):')" .
echo 3 "$("$__progname" -o sh -c 'echo :$((10))/$((010)),$((0x10)):')" .
expected-stdout:
:10.10.16.
---
name: integer-base-check-flat-legacy
description:
Check behaviour matches POSuX for LEGACY KSH
category: shell:legacy-yes
stdin:
echo :$((10)).$((010)).$((0x10)).
expected-stdout:
:10.8.16.
1 :10/10,16: .
2 :10/8,16: .
3 :10/10,16: .
---
name: integer-base-check-numeric-from
description:
@ -3913,6 +4034,13 @@ expected-stdout:
s:-9223372036854775808.-1.0.
u:9223372036854775808.18446744073709551615.0.
---
name: integer-size-FAIL-to-detect
description:
Notify the user that their ints are not 32 or 64 bit
category: int:u
stdin:
:
---
name: lineno-stdin
description:
See if $LINENO is updated and can be modified.
@ -4245,7 +4373,7 @@ description:
should print 0 according to POSIX (dash, bash, ksh93, posh)
but not 0 according to the getopt(1) manual page, ksh88, and
Bourne sh (such as /bin/sh on Solaris).
In mksh R39b, we honour POSIX except when -o sh is set.
We honour POSIX except when -o sh is set.
category: shell:legacy-no
stdin:
showf() {
@ -4265,10 +4393,15 @@ stdin:
showf
set -- `false`
echo rv=$?
set -o posix -o sh
showf
set -- `false`
echo rv=$?
expected-stdout:
FPOSIX=0 FSH=0 rv=0
FPOSIX=0 FSH=1 rv=1
FPOSIX=1 FSH=0 rv=0
FPOSIX=1 FSH=1 rv=0
---
name: regression-10-legacy
description:
@ -4297,10 +4430,15 @@ stdin:
showf
set -- `false`
echo rv=$?
set -o posix -o sh
showf
set -- `false`
echo rv=$?
expected-stdout:
FPOSIX=0 FSH=0 rv=1
FPOSIX=0 FSH=1 rv=1
FPOSIX=1 FSH=0 rv=1
FPOSIX=1 FSH=0 rv=0
FPOSIX=1 FSH=1 rv=0
---
name: regression-11
description:
@ -4663,18 +4801,16 @@ expected-stdout:
---
name: regression-39
description:
set -e: errors in command substitutions aren't ignored
Not clear if they should be or not... bash passes here
this may actually be required for make, so changed the
test to make this an mksh feature, not a bug
arguments: !-e!
Only posh and oksh(2013-07) say hi below; FreeBSD sh,
GNU bash in POSIX mode, dash, ksh93, mksh dont. 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:
/.*/
---

View file

@ -1,5 +1,5 @@
# $Id$
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.77 2013/02/17 15:58:26 tg Exp $
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.84 2013/08/10 13:43:50 tg Exp $
#-
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013
@ -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

View file

@ -1,4 +1,4 @@
/* $OpenBSD: edit.c,v 1.37 2013/01/21 10:13:24 halex Exp $ */
/* $OpenBSD: edit.c,v 1.38 2013/06/03 15:41:59 tedu Exp $ */
/* $OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $ */
/* $OpenBSD: emacs.c,v 1.44 2011/09/05 04:50:33 marco Exp $ */
/* $OpenBSD: vi.c,v 1.26 2009/06/29 22:50:19 martynas Exp $ */
@ -28,7 +28,7 @@
#ifndef MKSH_NO_CMDLINE_EDITING
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.265 2013/02/10 19:05:36 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.270 2013/08/14 20:26:17 tg Exp $");
/*
* in later versions we might use libtermcap for this, but since external
@ -66,7 +66,7 @@ static X_chars edchars;
static char editmode;
static int xx_cols; /* for Emacs mode */
static int modified; /* buffer has been "modified" */
static char holdbuf[LINE]; /* place to hold last edit buffer */
static char *holdbufp; /* place to hold last edit buffer */
static int x_getc(void);
static void x_putcf(int);
@ -81,10 +81,10 @@ static char *x_glob_hlp_tilde_and_rem_qchar(char *, bool);
static int x_basename(const char *, const char *);
static void x_free_words(int, char **);
static int x_escape(const char *, size_t, int (*)(const char *, size_t));
static int x_emacs(char *, size_t);
static int x_emacs(char *);
static void x_init_prompt(void);
#if !MKSH_S_NOVI
static int x_vi(char *, size_t);
static int x_vi(char *);
#endif
#define x_flush() shf_flush(shl_out)
@ -110,17 +110,17 @@ static int x_e_rebuildline(const char *);
* read an edited command line
*/
int
x_read(char *buf, size_t len)
x_read(char *buf)
{
int i;
x_mode(true);
modified = 1;
if (Flag(FEMACS) || Flag(FGMACS))
i = x_emacs(buf, len);
i = x_emacs(buf);
#if !MKSH_S_NOVI
else if (Flag(FVI))
i = x_vi(buf, len);
i = x_vi(buf);
#endif
else
/* internal error */
@ -919,7 +919,6 @@ static bool x_adj_ok;
*/
static int x_adj_done; /* is incremented by x_adjust() */
static int x_col;
static int x_displen;
static int x_arg; /* general purpose arg */
static bool x_arg_defaulted; /* x_arg not explicitly set; defaulted to 1 */
@ -944,9 +943,6 @@ static int x_curprefix;
static char *macroptr; /* bind key macro active? */
#endif
#if !MKSH_S_NOVI
static int cur_col; /* current column on line */
static int pwidth; /* width of prompt */
static int prompt_trunc; /* how much of prompt to truncate */
static int winwidth; /* width of window */
static char *wbuf[2]; /* window buffers */
static int wbuf_len; /* length of window buffers (x_cols - 3) */
@ -955,13 +951,16 @@ static char morec; /* more character at right of window */
static int lastref; /* argument to last refresh() */
static int holdlen; /* length of holdbuf */
#endif
static bool prompt_redraw; /* false if newline forced after prompt */
static int pwidth; /* width of prompt */
static int prompt_trunc; /* how much of prompt to truncate or -1 */
static int x_col; /* current column on line */
static int x_ins(const char *);
static void x_delete(size_t, bool);
static size_t x_bword(void);
static size_t x_fword(bool);
static void x_goto(char *);
static char *x_bs0(char *, char *);
static void x_bs3(char **);
static int x_size_str(char *);
static int x_size2(char *, char **);
@ -1170,30 +1169,25 @@ x_e_getmbc(char *sbuf)
static void
x_init_prompt(void)
{
x_col = promptlen(prompt);
x_adj_ok = true;
prompt_redraw = true;
if (x_col >= xx_cols)
x_col %= xx_cols;
x_displen = xx_cols - 2 - x_col;
x_adj_done = 0;
pprompt(prompt, 0);
if (x_displen < 1) {
x_col = 0;
x_displen = xx_cols - 2;
prompt_trunc = pprompt(prompt, 0);
pwidth = prompt_trunc % x_cols;
prompt_trunc -= pwidth;
if ((mksh_uari_t)pwidth > ((mksh_uari_t)x_cols - 3 - MIN_EDIT_SPACE)) {
/* force newline after prompt */
prompt_trunc = -1;
pwidth = 0;
x_e_putc2('\n');
prompt_redraw = false;
}
}
static int
x_emacs(char *buf, size_t len)
x_emacs(char *buf)
{
int c, i;
unsigned char f;
xbp = xbuf = buf; xend = buf + len;
xbp = xbuf = buf;
xend = buf + LINE;
xlp = xcp = xep = buf;
*xcp = 0;
xlp_valid = true;
@ -1202,8 +1196,10 @@ x_emacs(char *buf, size_t len)
x_histp = histptr + 1;
x_last_command = XFUNC_error;
xx_cols = x_cols;
x_init_prompt();
x_displen = (xx_cols = x_cols) - 2 - (x_col = pwidth);
x_adj_done = 0;
x_adj_ok = true;
x_histncp = NULL;
if (x_nextcmd >= 0) {
@ -1561,11 +1557,7 @@ x_fword(bool move)
static void
x_goto(char *cp)
{
if (cp >= xep)
cp = xep;
else if (UTFMODE)
while ((cp > xbuf) && ((*cp & 0xC0) == 0x80))
--cp;
cp = cp >= xep ? xep : x_bs0(cp, xbuf);
if (cp < xbp || cp >= utf_skipcols(xbp, x_displen)) {
/* we are heading off screen */
xcp = cp;
@ -1581,16 +1573,22 @@ x_goto(char *cp)
}
}
static char *
x_bs0(char *cp, char *lower_bound)
{
if (UTFMODE)
while ((!lower_bound || (cp > lower_bound)) &&
((*(unsigned char *)cp & 0xC0) == 0x80))
--cp;
return (cp);
}
static void
x_bs3(char **p)
{
int i;
(*p)--;
if (UTFMODE)
while (((unsigned char)**p & 0xC0) == 0x80)
(*p)--;
*p = x_bs0((*p) - 1, NULL);
i = x_size2(*p, NULL);
while (i--)
x_e_putc2('\b');
@ -1824,7 +1822,7 @@ x_load_hist(char **hp)
char *sp = NULL;
if (hp == histptr + 1) {
sp = holdbuf;
sp = holdbufp;
modified = 0;
} else if (hp < history || hp > histptr) {
x_e_putc2(7);
@ -1835,7 +1833,7 @@ x_load_hist(char **hp)
x_histp = hp;
oldsize = x_size_str(xbuf);
if (modified)
strlcpy(holdbuf, xbuf, sizeof(holdbuf));
strlcpy(holdbufp, xbuf, LINE);
strlcpy(xbuf, sp, xend - xbuf);
xbp = xbuf;
xep = xcp = xbuf + strlen(xbuf);
@ -2080,7 +2078,7 @@ x_cls(int c MKSH_A_UNUSED)
static void
x_redraw(int limit)
{
int i, j, x_trunc = 0;
int i, j;
char *cp;
x_adj_ok = false;
@ -2090,19 +2088,11 @@ x_redraw(int limit)
x_e_putc2('\r');
x_flush();
if (xbp == xbuf) {
x_col = promptlen(prompt);
if (x_col >= xx_cols)
x_trunc = (x_col / xx_cols) * xx_cols;
if (prompt_redraw)
pprompt(prompt, x_trunc);
if (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 *)&macro, 0, sizeof(macro));
}
}
@ -5425,8 +5474,11 @@ x_init(void)
/* ^W */
edchars.werase = 027;
/* initialise Emacs command line editing mode */
/* command line editing specific memory allocation */
ainit(AEDIT);
holdbufp = alloc(LINE, AEDIT);
/* initialise Emacs command line editing mode */
x_nextcmd = -1;
x_tab = alloc2(X_NTABS, sizeof(*x_tab), AEDIT);

View file

@ -1,4 +1,4 @@
/* $OpenBSD: eval.c,v 1.37 2011/10/11 14:32:43 otto Exp $ */
/* $OpenBSD: eval.c,v 1.39 2013/07/01 17:25:27 jca Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.136 2013/02/10 23:43:59 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.142 2013/07/24 18:03:57 tg Exp $");
/*
* string expansion
@ -33,15 +33,21 @@ __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.136 2013/02/10 23:43:59 tg Exp $");
*/
/* expansion generator state */
typedef struct Expand {
/* int type; */ /* see expand() */
const char *str; /* string */
typedef struct {
/* not including an "int type;" member, see expand() */
/* string */
const char *str;
/* source */
union {
const char **strv; /* string[] */
struct shf *shf; /* file */
} u; /* source */
struct tbl *var; /* variable in ${var..} */
bool split; /* split "$@" / call waitlast $() */
/* string[] */
const char **strv;
/* file */
struct shf *shf;
} u;
/* variable in ${var...} */
struct tbl *var;
/* split "$@" / call waitlast in $() */
bool split;
} Expand;
#define XBASE 0 /* scanning original */
@ -59,7 +65,7 @@ typedef struct Expand {
static int varsub(Expand *, const char *, const char *, int *, int *);
static int comsub(Expand *, const char *, int);
static void funsub(struct op *);
static char *valsub(struct op *, Area *);
static char *trimsub(char *, char *, int);
static void glob(char *, XPtrV *, bool);
static void globit(XString *, char **, char *, XPtrV *, int);
@ -198,33 +204,46 @@ typedef struct SubType {
} SubType;
void
expand(const char *cp, /* input word */
XPtrV *wp, /* output words */
int f) /* DO* flags */
expand(
/* input word */
const char *ccp,
/* output words */
XPtrV *wp,
/* DO* flags */
int f)
{
int c = 0;
int type; /* expansion type */
int quote = 0; /* quoted */
XString ds; /* destination string */
char *dp; /* destination */
const char *sp; /* source */
int fdo, word; /* second pass flags; have word */
int doblank; /* field splitting of parameter/command subst */
/* expansion type */
int type;
/* quoted */
int quote = 0;
/* destination string and live pointer */
XString ds;
char *dp;
/* source */
const char *sp;
/* second pass flags */
int fdo;
/* have word */
int word;
/* field splitting of parameter/command substitution */
int doblank;
/* expansion variables */
Expand x = {
/* expansion variables */
NULL, { NULL }, NULL, 0
};
SubType st_head, *st;
/* For trailing newlines in COMSUB */
/* record number of trailing newlines in COMSUB */
int newlines = 0;
bool saw_eq, make_magic;
int tilde_ok;
size_t len;
char *cp;
if (cp == NULL)
if (ccp == NULL)
internal_errorf("expand(NULL)");
/* for alias, readonly, set, typeset commands */
if ((f & DOVACHECK) && is_wdvarassign(cp)) {
if ((f & DOVACHECK) && is_wdvarassign(ccp)) {
f &= ~(DOVACHECK|DOBLANK|DOGLOB|DOTILDE);
f |= DOASNTILDE;
}
@ -238,7 +257,7 @@ expand(const char *cp, /* input word */
/* init destination string */
Xinit(ds, dp, 128, ATEMP);
type = XBASE;
sp = cp;
sp = ccp;
fdo = 0;
saw_eq = false;
/* must be 1/0 */
@ -279,27 +298,26 @@ expand(const char *cp, /* input word */
continue;
case COMSUB:
case FUNSUB:
case VALSUB:
tilde_ok = 0;
if (f & DONTRUNCOMMAND) {
word = IFS_WORD;
*dp++ = '$';
if (c == FUNSUB) {
*dp++ = '{';
*dp++ = ' ';
} else
*dp++ = '(';
*dp++ = c == COMSUB ? '(' : '{';
if (c != COMSUB)
*dp++ = c == FUNSUB ? ' ' : '|';
while (*sp != '\0') {
Xcheck(ds, dp);
*dp++ = *sp++;
}
if (c == FUNSUB) {
if (c != COMSUB) {
*dp++ = ';';
*dp++ = '}';
} else
*dp++ = ')';
} else {
type = comsub(&x, sp, c);
if (type == XCOM && (f&DOBLANK))
if (type != XBASE && (f & DOBLANK))
doblank++;
sp = strnul(sp) + 1;
newlines = 0;
@ -317,7 +335,6 @@ expand(const char *cp, /* input word */
*dp++ = ')'; *dp++ = ')';
} else {
struct tbl v;
char *p;
v.flag = DEFINED|ISSET|INTEGER;
/* not default */
@ -326,9 +343,10 @@ expand(const char *cp, /* input word */
v_evaluate(&v, substitute(sp, 0),
KSH_UNWIND_ERROR, true);
sp = strnul(sp) + 1;
for (p = str_val(&v); *p; ) {
cp = str_val(&v);
while (*cp) {
Xcheck(ds, dp);
*dp++ = *p++;
*dp++ = *cp++;
}
}
continue;
@ -394,8 +412,7 @@ expand(const char *cp, /* input word */
if (stype)
sp += slen;
switch (stype & 0x17F) {
case 0x100 | '#':
{
case 0x100 | '#': {
char *beg, *end;
mksh_ari_t seed;
register uint32_t h;
@ -416,8 +433,7 @@ expand(const char *cp, /* input word */
(unsigned int)h);
break;
}
case 0x100 | 'Q':
{
case 0x100 | 'Q': {
struct shf shf;
shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
@ -839,7 +855,10 @@ expand(const char *cp, /* input word */
if (c == 0) {
if (quote && !x.split)
continue;
/* this is so we don't terminate */
c = ' ';
/* now force-emit a word */
goto emit_word;
}
if (quote && x.split) {
/* terminate word for "$@" */
@ -850,14 +869,19 @@ expand(const char *cp, /* input word */
break;
case XCOM:
if (newlines) {
/* Spit out saved NLs */
if (x.u.shf == NULL) {
/* $(<...) failed */
subst_exstat = 1;
/* fake EOF */
c = EOF;
} else if (newlines) {
/* spit out saved NLs */
c = '\n';
--newlines;
} else {
while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
if (c == '\n')
/* Save newlines */
/* save newlines */
newlines++;
if (newlines && c != EOF) {
shf_ungetc(c, x.u.shf);
@ -867,7 +891,8 @@ expand(const char *cp, /* input word */
}
if (c == EOF) {
newlines = 0;
shf_close(x.u.shf);
if (x.u.shf)
shf_close(x.u.shf);
if (x.split)
subst_exstat = waitlast();
type = XBASE;
@ -895,21 +920,21 @@ expand(const char *cp, /* input word */
*/
if (word == IFS_WORD ||
(!ctype(c, C_IFSWS) && c && word == IFS_NWS)) {
char *p;
emit_word:
*dp++ = '\0';
p = Xclose(ds, dp);
cp = Xclose(ds, dp);
if (fdo & DOBRACE)
/* also does globbing */
alt_expand(wp, p, p,
p + Xlength(ds, (dp - 1)),
alt_expand(wp, cp, cp,
cp + Xlength(ds, (dp - 1)),
fdo | (f & DOMARKDIRS));
else if (fdo & DOGLOB)
glob(p, wp, tobool(f & DOMARKDIRS));
glob(cp, wp, tobool(f & DOMARKDIRS));
else if ((f & DOPAT) || !(fdo & DOMAGIC))
XPput(*wp, p);
XPput(*wp, cp);
else
XPput(*wp, debunk(p, p, strlen(p) + 1));
XPput(*wp, debunk(cp, cp,
strlen(cp) + 1));
fdo = 0;
saw_eq = false;
tilde_ok = (f & (DOTILDE|DOASNTILDE)) ? 1 : 0;
@ -920,10 +945,8 @@ expand(const char *cp, /* input word */
return;
} else if (type == XSUB && ctype(c, C_IFS) &&
!ctype(c, C_IFSWS) && Xlength(ds, dp) == 0) {
char *p;
*(p = alloc(1, ATEMP)) = '\0';
XPput(*wp, p);
*(cp = alloc(1, ATEMP)) = '\0';
XPput(*wp, cp);
type = XSUBMID;
}
if (word != IFS_NWS)
@ -932,10 +955,8 @@ expand(const char *cp, /* input word */
if (type == XSUB) {
if (word == IFS_NWS &&
Xlength(ds, dp) == 0) {
char *p;
*(p = alloc(1, ATEMP)) = '\0';
XPput(*wp, p);
*(cp = alloc(1, ATEMP)) = '\0';
XPput(*wp, cp);
}
type = XSUBMID;
}
@ -1002,18 +1023,17 @@ expand(const char *cp, /* input word */
if (type == XBASE &&
(f & (DOTILDE|DOASNTILDE)) &&
(tilde_ok & 2)) {
const char *p;
char *dp_x;
const char *tcp;
char *tdp = dp;
dp_x = dp;
p = maybe_expand_tilde(sp,
&ds, &dp_x,
tcp = maybe_expand_tilde(sp,
&ds, &tdp,
f & DOASNTILDE);
if (p) {
if (dp != dp_x)
if (tcp) {
if (dp != tdp)
word = IFS_WORD;
dp = dp_x;
sp = p;
dp = tdp;
sp = tcp;
continue;
}
}
@ -1176,8 +1196,10 @@ varsub(Expand *xp, const char *sp, const char *word,
c = sp[0];
if (c == '*' || c == '@') {
switch (stype & 0x17F) {
case '=': /* can't assign to a vector */
case '%': /* can't trim a vector (yet) */
/* can't assign to a vector */
case '=':
/* can't trim a vector (yet) */
case '%':
case '#':
case '0':
case '/':
@ -1204,8 +1226,10 @@ varsub(Expand *xp, const char *sp, const char *word,
XPtrV wv;
switch (stype & 0x17F) {
case '=': /* can't assign to a vector */
case '%': /* can't trim a vector (yet) */
/* can't assign to a vector */
case '=':
/* can't trim a vector (yet) */
case '%':
case '#':
case '?':
case '0':
@ -1317,33 +1341,41 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
SHF_MAPHI|SHF_CLEXEC);
if (shf == NULL)
errorf("%s: %s %s", name, "can't open", "$() input");
warningf(!Flag(FTALKING), "%s: %s %s: %s", name,
"can't open", "$(<...) input", cstrerror(errno));
} else if (fn == FUNSUB) {
int ofd1;
struct temp *tf = NULL;
/* create a temporary file, open for writing */
/*
* create a temporary file, open for reading and writing,
* with an shf open for reading (buffered) but yet unused
*/
maketemp(ATEMP, TT_FUNSUB, &tf);
if (!tf->shf) {
errorf("can't %s temporary file %s: %s",
"create", tf->tffn, cstrerror(errno));
}
/* save stdout and make the temporary file it */
/* extract shf from temporary file, unlink and free it */
shf = tf->shf;
unlink(tf->tffn);
afree(tf, ATEMP);
/* save stdout and let it point to the tempfile */
ofd1 = savefd(1);
ksh_dup2(shf_fileno(tf->shf), 1, false);
ksh_dup2(shf_fileno(shf), 1, false);
/*
* run tree, with output thrown into the tempfile,
* in a new function block
*/
funsub(t);
valsub(t, NULL);
subst_exstat = exstat & 0xFF;
/* close the tempfile and restore regular stdout */
shf_close(tf->shf);
/* rewind the tempfile and restore regular stdout */
lseek(shf_fileno(shf), (off_t)0, SEEK_SET);
restfd(1, ofd1);
/* now open, unlink and free the tempfile for reading */
shf = shf_open(tf->tffn, O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
unlink(tf->tffn);
afree(tf, ATEMP);
} else if (fn == VALSUB) {
xp->str = valsub(t, ATEMP);
subst_exstat = exstat & 0xFF;
return (XSUB);
} else {
int ofd1, pv[2];
@ -1495,11 +1527,11 @@ globit(XString *xs, /* dest string */
*/
if ((check & GF_EXCHECK) ||
((check & GF_MARKDIR) && (check & GF_GLOBBED))) {
#define stat_check() (stat_done ? stat_done : \
(stat_done = stat(Xstring(*xs, xp), &statb) < 0 \
? -1 : 1))
#define stat_check() (stat_done ? stat_done : (stat_done = \
stat(Xstring(*xs, xp), &statb) < 0 ? -1 : 1))
struct stat lstatb, statb;
int stat_done = 0; /* -1: failed, 1 ok */
/* -1: failed, 1 ok, 0 not yet done */
int stat_done = 0;
if (mksh_lstat(Xstring(*xs, xp), &lstatb) < 0)
return;
@ -1801,12 +1833,21 @@ alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo)
}
/* helper function due to setjmp/longjmp woes */
static void
funsub(struct op *t)
static char *
valsub(struct op *t, Area *ap)
{
char * volatile cp = NULL;
struct tbl * volatile vp = NULL;
newenv(E_FUNC);
newblock();
e->type = E_FUNC;
if (ap)
vp = local("REPLY", false);
if (!kshsetjmp(e->jbuf))
execute(t, XXCOM | XERROK, NULL);
popblock();
if (vp)
strdupx(cp, str_val(vp), ap);
quitenv(NULL);
return (cp);
}

View file

@ -1,4 +1,4 @@
/* $OpenBSD: exec.c,v 1.49 2009/01/29 23:27:26 jaredy Exp $ */
/* $OpenBSD: exec.c,v 1.50 2013/06/10 21:09:27 millert Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.116 2013/02/17 05:40:15 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.125 2013/07/21 20:44:44 tg Exp $");
#ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL "/bin/sh"
@ -106,7 +106,7 @@ execute(struct op * volatile t,
/* set variable to its expanded value */
z = strlen(cp) + 1;
if (notoktomul(z, 2) || notoktoadd(z * 2, n))
internal_errorf(Toomem, (unsigned long)-1);
internal_errorf(Toomem, (size_t)-1);
dp = alloc(z * 2 + n, ATEMP);
memcpy(dp, t->vars[0], n);
t->vars[0] = dp;
@ -138,14 +138,6 @@ execute(struct op * volatile t,
/* Allow option parsing (bizarre, but POSIX) */
timex_hook(t, &up);
ap = (const char **)up;
if (Flag(FXTRACE) && ap[0]) {
shf_puts(substitute(str_val(global("PS4")), 0),
shl_out);
for (i = 0; ap[i]; i++)
shf_fprintf(shl_out, "%s%c", ap[i],
ap[i + 1] ? ' ' : '\n');
shf_flush(shl_out);
}
if (ap[0])
tp = findcom(ap[0], FC_BI|FC_FUNC);
}
@ -305,10 +297,12 @@ execute(struct op * volatile t,
case TAND:
rv = execute(t->left, XERROK, xerrok);
if ((rv == 0) == (t->type == TAND))
rv = execute(t->right, XERROK, xerrok);
flags |= XERROK;
if (xerrok)
*xerrok = 1;
rv = execute(t->right, flags & XERROK, xerrok);
else {
flags |= XERROK;
if (xerrok)
*xerrok = 1;
}
break;
case TBANG:
@ -335,6 +329,7 @@ execute(struct op * volatile t,
case TFOR:
case TSELECT: {
volatile bool is_first = true;
ap = (t->vars == NULL) ? e->loc->argv + 1 :
(const char **)eval((const char **)t->vars,
DOBLANK | DOGLOB | DOTILDE);
@ -639,27 +634,44 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
l_assign = e->loc;
if (Flag(FEXPORT))
type_flags |= EXPORT;
if (Flag(FXTRACE))
change_xtrace(2, false);
for (i = 0; t->vars[i]; i++) {
/* do NOT lookup in the new var/fn block just created */
e->loc = l_expand;
cp = evalstr(t->vars[i], DOASNTILDE);
e->loc = l_assign;
/* but assign in there as usual */
if (Flag(FXTRACE)) {
if (i == 0)
shf_puts(substitute(str_val(global("PS4")), 0),
shl_out);
shf_fprintf(shl_out, "%s%c", cp,
t->vars[i + 1] ? ' ' : '\n');
if (!t->vars[i + 1])
shf_flush(shl_out);
const char *ccp;
ccp = skip_varname(cp, true);
if (*ccp == '+')
++ccp;
if (*ccp == '=')
++ccp;
shf_write(cp, ccp - cp, shl_xtrace);
print_value_quoted(shl_xtrace, ccp);
shf_putc(' ', shl_xtrace);
}
/* but assign in there as usual */
typeset(cp, type_flags, 0, 0, 0);
if (bourne_function_call && !(type_flags & EXPORT))
typeset(cp, LOCAL|LOCAL_COPY|EXPORT, 0, 0, 0);
}
if (Flag(FXTRACE)) {
change_xtrace(2, false);
if (ap[rv = 0]) {
xtrace_ap_loop:
print_value_quoted(shl_xtrace, ap[rv]);
if (ap[++rv]) {
shf_putc(' ', shl_xtrace);
goto xtrace_ap_loop;
}
}
change_xtrace(1, false);
}
if ((cp = *ap) == NULL) {
rv = subst_exstat;
goto Leave;
@ -700,10 +712,9 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
break;
}
if (include(tp->u.fpath, 0, NULL, false) < 0) {
rv = errno;
warningf(true, "%s: %s %s %s: %s", cp,
"can't open", "function definition file",
tp->u.fpath, cstrerror(rv));
tp->u.fpath, cstrerror(errno));
rv = 127;
break;
}
@ -740,9 +751,9 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
getopts_reset(1);
}
old_xflag = Flag(FXTRACE);
Flag(FXTRACE) |= tp->flag & TRACE ? 1 : 0;
old_xflag = Flag(FXTRACE) ? 1 : 0;
change_xtrace((Flag(FXTRACEREC) ? old_xflag : 0) |
((tp->flag & TRACE) ? 1 : 0), false);
old_inuse = tp->flag & FINUSE;
tp->flag |= FINUSE;
@ -751,9 +762,11 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
execute(tp->val.t, flags & XERROK, NULL);
i = LRETURN;
}
kshname = old_kshname;
Flag(FXTRACE) = old_xflag;
change_xtrace(old_xflag, false);
tp->flag = (tp->flag & ~FINUSE) | old_inuse;
/*
* Were we deleted while executing? If so, free the
* execution tree. TODO: Unfortunately, the table entry
@ -1033,25 +1046,23 @@ const char *
builtin(const char *name, int (*func) (const char **))
{
struct tbl *tp;
uint32_t flag;
uint32_t flag = DEFINED;
/* see if any flags should be set for this builtin */
for (flag = 0; ; name++) {
while (1) {
if (*name == '=')
/* command does variable assignment */
flag |= KEEPASN;
else if (*name == '*')
/* POSIX special builtin */
flag |= SPEC_BI;
else if (*name == '+')
/* POSIX regular builtin */
flag |= REG_BI;
else
break;
name++;
}
tp = ktenter(&builtins, name, hash(name));
tp->flag = DEFINED | flag;
tp->flag = flag;
tp->type = CSHELL;
tp->val.f = func;
@ -1083,7 +1094,7 @@ findcom(const char *name, int flags)
tbi = (flags & FC_BI) ? ktsearch(&builtins, name, h) : NULL;
/*
* POSIX says special builtins first, then functions, then
* POSIX regular builtins, then search path...
* regular builtins, then search path...
*/
if ((flags & FC_SPECBI) && tbi && (tbi->flag & SPEC_BI))
tp = tbi;
@ -1098,9 +1109,7 @@ findcom(const char *name, int flags)
&tp->u2.errnov);
}
}
if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
tp = tbi;
if (!tp && (flags & FC_UNREGBI) && tbi)
if (!tp && (flags & FC_NORMBI) && tbi)
tp = tbi;
if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
tp = ktsearch(&taliases, name, h);
@ -1298,10 +1307,11 @@ iosetup(struct ioword *iop, struct tbl *tp)
iotmp.name = (iotype == IOHERE) ? NULL : cp;
iotmp.flag |= IONAMEXP;
if (Flag(FXTRACE))
shellf("%s%s\n",
substitute(str_val(global("PS4")), 0),
snptreef(NULL, 32, "%R", &iotmp));
if (Flag(FXTRACE)) {
change_xtrace(2, false);
fptreef(shl_xtrace, 0, "%R", &iotmp);
change_xtrace(1, false);
}
switch (iotype) {
case IOREAD:
@ -1345,8 +1355,11 @@ iosetup(struct ioword *iop, struct tbl *tp)
} else if ((u = check_fd(cp,
X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
&emsg)) < 0) {
char *sp;
warningf(true, "%s: %s",
snptreef(NULL, 32, "%R", &iotmp), emsg);
(sp = snptreef(NULL, 32, "%R", &iotmp)), emsg);
afree(sp, ATEMP);
return (-1);
}
if (u == iop->unit)
@ -1395,12 +1408,14 @@ iosetup(struct ioword *iop, struct tbl *tp)
else if (u != iop->unit) {
if (ksh_dup2(u, iop->unit, true) < 0) {
int eno;
char *sp;
eno = errno;
warningf(true, "%s %s %s",
"can't finish (dup) redirection",
snptreef(NULL, 32, "%R", &iotmp),
(sp = snptreef(NULL, 32, "%R", &iotmp)),
cstrerror(eno));
afree(sp, ATEMP);
if (iotype != IODUP)
close(u);
return (-1);
@ -1548,10 +1563,8 @@ do_selectargs(const char **ap, bool print_menu)
if (call_builtin(findcom("read", FC_BI), read_args, Tselect))
return (NULL);
s = str_val(global("REPLY"));
if (*s) {
getn(s, &i);
if (*s && getn(s, &i))
return ((i >= 1 && i <= argct) ? ap[i - 1] : null);
}
print_menu = true;
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* $OpenBSD: c_ksh.c,v 1.33 2009/02/07 14:03:24 kili Exp $ */
/* $OpenBSD: c_sh.c,v 1.41 2010/03/27 09:10:01 jmc Exp $ */
/* $OpenBSD: c_sh.c,v 1.43 2013/04/19 17:39:45 deraadt Exp $ */
/* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */
/* $OpenBSD: c_ulimit.c,v 1.17 2008/03/21 12:51:19 millert Exp $ */
@ -38,7 +38,7 @@
#endif
#endif
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.238 2013/02/18 22:47:32 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.244 2013/06/03 22:28:32 tg Exp $");
#if HAVE_KILLPG
/*
@ -84,70 +84,69 @@ c_false(const char **wp MKSH_A_UNUSED)
}
/*
* A leading = means assignments before command are kept;
* a leading * means a POSIX special builtin;
* a leading + means a POSIX regular builtin
* (* and + should not be combined).
* A leading = means assignments before command are kept.
* A leading * means a POSIX special builtin.
*/
const struct builtin mkshbuiltins[] = {
{"*=.", c_dot},
{"*=:", c_true},
{"[", c_test},
/* no =: AT&T manual wrong */
{Talias, c_alias},
{"*=break", c_brkcont},
{Tgbuiltin, c_builtin},
{"cat", c_cat},
{"cd", c_cd},
/* dash compatibility hack */
{"chdir", c_cd},
{"command", c_command},
{"*=continue", c_brkcont},
{"echo", c_print},
{"*=eval", c_eval},
{"*=exec", c_exec},
{"*=exit", c_exitreturn},
{"+false", c_false},
{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);
}

View file

@ -1,7 +1,8 @@
/* $OpenBSD: jobs.c,v 1.38 2009/12/12 04:28:44 deraadt Exp $ */
/* $OpenBSD: jobs.c,v 1.39 2009/12/13 04:36:48 deraadt Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
* 2012, 2013
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -22,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.94 2012/12/28 02:28:36 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.100 2013/07/26 20:33:23 tg Exp $");
#if HAVE_KILLPG
#define mksh_killpg killpg
@ -44,12 +45,11 @@ struct proc {
int state;
int status; /* wait status */
/* process command string from vistree */
char command[64 - (ALLOC_SIZE + sizeof(Proc *) + sizeof(pid_t) +
char command[256 - (ALLOC_SIZE + sizeof(Proc *) + sizeof(pid_t) +
2 * sizeof(int))];
};
/* Notify/print flag - j_print() argument */
#define JP_NONE 0 /* don't print anything */
#define JP_SHORT 1 /* print signals processes were killed by */
#define JP_MEDIUM 2 /* print [job-num] -/+ command */
#define JP_LONG 3 /* print [job-num] -/+ pid command */
@ -102,17 +102,14 @@ struct job {
#define JW_PIPEST 0x08 /* want PIPESTATUS */
/* Error codes for j_lookup() */
#define JL_OK 0
#define JL_NOSUCH 1 /* no such job */
#define JL_AMBIG 2 /* %foo or %?foo is ambiguous */
#define JL_INVALID 3 /* non-pid, non-% job id */
#define JL_NOSUCH 0 /* no such job */
#define JL_AMBIG 1 /* %foo or %?foo is ambiguous */
#define JL_INVALID 2 /* non-pid, non-% job id */
static const char * const lookup_msgs[] = {
null,
"no such job",
"ambiguous",
"argument must be %job or process id",
NULL
"argument must be %job or process id"
};
static Job *job_list; /* job list */
@ -463,7 +460,7 @@ exchild(struct op *t, int flags,
forksleep <<= 1;
}
/* ensure $RANDOM changes between parent and child */
rndset((long)cldpid);
rndset((unsigned long)cldpid);
/* fork failed? */
if (cldpid < 0) {
kill_job(j, SIGKILL);
@ -506,9 +503,6 @@ exchild(struct op *t, int flags,
/* Do this before restoring signal */
if (flags & XCOPROC)
coproc_cleanup(false);
#ifndef MKSH_NOPROSPECTOFWORK
sigprocmask(SIG_SETMASK, &omask, NULL);
#endif
cleanup_parents_env();
#ifndef MKSH_UNEMPLOYED
/*
@ -543,6 +537,10 @@ exchild(struct op *t, int flags,
}
/* in case of $(jobs) command */
remove_job(j, "child");
#ifndef MKSH_NOPROSPECTOFWORK
/* remove_job needs SIGCHLD blocked still */
sigprocmask(SIG_SETMASK, &omask, NULL);
#endif
nzombie = 0;
#ifndef MKSH_UNEMPLOYED
ttypgrp_ok = false;
@ -906,7 +904,7 @@ j_jobs(const char *cp, int slp,
zflag = 1;
}
if (cp) {
int ecode;
int ecode;
if ((j = j_lookup(cp, &ecode)) == NULL) {
#ifndef MKSH_NOPROSPECTOFWORK
@ -1220,6 +1218,8 @@ j_waitj(Job *j,
ARRAY | INT_U | AINDEX;
got_array:
vp->val.i = proc_errorlevel(p);
if (Flag(FPIPEFAIL) && vp->val.i)
rv = vp->val.i;
p = p->next;
}
}
@ -1251,8 +1251,7 @@ j_waitj(Job *j,
static void
j_sigchld(int sig MKSH_A_UNUSED)
{
/* this runs inside interrupt context, with errno saved */
int saved_errno = errno;
Job *j;
Proc *p = NULL;
pid_t pid;
@ -1340,7 +1339,7 @@ j_sigchld(int sig MKSH_A_UNUSED)
#ifdef MKSH_NO_SIGSUSPEND
sigprocmask(SIG_SETMASK, &omask, NULL);
#endif
/* nothing */;
errno = saved_errno;
}
/*

View file

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2009, 2010, 2011
* Copyright (c) 2009, 2010, 2011, 2013
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -20,7 +20,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.19 2011/09/07 15:24:16 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.20 2013/06/03 22:28:33 tg Exp $");
/* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */
#if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0)
@ -100,7 +100,7 @@ aresize(void *ptr, size_t numb, Area *ap)
|| ALLOC_ISUNALIGNED(lp)
#endif
)
internal_errorf(Toomem, (unsigned long)numb);
internal_errorf(Toomem, numb);
/* this only works because Area is an ALLOC_ITEM */
lp->next = ap->next;
ap->next = lp;

View file

@ -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
View 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 persons 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 .

View file

@ -1,4 +1,4 @@
/* $OpenBSD: main.c,v 1.51 2012/09/10 01:25:30 tedu Exp $ */
/* $OpenBSD: main.c,v 1.52 2013/06/15 17:25:19 millert Exp $ */
/* $OpenBSD: tty.c,v 1.9 2006/03/14 22:08:01 deraadt Exp $ */
/* $OpenBSD: io.c,v 1.22 2006/03/17 16:30:13 millert Exp $ */
/* $OpenBSD: table.c,v 1.15 2012/02/19 07:52:30 otto Exp $ */
@ -34,7 +34,7 @@
#include <locale.h>
#endif
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.260 2013/02/10 21:42:16 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.269 2013/07/25 18:07:46 tg Exp $");
extern char **environ;
@ -48,6 +48,7 @@ extern char **environ;
static uint8_t isuc(const char *);
static int main_init(int, const char *[], Source **, struct block **);
uint32_t chvt_rndsetup(const void *, size_t);
void chvt_reinit(void);
static void reclaim(void);
static void remove_temps(struct temp *);
@ -137,15 +138,25 @@ rndsetup(void)
/* introduce variation (and yes, second arg MBZ for portability) */
mksh_TIME(bufptr->tv);
h = chvt_rndsetup(bufptr, sizeof(*bufptr));
afree(cp, APERM);
return ((mksh_uari_t)h);
}
uint32_t
chvt_rndsetup(const void *bp, size_t sz)
{
register uint32_t h;
NZATInit(h);
/* variation through pid, ppid, and the works */
NZATUpdateMem(h, &rndsetupstate, sizeof(rndsetupstate));
/* some variation, some possibly entropy, depending on OE */
NZATUpdateMem(h, bufptr, sizeof(*bufptr));
NZATUpdateMem(h, bp, sz);
NZAATFinish(h);
afree(cp, APERM);
return ((mksh_uari_t)h);
return (h);
}
void
@ -238,7 +249,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
/* define built-in commands and see if we were called as one */
ktinit(APERM, &builtins,
/* currently up to 50 builtins: 75% of 128 = 2^7 */
/* currently up to 51 builtins: 75% of 128 = 2^7 */
7);
for (i = 0; mkshbuiltins[i].name != NULL; i++)
if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
@ -251,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;

View file

@ -3,7 +3,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012
* 2011, 2012, 2013
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -30,7 +30,7 @@
#include <grp.h>
#endif
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.205 2012/12/17 23:18:08 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.214 2013/08/11 14:57:09 tg Exp $");
#define KSH_CHVT_FLAG
#ifdef MKSH_SMALL
@ -54,7 +54,7 @@ static int do_gmatch(const unsigned char *, const unsigned char *,
const unsigned char *, const unsigned char *);
static const unsigned char *cclass(const unsigned char *, unsigned char);
#ifdef KSH_CHVT_CODE
static void chvt(const char *);
static void chvt(const Getopt *);
#endif
/*XXX this should go away */
@ -123,10 +123,15 @@ Xcheck_grow(XString *xsp, const char *xp, size_t more)
return (xsp->beg + (xp - old_beg));
}
#define SHFLAGS_DEFNS
#include "sh_flags.h"
const struct shoption options[] = {
#define OFC(i) (options[i][-2])
#define OFF(i) (((const unsigned char *)options[i])[-1])
#define OFN(i) (options[i])
const char * const options[] = {
#define SHFLAGS_ITEMS
#include "sh_flags.h"
};
@ -137,15 +142,20 @@ const struct shoption options[] = {
size_t
option(const char *n)
{
size_t i;
size_t i = 0;
if ((n[0] == '-' || n[0] == '+') && n[1] && !n[2]) {
for (i = 0; i < NELEM(options); i++)
if (options[i].c == n[1])
if ((n[0] == '-' || n[0] == '+') && n[1] && !n[2])
while (i < NELEM(options)) {
if (OFC(i) == n[1])
return (i);
} 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

View file

@ -1,5 +1,5 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.305 2013/02/19 18:45:20 tg Exp $
.\" $OpenBSD: ksh.1,v 1.145 2013/01/17 21:20:25 jmc Exp $
.\" $MirOS: src/bin/mksh/mksh.1,v 1.320 2013/08/10 14:11:39 tg Exp $
.\" $OpenBSD: ksh.1,v 1.147 2013/06/13 19:43:09 millert Exp $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
.\" 2010, 2011, 2012, 2013
@ -74,7 +74,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
.Dd $Mdocdate: February 19 2013 $
.Dd $Mdocdate: August 10 2013 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -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 */

View file

@ -1,11 +1,22 @@
#if defined(SHFLAGS_DEFNS)
__RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.12 2012/06/28 20:14:17 tg Exp $");
#define FN(sname,cname,ochar,flags) /* nothing */
__RCSID("$MirOS: src/bin/mksh/sh_flags.h,v 1.16 2013/08/11 14:57:11 tg Exp $");
#define FN(sname,cname,ochar,flags) \
static const struct { \
/* character flag (if any) */ \
char c; \
/* OF_* */ \
unsigned char optflags; \
/* long name of option */ \
char name[sizeof(sname)]; \
} shoptione_ ## cname = { \
ochar, flags, sname \
};
#elif defined(SHFLAGS_ENUMS)
#define FN(sname,cname,ochar,flags) cname,
#define F0(sname,cname,ochar,flags) cname = 0,
#elif defined(SHFLAGS_ITEMS)
#define FN(sname,cname,ochar,flags) { sname, ochar, flags },
#define FN(sname,cname,ochar,flags) \
((const char *)(&shoptione_ ## cname)) + 2,
#endif
#ifndef F0
@ -45,6 +56,9 @@ FN("gmacs", FGMACS, 0, OF_ANY)
/* ./. reading EOF does not exit */
FN("ignoreeof", FIGNOREEOF, 0, OF_ANY)
/* ./. inherit -x flag */
FN("inherit-xtrace", FXTRACEREC, 0, OF_ANY)
/* -i interactive shell */
FN("interactive", FTALKING, 'i', OF_CMDLINE)
@ -88,7 +102,10 @@ FN("nounset", FNOUNSET, 'u', OF_ANY)
/* ./. don't do logical cds/pwds (non-standard) */
FN("physical", FPHYSICAL, 0, OF_ANY)
/* ./. pdksh compat: somewhat more POSIXish mode (non-standard) */
/* ./. errorlevel of a pipeline is the rightmost nonzero value */
FN("pipefail", FPIPEFAIL, 0, OF_ANY)
/* ./. adhere more closely to POSIX even when undesirable */
FN("posix", FPOSIX, 0, OF_ANY)
/* -p use suid_profile; privileged shell */
@ -97,7 +114,7 @@ FN("privileged", FPRIVILEGED, 'p', OF_ANY)
/* -r restricted shell */
FN("restricted", FRESTRICTED, 'r', OF_CMDLINE)
/* ./. pdksh compat: called as sh not mksh; kludge mode (non-standard) */
/* ./. kludge mode for better compat with traditional sh (OS-specific) */
FN("sh", FSH, 0, OF_ANY)
/* -s (invocation) parse stdin (pseudo non-standard) */
@ -130,17 +147,17 @@ FN("viraw", FVIRAW, 0, OF_ANY)
FN("xtrace", FXTRACE, 'x', OF_ANY)
/* -c (invocation) execute specified command */
FN(NULL, FCOMMAND, 'c', OF_CMDLINE)
FN("", FCOMMAND, 'c', OF_CMDLINE)
/*
* anonymous flags: used internally by shell only (not visible to user)
*/
/* ./. direct builtin call (divined from argv[0] multi-call binary) */
FN(NULL, FAS_BUILTIN, 0, OF_INTERNAL)
FN("", FAS_BUILTIN, 0, OF_INTERNAL)
/* ./. (internal) initial shell was interactive */
FN(NULL, FTALKING_I, 0, OF_INTERNAL)
FN("", FTALKING_I, 0, OF_INTERNAL)
#undef FN
#undef F0

View file

@ -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;

View file

@ -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 {

View file

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012
* 2011, 2012, 2013
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -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
View file

@ -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;