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 \
-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)
-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 \
-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 \
addvar LDFLAGS \
-nostdlib \
-Bdynamic \
+ -fPIE \
-pie \
-Wl,-dynamic-linker,/system/bin/linker \
-Wl,--gc-sections \
-Wl,-z,relro \
-Wl,-z,now \
-Wl,--warn-shared-textrel \
+ -Wl,--fatal-warnings \
-Wl,--icf=safe \
-Wl,--fix-cortex-a8 \
-Wl,--no-undefined \
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
# 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
: ${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'
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 {
#!/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
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
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
ac_ifcpp() {
expr=$1; shift
ac_testn "$@" <<-EOF
+ extern int thiswillneverbedefinedIhope(void);
int main(void) { return (
#$expr
0
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
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
: ${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"
ct="uslc"
#elif defined(__LCC__)
ct="lcc"
+#elif defined(MKSH_MAYBE_KENCC)
+/* and none of the above matches */
+ct="kencc"
#else
ct="unknown"
#endif
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
'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
HAVE_COMPILER_KNOWN=1
fi
-if test $ct = sunpro; then
- test x"$save_NOWARN" = x"" && save_NOWARN='-errwarn=%none'
- ac_flags 0 errwarnnone "$save_NOWARN"
- test 1 = $HAVE_CAN_ERRWARNNONE || save_NOWARN=
- ac_flags 0 errwarnall "-errwarn=%all"
- test 1 = $HAVE_CAN_ERRWARNALL && DOWARN="-errwarn=%all"
-elif test $ct = hpcc; then
+case $ct in
+bcc)
+ save_NOWARN="${ccpc}-w"
+ DOWARN="${ccpc}-w!"
+ ;;
+dec)
+ # -msg_* flags not used yet, or is -w2 correct?
+ ;;
+dmc)
+ save_NOWARN="${ccpc}-w"
+ DOWARN="${ccpc}-wx"
+ ;;
+hpcc)
save_NOWARN=
DOWARN=+We
-elif test $ct = mipspro; then
+ ;;
+kencc)
+ save_NOWARN=
+ DOWARN=
+ ;;
+mipspro)
save_NOWARN=
DOWARN="-diag_error 1-10000"
-elif test $ct = msc; then
+ ;;
+msc)
save_NOWARN="${ccpc}/w"
DOWARN="${ccpc}/WX"
-elif test $ct = dmc; then
- save_NOWARN="${ccpc}-w"
- DOWARN="${ccpc}-wx"
-elif test $ct = bcc; then
- save_NOWARN="${ccpc}-w"
- DOWARN="${ccpc}-w!"
-elif test $ct = dec; then
- : -msg_* flags not used yet, or is -w2 correct?
-elif test $ct = xlc; then
- save_NOWARN=-qflag=i:e
- DOWARN=-qflag=i:i
-elif test $ct = tendra; then
+ ;;
+sunpro)
+ test x"$save_NOWARN" = x"" && save_NOWARN='-errwarn=%none'
+ ac_flags 0 errwarnnone "$save_NOWARN"
+ test 1 = $HAVE_CAN_ERRWARNNONE || save_NOWARN=
+ ac_flags 0 errwarnall "-errwarn=%all"
+ test 1 = $HAVE_CAN_ERRWARNALL && DOWARN="-errwarn=%all"
+ ;;
+tendra)
save_NOWARN=-w
-elif test $ct = ucode; then
+ ;;
+ucode)
save_NOWARN=
DOWARN=-w2
-elif test $ct = watcom; then
+ ;;
+watcom)
save_NOWARN=
DOWARN=-Wc,-we
-else
+ ;;
+xlc)
+ save_NOWARN=-qflag=i:e
+ DOWARN=-qflag=i:i
+ ;;
+*)
test x"$save_NOWARN" = x"" && save_NOWARN=-Wno-error
ac_flags 0 wnoerror "$save_NOWARN"
test 1 = $HAVE_CAN_WNOERROR || save_NOWARN=
ac_flags 0 werror -Werror
test 1 = $HAVE_CAN_WERROR && DOWARN=-Werror
-fi
-
-test $ct = icc && DOWARN="$DOWARN -wd1419"
+ test $ct = icc && DOWARN="$DOWARN -wd1419"
+ ;;
+esac
NOWARN=$save_NOWARN
#
#
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
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
*\ -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
"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
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
#
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
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
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
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
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
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" && \
#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
#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
#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
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'
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"
#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 */
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));
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
fi
#
-# runtime checks
-# once this is more than one, check if we can do runtime
-# checks (not cross-compiling) first to save on warnings
-#
-$e "${bi}run-time checks follow$ao, please ignore any weird errors"
-
-if ac_testnnd silent_idivwrapv '' '(run-time) whether signed integer division overflows wrap silently' <<-'EOF'
- #define MKSH_INCLUDES_ONLY
- #include "sh.h"
- #if !defined(MKSH_LEGACY_MODE) || HAVE_LONG_32BIT
- #define IDIVWRAPV_VL (mksh_uari_t)0x80000000UL
- #elif HAVE_LONG_64BIT
- #define IDIVWRAPV_VL (mksh_uari_t)0x8000000000000000UL
- #else
- # error "cannot check this"
- #endif
- #ifdef SIGFPE
- static void fpe_catcher(int) MKSH_A_NORETURN;
- #endif
- int main(int ac, char **av) {
- mksh_ari_t o1, o2, r1, r2;
-
- #ifdef SIGFPE
- signal(SIGFPE, fpe_catcher);
- #endif
- o1 = (mksh_ari_t)IDIVWRAPV_VL;
- o2 = -ac;
- r1 = o1 / o2;
- r2 = o1 % o2;
- if (r1 == o1 && r2 == 0) {
- printf("si");
- return (0);
- }
- printf("no %d %d %d %d %s", (int)o1, (int)o2, (int)r1,
- (int)r2, av[0]);
- return (1);
- }
- #ifdef SIGFPE
- static const char fpe_msg[] = "no, got SIGFPE, what were they smoking?";
- #define fpe_msglen (sizeof(fpe_msg) - 1)
- static void fpe_catcher(int sig MKSH_A_UNUSED) {
- _exit(write(1, fpe_msg, fpe_msglen) == fpe_msglen ? 2 : 3);
- }
- #endif
-EOF
-then
- if test $fv = 0; then
- echo "| hrm, compiling this failed, but we will just failback"
- else
- echo "| running test programme; this will fail if cross-compiling"
- echo "| in which case we will gracefully degrade to the default"
- ./$tcfn >vv.out 2>&1
- rv=$?
- echo "| result: `cat vv.out`"
- fv=0
- test $rv = 0 && test x"`cat vv.out`" = x"si" && fv=1
- fi
- rmf conftest.c conftest.o ${tcfn}* vv.out
- ac_testdone
-fi
-ac_cppflags
-
-$e "${bi}end of run-time checks$ao"
-
-#
# Compiler: Praeprocessor (only if needed)
#
test 0 = $HAVE_SYS_SIGNAME && if ac_testinit cpp_dd '' \
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
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
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"
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
"/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.
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"
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
-# $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
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
-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
"os:$os", '1'
);
-$temps = "/tmp/rts$$";
-$tempi = "/tmp/rti$$";
-$tempo = "/tmp/rto$$";
-$tempe = "/tmp/rte$$";
-$tempdir = "/tmp/rtd$$";
-
$nfailed = 0;
$nifailed = 0;
$nxfailed = 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;
}
$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;
}
%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);
$| = 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);
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;
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;
-# $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
# 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:
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:
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
---
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.
5:0=0.
6:-2147483648=2147483648.
7:2147483647=2147483647.
+ 8:-3=2147483645.
+ 9:-2=4294967294.
---
name: arith-unsigned-1
description:
\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.
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
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:
---
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:
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.
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() {
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:
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:
---
name: regression-39
description:
- set -e: errors in command substitutions aren't ignored
- Not clear if they should be or not... bash passes here
- this may actually be required for make, so changed the
- test to make this an mksh feature, not a bug
-arguments: !-e!
+ Only posh and oksh(2013-07) say “hi” below; FreeBSD sh,
+ GNU bash in POSIX mode, dash, ksh93, mksh don’t. All of
+ them exit 0. The POSIX behaviour is needed by BSD make.
stdin:
+ set -e
echo `false; echo hi`
-#expected-fail: yes
-#expected-stdout:
-# hi
+ echo $?
expected-stdout:
+ 0
---
name: regression-40
description:
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.
---
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
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
---
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
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
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
expected-stdout:
ab
---
+name: print-cr
+description:
+ Check that CR+LF is not collapsed into LF as some MSYS shells wrongly do
+stdin:
+ echo '#!'"$__progname" >foo
+ cat >>foo <<-'EOF'
+ print -n -- '220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT\r\n220->> Bitte keine Werbung einwerfen! <<\r\r\n220 Who do you wanna pretend to be today'
+ print \?\r
+ EOF
+ chmod +x foo
+ echo "[$(./foo)]"
+ ./foo | while IFS= read -r line; do
+ print -r -- "{$line}"
+ done
+expected-stdout:
+ [220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT\r
+ 220->> Bitte keine Werbung einwerfen! <<\r\r
+ 220 Who do you wanna pretend to be today?\r]
+ {220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT\r}
+ {220->> Bitte keine Werbung einwerfen! <<\r\r}
+ {220 Who do you wanna pretend to be today?\r}
+---
name: print-nul-chars
description:
Check handling of NUL characters for print and COMSUB
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 {
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 {
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 {
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
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
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
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 {
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
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
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 $
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"
}
inline_TWHILE() {
i=1
- while let " i < 10 "
+ while let] " i < 10 "
do
echo $i
let ++i
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
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
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
}
inline_TWHILE() {
i=1
- while let " i < 10 " >&3
+ while let] " i < 10 " >&3
do
echo $i
let ++i
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
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
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
time-limit: 3
stdin:
baz() {
- typeset -n foo=foo
+ typeset -n foo=fnord fnord=foo
foo[0]=bar
}
set -A foo bad
echo blah $foo .
expected-stdout:
sind bad .
- blah bar .
+ blah bad .
+expected-stderr-pattern:
+ /fnord: expression recurses on parameter/
---
name: better-parens-1a
description:
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:
+ /.*/
+---
# $Id$
-# $MirOS: src/bin/mksh/dot.mkshrc,v 1.77 2013/02/17 15:58:26 tg Exp $
+# $MirOS: src/bin/mksh/dot.mkshrc,v 1.84 2013/08/10 13:43:50 tg Exp $
#-
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013
#-
# ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells
+# catch non-mksh (including lksh) trying to shell this file
+case $KSH_VERSION in
+*MIRBSD\ KSH*) ;;
+*) return 0 ;;
+esac
+
PS1='#'; (( USER_ID )) && PS1='$'; [[ ${HOSTNAME:=$(ulimit -c 0; hostname -s \
2>/dev/null)} = *([ ]|localhost) ]] && HOSTNAME=$(ulimit -c 0; hostname \
2>/dev/null); : ${EDITOR:=/bin/ed} ${HOSTNAME:=nil} ${TERM:=vt100}
-function precmd {
+: ${MKSH:=$(whence -p mksh)}; PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
local e=$?
- (( e )) && print -n "$e|"
- # precmd is required to retain the errorlevel when ${ …;} is used
+ (( e )) && REPLY+="$e|"
+ REPLY+=${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?)}
+ REPLY+=@${HOSTNAME%%.*}:
+
+ local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~}
+ local m=${%d} n p=...; (( m > 0 )) || m=${#d}
+ (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
+ REPLY+=$p$d
+
return $e
-}
-PS1=$'\001\r''${ precmd;}${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?
- )}@${HOSTNAME%%.*}:${ local e=$? d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || \
- d=${d/#$p/~}; local m=${%d} n p=...; (( m > 0 )) || m=${#d}
- (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || \
- p=; print -nr -- "$p$d"; return $e;} '"$PS1 "
-: ${MKSH:=$(whence -p mksh)}; export EDITOR HOSTNAME MKSH TERM USER
+} '"$PS1 "; export EDITOR HOSTNAME MKSH TERM USER
alias ls=ls
unalias ls
alias l='ls -F'
alias la='l -a'
alias ll='l -l'
alias lo='l -alo'
+alias doch='sudo mksh -c "$(fc -ln -1)"'
whence -p rot13 >/dev/null || alias rot13='tr \
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
-whence -p hd >/dev/null || function hd {
- hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \
- -e '" |" "%_p"' -e '"|\n"' "$@"
-}
+if whence -p hd >/dev/null; then :; elif whence -p hexdump >/dev/null; then
+ function hd {
+ hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \
+ -e '" |" "%_p"' -e '"|\n"' "$@"
+ }
+else
+ function hd {
+ local -Uui16 -Z11 pos=0
+ local -Uui16 -Z5 hv=2147483647
+ local dasc line i
+
+ cat "$@" | { set +U; if read -arN -1 line; then
+ typeset -i1 line
+ i=0
+ while (( i < ${#line[*]} )); do
+ hv=${line[i++]}
+ if (( (pos & 15) == 0 )); then
+ (( pos )) && print -r -- "$dasc|"
+ print -n "${pos#16#} "
+ dasc=' |'
+ fi
+ print -n "${hv#16#} "
+ if (( (hv < 32) || (hv > 126) )); then
+ dasc+=.
+ else
+ dasc+=${line[i-1]#1#}
+ fi
+ (( (pos++ & 15) == 7 )) && print -n -- '- '
+ done
+ while (( pos & 15 )); do
+ print -n ' '
+ (( (pos++ & 15) == 7 )) && print -n -- '- '
+ done
+ (( hv == 2147483647 )) || print -r -- "$dasc|"
+ fi; }
+ }
+fi
# Berkeley C shell compatible dirs, popd, and pushd functions
# Z shell compatible chpwd() hook, used to update DIRSTACK[0]
[[ -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
-/* $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 $ */
#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
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);
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)
* 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 */
*/
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 */
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) */
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 **);
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;
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) {
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;
}
}
+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');
char *sp = NULL;
if (hp == histptr + 1) {
- sp = holdbuf;
+ sp = holdbufp;
modified = 0;
} else if (hp < history || hp > histptr) {
x_e_putc2(7);
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);
static void
x_redraw(int limit)
{
- int i, j, x_trunc = 0;
+ int i, j;
char *cp;
x_adj_ok = false;
x_e_putc2('\r');
x_flush();
if (xbp == xbuf) {
- x_col = promptlen(prompt);
- if (x_col >= xx_cols)
- x_trunc = (x_col / xx_cols) * xx_cols;
- if (prompt_redraw)
- pprompt(prompt, x_trunc);
- }
- if (x_col >= xx_cols)
- x_col %= xx_cols;
- x_displen = xx_cols - 2 - x_col;
- if (x_displen < 1) {
- x_col = 0;
- x_displen = xx_cols - 2;
+ if (prompt_trunc != -1)
+ pprompt(prompt, prompt_trunc);
+ x_col = pwidth;
}
+ x_displen = xx_cols - 2 - x_col;
xlp_valid = false;
x_zots(xbp);
if (xbp != xbuf || xep > xlp)
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();
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);
/* 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 */
#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 */
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 */
} expanded;
static int
-x_vi(char *buf, size_t len)
+x_vi(char *buf)
{
int c;
ohnum = hnum = hlast = histnum(-1) + 1;
insert = INSERT;
saved_inslen = inslen;
- first_insert = 1;
+ first_insert = true;
inslen = 0;
vi_macro_reset();
+ ebuf.cbuf = buf;
+ if (undobuf.cbuf == NULL) {
+ ibuf = alloc(LINE, AEDIT);
+ ybuf = alloc(LINE, AEDIT);
+ undobuf.cbuf = alloc(LINE, AEDIT);
+ }
+ undobuf.cbufsize = ebuf.cbufsize = LINE;
+ undobuf.linelen = ebuf.linelen = 0;
+ undobuf.cursor = ebuf.cursor = 0;
+ undobuf.winleft = ebuf.winleft = 0;
es = &ebuf;
- es->cbuf = buf;
undo = &undobuf;
- undo->cbufsize = es->cbufsize = len > LINE ? LINE : len;
-
- es->linelen = undo->linelen = 0;
- es->cursor = undo->cursor = 0;
- es->winleft = undo->winleft = 0;
- cur_col = promptlen(prompt);
- prompt_trunc = (cur_col / x_cols) * x_cols;
- cur_col -= prompt_trunc;
-
- pprompt(prompt, 0);
- if ((mksh_uari_t)cur_col > (mksh_uari_t)x_cols - 3 - MIN_EDIT_SPACE) {
- prompt_redraw = false;
- cur_col = 0;
- x_putc('\n');
- } else
- prompt_redraw = true;
- pwidth = cur_col;
+ x_init_prompt();
+ x_col = pwidth;
- if (!wbuf_len || wbuf_len != x_cols - 3) {
- wbuf_len = x_cols - 3;
- wbuf[0] = aresize(wbuf[0], wbuf_len, APERM);
- wbuf[1] = aresize(wbuf[1], wbuf_len, APERM);
+ if (wbuf_len != x_cols - 3 && ((wbuf_len = x_cols - 3))) {
+ wbuf[0] = aresize(wbuf[0], wbuf_len, AEDIT);
+ wbuf[1] = aresize(wbuf[1], wbuf_len, AEDIT);
}
if (wbuf_len) {
memset(wbuf[0], ' ', wbuf_len);
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';
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);
}
es->cursor = 0;
es->linelen = 0;
putbuf(KSH_VERSION,
- strlen(KSH_VERSION), 0);
+ strlen(KSH_VERSION), false);
refresh(0);
}
}
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:
case Ctrl('['):
expanded = NONE;
if (first_insert) {
- first_insert = 0;
+ first_insert = false;
if (inslen == 0) {
inslen = saved_inslen;
return (redo_insert(0));
* 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';
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--;
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--;
hnum = c2;
ohnum = hnum;
}
+ if (argcnt >= 2) {
+ /* flag from cursor-up command */
+ es->cursor = argcnt - 2;
+ return (0);
+ }
break;
case '_':
{
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);
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--;
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++;
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--;
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
{
es->cursor = 0;
es->linelen = holdlen;
- memmove(es->cbuf, holdbuf, holdlen);
+ memmove(es->cbuf, holdbufp, holdlen);
}
/* return a new edstate */
{
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;
static void
free_edstate(struct edstate *old)
{
- afree(old->cbuf, APERM);
- afree(old, APERM);
+ afree(old->cbuf, AEDIT);
+ afree(old, AEDIT);
}
/*
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);
}
static int
-findch(int ch, int cnt, int forw, int incl)
+findch(int ch, int cnt, bool forw, bool incl)
{
int ncursor;
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
x_putc('\r');
x_putc('\n');
}
- if (prompt_redraw)
+ if (prompt_trunc != -1)
pprompt(prompt, prompt_trunc);
- cur_col = pwidth;
+ x_col = pwidth;
morec = ' ';
}
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++;
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;
}
rval = -1;
break;
}
- if (++i < nwords && putbuf(" ", 1, 0) != 0) {
+ if (++i < nwords && putbuf(" ", 1, false) != 0) {
rval = -1;
break;
}
*/
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);
vi_macro_reset(void)
{
if (macro.p) {
- afree(macro.buf, APERM);
+ afree(macro.buf, AEDIT);
memset((char *)¯o, 0, sizeof(macro));
}
}
/* ^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);
-/* $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,
#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
*/
/* 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 */
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);
} 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;
}
/* init destination string */
Xinit(ds, dp, 128, ATEMP);
type = XBASE;
- sp = cp;
+ sp = ccp;
fdo = 0;
saw_eq = false;
/* must be 1/0 */
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;
*dp++ = ')'; *dp++ = ')';
} else {
struct tbl v;
- char *p;
v.flag = DEFINED|ISSET|INTEGER;
/* not default */
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;
if (stype)
sp += slen;
switch (stype & 0x17F) {
- case 0x100 | '#':
- {
+ case 0x100 | '#': {
char *beg, *end;
mksh_ari_t seed;
register uint32_t h;
(unsigned int)h);
break;
}
- case 0x100 | 'Q':
- {
+ case 0x100 | 'Q': {
struct shf shf;
shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
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 "$@" */
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);
}
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;
*/
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;
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)
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;
}
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;
}
}
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 '/':
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':
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];
*/
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;
}
/* 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);
}
-/* $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,
#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"
/* 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;
/* 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);
}
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:
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);
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;
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;
}
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;
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
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;
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;
&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);
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:
} 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)
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);
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;
}
}
-/* $OpenBSD: expr.c,v 1.21 2009/06/01 19:00:57 deraadt Exp $ */
+/* $OpenBSD: expr.c,v 1.22 2013/03/28 08:39:28 nicm Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.61 2013/02/15 18:36:48 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.72 2013/07/21 18:38:56 tg Exp $");
-#if !HAVE_SILENT_IDIVWRAPV
-#if !defined(MKSH_LEGACY_MODE) || HAVE_LONG_32BIT
-#define IDIVWRAPV_VL (mksh_uari_t)0x80000000UL
-#define IDIVWRAPV_VR (mksh_uari_t)0xFFFFFFFFUL
-#elif HAVE_LONG_64BIT
-#define IDIVWRAPV_VL (mksh_uari_t)0x8000000000000000UL
-#define IDIVWRAPV_VR (mksh_uari_t)0xFFFFFFFFFFFFFFFFUL
-#else
-# warning "cannot guarantee integer division wraparound"
-#undef HAVE_SILENT_IDIVWRAPV
-#define HAVE_SILENT_IDIVWRAPV 1
-#endif
-#endif
-
-/* The order of these enums is constrained by the order of opinfo[] */
+/* the order of these enums is constrained by the order of opinfo[] */
enum token {
/* some (long) unary operators */
O_PLUSPLUS = 0, O_MINUSMINUS,
O_EQ, O_NE,
/* assignments are assumed to be in range O_ASN .. O_BORASN */
O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
+#ifndef MKSH_LEGACY_MODE
+ O_ROLASN, O_RORASN,
+#endif
O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
+ /* binary non-assignment operators */
+#ifndef MKSH_LEGACY_MODE
+ O_ROL, O_ROR,
+#endif
O_LSHIFT, O_RSHIFT,
O_LE, O_GE, O_LT, O_GT,
O_LAND,
/* things that don't appear in the opinfo[] table */
VAR, LIT, END, BAD
};
-#define IS_BINOP(op) (((int)op) >= (int)O_EQ && ((int)op) <= (int)O_COMMA)
#define IS_ASSIGNOP(op) ((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
/* precisions; used to be enum prec but we do arithmetics on it */
-#define P_PRIMARY 0 /* VAR, LIT, (), ~ ! - + */
+#define P_PRIMARY 0 /* VAR, LIT, (), ! ~ ++ -- */
#define P_MULT 1 /* * / % */
#define P_ADD 2 /* + - */
-#define P_SHIFT 3 /* << >> */
+#define P_SHIFT 3 /* <<< >>> << >> */
#define P_RELATION 4 /* < <= > >= */
#define P_EQUALITY 5 /* == != */
#define P_BAND 6 /* & */
#define P_LAND 9 /* && */
#define P_LOR 10 /* || */
#define P_TERN 11 /* ?: */
-#define P_ASSIGN 12 /* = *= /= %= += -= <<= >>= &= ^= |= */
+ /* = += -= *= /= %= <<<= >>>= <<= >>= &= ^= |= */
+#define P_ASSIGN 12
#define P_COMMA 13 /* , */
#define MAX_PREC P_COMMA
struct opinfo {
- char name[4];
- int len; /* name length */
- int prec; /* precedence: lower is higher */
+ char name[5];
+ /* name length */
+ uint8_t len;
+ /* precedence: lower is higher */
+ uint8_t prec;
};
-/* Tokens in this table must be ordered so the longest are first
+/*
+ * Tokens in this table must be ordered so the longest are first
* (eg, += before +). If you change something, change the order
* of enum token too.
*/
static const struct opinfo opinfo[] = {
- { "++", 2, P_PRIMARY }, /* before + */
- { "--", 2, P_PRIMARY }, /* before - */
- { "==", 2, P_EQUALITY }, /* before = */
- { "!=", 2, P_EQUALITY }, /* before ! */
- { "=", 1, P_ASSIGN }, /* keep assigns in a block */
- { "*=", 2, P_ASSIGN },
- { "/=", 2, P_ASSIGN },
- { "%=", 2, P_ASSIGN },
- { "+=", 2, P_ASSIGN },
- { "-=", 2, P_ASSIGN },
- { "<<=", 3, P_ASSIGN },
- { ">>=", 3, P_ASSIGN },
- { "&=", 2, P_ASSIGN },
- { "^=", 2, P_ASSIGN },
- { "|=", 2, P_ASSIGN },
- { "<<", 2, P_SHIFT },
- { ">>", 2, P_SHIFT },
- { "<=", 2, P_RELATION },
- { ">=", 2, P_RELATION },
- { "<", 1, P_RELATION },
- { ">", 1, P_RELATION },
- { "&&", 2, P_LAND },
- { "||", 2, P_LOR },
- { "*", 1, P_MULT },
- { "/", 1, P_MULT },
- { "%", 1, P_MULT },
- { "+", 1, P_ADD },
- { "-", 1, P_ADD },
- { "&", 1, P_BAND },
- { "^", 1, P_BXOR },
- { "|", 1, P_BOR },
- { "?", 1, P_TERN },
- { ",", 1, P_COMMA },
- { "~", 1, P_PRIMARY },
- { "!", 1, P_PRIMARY },
- { "(", 1, P_PRIMARY },
- { ")", 1, P_PRIMARY },
- { ":", 1, P_PRIMARY },
- { "", 0, P_PRIMARY }
+ { "++", 2, P_PRIMARY }, /* before + */
+ { "--", 2, P_PRIMARY }, /* before - */
+ { "==", 2, P_EQUALITY }, /* before = */
+ { "!=", 2, P_EQUALITY }, /* before ! */
+ { "=", 1, P_ASSIGN }, /* keep assigns in a block */
+ { "*=", 2, P_ASSIGN },
+ { "/=", 2, P_ASSIGN },
+ { "%=", 2, P_ASSIGN },
+ { "+=", 2, P_ASSIGN },
+ { "-=", 2, P_ASSIGN },
+#ifndef MKSH_LEGACY_MODE
+ { "<<<=", 4, P_ASSIGN }, /* before <<< */
+ { ">>>=", 4, P_ASSIGN }, /* before >>> */
+#endif
+ { "<<=", 3, P_ASSIGN },
+ { ">>=", 3, P_ASSIGN },
+ { "&=", 2, P_ASSIGN },
+ { "^=", 2, P_ASSIGN },
+ { "|=", 2, P_ASSIGN },
+#ifndef MKSH_LEGACY_MODE
+ { "<<<", 3, P_SHIFT }, /* before << */
+ { ">>>", 3, P_SHIFT }, /* before >> */
+#endif
+ { "<<", 2, P_SHIFT },
+ { ">>", 2, P_SHIFT },
+ { "<=", 2, P_RELATION },
+ { ">=", 2, P_RELATION },
+ { "<", 1, P_RELATION },
+ { ">", 1, P_RELATION },
+ { "&&", 2, P_LAND },
+ { "||", 2, P_LOR },
+ { "*", 1, P_MULT },
+ { "/", 1, P_MULT },
+ { "%", 1, P_MULT },
+ { "+", 1, P_ADD },
+ { "-", 1, P_ADD },
+ { "&", 1, P_BAND },
+ { "^", 1, P_BXOR },
+ { "|", 1, P_BOR },
+ { "?", 1, P_TERN },
+ { ",", 1, P_COMMA },
+ { "~", 1, P_PRIMARY },
+ { "!", 1, P_PRIMARY },
+ { "(", 1, P_PRIMARY },
+ { ")", 1, P_PRIMARY },
+ { ":", 1, P_PRIMARY },
+ { "", 0, P_PRIMARY }
};
typedef struct expr_state {
/* token from token() */
enum token tok;
/* don't do assignments (for ?:, &&, ||) */
- short noassign;
+ uint8_t noassign;
/* evaluating an $(()) expression? */
bool arith;
/* unsigned arithmetic calculation */
bool natural;
} Expr_state;
-#define bivui(x, op, y) (es->natural ? \
- (mksh_uari_t)((x)->val.u op (y)->val.u) : \
- (mksh_uari_t)((x)->val.i op (y)->val.i) \
-)
-
enum error_type {
ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
ET_LVALUE, ET_RDONLY, ET_STR
static void evalerr(Expr_state *, enum error_type, const char *)
MKSH_A_NORETURN;
-static struct tbl *evalexpr(Expr_state *, int);
+static struct tbl *evalexpr(Expr_state *, unsigned int);
static void exprtoken(Expr_state *);
static struct tbl *do_ppmm(Expr_state *, enum token, struct tbl *, bool);
static void assign_check(Expr_state *, enum token, struct tbl *);
struct tbl v;
int ret;
- v.flag = DEFINED|INTEGER;
+ v.flag = DEFINED | INTEGER;
v.type = 0;
ret = v_evaluate(&v, expr, error_ok, arith);
*rval = v.val.i;
unwind(LAEXPR);
}
+/* do a ++ or -- operation */
static struct tbl *
-evalexpr(Expr_state *es, int prec)
+do_ppmm(Expr_state *es, enum token op, struct tbl *vasn, bool is_prefix)
+{
+ struct tbl *vl;
+ mksh_uari_t oval;
+
+ assign_check(es, op, vasn);
+
+ vl = intvar(es, vasn);
+ oval = vl->val.u;
+ if (op == O_PLUSPLUS)
+ ++vl->val.u;
+ else
+ --vl->val.u;
+ if (!es->noassign) {
+ if (vasn->flag & INTEGER)
+ setint_v(vasn, vl, es->arith);
+ else
+ setint(vasn, vl->val.i);
+ }
+ if (!is_prefix)
+ /* undo the increment/decrement */
+ vl->val.u = oval;
+
+ return (vl);
+}
+
+static struct tbl *
+evalexpr(Expr_state *es, unsigned int prec)
{
struct tbl *vl, *vr = NULL, *vasn;
enum token op;
- mksh_uari_t res = 0;
+ mksh_uari_t res = 0, t1, t2, t3;
if (prec == P_PRIMARY) {
- op = es->tok;
- if (op == O_BNOT || op == O_LNOT || op == O_MINUS ||
- op == O_PLUS) {
+ switch ((int)(op = es->tok)) {
+ case O_BNOT:
+ case O_LNOT:
+ case O_MINUS:
+ case O_PLUS:
exprtoken(es);
vl = intvar(es, evalexpr(es, P_PRIMARY));
- if (op == O_BNOT)
- vl->val.i = ~vl->val.i;
- else if (op == O_LNOT)
- vl->val.i = !vl->val.i;
- else if (op == O_MINUS)
- vl->val.i = -vl->val.i;
- /* op == O_PLUS is a no-op */
- } else if (op == OPEN_PAREN) {
+ switch ((int)op) {
+ case O_BNOT:
+ vl->val.u = ~vl->val.u;
+ break;
+ case O_LNOT:
+ vl->val.u = !vl->val.u;
+ break;
+ case O_MINUS:
+ vl->val.u = -vl->val.u;
+ break;
+ case O_PLUS:
+ /* nop */
+ break;
+ }
+ break;
+
+ case OPEN_PAREN:
exprtoken(es);
vl = evalexpr(es, MAX_PREC);
if (es->tok != CLOSE_PAREN)
evalerr(es, ET_STR, "missing )");
exprtoken(es);
- } else if (op == O_PLUSPLUS || op == O_MINUSMINUS) {
+ break;
+
+ case O_PLUSPLUS:
+ case O_MINUSMINUS:
exprtoken(es);
vl = do_ppmm(es, op, es->val, true);
exprtoken(es);
- } else if (op == VAR || op == LIT) {
+ break;
+
+ case VAR:
+ case LIT:
vl = es->val;
exprtoken(es);
- } else {
+ break;
+
+ default:
evalerr(es, ET_UNEXPECTED, NULL);
/* NOTREACHED */
}
+
if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
vl = do_ppmm(es, es->tok, vl, false);
exprtoken(es);
}
+
return (vl);
+ /* prec == P_PRIMARY */
}
+
vl = evalexpr(es, prec - 1);
- for (op = es->tok; IS_BINOP(op) && opinfo[(int)op].prec == prec;
- op = es->tok) {
+ while ((int)(op = es->tok) >= (int)O_EQ && (int)op <= (int)O_COMMA &&
+ opinfo[(int)op].prec == prec) {
exprtoken(es);
vasn = vl;
if (op != O_ASN)
if (!es->noassign)
assign_check(es, op, vasn);
vr = intvar(es, evalexpr(es, P_ASSIGN));
- } else if (op != O_TERN && op != O_LAND && op != O_LOR)
+ } else if (op == O_TERN) {
+ bool ev = vl->val.u != 0;
+
+ if (!ev)
+ es->noassign++;
+ vl = evalexpr(es, MAX_PREC);
+ if (!ev)
+ es->noassign--;
+ if (es->tok != CTERN)
+ evalerr(es, ET_STR, "missing :");
+ exprtoken(es);
+ if (ev)
+ es->noassign++;
+ vr = evalexpr(es, P_TERN);
+ if (ev)
+ es->noassign--;
+ vl = ev ? vl : vr;
+ continue;
+ } else if (op != O_LAND && op != O_LOR)
vr = intvar(es, evalexpr(es, prec - 1));
- if ((op == O_DIV || op == O_MOD || op == O_DIVASN ||
- op == O_MODASN) && vr->val.i == 0) {
- if (es->noassign)
- vr->val.i = 1;
- else
- evalerr(es, ET_STR, "zero divisor");
+
+ /* common ops setup */
+ switch ((int)op) {
+ case O_DIV:
+ case O_DIVASN:
+ case O_MOD:
+ case O_MODASN:
+ if (vr->val.u == 0) {
+ if (!es->noassign)
+ evalerr(es, ET_STR, "zero divisor");
+ vr->val.u = 1;
+ }
+ /* calculate the absolute values */
+ t1 = vl->val.i < 0 ? -vl->val.u : vl->val.u;
+ t2 = vr->val.i < 0 ? -vr->val.u : vr->val.u;
+ break;
+#ifndef MKSH_LEGACY_MODE
+ case O_LSHIFT:
+ case O_LSHIFTASN:
+ case O_RSHIFT:
+ case O_RSHIFTASN:
+ case O_ROL:
+ case O_ROLASN:
+ case O_ROR:
+ case O_RORASN:
+ t1 = vl->val.u;
+ t2 = vr->val.u & 31;
+ break;
+#endif
+ case O_LAND:
+ case O_LOR:
+ t1 = vl->val.u;
+ t2 = 0; /* gcc */
+ break;
+ default:
+ t1 = vl->val.u;
+ t2 = vr->val.u;
+ break;
}
+
+#define cmpop(op) (es->natural ? \
+ (mksh_uari_t)(vl->val.u op vr->val.u) : \
+ (mksh_uari_t)(vl->val.i op vr->val.i) \
+)
+
+ /* op calculation */
switch ((int)op) {
case O_TIMES:
case O_TIMESASN:
- res = bivui(vl, *, vr);
+ res = t1 * t2;
break;
+ case O_MOD:
+ case O_MODASN:
+ if (es->natural) {
+ res = vl->val.u % vr->val.u;
+ break;
+ }
+ goto signed_division;
case O_DIV:
case O_DIVASN:
-#if !HAVE_SILENT_IDIVWRAPV
+ if (es->natural) {
+ res = vl->val.u / vr->val.u;
+ break;
+ }
+ signed_division:
/*
- * we are doing the comparisons here for the
- * signed arithmetics (!es->natural) case,
- * but the exact value checks and the bypass
- * case assignments are done unsignedly as
- * several compilers bitch around otherwise
+ * a / b = abs(a) / abs(b) * sgn((u)a^(u)b)
*/
- if (!es->natural &&
- vl->val.u == IDIVWRAPV_VL &&
- vr->val.u == IDIVWRAPV_VR) {
- /* -2147483648 / -1 = 2147483648 */
- /* this ^ is really (1 << 31) though */
- res = IDIVWRAPV_VL;
- } else
-#endif
- res = bivui(vl, /, vr);
- break;
- case O_MOD:
- case O_MODASN:
-#if !HAVE_SILENT_IDIVWRAPV
- /* see O_DIV / O_DIVASN for the reason behind this */
- if (!es->natural &&
- vl->val.u == IDIVWRAPV_VL &&
- vr->val.u == IDIVWRAPV_VR) {
- /* -2147483648 % -1 = 0 */
- res = 0;
- } else
+ t3 = t1 / t2;
+#ifndef MKSH_LEGACY_MODE
+ res = ((vl->val.u ^ vr->val.u) & 0x80000000) ? -t3 : t3;
+#else
+ res = ((t1 == vl->val.u ? 0 : 1) ^
+ (t2 == vr->val.u ? 0 : 1)) ? -t3 : t3;
#endif
- res = bivui(vl, %, vr);
+ if (op == O_MOD || op == O_MODASN) {
+ /*
+ * primitive modulo, to get the sign of
+ * the result correct:
+ * (a % b) = a - ((a / b) * b)
+ * the subtraction and multiplication
+ * are, amazingly enough, sign ignorant
+ */
+ res = vl->val.u - (res * vr->val.u);
+ }
break;
case O_PLUS:
case O_PLUSASN:
- res = bivui(vl, +, vr);
+ res = t1 + t2;
break;
case O_MINUS:
case O_MINUSASN:
- res = bivui(vl, -, vr);
+ res = t1 - t2;
+ break;
+#ifndef MKSH_LEGACY_MODE
+ case O_ROL:
+ case O_ROLASN:
+ res = (t1 << t2) | (t1 >> (32 - t2));
break;
+ case O_ROR:
+ case O_RORASN:
+ res = (t1 >> t2) | (t1 << (32 - t2));
+ break;
+#endif
case O_LSHIFT:
case O_LSHIFTASN:
- res = bivui(vl, <<, vr);
+ res = t1 << t2;
break;
case O_RSHIFT:
case O_RSHIFTASN:
- res = bivui(vl, >>, vr);
+ res = es->natural || vl->val.i >= 0 ?
+ t1 >> t2 :
+ ~(~t1 >> t2);
break;
case O_LT:
- res = bivui(vl, <, vr);
+ res = cmpop(<);
break;
case O_LE:
- res = bivui(vl, <=, vr);
+ res = cmpop(<=);
break;
case O_GT:
- res = bivui(vl, >, vr);
+ res = cmpop(>);
break;
case O_GE:
- res = bivui(vl, >=, vr);
+ res = cmpop(>=);
break;
case O_EQ:
- res = bivui(vl, ==, vr);
+ res = t1 == t2;
break;
case O_NE:
- res = bivui(vl, !=, vr);
+ res = t1 != t2;
break;
case O_BAND:
case O_BANDASN:
- res = bivui(vl, &, vr);
+ res = t1 & t2;
break;
case O_BXOR:
case O_BXORASN:
- res = bivui(vl, ^, vr);
+ res = t1 ^ t2;
break;
case O_BOR:
case O_BORASN:
- res = bivui(vl, |, vr);
+ res = t1 | t2;
break;
case O_LAND:
- if (!vl->val.i)
+ if (!t1)
es->noassign++;
vr = intvar(es, evalexpr(es, prec - 1));
- res = bivui(vl, &&, vr);
- if (!vl->val.i)
+ res = t1 && vr->val.u;
+ if (!t1)
es->noassign--;
break;
case O_LOR:
- if (vl->val.i)
+ if (t1)
es->noassign++;
vr = intvar(es, evalexpr(es, prec - 1));
- res = bivui(vl, ||, vr);
- if (vl->val.i)
+ res = t1 || vr->val.u;
+ if (t1)
es->noassign--;
break;
- case O_TERN:
- {
- bool ev = vl->val.i != 0;
-
- if (!ev)
- es->noassign++;
- vl = evalexpr(es, MAX_PREC);
- if (!ev)
- es->noassign--;
- if (es->tok != CTERN)
- evalerr(es, ET_STR, "missing :");
- exprtoken(es);
- if (ev)
- es->noassign++;
- vr = evalexpr(es, P_TERN);
- if (ev)
- es->noassign--;
- vl = ev ? vl : vr;
- }
- break;
case O_ASN:
- res = vr->val.u;
- break;
case O_COMMA:
- res = vr->val.u;
+ res = t2;
break;
}
+
+#undef cmpop
+
if (IS_ASSIGNOP(op)) {
vr->val.u = res;
if (!es->noassign) {
if (vasn->flag & INTEGER)
setint_v(vasn, vr, es->arith);
else
- setint(vasn, (mksh_ari_t)res);
+ setint(vasn, vr->val.i);
}
vl = vr;
- } else if (op != O_TERN)
+ } else
vl->val.u = res;
}
return (vl);
int c;
char *tvar;
- /* skip white space */
+ /* skip whitespace */
skip_spaces:
while ((c = *cp), ksh_isspace(c))
++cp;
if (es->tokp == es->expression && c == '#') {
/* expression begins with # */
- es->natural = true; /* switch to unsigned */
+ /* switch to unsigned */
+ es->natural = true;
++cp;
goto skip_spaces;
}
if (len == 0)
evalerr(es, ET_STR, "missing ]");
cp += len;
- } else if (c == '(' /*)*/ ) {
- /* todo: add math functions (all take single argument):
- * abs acos asin atan cos cosh exp int log sin sinh sqrt
- * tan tanh
- */
- ;
}
if (es->noassign) {
es->val = tempvar();
es->tokp = cp;
}
-/* Do a ++ or -- operation */
-static struct tbl *
-do_ppmm(Expr_state *es, enum token op, struct tbl *vasn, bool is_prefix)
-{
- struct tbl *vl;
- mksh_ari_t oval;
-
- assign_check(es, op, vasn);
-
- vl = intvar(es, vasn);
- oval = vl->val.i;
- if (op == O_PLUSPLUS) {
- if (es->natural)
- ++vl->val.u;
- else
- ++vl->val.i;
- } else {
- if (es->natural)
- --vl->val.u;
- else
- --vl->val.i;
- }
- if (vasn->flag & INTEGER)
- setint_v(vasn, vl, es->arith);
- else
- setint(vasn, vl->val.i);
- if (!is_prefix)
- /* undo the increment/decrement */
- vl->val.i = oval;
-
- return (vl);
-}
-
static void
assign_check(Expr_state *es, enum token op, struct tbl *vasn)
{
return ((char *)d - dst);
}
-
-#ifndef MKSH_mirbsd_wcwidth
-/* --- begin of wcwidth.c excerpt --- */
-/*-
- * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
- *
- * Permission to use, copy, modify, and distribute this software
- * for any purpose and without fee is hereby granted. The author
- * disclaims all warranties with regard to this software.
- */
-
-__RCSID("$miros: src/lib/libc/i18n/wcwidth.c,v 1.11 2012/09/01 23:46:43 tg Exp $");
-
-int
-utf_wcwidth(unsigned int c)
-{
- static const struct cbset {
- unsigned short first;
- unsigned short last;
- } comb[] = {
- /* Unicode 6.1.0 BMP */
- { 0x0300, 0x036F }, { 0x0483, 0x0489 }, { 0x0591, 0x05BD },
- { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 },
- { 0x05C7, 0x05C7 }, { 0x0600, 0x0604 }, { 0x0610, 0x061A },
- { 0x064B, 0x065F }, { 0x0670, 0x0670 }, { 0x06D6, 0x06DD },
- { 0x06DF, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
- { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
- { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0816, 0x0819 },
- { 0x081B, 0x0823 }, { 0x0825, 0x0827 }, { 0x0829, 0x082D },
- { 0x0859, 0x085B }, { 0x08E4, 0x08FE }, { 0x0900, 0x0902 },
- { 0x093A, 0x093A }, { 0x093C, 0x093C }, { 0x0941, 0x0948 },
- { 0x094D, 0x094D }, { 0x0951, 0x0957 }, { 0x0962, 0x0963 },
- { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 },
- { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 },
- { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 },
- { 0x0A4B, 0x0A4D }, { 0x0A51, 0x0A51 }, { 0x0A70, 0x0A71 },
- { 0x0A75, 0x0A75 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
- { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
- { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
- { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B44 }, { 0x0B4D, 0x0B4D },
- { 0x0B56, 0x0B56 }, { 0x0B62, 0x0B63 }, { 0x0B82, 0x0B82 },
- { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 },
- { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 },
- { 0x0C62, 0x0C63 }, { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF },
- { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, { 0x0CE2, 0x0CE3 },
- { 0x0D41, 0x0D44 }, { 0x0D4D, 0x0D4D }, { 0x0D62, 0x0D63 },
- { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
- { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
- { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
- { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
- { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
- { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F8D, 0x0F97 },
- { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
- { 0x1032, 0x1037 }, { 0x1039, 0x103A }, { 0x103D, 0x103E },
- { 0x1058, 0x1059 }, { 0x105E, 0x1060 }, { 0x1071, 0x1074 },
- { 0x1082, 0x1082 }, { 0x1085, 0x1086 }, { 0x108D, 0x108D },
- { 0x109D, 0x109D }, { 0x1160, 0x11FF }, { 0x135D, 0x135F },
- { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
- { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
- { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
- { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
- { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
- { 0x1A17, 0x1A18 }, { 0x1A56, 0x1A56 }, { 0x1A58, 0x1A5E },
- { 0x1A60, 0x1A60 }, { 0x1A62, 0x1A62 }, { 0x1A65, 0x1A6C },
- { 0x1A73, 0x1A7C }, { 0x1A7F, 0x1A7F }, { 0x1B00, 0x1B03 },
- { 0x1B34, 0x1B34 }, { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C },
- { 0x1B42, 0x1B42 }, { 0x1B6B, 0x1B73 }, { 0x1B80, 0x1B81 },
- { 0x1BA2, 0x1BA5 }, { 0x1BA8, 0x1BA9 }, { 0x1BAB, 0x1BAB },
- { 0x1BE6, 0x1BE6 }, { 0x1BE8, 0x1BE9 }, { 0x1BED, 0x1BED },
- { 0x1BEF, 0x1BF1 }, { 0x1C2C, 0x1C33 }, { 0x1C36, 0x1C37 },
- { 0x1CD0, 0x1CD2 }, { 0x1CD4, 0x1CE0 }, { 0x1CE2, 0x1CE8 },
- { 0x1CED, 0x1CED }, { 0x1CF4, 0x1CF4 }, { 0x1DC0, 0x1DE6 },
- { 0x1DFC, 0x1DFF }, { 0x200B, 0x200F }, { 0x202A, 0x202E },
- { 0x2060, 0x2064 }, { 0x206A, 0x206F }, { 0x20D0, 0x20F0 },
- { 0x2CEF, 0x2CF1 }, { 0x2D7F, 0x2D7F }, { 0x2DE0, 0x2DFF },
- { 0x302A, 0x302D }, { 0x3099, 0x309A }, { 0xA66F, 0xA672 },
- { 0xA674, 0xA67D }, { 0xA69F, 0xA69F }, { 0xA6F0, 0xA6F1 },
- { 0xA802, 0xA802 }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
- { 0xA825, 0xA826 }, { 0xA8C4, 0xA8C4 }, { 0xA8E0, 0xA8F1 },
- { 0xA926, 0xA92D }, { 0xA947, 0xA951 }, { 0xA980, 0xA982 },
- { 0xA9B3, 0xA9B3 }, { 0xA9B6, 0xA9B9 }, { 0xA9BC, 0xA9BC },
- { 0xAA29, 0xAA2E }, { 0xAA31, 0xAA32 }, { 0xAA35, 0xAA36 },
- { 0xAA43, 0xAA43 }, { 0xAA4C, 0xAA4C }, { 0xAAB0, 0xAAB0 },
- { 0xAAB2, 0xAAB4 }, { 0xAAB7, 0xAAB8 }, { 0xAABE, 0xAABF },
- { 0xAAC1, 0xAAC1 }, { 0xAAEC, 0xAAED }, { 0xAAF6, 0xAAF6 },
- { 0xABE5, 0xABE5 }, { 0xABE8, 0xABE8 }, { 0xABED, 0xABED },
- { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE26 },
- { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }
- };
- size_t min = 0, mid, max = NELEM(comb) - 1;
-
- /* test for 8-bit control characters */
- if (c < 32 || (c >= 0x7F && c < 0xA0))
- return (c ? -1 : 0);
-
- /* binary search in table of non-spacing characters */
- if (c >= comb[0].first && c <= comb[max].last)
- while (max >= min) {
- mid = (min + max) / 2;
- if (c > comb[mid].last)
- min = mid + 1;
- else if (c < comb[mid].first)
- max = mid - 1;
- else
- return (0);
- }
-
- /* if we arrive here, c is not a combining or C0/C1 control char */
-
- return ((c >= 0x1100 && (
- c <= 0x115F || /* Hangul Jamo init. consonants */
- c == 0x2329 || c == 0x232A ||
- (c >= 0x2E80 && c <= 0xA4CF && c != 0x303F) || /* CJK ... Yi */
- (c >= 0xAC00 && c <= 0xD7A3) || /* Hangul Syllables */
- (c >= 0xF900 && c <= 0xFAFF) || /* CJK Compatibility Ideographs */
- (c >= 0xFE10 && c <= 0xFE19) || /* Vertical forms */
- (c >= 0xFE30 && c <= 0xFE6F) || /* CJK Compatibility Forms */
- (c >= 0xFF00 && c <= 0xFF60) || /* Fullwidth Forms */
- (c >= 0xFFE0 && c <= 0xFFE6))) ? 2 : 1);
-}
-/* --- end of wcwidth.c excerpt --- */
-#endif
-
/*
* Wrapper around access(2) because it says root can execute everything
* on some operating systems. Does not set errno, no user needs it. Use
return (rv);
}
+
+#ifndef MKSH_mirbsd_wcwidth
+/* From: X11/xc/programs/xterm/wcwidth.c,v 1.6 2013/05/31 23:27:09 tg Exp $ */
+
+struct mb_ucsrange {
+ unsigned short beg;
+ unsigned short end;
+};
+
+static int mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems,
+ unsigned int val);
+
+/*
+ * Generated by MirOS: contrib/code/Snippets/eawparse,v 1.1 2013/05/31 23:27:16 tg Exp $
+ * from Unicode 6.2.0
+ */
+
+static const struct mb_ucsrange mb_ucs_combining[] = {
+ { 0x0300, 0x036F },
+ { 0x0483, 0x0489 },
+ { 0x0591, 0x05BD },
+ { 0x05BF, 0x05BF },
+ { 0x05C1, 0x05C2 },
+ { 0x05C4, 0x05C5 },
+ { 0x05C7, 0x05C7 },
+ { 0x0600, 0x0604 },
+ { 0x0610, 0x061A },
+ { 0x064B, 0x065F },
+ { 0x0670, 0x0670 },
+ { 0x06D6, 0x06DD },
+ { 0x06DF, 0x06E4 },
+ { 0x06E7, 0x06E8 },
+ { 0x06EA, 0x06ED },
+ { 0x070F, 0x070F },
+ { 0x0711, 0x0711 },
+ { 0x0730, 0x074A },
+ { 0x07A6, 0x07B0 },
+ { 0x07EB, 0x07F3 },
+ { 0x0816, 0x0819 },
+ { 0x081B, 0x0823 },
+ { 0x0825, 0x0827 },
+ { 0x0829, 0x082D },
+ { 0x0859, 0x085B },
+ { 0x08E4, 0x08FE },
+ { 0x0900, 0x0902 },
+ { 0x093A, 0x093A },
+ { 0x093C, 0x093C },
+ { 0x0941, 0x0948 },
+ { 0x094D, 0x094D },
+ { 0x0951, 0x0957 },
+ { 0x0962, 0x0963 },
+ { 0x0981, 0x0981 },
+ { 0x09BC, 0x09BC },
+ { 0x09C1, 0x09C4 },
+ { 0x09CD, 0x09CD },
+ { 0x09E2, 0x09E3 },
+ { 0x0A01, 0x0A02 },
+ { 0x0A3C, 0x0A3C },
+ { 0x0A41, 0x0A42 },
+ { 0x0A47, 0x0A48 },
+ { 0x0A4B, 0x0A4D },
+ { 0x0A51, 0x0A51 },
+ { 0x0A70, 0x0A71 },
+ { 0x0A75, 0x0A75 },
+ { 0x0A81, 0x0A82 },
+ { 0x0ABC, 0x0ABC },
+ { 0x0AC1, 0x0AC5 },
+ { 0x0AC7, 0x0AC8 },
+ { 0x0ACD, 0x0ACD },
+ { 0x0AE2, 0x0AE3 },
+ { 0x0B01, 0x0B01 },
+ { 0x0B3C, 0x0B3C },
+ { 0x0B3F, 0x0B3F },
+ { 0x0B41, 0x0B44 },
+ { 0x0B4D, 0x0B4D },
+ { 0x0B56, 0x0B56 },
+ { 0x0B62, 0x0B63 },
+ { 0x0B82, 0x0B82 },
+ { 0x0BC0, 0x0BC0 },
+ { 0x0BCD, 0x0BCD },
+ { 0x0C3E, 0x0C40 },
+ { 0x0C46, 0x0C48 },
+ { 0x0C4A, 0x0C4D },
+ { 0x0C55, 0x0C56 },
+ { 0x0C62, 0x0C63 },
+ { 0x0CBC, 0x0CBC },
+ { 0x0CBF, 0x0CBF },
+ { 0x0CC6, 0x0CC6 },
+ { 0x0CCC, 0x0CCD },
+ { 0x0CE2, 0x0CE3 },
+ { 0x0D41, 0x0D44 },
+ { 0x0D4D, 0x0D4D },
+ { 0x0D62, 0x0D63 },
+ { 0x0DCA, 0x0DCA },
+ { 0x0DD2, 0x0DD4 },
+ { 0x0DD6, 0x0DD6 },
+ { 0x0E31, 0x0E31 },
+ { 0x0E34, 0x0E3A },
+ { 0x0E47, 0x0E4E },
+ { 0x0EB1, 0x0EB1 },
+ { 0x0EB4, 0x0EB9 },
+ { 0x0EBB, 0x0EBC },
+ { 0x0EC8, 0x0ECD },
+ { 0x0F18, 0x0F19 },
+ { 0x0F35, 0x0F35 },
+ { 0x0F37, 0x0F37 },
+ { 0x0F39, 0x0F39 },
+ { 0x0F71, 0x0F7E },
+ { 0x0F80, 0x0F84 },
+ { 0x0F86, 0x0F87 },
+ { 0x0F8D, 0x0F97 },
+ { 0x0F99, 0x0FBC },
+ { 0x0FC6, 0x0FC6 },
+ { 0x102D, 0x1030 },
+ { 0x1032, 0x1037 },
+ { 0x1039, 0x103A },
+ { 0x103D, 0x103E },
+ { 0x1058, 0x1059 },
+ { 0x105E, 0x1060 },
+ { 0x1071, 0x1074 },
+ { 0x1082, 0x1082 },
+ { 0x1085, 0x1086 },
+ { 0x108D, 0x108D },
+ { 0x109D, 0x109D },
+ { 0x1160, 0x11FF },
+ { 0x135D, 0x135F },
+ { 0x1712, 0x1714 },
+ { 0x1732, 0x1734 },
+ { 0x1752, 0x1753 },
+ { 0x1772, 0x1773 },
+ { 0x17B4, 0x17B5 },
+ { 0x17B7, 0x17BD },
+ { 0x17C6, 0x17C6 },
+ { 0x17C9, 0x17D3 },
+ { 0x17DD, 0x17DD },
+ { 0x180B, 0x180D },
+ { 0x18A9, 0x18A9 },
+ { 0x1920, 0x1922 },
+ { 0x1927, 0x1928 },
+ { 0x1932, 0x1932 },
+ { 0x1939, 0x193B },
+ { 0x1A17, 0x1A18 },
+ { 0x1A56, 0x1A56 },
+ { 0x1A58, 0x1A5E },
+ { 0x1A60, 0x1A60 },
+ { 0x1A62, 0x1A62 },
+ { 0x1A65, 0x1A6C },
+ { 0x1A73, 0x1A7C },
+ { 0x1A7F, 0x1A7F },
+ { 0x1B00, 0x1B03 },
+ { 0x1B34, 0x1B34 },
+ { 0x1B36, 0x1B3A },
+ { 0x1B3C, 0x1B3C },
+ { 0x1B42, 0x1B42 },
+ { 0x1B6B, 0x1B73 },
+ { 0x1B80, 0x1B81 },
+ { 0x1BA2, 0x1BA5 },
+ { 0x1BA8, 0x1BA9 },
+ { 0x1BAB, 0x1BAB },
+ { 0x1BE6, 0x1BE6 },
+ { 0x1BE8, 0x1BE9 },
+ { 0x1BED, 0x1BED },
+ { 0x1BEF, 0x1BF1 },
+ { 0x1C2C, 0x1C33 },
+ { 0x1C36, 0x1C37 },
+ { 0x1CD0, 0x1CD2 },
+ { 0x1CD4, 0x1CE0 },
+ { 0x1CE2, 0x1CE8 },
+ { 0x1CED, 0x1CED },
+ { 0x1CF4, 0x1CF4 },
+ { 0x1DC0, 0x1DE6 },
+ { 0x1DFC, 0x1DFF },
+ { 0x200B, 0x200F },
+ { 0x202A, 0x202E },
+ { 0x2060, 0x2064 },
+ { 0x206A, 0x206F },
+ { 0x20D0, 0x20F0 },
+ { 0x2CEF, 0x2CF1 },
+ { 0x2D7F, 0x2D7F },
+ { 0x2DE0, 0x2DFF },
+ { 0x302A, 0x302D },
+ { 0x3099, 0x309A },
+ { 0xA66F, 0xA672 },
+ { 0xA674, 0xA67D },
+ { 0xA69F, 0xA69F },
+ { 0xA6F0, 0xA6F1 },
+ { 0xA802, 0xA802 },
+ { 0xA806, 0xA806 },
+ { 0xA80B, 0xA80B },
+ { 0xA825, 0xA826 },
+ { 0xA8C4, 0xA8C4 },
+ { 0xA8E0, 0xA8F1 },
+ { 0xA926, 0xA92D },
+ { 0xA947, 0xA951 },
+ { 0xA980, 0xA982 },
+ { 0xA9B3, 0xA9B3 },
+ { 0xA9B6, 0xA9B9 },
+ { 0xA9BC, 0xA9BC },
+ { 0xAA29, 0xAA2E },
+ { 0xAA31, 0xAA32 },
+ { 0xAA35, 0xAA36 },
+ { 0xAA43, 0xAA43 },
+ { 0xAA4C, 0xAA4C },
+ { 0xAAB0, 0xAAB0 },
+ { 0xAAB2, 0xAAB4 },
+ { 0xAAB7, 0xAAB8 },
+ { 0xAABE, 0xAABF },
+ { 0xAAC1, 0xAAC1 },
+ { 0xAAEC, 0xAAED },
+ { 0xAAF6, 0xAAF6 },
+ { 0xABE5, 0xABE5 },
+ { 0xABE8, 0xABE8 },
+ { 0xABED, 0xABED },
+ { 0xFB1E, 0xFB1E },
+ { 0xFE00, 0xFE0F },
+ { 0xFE20, 0xFE26 },
+ { 0xFEFF, 0xFEFF },
+ { 0xFFF9, 0xFFFB }
+};
+
+static const struct mb_ucsrange mb_ucs_fullwidth[] = {
+ { 0x1100, 0x115F },
+ { 0x2329, 0x232A },
+ { 0x2E80, 0x303E },
+ { 0x3040, 0xA4CF },
+ { 0xA960, 0xA97F },
+ { 0xAC00, 0xD7A3 },
+ { 0xF900, 0xFAFF },
+ { 0xFE10, 0xFE19 },
+ { 0xFE30, 0xFE6F },
+ { 0xFF00, 0xFF60 },
+ { 0xFFE0, 0xFFE6 }
+};
+
+/* simple binary search in ranges, with bounds optimisation */
+static int
+mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems, unsigned int val)
+{
+ size_t min = 0, mid, max = elems;
+
+ if (val < arr[min].beg || val > arr[max - 1].end)
+ return (0);
+
+ while (min < max) {
+ mid = (min + max) / 2;
+
+ if (val < arr[mid].beg)
+ max = mid;
+ else if (val > arr[mid].end)
+ min = mid + 1;
+ else
+ return (1);
+ }
+ return (0);
+}
+
+/* Unix column width of a wide character (Unicode code point, really) */
+int
+utf_wcwidth(unsigned int wc)
+{
+ /* except NUL, C0/C1 control characters and DEL yield -1 */
+ if (wc < 0x20 || (wc >= 0x7F && wc < 0xA0))
+ return (wc ? -1 : 0);
+
+ /* combining characters use 0 screen columns */
+ if (mb_ucsbsearch(mb_ucs_combining, NELEM(mb_ucs_combining), wc))
+ return (0);
+
+ /* all others use 1 or 2 screen columns */
+ if (mb_ucsbsearch(mb_ucs_fullwidth, NELEM(mb_ucs_fullwidth), wc))
+ return (2);
+ return (1);
+}
+#endif
/* $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 $ */
#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
/*
}
/*
- * A leading = means assignments before command are kept;
- * a leading * means a POSIX special builtin;
- * a leading + means a POSIX regular builtin
- * (* and + should not be combined).
+ * A leading = means assignments before command are kept.
+ * A leading * means a POSIX special builtin.
*/
const struct builtin mkshbuiltins[] = {
{"*=.", c_dot},
{"*=:", c_true},
{"[", c_test},
+ /* no =: AT&T manual wrong */
+ {Talias, c_alias},
{"*=break", c_brkcont},
{Tgbuiltin, c_builtin},
+ {"cat", c_cat},
+ {"cd", c_cd},
+ /* dash compatibility hack */
+ {"chdir", c_cd},
+ {"command", c_command},
{"*=continue", c_brkcont},
+ {"echo", c_print},
{"*=eval", c_eval},
{"*=exec", c_exec},
{"*=exit", c_exitreturn},
- {"+false", c_false},
- {"*=return", c_exitreturn},
- {Tsgset, c_set},
- {"*=shift", c_shift},
- {"=times", c_times},
- {"*=trap", c_trap},
- {"+=wait", c_wait},
- {"+read", c_read},
- {"test", c_test},
- {"+true", c_true},
- {"ulimit", c_ulimit},
- {"+umask", c_umask},
- {Tsgunset, c_unset},
- /* no =: AT&T manual wrong */
- {Tpalias, c_alias},
- {"+cd", c_cd},
- /* dash compatibility hack */
- {"chdir", c_cd},
- {"+command", c_command},
- {"echo", c_print},
{Tsgexport, c_typeset},
- {"+fc", c_fc},
- {"+getopts", c_getopts},
+ {"false", c_false},
+ {"fc", c_fc},
+ {"getopts", c_getopts},
{"=global", c_typeset},
- {"+jobs", c_jobs},
- {"+kill", c_kill},
+ {"jobs", c_jobs},
+ {"kill", c_kill},
{"let", c_let},
+ {"let]", c_let},
{"print", c_print},
-#ifdef MKSH_PRINTF_BUILTIN
- {"printf", c_printf},
-#endif
{"pwd", c_pwd},
+ {"read", c_read},
{Tsgreadonly, c_typeset},
+ {"realpath", c_realpath},
+ {"rename", c_rename},
+ {"*=return", c_exitreturn},
+ {Tsgset, c_set},
+ {"*=shift", c_shift},
+ {"test", c_test},
+ {"*=times", c_times},
+ {"*=trap", c_trap},
+ {"true", c_true},
{T_typeset, c_typeset},
- {Tpunalias, c_unalias},
+ {"ulimit", c_ulimit},
+ {"umask", c_umask},
+ {Tunalias, c_unalias},
+ {Tsgunset, c_unset},
+ {"=wait", c_wait},
{"whence", c_whence},
#ifndef MKSH_UNEMPLOYED
- {"+bg", c_fgbg},
- {"+fg", c_fgbg},
+ {"bg", c_fgbg},
+ {"fg", c_fgbg},
#endif
#ifndef MKSH_NO_CMDLINE_EDITING
{"bind", c_bind},
#endif
- {"cat", c_cat},
#if HAVE_MKNOD
{"mknod", c_mknod},
#endif
- {"realpath", c_realpath},
- {"rename", c_rename},
+#ifdef MKSH_PRINTF_BUILTIN
+ {"printf", c_printf},
+#endif
#if HAVE_SELECT
{"sleep", c_sleep},
#endif
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;
}
}
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);
* 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
}
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);
}
-/* $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
#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
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 */
#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 */
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);
/* 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
/*
}
/* 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;
zflag = 1;
}
if (cp) {
- int ecode;
+ int ecode;
if ((j = j_lookup(cp, &ecode)) == NULL) {
#ifndef MKSH_NOPROSPECTOFWORK
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;
}
}
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;
#ifdef MKSH_NO_SIGSUSPEND
sigprocmask(SIG_SETMASK, &omask, NULL);
#endif
- /* nothing */;
+ errno = saved_errno;
}
/*
/*-
- * 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
#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)
|| 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;
-/* $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,
#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
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;
}
break;
case '\'':
- open_ssquote:
+ open_ssquote_unless_heredoc:
+ if ((cf & HEREDOC))
+ goto store_char;
*wp++ = OQUOTE;
ignore_backslash_newline++;
PUSH_STATE(SSQUOTE);
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
PUSH_STATE(STBRACEKORN);
} else {
ungetsc(c);
- if (state == SDQUOTE)
+ if (state == SDQUOTE ||
+ state == SQBRACE)
PUSH_STATE(SQBRACE);
else
PUSH_STATE(SBRACE);
case SSQUOTE:
if (c == '\'') {
POP_STATE();
+ if ((cf & HEREDOC) || state == SQBRACE)
+ goto store_char;
*wp++ = CQUOTE;
ignore_backslash_newline--;
} else {
case SBRACE:
if (c == '\'')
- goto open_ssquote;
+ goto open_ssquote_unless_heredoc;
else if (c == '\\')
goto getsc_qchar;
common_SQBRACE:
}
break;
case '\'':
- goto open_ssquote;
+ goto open_ssquote_unless_heredoc;
case '$':
if ((c2 = getsc()) == '\'') {
open_sequote:
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)
Flag(FEMACS) || Flag(FGMACS))) {
int nread;
- nread = x_read(xp, LINE);
+ nread = x_read(xp);
if (nread < 0)
/* read error */
nread = 0;
}
}
-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;
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).
--- /dev/null
+.\" $MirOS: src/bin/mksh/lksh.1,v 1.5 2013/05/22 18:18:06 tg Exp $
+.\"-
+.\" Copyright (c) 2008, 2009, 2010, 2012, 2013
+.\" Thorsten “mirabilos” Glaser <tg@mirbsd.org>
+.\"
+.\" Provided that these terms and disclaimer and all copyright notices
+.\" are retained or reproduced in an accompanying document, permission
+.\" is granted to deal in this work without restriction, including un‐
+.\" limited rights to use, publicly perform, distribute, sell, modify,
+.\" merge, give away, or sublicence.
+.\"
+.\" This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
+.\" the utmost extent permitted by applicable law, neither express nor
+.\" implied; without malicious intent or gross negligence. In no event
+.\" may a licensor, author or contributor be held liable for indirect,
+.\" direct, other damage, loss, or other issues arising in any way out
+.\" of dealing in the work, even if advised of the possibility of such
+.\" damage or existence of a defect, except proven that it results out
+.\" of said person’s immediate fault when using the work as intended.
+.\"-
+.\" Try to make GNU groff and AT&T nroff more compatible
+.\" * ` generates ‘ in gnroff, so use \`
+.\" * ' generates ’ in gnroff, \' generates ´, so use \*(aq
+.\" * - generates ‐ in gnroff, \- generates −, so .tr it to -
+.\" thus use - for hyphens and \- for minus signs and option dashes
+.\" * ~ is size-reduced and placed atop in groff, so use \*(TI
+.\" * ^ is size-reduced and placed atop in groff, so use \*(ha
+.\" * \(en does not work in nroff, so use \*(en
+.\" * <>| are problematic, so redefine and use \*(Lt\*(Gt\*(Ba
+.\" Also make sure to use \& especially with two-letter words.
+.\" The section after the "doc" macropackage has been loaded contains
+.\" additional code to convene between the UCB mdoc macropackage (and
+.\" its variant as BSD mdoc in groff) and the GNU mdoc macropackage.
+.\"
+.ie \n(.g \{\
+. if \ 1\*[.T]\ 1ascii\ 1 .tr \-\N'45'
+. if \ 1\*[.T]\ 1latin1\ 1 .tr \-\N'45'
+. if \ 1\*[.T]\ 1utf8\ 1 .tr \-\N'45'
+. ds <= \[<=]
+. ds >= \[>=]
+. ds Rq \[rq]
+. ds Lq \[lq]
+. ds sL \(aq
+. ds sR \(aq
+. if \ 1\*[.T]\ 1utf8\ 1 .ds sL `
+. if \ 1\*[.T]\ 1ps\ 1 .ds sL `
+. if \ 1\*[.T]\ 1utf8\ 1 .ds sR '
+. if \ 1\*[.T]\ 1ps\ 1 .ds sR '
+. ds aq \(aq
+. ds TI \(ti
+. ds ha \(ha
+. ds en \(en
+.\}
+.el \{\
+. ds aq '
+. ds TI ~
+. ds ha ^
+. ds en \(em
+.\}
+.\"
+.\" Implement .Dd with the Mdocdate RCS keyword
+.\"
+.rn Dd xD
+.de Dd
+.ie \a\\$1\a$Mdocdate:\a \{\
+. xD \\$2 \\$3, \\$4
+.\}
+.el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
+..
+.\"
+.\" .Dd must come before definition of .Mx, because when called
+.\" with -mandoc, it might implement .Mx itself, but we want to
+.\" use our own definition. And .Dd must come *first*, always.
+.\"
+.Dd $Mdocdate: May 22 2013 $
+.\"
+.\" Check which macro package we use, and do other -mdoc setup.
+.\"
+.ie \n(.g \{\
+. if \ 1\*[.T]\ 1utf8\ 1 .tr \[la]\*(Lt
+. if \ 1\*[.T]\ 1utf8\ 1 .tr \[ra]\*(Gt
+. ie d volume-ds-1 .ds tT gnu
+. el .ds tT bsd
+.\}
+.el .ds tT ucb
+.\"
+.\" Implement .Mx (MirBSD)
+.\"
+.ie "\*(tT"gnu" \{\
+. eo
+. de Mx
+. nr curr-font \n[.f]
+. nr curr-size \n[.ps]
+. ds str-Mx \f[\n[curr-font]]\s[\n[curr-size]u]
+. ds str-Mx1 \*[Tn-font-size]\%MirOS\*[str-Mx]
+. if !\n[arg-limit] \
+. if \n[.$] \{\
+. ds macro-name Mx
+. parse-args \$@
+. \}
+. if (\n[arg-limit] > \n[arg-ptr]) \{\
+. nr arg-ptr +1
+. ie (\n[type\n[arg-ptr]] == 2) \
+. as str-Mx1 \~\*[arg\n[arg-ptr]]
+. el \
+. nr arg-ptr -1
+. \}
+. ds arg\n[arg-ptr] "\*[str-Mx1]
+. nr type\n[arg-ptr] 2
+. ds space\n[arg-ptr] "\*[space]
+. nr num-args (\n[arg-limit] - \n[arg-ptr])
+. nr arg-limit \n[arg-ptr]
+. if \n[num-args] \
+. parse-space-vector
+. print-recursive
+..
+. ec
+. ds sP \s0
+. ds tN \*[Tn-font-size]
+.\}
+.el \{\
+. de Mx
+. nr cF \\n(.f
+. nr cZ \\n(.s
+. ds aa \&\f\\n(cF\s\\n(cZ
+. if \\n(aC==0 \{\
+. ie \\n(.$==0 \&MirOS\\*(aa
+. el .aV \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
+. \}
+. if \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. ie \\n(C\\n(aP==2 \{\
+. as b1 \&MirOS\ #\&\\*(A\\n(aP\\*(aa
+. ie \\n(aC>\\n(aP \{\
+. nr aP \\n(aP+1
+. nR
+. \}
+. el .aZ
+. \}
+. el \{\
+. as b1 \&MirOS\\*(aa
+. nR
+. \}
+. \}
+..
+.\}
+.\"-
+.Dt LKSH 1
+.Os MirBSD
+.Sh NAME
+.Nm lksh
+.Nd Legacy Korn shell built on mksh
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl +abCefhiklmnprUuvXx
+.Op Fl +o Ar opt
+.Oo
+.Fl c Ar string \*(Ba
+.Fl s \*(Ba
+.Ar file
+.Op Ar args ...
+.Oc
+.Ek
+.Sh DESCRIPTION
+.Nm
+is a command interpreter intended exclusively for running legacy
+shell scripts.
+It is built on
+.Nm mksh ;
+refer to its manual page for details on the scripting language.
+It is recommended to port scripts to
+.Nm mksh
+instead of relying on legacy or idiotic POSIX-mandated behaviour,
+since the MirBSD Korn Shell scripting language is much more consistent.
+.Sh LEGACY MODE
+.Nm
+has the following differences from
+.Nm mksh :
+.Bl -bullet
+.It
+There is no explicit support for interactive use,
+nor any command line editing or history code.
+Hence,
+.Nm
+is not suitable as a user's login shell, either; use
+.Nm mksh
+instead.
+.It
+The
+.Ev KSH_VERSION
+string identifies
+.Nm
+as
+.Dq LEGACY KSH
+instead of
+.Dq MIRBSD KSH .
+.It
+.Nm
+only offers the traditional ten file descriptors to scripts.
+.It
+.Nm
+uses
+.Tn POSIX
+arithmetics, which has quite a few implications:
+The data type for arithmetics is the host ISO C
+.Vt long
+data type.
+Signed integer wraparound is Undefined Behaviour.
+The sign of the result of a modulo operation with at least one
+negative operand is unspecified.
+Shift operations on negative numbers are unspecified.
+Division of the largest negative number by \-1 is Undefined Behaviour.
+The compiler is permitted to delete all data and crash the system
+if Undefined Behaviour occurs.
+.It
+The rotation arithmetic operators are not available.
+.It
+The shift arithmetic operators take all bits of the second operand into
+account; if they exceed permitted precision, the result is unspecified.
+.It
+The
+.Tn GNU
+.Nm bash
+extension &\*(Gt to redirect stdout and stderr in one go is not parsed.
+.It
+The
+.Nm mksh
+command line option
+.Fl T
+is not available.
+.It
+Unless
+.Ic set -o posix
+is active,
+.Nm
+always uses traditional mode for constructs like:
+.Bd -literal -offset indent
+$ set -- $(getopt ab:c "$@")
+$ echo $?
+.Ed
+.Pp
+POSIX mandates this to show 0, but traditional mode
+passes through the errorlevel from the
+.Xr getopt 1
+command.
+.It
+.Nm lksh ,
+unlike
+.At
+.Nm ksh ,
+does not keep file descriptors \*(Gt 2 private.
+.El
+.Sh SEE ALSO
+.Xr mksh 1
+.Pp
+.Pa https://www.mirbsd.org/mksh.htm
+.Pp
+.Pa https://www.mirbsd.org/ksh\-chan.htm
+.Sh CAVEATS
+To use
+.Nm
+as
+.Pa /bin/sh ,
+compilation to enable
+.Ic set -o posix
+by default is highly recommended for better standards compliance.
+.Pp
+.Nm
+tries to make a cross between a legacy bourne/posix compatibl-ish
+shell and a legacy pdksh-alike but
+.Dq legacy
+is not exactly specified.
+.Pp
+The
+.Ic set
+built-in command does not have all options one would expect
+from a full-blown
+.Nm mksh
+or
+.Nm pdksh .
+.Pp
+Talk to the
+.Mx
+development team using the mailing list at
+.Aq miros\-mksh@mirbsd.org
+or the
+.Li \&#\&!/bin/mksh
+.Pq or Li \&#ksh
+IRC channel at
+.Pa irc.freenode.net
+.Pq Port 6697 SSL, 6667 unencrypted
+if you need any further quirks or assistance,
+and consider migrating your legacy scripts to work with
+.Nm mksh
+instead of requiring
+.Nm .
-/* $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 $ */
#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;
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 *);
/* 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
/* 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,
if (argi < 0)
return (1);
+#if defined(MKSH_BINSHPOSIX) || defined(MKSH_BINSHREDUCED)
+ /* are we called as -sh or /bin/sh or so? */
+ if (!strcmp(ccp, "sh")) {
+ /* either also turns off braceexpand */
+#ifdef MKSH_BINSHPOSIX
+ /* enable better POSIX conformance */
+ change_flag(FPOSIX, OF_FIRSTTIME, true);
+#endif
#ifdef MKSH_BINSHREDUCED
- /* set FSH if we're called as -sh or /bin/sh or so */
- if (!strcmp(ccp, "sh"))
+ /* enable kludge/compat mode */
change_flag(FSH, OF_FIRSTTIME, true);
#endif
+ }
+#endif
}
initvar();
*/
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
return (1);
}
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(MKSH_LEGACY_MODE)
/* test wraparound of arithmetic types */
{
volatile long xl;
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");
}
/* 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;
#ifndef MKSH_NO_CMDLINE_EDITING
x_done();
#endif
+#ifndef MKSH_NOPROSPECTOFWORK
+ /* block at least SIGCHLD during/after afreeall */
+ sigprocmask(SIG_BLOCK, &sm_sigchld, NULL);
+#endif
afreeall(APERM);
for (fd = 3; fd < NUFILE; fd++)
if ((i = fcntl(fd, F_GETFD, 0)) != -1 &&
/* 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 != '/')
{
char *cp;
size_t len;
- int i;
+ int i, j;
struct temp *tp;
const char *dir;
struct stat sb;
}
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;
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012
+ * 2011, 2012, 2013
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include <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
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 */
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"
};
size_t
option(const char *n)
{
- size_t i;
+ size_t i = 0;
- if ((n[0] == '-' || n[0] == '+') && n[1] && !n[2]) {
- for (i = 0; i < NELEM(options); i++)
- if (options[i].c == n[1])
+ if ((n[0] == '-' || n[0] == '+') && n[1] && !n[2])
+ while (i < NELEM(options)) {
+ if (OFC(i) == n[1])
+ return (i);
+ ++i;
+ }
+ else
+ while (i < NELEM(options)) {
+ if (!strcmp(OFN(i), n))
return (i);
- } else for (i = 0; i < NELEM(options); i++)
- if (options[i].name && strcmp(options[i].name, n) == 0)
- return (i);
+ ++i;
+ }
return ((size_t)-1);
}
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);
}
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;
}
} 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);
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);
}
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
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.
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';
*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';
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
* 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");
errorf("no TIOCSCTTY ioctl");
#else
change_flag(FTALKING, OF_CMDLINE, true);
- chvt(go.optarg);
+ chvt(&go);
break;
#endif
#endif
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;
}
(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++;
}
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));
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);
}
/* 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++) {
#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))
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
-.\" $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
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
-.Dd $Mdocdate: February 19 2013 $
+.Dd $Mdocdate: August 10 2013 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
.Nm
.Bk -words
.Op Fl +abCefhiklmnprUuvXx
-.Op Fl T Ar /dev/ttyCn \*(Ba \-
+.Oo
+.Fl T Oo Ar \&! Oc Ns Ar tty
+\*(Ba
+.Ar \&\-
+.Oc
.Op Fl +o Ar option
.Oo
.Fl c Ar string \*(Ba
.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
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
.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
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
.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 ,
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
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
.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
.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.
.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 ?
.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
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
.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.
The original
.Nm ksh
and POSIX differ somewhat in which commands are considered
-special or regular:
+special or regular.
.Pp
-POSIX special commands
+POSIX special built-in utilities:
.Pp
.Ic \&. , \&: , break , continue ,
.Ic eval , exec , exit , export ,
.Ic readonly , return , set , shift ,
-.Ic trap , unset , wait
+.Ic times , trap , unset
.Pp
Additional
.Nm
-special commands
-.Pp
-.Ic builtin , global , times , typeset
-.Pp
-Very special commands
-.Pq non-POSIX
+commands keeping assignments:
.Pp
-.Ic alias , readonly , set , typeset
+.Ic builtin , global , typeset , wait
.Pp
-POSIX regular commands
+Builtins that are not special:
.Pp
-.Ic alias , bg , cd , command ,
+.Ic [ , alias , bg , bind ,
+.Ic cat , cd , command , echo ,
.Ic false , fc , fg , getopts ,
-.Ic jobs , kill , read , true ,
-.Ic umask , unalias
-.Pp
-Additional
-.Nm
-regular commands
-.Pp
-.Ic \&[ , chdir , bind , cat ,
-.Ic echo , let , mknod , print ,
-.Ic pwd , realpath , rename , sleep ,
-.Ic test , ulimit , whence
-.Pp
-In the future, the additional
-.Nm
-special and regular commands may be treated
-differently from the POSIX special and regular commands.
+.Ic jobs , kill , let , mknod ,
+.Ic print , pwd , read , realpath ,
+.Ic rename , sleep , test , true ,
+.Ic ulimit , umask , unalias , whence
.Pp
Once the type of command has been determined, any command-line parameter
assignments are performed and exported for the duration of the command.
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
.Ev OPTIND ,
may lead to unexpected results.
.Pp
+.It global Ar ...
+See
+.Ic typeset .
+.Pp
.It Xo
.Ic hash
.Op Fl r
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
.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
.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
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
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
.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
.\" 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,
.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 ,
/* $OpenBSD: table.h,v 1.8 2012/02/19 07:52:30 otto Exp $ */
/* $OpenBSD: tree.h,v 1.10 2005/03/28 21:28:22 deraadt Exp $ */
/* $OpenBSD: expand.h,v 1.6 2005/03/30 17:16:37 deraadt Exp $ */
-/* $OpenBSD: lex.h,v 1.12 2013/01/20 14:47:46 stsp Exp $ */
+/* $OpenBSD: lex.h,v 1.13 2013/03/03 19:11:34 guenther Exp $ */
/* $OpenBSD: proto.h,v 1.34 2012/06/27 07:17:19 otto Exp $ */
/* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */
/* $OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $ */
#endif
#ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.639 2013/02/19 18:45:22 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.667 2013/08/14 20:26:19 tg Exp $");
#endif
-#define MKSH_VERSION "R43 2013/02/19"
+#define MKSH_VERSION "R48 2013/08/14"
/* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES
#endif
#if defined(DEBUG) || !HAVE_STRERROR
+#undef strerror
#define strerror /* poisoned */ dontuse_strerror
#define cstrerror /* replaced */ cstrerror
extern const char *cstrerror(int);
/* 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__);
#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
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)
#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)
{
#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"
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");
* 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
/* 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.
#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
/* 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 */
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.
*/
#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
#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 */
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);
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);
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 */
#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
/* ./. 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)
/* ./. 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 */
/* -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) */
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
-/* $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
#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 */
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);
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;
return (shf_sclose(&shf));
}
-#define BUF_SIZE 128
-
#define FL_HASH 0x001 /* '#' seen */
#define FL_PLUS 0x002 /* '+' seen */
#define FL_RIGHT 0x004 /* '-' seen */
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;
-/* $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
#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) */
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);
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;
}
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;
}
} 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;
}
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
t = pipeline(0);
if (t == NULL)
syntaxerr(NULL);
- t = block(TBANG, NOBLOCK, t, NOWORDS);
+ t = block(TBANG, NULL, t);
break;
case TIME:
t->str[0] = '\0';
t->str[1] = '\0';
}
- t = block(TTIME, t, NOBLOCK, NOWORDS);
+ t = block(TTIME, t, NULL);
break;
case FUNCTION:
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);
} while (token(0) == '|');
REJECT;
XPput(ptns, NULL);
- t->vars = (char **) XPclose(ptns);
+ t->vars = (char **)XPclose(ptns);
musthave(')', 0);
t->left = c_list(true);
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));
}
/*
*/
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);
}
struct yyrecursive_state *ys;
int stok, etok;
- if (subtype == FUNSUB) {
+ if (subtype != COMSUB) {
stok = '{';
etok = '}';
} else {
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012
+ * 2011, 2012, 2013
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.67 2012/12/04 01:10:35 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.71 2013/07/26 20:33:24 tg Exp $");
#define INDENT 8
static void ptree(struct op *, int, struct shf *);
-static void pioact(struct shf *, int, struct ioword *);
+static void pioact(struct shf *, struct ioword *);
static const char *wdvarput(struct shf *, const char *, int, int);
static void vfptreef(struct shf *, int, const char *, va_list);
static struct ioword **iocopy(struct ioword **, Area *);
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) {
}
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;
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);
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;
}
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:
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);
break;
case COMSUB:
case FUNSUB:
+ case VALSUB:
case EXPRSUB:
while (*wp++ != 0)
;
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) {
case FUNSUB:
shf_puts("FUNSUB<", shf);
goto dumpsub;
+ case VALSUB:
+ shf_puts("VALSUB<", shf);
+ goto dumpsub;
case EXPRSUB:
shf_puts("EXPRSUB<", shf);
goto dumpsub;
-/* $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,
#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
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 *);
/*
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 ('#') +
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;
}
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)
* 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;
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);
}
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;
/* 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,
* 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 {
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);
}
}
static void
getspec(struct tbl *vp)
{
- register mksh_ari_t i;
+ mksh_ari_u num;
int st;
struct timeval tv;
}
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 */
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:
/*
*/
if (vp->flag & ISSET) {
mksh_TIME(tv);
- i = tv.tv_sec - seconds;
+ num.i = tv.tv_sec - seconds;
} else
return;
break;
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;
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;
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;
}
}
}
void
-rndset(long v)
+rndset(unsigned long v)
{
register uint32_t h;