diff --git a/Android.mk b/Android.mk index 2d572bd..6fd3f57 100644 --- a/Android.mk +++ b/Android.mk @@ -45,7 +45,7 @@ LOCAL_CFLAGS += \ -Wno-deprecated-declarations \ -fno-asynchronous-unwind-tables \ -fno-strict-aliasing \ - -fstack-protector -fwrapv \ + -fstack-protector-strong -fwrapv \ # ...and CPPFLAGS. LOCAL_CFLAGS += \ @@ -79,6 +79,6 @@ LOCAL_CFLAGS += \ -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 -DMKSH_BUILD_R=504 + -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=505 include $(BUILD_EXECUTABLE) diff --git a/Makefrag.inc b/Makefrag.inc index b7a35bd..c5d5f6d 100644 --- a/Makefrag.inc +++ b/Makefrag.inc @@ -1,4 +1,4 @@ -# Makefile fragment for building mksh R50 2014/10/03 +# Makefile fragment for building mksh R50 2015/03/01 PROG= mksh MAN= mksh.1 @@ -8,11 +8,11 @@ OBJS_BP= lalloc.o eval.o exec.o expr.o funcs.o histrap.o jobs.o lex.o main.o mi INDSRCS= emacsfn.h rlimits.opt sh.h sh_flags.opt var_spec.h NONSRCS_INST= dot.mkshrc $(MAN) NONSRCS_NOINST= Build.sh Makefile Rebuild.sh check.pl check.t test.sh -CC= /huge-ssd/aosp-x86_64/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8/bin/*-gcc -CFLAGS= -fno-exceptions -Wno-multichar -fpic -fPIE -ffunction-sections -fdata-sections -funwind-tables -fstack-protector -Wa,--noexecstack -Werror=format-security -fno-short-enums -Wno-unused-but-set-variable -fno-builtin-sin -fno-strict-volatile-bitfields -Wno-psabi -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -g -Wstrict-aliasing=2 -fgcse-after-reload -frerun-cse-after-loop -frename-registers -Os -fomit-frame-pointer -fno-strict-aliasing -Wno-deprecated-declarations -fno-asynchronous-unwind-tables -fwrapv -CPPFLAGS= -I. -I'../src' -isystem /huge-ssd/aosp-x86_64/bionic/libc/arch-x86/include -isystem /huge-ssd/aosp-x86_64/bionic/libc/include -isystem /huge-ssd/aosp-x86_64/bionic/libc/kernel/uapi -isystem /huge-ssd/aosp-x86_64/bionic/libc/kernel/uapi/asm-x86 -isystem /huge-ssd/aosp-x86_64/bionic/libm/include -isystem /huge-ssd/aosp-x86_64/bionic/libm/include/x86 -D_FORTIFY_SOURCE=2 -I/huge-ssd/aosp-x86_64/build/core/combo/include/arch/linux-x86/ -DANDROID -DNDEBUG -UDEBUG -DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_CONSERVATIVE_FDS -DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN -DHAVE_ATTRIBUTE_BOUNDED=0 -DHAVE_ATTRIBUTE_FORMAT=1 -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1 -DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1 -DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=1 -DHAVE_SYS_BSDTYPES_H=0 -DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SYSMACROS_H=1 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_LIBGEN_H=1 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 -DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 -DHAVE_CAN_INT8TYPE=1 -DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=1 -DHAVE_SIG_T=1 -DHAVE_SYS_ERRLIST=0 -DHAVE_SYS_SIGNAME=1 -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 -DHAVE_LOCK_FCNTL=1 -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_ISSETUGID=0 -DHAVE_KILLPG=1 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 -DHAVE_NICE=1 -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=0 -DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 -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 -DMKSH_BUILD_R=503 -LDFLAGS= -nostdlib -Bdynamic -fPIE -pie -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined /huge-ssd/aosp-x86_64/out/target/product/generic_x86_64/obj/lib/crtbegin_dynamic.o -LIBS= -L/huge-ssd/aosp-x86_64/out/target/product/generic_x86_64/obj/lib -Wl,-rpath-link=/huge-ssd/aosp-x86_64/out/target/product/generic_x86_64/obj/lib -Wl,--no-whole-archive /huge-ssd/aosp-x86_64/out/target/product/generic_x86_64/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a -lc /huge-ssd/aosp-x86_64/out/target/product/generic_x86_64/obj/lib/crtend_android.o +CC= /huge-ssd/aosp-arm64/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/*-gcc +CFLAGS= -fno-exceptions -Wno-multichar -fpic -fPIE -ffunction-sections -fdata-sections -funwind-tables -fstack-protector -Wa,--noexecstack -Werror=format-security -fno-short-enums -Wno-unused-but-set-variable -fno-builtin-sin -fno-strict-volatile-bitfields -Wno-psabi -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -g -Wstrict-aliasing=2 -fgcse-after-reload -frerun-cse-after-loop -frename-registers -Os -fomit-frame-pointer -fno-strict-aliasing -Wno-deprecated-declarations -fno-asynchronous-unwind-tables -fstack-protector-strong -fwrapv +CPPFLAGS= -I. -I'../src' -isystem /huge-ssd/aosp-arm64/bionic/libc/arch-arm64/include -isystem /huge-ssd/aosp-arm64/bionic/libc/include -isystem /huge-ssd/aosp-arm64/bionic/libc/kernel/uapi -isystem /huge-ssd/aosp-arm64/bionic/libc/kernel/uapi/asm-arm64 -isystem /huge-ssd/aosp-arm64/bionic/libm/include -isystem /huge-ssd/aosp-arm64/bionic/libm/include/arm64 -D_FORTIFY_SOURCE=2 -include /huge-ssd/aosp-arm64/build/core/combo/include/arch/linux-arm64/AndroidConfig.h -I/huge-ssd/aosp-arm64/build/core/combo/include/arch/linux-arm64/ -DANDROID -DNDEBUG -UDEBUG -DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_CONSERVATIVE_FDS -DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN -DHAVE_ATTRIBUTE_BOUNDED=0 -DHAVE_ATTRIBUTE_FORMAT=1 -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1 -DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1 -DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=1 -DHAVE_SYS_BSDTYPES_H=0 -DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SYSMACROS_H=1 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_LIBGEN_H=1 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 -DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 -DHAVE_CAN_INT8TYPE=1 -DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=1 -DHAVE_SIG_T=1 -DHAVE_SYS_ERRLIST=0 -DHAVE_SYS_SIGNAME=1 -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 -DHAVE_LOCK_FCNTL=1 -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_ISSETUGID=0 -DHAVE_KILLPG=1 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 -DHAVE_NICE=1 -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=0 -DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 -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 -DMKSH_BUILD_R=505 +LDFLAGS= -nostdlib -Bdynamic -fPIE -pie -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined /huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib/crtbegin_dynamic.o +LIBS= -L/huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib -Wl,-rpath-link=/huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib -Wl,--no-whole-archive /huge-ssd/aosp-arm64/out/target/product/flounder/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a -lc /huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib/crtend_android.o .depend $(OBJS_BP): rlimits.gen sh_flags.gen rlimits.gen: ../src/Build.sh ../src/rlimits.opt diff --git a/mkshrc b/mkshrc index 98cbeac..510fdb7 100644 --- a/mkshrc +++ b/mkshrc @@ -31,7 +31,7 @@ function hd { local dasc line i cat "$@" | { set +U; if read -arN -1 line; then - typeset -i1 line + typeset -i1 'line[*]' i=0 while (( i < ${#line[*]} )); do hv=${line[i++]} @@ -60,7 +60,7 @@ function setenv { eval export "\"$1\""'="$2"' } -for p in ~/.bin; do +for p in ~/bin; do [[ -d $p/. ]] || continue [[ :$PATH: = *:$p:* ]] || PATH=$p:$PATH done diff --git a/src/Build.sh b/src/Build.sh index c59163b..5c90eb8 100644 --- a/src/Build.sh +++ b/src/Build.sh @@ -1,5 +1,5 @@ #!/bin/sh -srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.669 2014/10/07 15:22:12 tg Exp $' +srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.669.2.2 2015/03/01 15:42:50 tg Exp $' #- # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013, 2014 @@ -1700,22 +1700,22 @@ rmf lft* # end of large file support test ac_test can_inttypes '!' stdint_h 1 "for standard 32-bit integer types" <<-'EOF' #include #include - int main(int ac, char **av) { return ((uint32_t)(ptrdiff_t)*av + (int32_t)ac); } + int main(int ac, char **av) { return ((uint32_t)(size_t)*av + (int32_t)ac); } EOF ac_test can_ucbints '!' can_inttypes 1 "for UCB 32-bit integer types" <<-'EOF' #include #include - int main(int ac, char **av) { return ((u_int32_t)(ptrdiff_t)*av + (int32_t)ac); } + int main(int ac, char **av) { return ((u_int32_t)(size_t)*av + (int32_t)ac); } EOF ac_test can_int8type '!' stdint_h 1 "for standard 8-bit integer type" <<-'EOF' #include #include - int main(int ac, char **av) { return ((uint8_t)(ptrdiff_t)av[ac]); } + int main(int ac, char **av) { return ((uint8_t)(size_t)av[ac]); } EOF ac_test can_ucbint8 '!' can_int8type 1 "for UCB 8-bit integer type" <<-'EOF' #include #include - int main(int ac, char **av) { return ((u_int8_t)(ptrdiff_t)av[ac]); } + int main(int ac, char **av) { return ((u_int8_t)(size_t)av[ac]); } EOF ac_test rlim_t <<-'EOF' @@ -1784,7 +1784,7 @@ else #define EXTERN #define MKSH_INCLUDES_ONLY #include "sh.h" - __RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.669 2014/10/07 15:22:12 tg Exp $"); + __RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.669.2.2 2015/03/01 15:42:50 tg Exp $"); int main(void) { printf("Hello, World!\n"); return (isatty(0)); } EOF case $cm in @@ -1969,13 +1969,13 @@ EOF ac_test setlocale_ctype '' 'setlocale(LC_CTYPE, "")' <<-'EOF' #include #include - int main(void) { return ((int)(ptrdiff_t)(void *)setlocale(LC_CTYPE, "")); } + int main(void) { return ((int)(size_t)(void *)setlocale(LC_CTYPE, "")); } EOF ac_test langinfo_codeset setlocale_ctype 0 'nl_langinfo(CODESET)' <<-'EOF' #include #include - int main(void) { return ((int)(ptrdiff_t)(void *)nl_langinfo(CODESET)); } + int main(void) { return ((int)(size_t)(void *)nl_langinfo(CODESET)); } EOF ac_test select <<-'EOF' @@ -2150,9 +2150,9 @@ cta(uari_has_32_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 cta(uari_wrap_32_bit, (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) > (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4)); -#define NUM 22 +#define NUM 21 #else -#define NUM 16 +#define NUM 15 #endif /* these are always required */ cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0); @@ -2161,11 +2161,10 @@ cta(uari_is_unsigned, (mksh_uari_t)-1 > (mksh_uari_t)0); 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_voidptr_same_size, sizeof(ptrdiff_t) == sizeof(void *)); -cta(ptrdifft_funcptr_same_size, sizeof(ptrdiff_t) == sizeof(void (*)(void))); +cta(sizet_voidptr_same_size, sizeof(size_t) == sizeof(void *)); +cta(sizet_funcptr_same_size, sizeof(size_t) == sizeof(void (*)(void))); /* our formatting routines assume this */ -cta(ptr_fits_in_long, sizeof(ptrdiff_t) <= sizeof(long)); +cta(ptr_fits_in_long, sizeof(size_t) <= sizeof(long)); /* for struct alignment people */ char padding[64 - NUM]; }; @@ -2264,6 +2263,11 @@ mksh_cfg= NSIG ;' >conftest.c # GNU sed 2.03 segfaults when optimising this to sed -n NSIG=`vq "$CPP $CFLAGS $CPPFLAGS $NOWARN conftest.c" | \ + grep -v '^#' | \ + sed '/mksh_cfg.*= *$/{ + N + s/\n/ / + }' | \ grep '^ *mksh_cfg *=' | \ sed 's/^ *mksh_cfg *=[ ]*\([()0-9x+-][()0-9x+ -]*\).*$/\1/'` case $NSIG in @@ -2295,6 +2299,11 @@ mksh_cfg= NSIG echo ';' >>conftest.c # GNU sed 2.03 croaks on optimising this, too vq "$CPP $CFLAGS $CPPFLAGS $NOWARN conftest.c" | \ + grep -v '^#' | \ + sed '/mksh_cfg.*= *$/{ + N + s/\n/ / + }' | \ grep '^ *mksh_cfg *=' | \ sed 's/^ *mksh_cfg *=[ ]*\([0-9][0-9x]*\).*$/:\1 '$name/ done | sed -n '/^:[^ ]/s/^://p' | while read nr name; do @@ -2316,7 +2325,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c addsrcs USE_PRINTF_BUILTIN printf.c test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose" -add_cppflags -DMKSH_BUILD_R=504 +add_cppflags -DMKSH_BUILD_R=505 $e $bi$me: Finished configuration testing, now producing output.$ao @@ -2431,9 +2440,12 @@ llvm) ;; esac echo ": # work around NeXTstep bug" >Rebuild.sh -for file in "$srcdir"/*.opt; do +cd "$srcdir" +optfiles=`echo *.opt` +cd "$curdir" +for file in $optfiles; do echo "echo + Running genopt on '$file'..." - echo "(srcfile='$file'; BUILDSH_RUN_GENOPT=1; . '$srcdir/Build.sh')" + echo "(srcfile='$srcdir/$file'; BUILDSH_RUN_GENOPT=1; . '$srcdir/Build.sh')" done >>Rebuild.sh echo set -x >>Rebuild.sh for file in $SRCS; do @@ -2467,11 +2479,11 @@ if test $cm = makefile; then extras='emacsfn.h rlimits.opt sh.h sh_flags.opt var_spec.h' test 0 = $HAVE_SYS_SIGNAME && extras="$extras signames.inc" gens= genq= - for file in "$srcdir"/*.opt; do + for file in $optfiles; do genf=`basename "$file" | sed 's/.opt$/.gen/'` gens="$gens $genf" - genq="$genq$nl$genf: $srcdir/Build.sh $file - srcfile=$file; BUILDSH_RUN_GENOPT=1; . $srcdir/Build.sh" + genq="$genq$nl$genf: $srcdir/Build.sh $srcdir/$file + srcfile=$srcdir/$file; BUILDSH_RUN_GENOPT=1; . $srcdir/Build.sh" done cat >Makefrag.inc < # # Provided that these terms and disclaimer and all copyright notices @@ -24,10 +24,13 @@ # http://www.research.att.com/~gsf/public/ifs.sh # # More testsuites at: -# http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD +# http://svnweb.freebsd.org/base/head/bin/test/tests/legacy_test.sh?view=co&content-type=text%2Fplain +# +# Integrated testsuites from: +# (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date expected-stdout: - @(#)MIRBSD KSH R50 2014/10/07 + @(#)MIRBSD KSH R50 2015/03/01 description: Check version of shell. stdin: @@ -36,7 +39,7 @@ name: KSH_VERSION category: shell:legacy-no --- expected-stdout: - @(#)LEGACY KSH R50 2014/10/07 + @(#)LEGACY KSH R50 2015/03/01 description: Check version of legacy shell. stdin: @@ -2359,6 +2362,14 @@ stdin: expected-stdout: baz --- +name: heredoc-9f +description: + Check long here strings +stdin: + cat <<< "$( : )aa" +expected-stdout: + aa +--- name: heredoc-10 description: Check direct here document assignment @@ -2389,6 +2400,14 @@ stdin: vf=<<<$'=f $x \x40=' # now check print -r -- "| va={$va} vb={$vb} vc={$vc} vd={$vd} ve={$ve} vf={$vf} |" + # check append + v=<<-EOF + vapp1 + EOF + v+=<<-EOF + vapp2 + EOF + print -r -- "| ${v//$'\n'/^} |" expected-stdout: function foo { vc=<<-EOF @@ -2404,6 +2423,7 @@ expected-stdout: } ve={=e $x \x40= } vf={=f $x @= } | + | vapp1^vapp2^ | --- name: heredoc-11 description: @@ -2433,6 +2453,14 @@ stdin: eval "$fnd" foo print -r -- "| va={$va} vb={$vb} vc={$vc} vd={$vd} |" + # check append + v=<<- + vapp1 + << + v+=<<-'' + vapp2 + + print -r -- "| ${v//$'\n'/^} |" expected-stdout: function foo { vc=<<- @@ -2450,6 +2478,52 @@ expected-stdout: } vc={=c u \x40= } vd={=d $x \x40= } | + | vapp1^vapp2^ | +--- +name: heredoc-12 +description: + Check here documents can use $* and $@; note shells vary: + • pdksh 5.2.14 acts the same + • dash has 1 and 2 the same but 3 lacks the space + • ksh93, bash4 differ in 2 by using space ipv colon +stdin: + set -- a b + nl=' + ' + IFS=" $nl"; n=1 + cat <"; done; echo; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } set -- A B C showargs 1 $* showargs 2 "$*" showargs 3 $@ showargs 4 "$@" expected-stdout: - <1> - <2> - <3> - <4> + <1> . + <2> . + <3> . + <4> . --- name: IFS-colon-1 description: Simple test, IFS=: stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } IFS=: set -- A B C showargs 1 $* @@ -3609,16 +3683,16 @@ stdin: showargs 3 $@ showargs 4 "$@" expected-stdout: - <1> - <2> - <3> - <4> + <1> . + <2> . + <3> . + <4> . --- name: IFS-null-1 description: Simple test, IFS="" stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } IFS="" set -- A B C showargs 1 $* @@ -3626,16 +3700,16 @@ stdin: showargs 3 $@ showargs 4 "$@" expected-stdout: - <1> - <2> - <3> - <4> + <1> . + <2> . + <3> . + <4> . --- name: IFS-space-colon-1 description: Simple test, IFS=: stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } IFS="$IFS:" set -- showargs 1 $* @@ -3644,52 +3718,52 @@ stdin: showargs 4 "$@" showargs 5 : "$@" expected-stdout: - <1> - <2> <> - <3> - <4> - <5> <:> + <1> . + <2> <> . + <3> . + <4> . + <5> <:> . --- name: IFS-space-colon-2 description: Simple test, IFS=: AT&T ksh fails this, POSIX says the test is correct. stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } IFS="$IFS:" set -- showargs :"$@" expected-stdout: - <:> + <:> . --- name: IFS-space-colon-4 description: Simple test, IFS=: stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } IFS="$IFS:" set -- showargs "$@$@" expected-stdout: - + . --- name: IFS-space-colon-5 description: Simple test, IFS=: Don't know what POSIX thinks of this. AT&T ksh does not do this. stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } IFS="$IFS:" set -- showargs "${@:-}" expected-stdout: - <> + <> . --- name: IFS-subst-1 description: Simple test, IFS=: stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } IFS="$IFS:" x=":b: :" echo -n '1:'; for i in $x ; do echo -n " [$i]" ; done ; echo @@ -3711,53 +3785,80 @@ stdin: expected-stdout: 1: [] [b] [] 2: [:b::] - <3> <> <> - <4> <:b::> + <3> <> <> . + <4> <:b::> . 5: [a] [b] - <6> + <6> . 7: [a] [] [c] - <8> <> + <8> <> . 9: [h] [ith] [ere] - <10> - <11> + <10> . + <11> . 12: [A] [B] [] [D] - <13> <> + <13> <> . --- name: IFS-subst-2 description: Check leading whitespace after trim does not make a field stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } x="X 1 2" showargs 1 shift ${x#X} expected-stdout: - <1> <1> <2> + <1> <1> <2> . --- -name: IFS-subst-3 +name: IFS-subst-3-arr description: Check leading IFS non-whitespace after trim does make a field but leading IFS whitespace does not, nor empty replacements stdin: - showargs() { for i; do echo -n " <$i>"; done; echo; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } showargs 0 ${-+} IFS=: showargs 1 ${-+:foo:bar} IFS=' ' showargs 2 ${-+ foo bar} expected-stdout: - <0> - <1> <> - <2> + <0> . + <1> <> . + <2> . +--- +name: IFS-subst-3-ass +description: + Check non-field semantics +stdin: + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } + showargs 0 x=${-+} + IFS=: + showargs 1 x=${-+:foo:bar} + IFS=' ' + showargs 2 x=${-+ foo bar} +expected-stdout: + <0> . + <1> . + <2> . +--- +name: IFS-subst-3-lcl +description: + Check non-field semantics, smaller corner case (LP#1381965) +stdin: + set -x + local regex=${2:-} + exit 1 +expected-exit: e != 0 +expected-stderr-pattern: + /regex=/ --- name: IFS-subst-4-1 description: reported by mikeserv stdin: + pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; } a='space divded argument here' IFS=\ ; set -- $a IFS= ; q="$*" ; nq=$* - printf '<%s>\n' "$*" $* "$q" "$nq" + pfn "$*" $* "$q" "$nq" [ "$q" = "$nq" ] && echo =true || echo =false expected-stdout: "; done; } a='space divded argument here' IFS=\ ; set -- $a IFS= ; q="$@" ; nq=$@ - printf '<%s>\n' "$*" $* "$q" "$nq" + pfn "$*" $* "$q" "$nq" [ "$q" = "$nq" ] && echo =true || echo =false expected-stdout: "; done; } a='space divded argument here' IFS=\ ; set -- $a; IFS= @@ -3806,14 +3909,14 @@ stdin: nqs=$* qk="$@" nqk=$@ - printf '= qs '; printf '<%s>\n' "$qs" - printf '=nqs '; printf '<%s>\n' "$nqs" - printf '= qk '; printf '<%s>\n' "$qk" - printf '=nqk '; printf '<%s>\n' "$nqk" - printf '~ qs '; printf '<%s>\n' "$*" - printf '~nqs '; printf '<%s>\n' $* - printf '~ qk '; printf '<%s>\n' "$@" - printf '~nqk '; printf '<%s>\n' $@ + print -nr -- '= qs '; pfn "$qs" + print -nr -- '=nqs '; pfn "$nqs" + print -nr -- '= qk '; pfn "$qk" + print -nr -- '=nqk '; pfn "$nqk" + print -nr -- '~ qs '; pfn "$*" + print -nr -- '~nqs '; pfn $* + print -nr -- '~ qk '; pfn "$@" + print -nr -- '~nqk '; pfn $@ expected-stdout: = qs @@ -3842,21 +3945,22 @@ name: IFS-subst-4-4 description: extended testsuite based on problem by mikeserv stdin: + pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; } a='space divded argument here' IFS=\ ; set -- $a; IFS= qs="$*" - printf '= qs '; printf '<%s>\n' "$qs" - printf '~ qs '; printf '<%s>\n' "$*" + print -nr -- '= qs '; pfn "$qs" + print -nr -- '~ qs '; pfn "$*" nqs=$* - printf '=nqs '; printf '<%s>\n' "$nqs" - printf '~nqs '; printf '<%s>\n' $* + print -nr -- '=nqs '; pfn "$nqs" + print -nr -- '~nqs '; pfn $* qk="$@" - printf '= qk '; printf '<%s>\n' "$qk" - printf '~ qk '; printf '<%s>\n' "$@" + print -nr -- '= qk '; pfn "$qk" + print -nr -- '~ qk '; pfn "$@" nqk=$@ - printf '=nqk '; printf '<%s>\n' "$nqk" - printf '~nqk '; printf '<%s>\n' $@ + print -nr -- '=nqk '; pfn "$nqk" + print -nr -- '~nqk '; pfn $@ expected-stdout: = qs @@ -3885,22 +3989,23 @@ name: IFS-subst-4-4p description: extended testsuite based on problem by mikeserv stdin: + pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; } a='space divded argument here' IFS=\ ; set -- $a; IFS= unset v qs=${v:-"$*"} - printf '= qs '; printf '<%s>\n' "$qs" - printf '~ qs '; printf '<%s>\n' ${v:-"$*"} + print -nr -- '= qs '; pfn "$qs" + print -nr -- '~ qs '; pfn ${v:-"$*"} nqs=${v:-$*} - printf '=nqs '; printf '<%s>\n' "$nqs" - printf '~nqs '; printf '<%s>\n' ${v:-$*} + print -nr -- '=nqs '; pfn "$nqs" + print -nr -- '~nqs '; pfn ${v:-$*} qk=${v:-"$@"} - printf '= qk '; printf '<%s>\n' "$qk" - printf '~ qk '; printf '<%s>\n' ${v:-"$@"} + print -nr -- '= qk '; pfn "$qk" + print -nr -- '~ qk '; pfn ${v:-"$@"} nqk=${v:-$@} - printf '=nqk '; printf '<%s>\n' "$nqk" - printf '~nqk '; printf '<%s>\n' ${v:-$@} + print -nr -- '=nqk '; pfn "$nqk" + print -nr -- '~nqk '; pfn ${v:-$@} expected-stdout: = qs @@ -3929,21 +4034,22 @@ name: IFS-subst-4-5 description: extended testsuite based on problem by mikeserv stdin: + pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; } a='space divded argument here' IFS=\ ; set -- $a; IFS=, qs="$*" - printf '= qs '; printf '<%s>\n' "$qs" - printf '~ qs '; printf '<%s>\n' "$*" + print -nr -- '= qs '; pfn "$qs" + print -nr -- '~ qs '; pfn "$*" nqs=$* - printf '=nqs '; printf '<%s>\n' "$nqs" - printf '~nqs '; printf '<%s>\n' $* + print -nr -- '=nqs '; pfn "$nqs" + print -nr -- '~nqs '; pfn $* qk="$@" - printf '= qk '; printf '<%s>\n' "$qk" - printf '~ qk '; printf '<%s>\n' "$@" + print -nr -- '= qk '; pfn "$qk" + print -nr -- '~ qk '; pfn "$@" nqk=$@ - printf '=nqk '; printf '<%s>\n' "$nqk" - printf '~nqk '; printf '<%s>\n' $@ + print -nr -- '=nqk '; pfn "$nqk" + print -nr -- '~nqk '; pfn $@ expected-stdout: = qs @@ -3972,22 +4078,23 @@ name: IFS-subst-4-5p description: extended testsuite based on problem by mikeserv stdin: + pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; } a='space divded argument here' IFS=\ ; set -- $a; IFS=, unset v qs=${v:-"$*"} - printf '= qs '; printf '<%s>\n' "$qs" - printf '~ qs '; printf '<%s>\n' ${v:-"$*"} + print -nr -- '= qs '; pfn "$qs" + print -nr -- '~ qs '; pfn ${v:-"$*"} nqs=${v:-$*} - printf '=nqs '; printf '<%s>\n' "$nqs" - printf '~nqs '; printf '<%s>\n' ${v:-$*} + print -nr -- '=nqs '; pfn "$nqs" + print -nr -- '~nqs '; pfn ${v:-$*} qk=${v:-"$@"} - printf '= qk '; printf '<%s>\n' "$qk" - printf '~ qk '; printf '<%s>\n' ${v:-"$@"} + print -nr -- '= qk '; pfn "$qk" + print -nr -- '~ qk '; pfn ${v:-"$@"} nqk=${v:-$@} - printf '=nqk '; printf '<%s>\n' "$nqk" - printf '~nqk '; printf '<%s>\n' ${v:-$@} + print -nr -- '=nqk '; pfn "$nqk" + print -nr -- '~nqk '; pfn ${v:-$@} expected-stdout: = qs @@ -4026,38 +4133,55 @@ description: 'emulate sh' zsh has extra fields in - a5ins (IFS_NWS unquoted $*) - b5ins, matching mksh’s + !!WARNING!! more to come: http://austingroupbugs.net/view.php?id=888 stdin: - "$__progname" -c 'IFS=; set -- "" 2 ""; printf "[%s]\n" $*; x=$*; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=; set -- "" 2 ""; pfb $*; x=$*; pfn "$x"' echo '=a1zns' - "$__progname" -c 'IFS=; set -- "" 2 ""; printf "[%s]\n" "$*"; x="$*"; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=; set -- "" 2 ""; pfb "$*"; x="$*"; pfn "$x"' echo '=a2zqs' - "$__progname" -c 'IFS=; set -- "" 2 ""; printf "[%s]\n" $@; x=$@; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=; set -- "" 2 ""; pfb $@; x=$@; pfn "$x"' echo '=a3zna' - "$__progname" -c 'IFS=; set -- "" 2 ""; printf "[%s]\n" "$@"; x="$@"; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=; set -- "" 2 ""; pfb "$@"; x="$@"; pfn "$x"' echo '=a4zqa' - "$__progname" -c 'IFS=,; set -- "" 2 ""; printf "[%s]\n" $*; x=$*; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=,; set -- "" 2 ""; pfb $*; x=$*; pfn "$x"' echo '=a5ins' - "$__progname" -c 'IFS=,; set -- "" 2 ""; printf "[%s]\n" "$*"; x="$*"; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=,; set -- "" 2 ""; pfb "$*"; x="$*"; pfn "$x"' echo '=a6iqs' - "$__progname" -c 'IFS=,; set -- "" 2 ""; printf "[%s]\n" $@; x=$@; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=,; set -- "" 2 ""; pfb $@; x=$@; pfn "$x"' echo '=a7ina' - "$__progname" -c 'IFS=,; set -- "" 2 ""; printf "[%s]\n" "$@"; x="$@"; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=,; set -- "" 2 ""; pfb "$@"; x="$@"; pfn "$x"' echo '=a8iqa' - "$__progname" -c 'IFS=; set -- A B "" "" C; printf "[%s]\n" $*; x=$*; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=; set -- A B "" "" C; pfb $*; x=$*; pfn "$x"' echo '=b1zns' - "$__progname" -c 'IFS=; set -- A B "" "" C; printf "[%s]\n" "$*"; x="$*"; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=; set -- A B "" "" C; pfb "$*"; x="$*"; pfn "$x"' echo '=b2zqs' - "$__progname" -c 'IFS=; set -- A B "" "" C; printf "[%s]\n" $@; x=$@; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=; set -- A B "" "" C; pfb $@; x=$@; pfn "$x"' echo '=b3zna' - "$__progname" -c 'IFS=; set -- A B "" "" C; printf "[%s]\n" "$@"; x="$@"; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=; set -- A B "" "" C; pfb "$@"; x="$@"; pfn "$x"' echo '=b4zqa' - "$__progname" -c 'IFS=,; set -- A B "" "" C; printf "[%s]\n" $*; x=$*; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=,; set -- A B "" "" C; pfb $*; x=$*; pfn "$x"' echo '=b5ins' - "$__progname" -c 'IFS=,; set -- A B "" "" C; printf "[%s]\n" "$*"; x="$*"; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=,; set -- A B "" "" C; pfb "$*"; x="$*"; pfn "$x"' echo '=b6iqs' - "$__progname" -c 'IFS=,; set -- A B "" "" C; printf "[%s]\n" $@; x=$@; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=,; set -- A B "" "" C; pfb $@; x=$@; pfn "$x"' echo '=b7ina' - "$__progname" -c 'IFS=,; set -- A B "" "" C; printf "[%s]\n" "$@"; x="$@"; printf "<%s>\n" "$x"' + "$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }; + IFS=,; set -- A B "" "" C; pfb "$@"; x="$@"; pfn "$x"' echo '=b8iqa' expected-stdout: [2] @@ -4133,13 +4257,69 @@ expected-stdout: =b8iqa --- +name: IFS-subst-6 +description: + Regression wrt. vector expansion in trim +stdin: + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } + IFS= + x=abc + set -- a b + showargs ${x#$*} +expected-stdout: + . +--- +name: IFS-subst-7 +description: + ksh93 bug wrt. vector expansion in trim +stdin: + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } + IFS="*" + a=abcd + set -- '' c + showargs "$*" ${a##"$*"} +expected-stdout: + <*c> . +--- +name: IFS-subst-8 +description: + http://austingroupbugs.net/view.php?id=221 +stdin: + n() { echo "$#"; }; n "${foo-$@}" +expected-stdout: + 1 +--- +name: IFS-subst-9 +description: + Scalar context for $*/$@ in [[ and case +stdin: + "$__progname" -c 'IFS=; set a b; [[ $* = "$1$2" ]]; echo 1 $?' sh a b + "$__progname" -c 'IFS=; [[ $* = ab ]]; echo 2 "$?"' sh a b + "$__progname" -c 'IFS=; [[ "$*" = ab ]]; echo 3 "$?"' sh a b + "$__progname" -c 'IFS=; [[ $* = a ]]; echo 4 "$?"' sh a b + "$__progname" -c 'IFS=; [[ "$*" = a ]]; echo 5 "$?"' sh a b + "$__progname" -c 'IFS=; [[ "$@" = a ]]; echo 6 "$?"' sh a b + "$__progname" -c 'IFS=; case "$@" in a) echo 7 a;; ab) echo 7 b;; a\ b) echo 7 ok;; esac' sh a b + "$__progname" -c 'IFS=; case $* in a) echo 8 a;; ab) echo 8 ok;; esac' sh a b + "$__progname" -c 'pfsp() { for s_arg in "$@"; do print -nr -- "<$s_arg> "; done; print .; }; IFS=; star=$* at="$@"; pfsp 9 "$star" "$at"' sh a b +expected-stdout: + 1 0 + 2 0 + 3 0 + 4 1 + 5 1 + 6 1 + 7 ok + 8 ok + <9> . +--- name: IFS-arith-1 description: http://austingroupbugs.net/view.php?id=832 stdin: ${ZSH_VERSION+false} || emulate sh ${BASH_VERSION+set -o posix} - showargs() { for x in "$@"; do echo -n "<$x> "; done; echo .; } + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } IFS=0 showargs $((1230456)) expected-stdout: @@ -7063,6 +7243,7 @@ description: XXX if the OS can already execute them, we lose note: cygwin execve(2) doesn't return to us with ENOEXEC, we lose note: Ultrix perl5 t4 returns 65280 (exit-code 255) and no text + XXX fails when LD_PRELOAD is set with -e and Perl chokes it (ASan) need-pass: no category: !os:cygwin,!os:msys,!os:ultrix,!os:uwin-nt,!smksh env-setup: !FOO=BAR! @@ -8013,6 +8194,66 @@ expected-stdout: .fnr:f: .f2r:f: --- +name: unset-fnc-local-ksh +description: + Check that “unset” removes a previous “local” + (ksh93 syntax compatible version); apparently, + there are shells which fail this? +stdin: + function f { + echo f0: $x + typeset x + echo f1: $x + x=fa + echo f2: $x + unset x + echo f3: $x + x=fb + echo f4: $x + } + x=o + echo before: $x + f + echo after: $x +expected-stdout: + before: o + f0: o + f1: + f2: fa + f3: o + f4: fb + after: fb +--- +name: unset-fnc-local-sh +description: + Check that “unset” removes a previous “local” + (Debian Policy §10.4 sh version); apparently, + there are shells which fail this? +stdin: + f() { + echo f0: $x + local x + echo f1: $x + x=fa + echo f2: $x + unset x + echo f3: $x + x=fb + echo f4: $x + } + x=o + echo before: $x + f + echo after: $x +expected-stdout: + before: o + f0: o + f1: + f2: fa + f3: o + f4: fb + after: fb +--- name: varexpand-substr-1 description: Check if bash-style substring expansion works @@ -8172,13 +8413,21 @@ name: varexpand-null-1 description: Ensure empty strings expand emptily stdin: - print x ${a} ${b} y - print z ${a#?} ${b%?} w - print v ${a=} ${b/c/d} u + print s ${a} . ${b} S + print t ${a#?} . ${b%?} T + print r ${a=} . ${b/c/d} R + print q + print s "${a}" . "${b}" S + print t "${a#?}" . "${b%?}" T + print r "${a=}" . "${b/c/d}" R expected-stdout: - x y - z w - v u + s . S + t . T + r . R + q + s . S + t . T + r . R --- name: varexpand-null-2 description: @@ -8194,13 +8443,41 @@ expected-stdout: name: varexpand-null-3 description: Ensure concatenating behaviour matches other shells - although the line 2<> is probably wrong? XNULLSUB case. stdin: - x=; printf "1<%s>\n" "$x$@" - set A; printf "2<%s>\n" "${@:+}" + showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; } + x=; showargs 1 "$x"$@ + set A; showargs 2 "${@:+}" + n() { echo "$#"; } + unset e + set -- a b + n """$@" + n "$@" + n "$@""" + n "$e""$@" + n "$@" + n "$@""$e" + set -- + n """$@" + n "$@" + n "$@""" + n "$e""$@" + n "$@" + n "$@""$e" expected-stdout: - 1<> - 2<> + <1> <> . + <2> <> . + 2 + 2 + 2 + 2 + 2 + 2 + 1 + 0 + 1 + 1 + 0 + 1 --- name: print-funny-chars description: @@ -10921,6 +11198,7 @@ stdin: (mypid=$$; try mypid) echo =15 ) 2>&1 | sed -e 's/^[^]]*]//' -e 's/^[^:]*: *//' + exit ${PIPESTATUS[0]} expected-stdout: y =1 @@ -11655,3 +11933,26 @@ expected-stdout: expected-stderr-pattern: /.*/ --- +name: xtrace-2 +description: + Check that "set -x" is off during PS4 expansion +stdin: + f() { + print -n "(f1:$-)" + set -x + print -n "(f2:$-)" + } + PS4='[(p:$-)$(f)] ' + print "(o0:$-)" + set -x -o inherit-xtrace + print "(o1:$-)" + set +x + print "(o2:$-)" +expected-stdout: + (o0:sh) + (o1:shx) + (o2:sh) +expected-stderr: + [(p:sh)(f1:sh)(f2:sh)] print '(o1:shx)' + [(p:sh)(f1:sh)(f2:sh)] set +x +--- diff --git a/src/dot.mkshrc b/src/dot.mkshrc index 233a10c..4878fd7 100644 --- a/src/dot.mkshrc +++ b/src/dot.mkshrc @@ -1,8 +1,8 @@ # $Id$ -# $MirOS: src/bin/mksh/dot.mkshrc,v 1.89 2014/07/28 21:45:44 tg Exp $ +# $MirOS: src/bin/mksh/dot.mkshrc,v 1.89.2.1 2015/01/11 22:39:44 tg Exp $ #- # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, -# 2011, 2012, 2013, 2014 +# 2011, 2012, 2013, 2014, 2015 # Thorsten Glaser # # Provided that these terms and disclaimer and all copyright notices @@ -67,7 +67,7 @@ else local dasc line i cat "$@" | { set +U; if read -arN -1 line; then - typeset -i1 line + typeset -i1 'line[*]' i=0 while (( i < ${#line[*]} )); do hv=${line[i++]} @@ -263,9 +263,8 @@ function smores { # base64 encoder and decoder, RFC compliant, NUL safe function Lb64decode { - [[ -o utf8-mode ]]; local u=$? + [[ -o utf8-mode ]]; local u=$? c s="$*" t set +U - local c s="$*" t= [[ -n $s ]] || { s=$(cat; print x); s=${s%x}; } local -i i=0 j=0 n=${#s} p=0 v x local -i16 o @@ -302,9 +301,8 @@ function Lb64decode { set -A Lb64encode_code -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \ a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + / function Lb64encode { - [[ -o utf8-mode ]]; local u=$? + [[ -o utf8-mode ]]; local u=$? c s t set +U - local c s t if (( $# )); then read -raN-1 s <<<"$*" unset s[${#s[*]}-1] @@ -342,9 +340,8 @@ function Lbafh_init { Lbafh_v=0 } function Lbafh_add { - [[ -o utf8-mode ]]; local u=$? + [[ -o utf8-mode ]]; local u=$? s set +U - local s if (( $# )); then read -raN-1 s <<<"$*" unset s[${#s[*]}-1] diff --git a/src/edit.c b/src/edit.c index ee5ed5c..9165ecd 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1,6 +1,6 @@ /* $OpenBSD: edit.c,v 1.39 2013/12/17 16:37:05 deraadt Exp $ */ /* $OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $ */ -/* $OpenBSD: emacs.c,v 1.48 2013/12/17 16:37:05 deraadt Exp $ */ +/* $OpenBSD: emacs.c,v 1.49 2015/02/16 01:44:41 tedu Exp $ */ /* $OpenBSD: vi.c,v 1.28 2013/12/18 16:45:46 deraadt Exp $ */ /*- @@ -28,7 +28,7 @@ #ifndef MKSH_NO_CMDLINE_EDITING -__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.276 2014/07/13 11:34:28 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.276.2.3 2015/03/01 15:42:56 tg Exp $"); /* * in later versions we might use libtermcap for this, but since external @@ -327,7 +327,7 @@ x_glob_hlp_tilde_and_rem_qchar(char *s, bool magic_flag) /* ok, so split into "~foo"/"bar" or "~"/"baz" */ *cp++ = 0; /* try to expand the tilde */ - if (!(dp = tilde(s + 1))) { + if (!(dp = do_tilde(s + 1))) { /* nope, revert damage */ *--cp = '/'; } else { @@ -592,8 +592,6 @@ x_cf_glob(int *flagsp, const char *buf, int buflen, int pos, int *startp, char **words = NULL; bool is_command; - mkssert(buf != NULL); - len = x_locate_word(buf, buflen, pos, startp, &is_command); if (!((*flagsp) & XCF_COMMAND)) is_command = false; @@ -1009,7 +1007,6 @@ enum emacs_funcs { static const struct x_ftab x_ftab[] = { #define EMACSFN_ITEMS #include "emacsfn.h" - { 0, NULL, 0 } }; static struct x_defbindings const x_defbindings[] = { @@ -2240,7 +2237,6 @@ x_push(int nchars) { char *cp; - mkssert(xcp != NULL); strndupx(cp, xcp, nchars, AEDIT); if (killstack[killsp]) afree(killstack[killsp], AEDIT); @@ -2455,8 +2451,7 @@ x_bind(const char *a1, const char *a2, /* List function names */ if (list) { for (f = 0; f < NELEM(x_ftab); f++) - if (x_ftab[f].xf_name && - !(x_ftab[f].xf_flags & XF_NOBIND)) + if (!(x_ftab[f].xf_flags & XF_NOBIND)) shprintf("%s\n", x_ftab[f].xf_name); return (0); } @@ -2517,8 +2512,7 @@ x_bind(const char *a1, const char *a2, #endif } else { for (f = 0; f < NELEM(x_ftab); f++) - if (x_ftab[f].xf_name && - strcmp(x_ftab[f].xf_name, a2) == 0) + if (!strcmp(x_ftab[f].xf_name, a2)) break; if (f == NELEM(x_ftab) || x_ftab[f].xf_flags & XF_NOBIND) { bi_errorf("%s: %s %s", a2, "no such", Tfunction); diff --git a/src/eval.c b/src/eval.c index 49a4c33..f9c189d 100644 --- a/src/eval.c +++ b/src/eval.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014 + * 2011, 2012, 2013, 2014, 2015 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.153 2014/10/07 15:22:16 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.158.2.4 2015/03/01 15:42:58 tg Exp $"); /* * string expansion @@ -59,10 +59,11 @@ typedef struct { #define XSUBMID 6 /* middle of expanding ${} */ /* States used for field splitting */ -#define IFS_WORD 0 /* word has chars (or quotes) */ +#define IFS_WORD 0 /* word has chars (or quotes except "$@") */ #define IFS_WS 1 /* have seen IFS white-space */ #define IFS_NWS 2 /* have seen IFS non-white-space */ #define IFS_IWS 3 /* begin of word, ignore IFS WS */ +#define IFS_QUOTE 4 /* beg.w/quote, become IFS_WORD unless "$@" */ static int varsub(Expand *, const char *, const char *, int *, int *); static int comsub(Expand *, const char *, int); @@ -70,7 +71,7 @@ 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); -static const char *maybe_expand_tilde(const char *, XString *, char **, int); +static const char *maybe_expand_tilde(const char *, XString *, char **, bool); #ifndef MKSH_NOPWNAM static char *homedir(char *); #endif @@ -237,7 +238,7 @@ expand( /* record number of trailing newlines in COMSUB */ int newlines = 0; bool saw_eq, make_magic; - int tilde_ok; + unsigned int tilde_ok; size_t len; char *cp; @@ -246,7 +247,7 @@ expand( /* for alias, readonly, set, typeset commands */ if ((f & DOVACHECK) && is_wdvarassign(ccp)) { f &= ~(DOVACHECK | DOBLANK | DOGLOB | DOTILDE); - f |= DOASNTILDE | DOASNFIELD; + f |= DOASNTILDE | DOSCALAR; } if (Flag(FNOGLOB)) f &= ~DOGLOB; @@ -290,7 +291,17 @@ expand( c = *sp++; break; case OQUOTE: - word = IFS_WORD; + switch (word) { + case IFS_QUOTE: + /* """something */ + word = IFS_WORD; + break; + case IFS_WORD: + break; + default: + word = IFS_QUOTE; + break; + } tilde_ok = 0; quote = 1; continue; @@ -383,6 +394,8 @@ expand( if (f & DOBLANK) doblank++; tilde_ok = 0; + if (word == IFS_QUOTE && type != XNULLSUB) + word = IFS_WORD; if (type == XBASE) { /* expand? */ if (!st->next) { @@ -516,7 +529,6 @@ expand( /* check for special cases */ d = str_val(st->var); - mkssert(d != NULL); switch (*pat) { case '#': /* anchor at begin */ @@ -622,7 +634,7 @@ expand( case '%': /* ! DOBLANK,DOBRACE,DOTILDE */ f = (f & DONTRUNCOMMAND) | - DOPAT | DOTEMP; + DOPAT | DOTEMP | DOSCALAR; st->quotew = quote = 0; /* * Prepend open pattern (so | @@ -631,7 +643,7 @@ expand( */ if (!Flag(FSH)) { *dp++ = MAGIC; - *dp++ = '@' | 0x80; + *dp++ = 0x80 | '@'; } break; case '=': @@ -664,7 +676,11 @@ expand( f |= DOTEMP; /* FALLTHROUGH */ default: - word = quote ? IFS_WORD : IFS_IWS; + /* '-' '+' '?' */ + if (quote) + word = IFS_WORD; + else if (dp == Xstring(ds, dp)) + word = IFS_IWS; /* Enable tilde expansion */ tilde_ok = 1; f |= DOTILDE; @@ -704,10 +720,16 @@ expand( x.str = trimsub(str_val(st->var), dp, st->stype); if (x.str[0] != '\0') { - word = IFS_WS; + word = IFS_IWS; type = XSUB; - } else - type = quote ? XSUB : XNULLSUB; + } else if (quote) { + word = IFS_WORD; + type = XSUB; + } else { + if (dp == Xstring(ds, dp)) + word = IFS_IWS; + type = XNULLSUB; + } if (f & DOBLANK) doblank++; st = st->prev; @@ -743,7 +765,7 @@ expand( if (f & DOBLANK) doblank++; st = st->prev; - word = quote || (!*x.str && (f & DOASNFIELD)) ? IFS_WORD : IFS_WS; + word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS; continue; case '?': { char *s = Xrestpos(ds, dp, st->base); @@ -759,11 +781,12 @@ expand( case 0x100 | 'Q': dp = Xrestpos(ds, dp, st->base); type = XSUB; - word = quote || (!*x.str && (f & DOASNFIELD)) ? IFS_WORD : IFS_WS; + word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS; if (f & DOBLANK) doblank++; st = st->prev; continue; + /* default: '-' '+' */ } st = st->prev; type = XBASE; @@ -799,8 +822,8 @@ expand( type = XBASE; if (f & DOBLANK) { doblank--; - if (dp == Xstring(ds, dp)) - word = IFS_WS; + if (dp == Xstring(ds, dp) && word != IFS_WORD) + word = IFS_IWS; } continue; @@ -834,15 +857,20 @@ expand( continue; } c = ifs0; - if ((f & DOASNFIELD)) { - /* assignment, do not field-split */ + if ((f & DOHEREDOC)) { + /* pseudo-field-split reliably */ + if (c == 0) + c = ' '; + break; + } + if ((f & DOSCALAR)) { + /* do not field-split */ if (x.split) { c = ' '; break; } - if (c == 0) { + if (c == 0) continue; - } } if (c == 0) { if (quote && !x.split) @@ -867,7 +895,7 @@ expand( /* $(<...) failed */ subst_exstat = 1; /* fake EOF */ - c = EOF; + c = -1; } else if (newlines) { /* spit out saved NLs */ c = '\n'; @@ -877,13 +905,13 @@ expand( if (c == '\n') /* save newlines */ newlines++; - if (newlines && c != EOF) { + if (newlines && c != -1) { shf_ungetc(c, x.u.shf); c = '\n'; --newlines; } } - if (c == EOF) { + if (c == -1) { newlines = 0; if (x.u.shf) shf_close(x.u.shf); @@ -911,7 +939,7 @@ expand( * IFS_IWS -/WS w/NWS - * (w means generate a word) */ - if ((word == IFS_WORD) || (c && + if ((word == IFS_WORD) || (word == IFS_QUOTE) || (c && (word == IFS_IWS || word == IFS_NWS) && !ctype(c, C_IFSWS))) { emit_word: @@ -1023,7 +1051,7 @@ expand( tcp = maybe_expand_tilde(sp, &ds, &tdp, - f & DOASNTILDE); + tobool(f & DOASNTILDE)); if (tcp) { if (dp != tdp) word = IFS_WORD; @@ -1659,7 +1687,7 @@ debunk(char *dp, const char *sp, size_t dlen) * past the name, otherwise returns 0. */ static const char * -maybe_expand_tilde(const char *p, XString *dsp, char **dpp, int isassign) +maybe_expand_tilde(const char *p, XString *dsp, char **dpp, bool isassign) { XString ts; char *dp = *dpp; @@ -1676,7 +1704,7 @@ maybe_expand_tilde(const char *p, XString *dsp, char **dpp, int isassign) } *tp = '\0'; r = (p[0] == EOS || p[0] == CHAR || p[0] == CSUBST) ? - tilde(Xstring(ts, tp)) : NULL; + do_tilde(Xstring(ts, tp)) : NULL; Xfree(ts, tp); if (r) { while (*r) { @@ -1698,7 +1726,7 @@ maybe_expand_tilde(const char *p, XString *dsp, char **dpp, int isassign) */ char * -tilde(char *cp) +do_tilde(char *cp) { char *dp = null; @@ -1745,28 +1773,30 @@ homedir(char *name) static void alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo) { - int count = 0; + unsigned int count = 0; char *brace_start, *brace_end, *comma = NULL; char *field_start; - char *p; + char *p = exp_start; /* search for open brace */ - for (p = exp_start; (p = strchr(p, MAGIC)) && p[1] != '{' /*}*/; p += 2) - ; + while ((p = strchr(p, MAGIC)) && p[1] != '{' /*}*/) + p += 2; brace_start = p; /* find matching close brace, if any */ if (p) { comma = NULL; count = 1; - for (p += 2; *p && count; p++) { - if (ISMAGIC(*p)) { - if (*++p == '{' /*}*/) - count++; + p += 2; + while (*p && count) { + if (ISMAGIC(*p++)) { + if (*p == '{' /*}*/) + ++count; else if (*p == /*{*/ '}') --count; else if (*p == ',' && count == 1) comma = p; + ++p; } } } @@ -1795,7 +1825,7 @@ alt_expand(XPtrV *wp, char *start, char *exp_start, char *end, int fdo) for (p = brace_start + 2; p != brace_end; p++) { if (ISMAGIC(*p)) { if (*++p == '{' /*}*/) - count++; + ++count; else if ((*p == /*{*/ '}' && --count == 0) || (*p == ',' && count == 1)) { char *news; diff --git a/src/exec.c b/src/exec.c index b60511d..9b94aaf 100644 --- a/src/exec.c +++ b/src/exec.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014 + * 2011, 2012, 2013, 2014, 2015 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.133 2014/10/03 17:32:11 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.137.2.2 2015/03/01 15:42:59 tg Exp $"); #ifndef MKSH_DEFAULT_EXECSHELL #define MKSH_DEFAULT_EXECSHELL "/bin/sh" @@ -32,7 +32,7 @@ __RCSID("$MirOS: src/bin/mksh/exec.c,v 1.133 2014/10/03 17:32:11 tg Exp $"); static int comexec(struct op *, struct tbl * volatile, const char **, int volatile, volatile int *); static void scriptexec(struct op *, const char **) MKSH_A_NORETURN; -static int call_builtin(struct tbl *, const char **, const char *); +static int call_builtin(struct tbl *, const char **, const char *, bool); static int iosetup(struct ioword *, struct tbl *); static int herein(struct ioword *, char **); static const char *do_selectargs(const char **, bool); @@ -81,6 +81,8 @@ execute(struct op * volatile t, /* we want to run an executable, do some variance checks */ if (t->type == TCOM) { /* check if this is 'var=<args[0] == NULL && @@ -94,20 +96,23 @@ execute(struct op * volatile t, /* the variable assignment begins with a valid varname */ (ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] && /* and has no right-hand side (i.e. "varname=") */ - ccp[0] == CHAR && ccp[1] == '=' && ccp[2] == EOS && + ccp[0] == CHAR && ((ccp[1] == '=' && ccp[2] == EOS) || + /* or "varname+=" */ (ccp[1] == '+' && ccp[2] == CHAR && + ccp[3] == '=' && ccp[4] == EOS)) && /* plus we can have a here document content */ herein(t->ioact[0], &cp) == 0 && cp && *cp) { char *sp = cp, *dp; - size_t n = ccp - t->vars[0] + 2, z; + size_t n = ccp - t->vars[0] + (ccp[1] == '+' ? 4 : 2); + size_t z; /* drop redirection (will be garbage collected) */ t->ioact = NULL; /* set variable to its expanded value */ - z = strlen(cp) + 1; - if (notoktomul(z, 2) || notoktoadd(z * 2, n)) + z = strlen(cp); + if (notoktomul(z, 2) || notoktoadd(z * 2, n + 1)) internal_errorf(Toomem, (size_t)-1); - dp = alloc(z * 2 + n, ATEMP); + dp = alloc(z * 2 + n + 1, APERM); memcpy(dp, t->vars[0], n); t->vars[0] = dp; dp += n; @@ -398,7 +403,7 @@ execute(struct op * volatile t, case TCASE: i = 0; - ccp = evalstr(t->str, DOTILDE); + ccp = evalstr(t->str, DOTILDE | DOSCALAR); for (t = t->left; t != NULL && t->type == TPAT; t = t->right) { for (ap = (const char **)t->vars; *ap; ap++) { if (i || ((s = evalstr(*ap, DOTILDE|DOPAT)) && @@ -441,7 +446,6 @@ execute(struct op * volatile t, case TEXEC: /* an eval'd TCOM */ - s = t->args[0]; up = makenv(); restoresigs(); cleanup_proc_env(); @@ -455,7 +459,7 @@ execute(struct op * volatile t, if (rv == ENOEXEC) scriptexec(t, (const char **)up); else - errorf("%s: %s", s, cstrerror(rv)); + errorf("%s: %s", t->str, cstrerror(rv)); } Break: exstat = rv & 0xFF; @@ -500,18 +504,21 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, /* Must be static (XXX but why?) */ static struct op texec; int type_flags; - bool keepasn_ok; + bool resetspec; int fcflags = FC_BI|FC_FUNC|FC_PATH; - bool bourne_function_call = false; struct block *l_expand, *l_assign; + int optc; + const char *exec_argv0 = NULL; + bool exec_clrenv = false; - /* - * snag the last argument for $_ XXX not the same as AT&T ksh, - * which only seems to set $_ after a newline (but not in - * functions/dot scripts, but in interactive and script) - - * perhaps save last arg here and set it in shell()?. - */ + /* snag the last argument for $_ */ if (Flag(FTALKING) && *(lastp = ap)) { + /* + * XXX not the same as AT&T ksh, which only seems to set $_ + * after a newline (but not in functions/dot scripts, but in + * interactive and script) - perhaps save last arg here and + * set it in shell()?. + */ while (*++lastp) ; /* setstr() can't fail here */ @@ -532,7 +539,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, * FOO=bar command FOO is neither kept nor exported * PATH=... foobar use new PATH in foobar search */ - keepasn_ok = true; + resetspec = false; while (tp && tp->type == CSHELL) { /* undo effects of command */ fcflags = FC_BI|FC_FUNC|FC_PATH; @@ -548,10 +555,25 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, } else if (tp->val.f == c_exec) { if (ap[1] == NULL) break; - ap++; + ksh_getopt_reset(&builtin_opt, GF_ERROR); + while ((optc = ksh_getopt(ap, &builtin_opt, "a:c")) != -1) + switch (optc) { + case 'a': + exec_argv0 = builtin_opt.optarg; + break; + case 'c': + exec_clrenv = true; + /* ensure we can actually do this */ + resetspec = true; + break; + default: + rv = 2; + goto Leave; + } + ap += builtin_opt.optind; flags |= XEXEC; } else if (tp->val.f == c_command) { - int optc, saw_p = 0; + bool saw_p = false; /* * Ugly dealing with options in two places (here @@ -559,8 +581,8 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, */ ksh_getopt_reset(&builtin_opt, 0); while ((optc = ksh_getopt(ap, &builtin_opt, ":p")) == 'p') - saw_p = 1; - if (optc != EOF) + saw_p = true; + if (optc != -1) /* command -vV or something */ break; /* don't look for functions */ @@ -579,7 +601,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, * POSIX says special builtins lose their status * if accessed using command. */ - keepasn_ok = false; + resetspec = true; if (!ap[0]) { /* ensure command with no args exits with 0 */ subst_exstat = 0; @@ -614,20 +636,21 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, if (t->u.evalflags & DOTCOMEXEC) flags |= XEXEC; l_expand = e->loc; - if (keepasn_ok && (!ap[0] || (tp && (tp->flag & KEEPASN)))) + if (!resetspec && (!ap[0] || (tp && (tp->flag & KEEPASN)))) type_flags = 0; else { /* create new variable/function block */ newblock(); /* ksh functions don't keep assignments, POSIX functions do. */ - if (keepasn_ok && tp && tp->type == CFUNC && - !(tp->flag & FKSH)) { - bourne_function_call = true; + if (!resetspec && tp && tp->type == CFUNC && + !(tp->flag & FKSH)) type_flags = EXPORT; - } else + else type_flags = LOCAL|LOCAL_COPY|EXPORT; } l_assign = e->loc; + if (exec_clrenv) + l_assign->flags |= BF_STOPENV; if (Flag(FEXPORT)) type_flags |= EXPORT; if (Flag(FXTRACE)) @@ -635,7 +658,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, 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 | DOASNFIELD); + cp = evalstr(t->vars[i], DOASNTILDE | DOSCALAR); e->loc = l_assign; if (Flag(FXTRACE)) { const char *ccp; @@ -651,8 +674,6 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, } /* 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)) { @@ -684,8 +705,8 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, /* shell built-in */ case CSHELL: - rv = call_builtin(tp, (const char **)ap, null); - if (!keepasn_ok && tp->val.f == c_shift) { + rv = call_builtin(tp, (const char **)ap, null, resetspec); + if (resetspec && tp->val.f == c_shift) { l_expand->argc = l_assign->argc; l_expand->argv = l_assign->argv; } @@ -810,14 +831,24 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, break; } - /* set $_ to programme's full path */ + /* set $_ to program's full path */ /* setstr() can't fail here */ setstr(typeset("_", LOCAL | EXPORT, 0, INTEGER, 0), tp->val.s, KSH_RETURN_ERROR); - if (flags&XEXEC) { + /* to fork, we set up a TEXEC node and call execute */ + texec.type = TEXEC; + /* for vistree/dumptree */ + texec.left = t; + texec.str = tp->val.s; + texec.args = ap; + + /* in this case we do not fork, of course */ + if (flags & XEXEC) { + if (exec_argv0) + texec.args[0] = exec_argv0; j_exit(); - if (!(flags&XBGND) + if (!(flags & XBGND) #ifndef MKSH_UNEMPLOYED || Flag(FMONITOR) #endif @@ -827,12 +858,6 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap, } } - /* to fork we set up a TEXEC node and call execute */ - texec.type = TEXEC; - /* for tprint */ - texec.left = t; - texec.str = tp->val.s; - texec.args = ap; rv = exchild(&texec, flags, xerrok, -1); break; } @@ -849,10 +874,8 @@ scriptexec(struct op *tp, const char **ap) { const char *sh; #ifndef MKSH_SMALL - unsigned char *cp; - /* 64 == MAXINTERP in MirBSD */ - char buf[64]; int fd; + unsigned char buf[68]; #endif union mksh_ccphack args, cap; @@ -866,33 +889,35 @@ scriptexec(struct op *tp, const char **ap) #ifndef MKSH_SMALL if ((fd = open(tp->str, O_RDONLY | O_BINARY)) >= 0) { - /* read first MAXINTERP octets from file */ - if (read(fd, buf, sizeof(buf)) <= 0) - /* read error -> no good */ - buf[0] = '\0'; + unsigned char *cp; + unsigned short m; + ssize_t n; + + /* read first couple of octets from file */ + n = read(fd, buf, sizeof(buf) - 1); close(fd); + /* read error or short read? */ + if (n < 5) + goto nomagic; + /* terminate buffer */ + buf[n] = '\0'; /* skip UTF-8 Byte Order Mark, if present */ - cp = (unsigned char *)buf; - if ((cp[0] == 0xEF) && (cp[1] == 0xBB) && (cp[2] == 0xBF)) - cp += 3; - /* save begin of shebang for later */ - fd = (char *)cp - buf; /* either 0 or (if BOM) 3 */ + cp = buf + (n = ((buf[0] == 0xEF) && (buf[1] == 0xBB) && + (buf[2] == 0xBF)) ? 3 : 0); - /* scan for newline (or CR) or NUL _before_ end of buffer */ - while ((size_t)((char *)cp - buf) < sizeof(buf)) - if (*cp == '\0' || *cp == '\n' || *cp == '\r') { - *cp = '\0'; - break; - } else - ++cp; + /* scan for newline or NUL (end of buffer) */ + while (*cp && *cp != '\n') + ++cp; /* if the shebang line is longer than MAXINTERP, bail out */ - if ((size_t)((char *)cp - buf) >= sizeof(buf)) + if (!*cp) goto noshebang; + /* replace newline by NUL */ + *cp = '\0'; /* restore begin of shebang position (buf+0 or buf+3) */ - cp = (unsigned char *)(buf + fd); - /* bail out if read error (above) or no shebang */ + cp = buf + n; + /* bail out if no shebang magic found */ if ((cp[0] != '#') || (cp[1] != '!')) goto noshebang; @@ -918,22 +943,24 @@ scriptexec(struct op *tp, const char **ap) if (*cp) *tp->args-- = (char *)cp; } + goto nomagic; noshebang: - if (buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' && - buf[3] == 'F') + m = buf[0] << 8 | buf[1]; + if (m == 0x7F45 && buf[2] == 'L' && buf[3] == 'F') errorf("%s: not executable: %d-bit ELF file", tp->str, - 32 * ((uint8_t)buf[4])); - fd = buf[0] << 8 | buf[1]; - if ((fd == /* OMAGIC */ 0407) || - (fd == /* NMAGIC */ 0410) || - (fd == /* ZMAGIC */ 0413) || - (fd == /* QMAGIC */ 0314) || - (fd == /* ECOFF_I386 */ 0x4C01) || - (fd == /* ECOFF_M68K */ 0x0150 || fd == 0x5001) || - (fd == /* ECOFF_SH */ 0x0500 || fd == 0x0005) || - (fd == /* "MZ" */ 0x4D5A) || - (fd == /* gzip */ 0x1F8B)) - errorf("%s: not executable: magic %04X", tp->str, fd); + 32 * buf[4]); + if ((m == /* OMAGIC */ 0407) || + (m == /* NMAGIC */ 0410) || + (m == /* ZMAGIC */ 0413) || + (m == /* QMAGIC */ 0314) || + (m == /* ECOFF_I386 */ 0x4C01) || + (m == /* ECOFF_M68K */ 0x0150 || m == 0x5001) || + (m == /* ECOFF_SH */ 0x0500 || m == 0x0005) || + (m == /* "MZ" */ 0x4D5A) || + (m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D)) + errorf("%s: not executable: magic %04X", tp->str, m); + nomagic: + ; } #endif args.ro = tp->args; @@ -952,7 +979,7 @@ shcomexec(const char **wp) struct tbl *tp; tp = ktsearch(&builtins, *wp, hash(*wp)); - return (call_builtin(tp, wp, "shcomexec")); + return (call_builtin(tp, wp, "shcomexec", false)); } /* @@ -1001,8 +1028,6 @@ define(const char *name, struct op *t) while (/* CONSTCOND */ 1) { tp = findfunc(name, nhash, true); - /* because findfunc:create=true */ - mkssert(tp != NULL); if (tp->flag & ISSET) was_set = true; @@ -1265,22 +1290,22 @@ search_path(const char *name, const char *lpath, } static int -call_builtin(struct tbl *tp, const char **wp, const char *where) +call_builtin(struct tbl *tp, const char **wp, const char *where, bool resetspec) { int rv; if (!tp) internal_errorf("%s: %s", where, wp[0]); builtin_argv0 = wp[0]; - builtin_flag = tp->flag; + builtin_spec = tobool(!resetspec && (tp->flag & SPEC_BI)); shf_reopen(1, SHF_WR, shl_stdout); shl_stdout_ok = true; ksh_getopt_reset(&builtin_opt, GF_ERROR); rv = (*tp->val.f)(wp); shf_flush(shl_stdout); shl_stdout_ok = false; - builtin_flag = 0; builtin_argv0 = NULL; + builtin_spec = false; return (rv); } @@ -1467,7 +1492,7 @@ hereinval(const char *content, int sub, char **resbuf, struct shf *shf) if (yylex(sub) != LWORD) internal_errorf("%s: %s", "herein", "yylex"); source = osource; - ccp = evalstr(yylval.cp, 0); + ccp = evalstr(yylval.cp, DOSCALAR | DOHEREDOC); } if (resbuf == NULL) @@ -1487,7 +1512,7 @@ herein(struct ioword *iop, char **resbuf) struct temp *h; int i; - /* ksh -c 'cat << EOF' can cause this... */ + /* ksh -c 'cat <heredoc == NULL) { warningf(true, "%s missing", "here document"); /* special to iosetup(): don't print error */ @@ -1522,7 +1547,7 @@ herein(struct ioword *iop, char **resbuf) return (-2); } - if (shf_close(shf) == EOF) { + if (shf_close(shf) == -1) { i = errno; close(fd); warningf(true, "can't %s temporary file %s: %s", @@ -1559,7 +1584,8 @@ do_selectargs(const char **ap, bool print_menu) if (print_menu || !*str_val(global("REPLY"))) pr_menu(ap); shellf("%s", str_val(global("PS3"))); - if (call_builtin(findcom("read", FC_BI), read_args, Tselect)) + if (call_builtin(findcom("read", FC_BI), read_args, Tselect, + false)) return (NULL); s = str_val(global("REPLY")); if (*s && getn(s, &i)) @@ -1709,6 +1735,7 @@ static const char * dbteste_getopnd(Test_env *te, Test_op op, bool do_eval) { const char *s = *te->pos.wp; + int flags = DOTILDE | DOSCALAR; if (!s) return (NULL); @@ -1719,11 +1746,9 @@ dbteste_getopnd(Test_env *te, Test_op op, bool do_eval) return (null); if (op == TO_STEQL || op == TO_STNEQ) - s = evalstr(s, DOTILDE | DOPAT); - else - s = evalstr(s, DOTILDE); + flags |= DOPAT; - return (s); + return (evalstr(s, flags)); } static void diff --git a/src/expr.c b/src/expr.c index 057666e..6b328ad 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: expr.c,v 1.23 2013/12/17 16:37:06 deraadt Exp $ */ +/* $OpenBSD: expr.c,v 1.24 2014/12/08 14:26:31 otto Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.76 2014/06/24 19:53:19 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.76.2.1 2015/01/25 15:44:05 tg Exp $"); /* the order of these enums is constrained by the order of opinfo[] */ enum token { diff --git a/src/funcs.c b/src/funcs.c index bb7971e..9603aff 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -5,7 +5,7 @@ /*- * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - * 2010, 2011, 2012, 2013, 2014 + * 2010, 2011, 2012, 2013, 2014, 2015 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -38,7 +38,7 @@ #endif #endif -__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.258 2014/09/03 19:55:51 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.259.2.2 2015/01/25 15:35:44 tg Exp $"); #if HAVE_KILLPG /* @@ -550,7 +550,7 @@ c_whence(const char **wp) if (vflag || (tp->type != CALIAS && tp->type != CEXEC && tp->type != CTALIAS)) shf_puts(id, shl_stdout); - if (vflag) + if (vflag) { switch (tp->type) { case CKEYWD: case CALIAS: @@ -559,11 +559,20 @@ c_whence(const char **wp) shf_puts(" is a", shl_stdout); break; } + switch (tp->type) { + case CKEYWD: + case CSHELL: + case CTALIAS: + case CEXEC: + shf_putc(' ', shl_stdout); + break; + } + } switch (tp->type) { case CKEYWD: if (vflag) - shf_puts(" reserved word", shl_stdout); + shf_puts("reserved word", shl_stdout); break; case CALIAS: if (vflag) @@ -590,16 +599,17 @@ c_whence(const char **wp) } break; case CSHELL: - if (vflag) - shprintf("%s %s %s", - (tp->flag & SPEC_BI) ? " special" : null, - "shell", Tbuiltin); + if (vflag) { + if (tp->flag & SPEC_BI) + shf_puts("special ", shl_stdout); + shprintf("%s %s", "shell", Tbuiltin); + } break; case CTALIAS: case CEXEC: if (tp->flag & ISSET) { if (vflag) { - shf_puts(" is ", shl_stdout); + shf_puts("is ", shl_stdout); if (tp->type == CTALIAS) shprintf("a tracked %s%s for ", (tp->flag & EXPORT) ? @@ -609,12 +619,12 @@ c_whence(const char **wp) shf_puts(tp->val.s, shl_stdout); } else { if (vflag) - shprintf(" %s\n", "not found"); + shf_puts("not found", shl_stdout); rv = 1; } break; default: - shprintf("%s is *GOK*", id); + shf_puts(" is *GOK*", shl_stdout); break; } if (vflag || !rv) @@ -1587,12 +1597,16 @@ c_shift(const char **wp) return (1); arg = wp[builtin_opt.optind]; - if (arg) { - evaluate(arg, &val, KSH_UNWIND_ERROR, false); - n = val; - } else + if (!arg) n = 1; - if (n < 0) { + else if (!evaluate(arg, &val, KSH_RETURN_ERROR, false)) { + /* error already printed */ + bi_errorfz(); + return (1); + } else if (!(n = val)) { + /* nothing to do */ + return (0); + } else if (n < 0) { bi_errorf("%s: %s", arg, "bad number"); return (1); } @@ -1813,7 +1827,7 @@ c_read(const char **wp) char *cp, *allocd = NULL, *xp; const char *ccp; XString xs; - ptrdiff_t xsave = 0; + size_t xsave = 0; mksh_ttyst tios; bool restore_tios = false; #if HAVE_SELECT @@ -2417,9 +2431,8 @@ c_set(const char **wp) return (c_typeset(args)); } - argi = parse_args(wp, OF_SET, &setargs); - if (argi < 0) - return (1); + if ((argi = parse_args(wp, OF_SET, &setargs)) < 0) + return (2); /* set $# and $* */ if (setargs) { wp += argi - 1; @@ -2794,8 +2807,6 @@ c_test(const char **wp) for (argc = 0; wp[argc]; argc++) ; - mkssert(argc > 0); - mkssert(wp[0] != NULL); if (strcmp(wp[0], "[") == 0) { if (strcmp(wp[--argc], "]") != 0) { diff --git a/src/histrap.c b/src/histrap.c index d15cc8d..6d2badf 100644 --- a/src/histrap.c +++ b/src/histrap.c @@ -1,9 +1,9 @@ -/* $OpenBSD: history.c,v 1.39 2010/05/19 17:36:08 jasper Exp $ */ +/* $OpenBSD: history.c,v 1.40 2014/11/20 15:22:39 tedu Exp $ */ /* $OpenBSD: trap.c,v 1.23 2010/05/19 17:36:08 jasper Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2014 + * 2011, 2012, 2014, 2015 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -27,7 +27,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134 2014/06/09 13:25:53 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134.2.3 2015/03/01 15:43:00 tg Exp $"); Trap sigtraps[NSIG + 1]; static struct sigaction Sigact_ign; @@ -303,7 +303,7 @@ c_fc(const char **wp) for (hp = rflag ? hlast : hfirst; hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1) shf_fprintf(shf, "%s\n", *hp); - if (shf_close(shf) == EOF) { + if (shf_close(shf) == -1) { bi_errorf("can't %s temporary file %s: %s", "write", tf->tffn, cstrerror(errno)); return (1); @@ -423,14 +423,14 @@ hist_get(const char *str, bool approx, bool allow_cur) if (getn(str, &n)) { hp = histptr + (n < 0 ? n : (n - hist_source->line)); - if ((ptrdiff_t)hp < (ptrdiff_t)history) { + if ((size_t)hp < (size_t)history) { if (approx) hp = hist_get_oldest(); else { bi_errorf("%s: %s", str, Tnot_in_history); hp = NULL; } - } else if ((ptrdiff_t)hp > (ptrdiff_t)histptr) { + } else if ((size_t)hp > (size_t)histptr) { if (approx) hp = hist_get_newest(allow_cur); else { @@ -634,7 +634,6 @@ histsave(int *lnp, const char *cmd, bool dowrite MKSH_A_UNUSED, bool ignoredups) char **hp; char *c, *cp; - mkssert(cmd != NULL); strdupx(c, cmd, APERM); if ((cp = strchr(c, '\n')) != NULL) *cp = '\0'; diff --git a/src/jobs.c b/src/jobs.c index 18179c1..d919c16 100644 --- a/src/jobs.c +++ b/src/jobs.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.105 2014/10/03 12:32:48 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.105.2.1 2015/01/25 15:44:06 tg Exp $"); #if HAVE_KILLPG #define mksh_killpg killpg @@ -1047,7 +1047,7 @@ j_async(void) static void j_set_async(Job *j) { - Job *jl, *oldest; + Job *jl, *oldest; if (async_job && (async_job->flags & (JF_KNOWN|JF_ZOMBIE)) == JF_ZOMBIE) remove_job(async_job, "async"); @@ -1084,7 +1084,7 @@ j_set_async(Job *j) static void j_startjob(Job *j) { - Proc *p; + Proc *p; j->flags |= JF_STARTED; for (p = j->proc_list; p->next; p = p->next) @@ -1421,8 +1421,8 @@ j_sigchld(int sig MKSH_A_UNUSED) static void check_job(Job *j) { - int jstate; - Proc *p; + int jstate; + Proc *p; /* XXX debugging (nasty - interrupt routine using shl_out) */ if (!(j->flags & JF_STARTED)) { @@ -1524,14 +1524,14 @@ check_job(Job *j) static void j_print(Job *j, int how, struct shf *shf) { - Proc *p; - int state; - int status; - int coredumped; - char jobchar = ' '; - char buf[64]; + Proc *p; + int state; + int status; + int coredumped; + char jobchar = ' '; + char buf[64]; const char *filler; - int output = 0; + int output = 0; if (how == JP_PGRP) { /* @@ -1737,8 +1737,8 @@ static Proc *free_procs; static Job * new_job(void) { - int i; - Job *newj, *j; + int i; + Job *newj, *j; if (free_jobs != NULL) { newj = free_jobs; @@ -1766,7 +1766,7 @@ new_job(void) static Proc * new_proc(void) { - Proc *p; + Proc *p; if (free_procs != NULL) { p = free_procs; @@ -1786,10 +1786,9 @@ new_proc(void) static void remove_job(Job *j, const char *where) { - Proc *p, *tmp; - Job **prev, *curr; + Proc *p, *tmp; + Job **prev, *curr; - mkssert(j != NULL); prev = &job_list; curr = job_list; while (curr && curr != j) { @@ -1830,9 +1829,8 @@ remove_job(Job *j, const char *where) static void put_job(Job *j, int where) { - Job **prev, *curr; + Job **prev, *curr; - mkssert(j != NULL); /* Remove job from list (if there) */ prev = &job_list; curr = job_list; @@ -1869,8 +1867,8 @@ put_job(Job *j, int where) static int kill_job(Job *j, int sig) { - Proc *p; - int rval = 0; + Proc *p; + int rval = 0; for (p = j->proc_list; p != NULL; p = p->next) if (p->pid != 0) diff --git a/src/lalloc.c b/src/lalloc.c index f5dc830..9c1dd6d 100644 --- a/src/lalloc.c +++ b/src/lalloc.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009, 2010, 2011, 2013 + * Copyright (c) 2009, 2010, 2011, 2013, 2014 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -20,7 +20,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.20 2013/06/03 22:28:33 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.20.2.1 2015/01/25 15:35:47 tg Exp $"); /* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */ #if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0) @@ -29,7 +29,7 @@ __RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.20 2013/06/03 22:28:33 tg Exp $"); #define remalloc(p,n) realloc_osi((p), (n)) #endif -#define ALLOC_ISUNALIGNED(p) (((ptrdiff_t)(p)) % ALLOC_SIZE) +#define ALLOC_ISUNALIGNED(p) (((size_t)(p)) % ALLOC_SIZE) static ALLOC_ITEM *findptr(ALLOC_ITEM **, char *, Area *); diff --git a/src/lex.c b/src/lex.c index 9d39998..502284a 100644 --- a/src/lex.c +++ b/src/lex.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.193 2014/06/29 11:28:28 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.193.2.1 2015/01/11 22:39:50 tg Exp $"); /* * states while lexing word @@ -854,7 +854,7 @@ yylex(int cf) *dp = '\0'; /* store the quoted string */ *wp++ = OQUOTE; - XcheckN(ws, wp, (dp - sp)); + XcheckN(ws, wp, (dp - sp) * 2); dp = sp; while ((c = *dp++)) { if (c == '\\') { @@ -1027,17 +1027,24 @@ yylex(int cf) /* copy word to unprefixed string ident */ sp = yylval.cp; dp = ident; - if ((cf & HEREDELIM) && (sp[1] == '<')) - while ((dp - ident) < IDENT) { - if ((c = *sp++) == CHAR) - *dp++ = *sp++; - else if ((c != OQUOTE) && (c != CQUOTE)) - break; + if ((cf & HEREDELIM) && (sp[1] == '<')) { + herestringloop: + switch ((c = *sp++)) { + case CHAR: + ++sp; + /* FALLTHROUGH */ + case OQUOTE: + case CQUOTE: + goto herestringloop; + default: + break; } - else + /* dummy value */ + *dp++ = 'x'; + } else while ((dp - ident) < IDENT && (c = *sp++) == CHAR) *dp++ = *sp++; - /* Make sure the ident array stays '\0' padded */ + /* make sure the ident array stays NUL padded */ memset(dp, 0, (ident + IDENT) - dp + 1); if (c != EOS) /* word is not unquoted */ diff --git a/src/main.c b/src/main.c index f12d9b9..59d0b1e 100644 --- a/src/main.c +++ b/src/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.54 2013/11/28 10:33:37 sobrado Exp $ */ +/* $OpenBSD: main.c,v 1.55 2015/02/09 09:09:30 jsg Exp $ */ /* $OpenBSD: tty.c,v 1.10 2014/08/10 02:44:26 guenther Exp $ */ /* $OpenBSD: io.c,v 1.25 2014/08/11 20:28:47 guenther Exp $ */ /* $OpenBSD: table.c,v 1.15 2012/02/19 07:52:30 otto Exp $ */ @@ -34,7 +34,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/main.c,v 1.284 2014/10/03 17:19:27 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/main.c,v 1.285.2.2 2015/03/01 15:43:01 tg Exp $"); extern char **environ; @@ -892,6 +892,13 @@ unwind(int i) /* FALLTHROUGH */ default: quitenv(NULL); + /* + * quitenv() may have reclaimed the memory + * used by source which will end badly when + * we jump to a function that expects it to + * be valid + */ + source = NULL; } } } @@ -1014,8 +1021,6 @@ cleanup_parents_env(void) struct env *ep; int fd; - mkssert(e != NULL); - /* * Don't clean up temporary files - parent will probably need them. * Also, can't easily reclaim memory since variables, etc. could be @@ -1244,7 +1249,7 @@ bi_errorf(const char *fmt, ...) * non-interactive shells to exit. * XXX odd use of KEEPASN; also may not want LERROR here */ - if (builtin_flag & SPEC_BI) { + if (builtin_spec) { builtin_argv0 = NULL; unwind(LERROR); } diff --git a/src/misc.c b/src/misc.c index 82d47d6..7c8d114 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1,9 +1,9 @@ -/* $OpenBSD: misc.c,v 1.38 2013/11/28 10:33:37 sobrado Exp $ */ +/* $OpenBSD: misc.c,v 1.39 2015/01/16 06:39:32 deraadt Exp $ */ /* $OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $ */ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014 + * 2011, 2012, 2013, 2014, 2015 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -30,7 +30,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.219 2014/01/05 21:57:27 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.219.2.2 2015/03/01 15:43:02 tg Exp $"); #define KSH_CHVT_FLAG #ifdef MKSH_SMALL @@ -281,15 +281,15 @@ change_flag(enum sh_flag f, int what, bool newset) #endif DO_SETUID(setresuid, (ksheuid, ksheuid, ksheuid)); #else /* !HAVE_SETRESUGID */ - /* seteuid, setegid, setgid don't EAGAIN on Linux */ -#ifndef MKSH__NO_SETEUGID - seteuid(ksheuid); -#endif - DO_SETUID(setuid, (ksheuid)); + /* setgid, setegid, seteuid don't EAGAIN on Linux */ + setgid(kshegid); #ifndef MKSH__NO_SETEUGID setegid(kshegid); #endif - setgid(kshegid); + DO_SETUID(setuid, (ksheuid)); +#ifndef MKSH__NO_SETEUGID + seteuid(ksheuid); +#endif #endif /* !HAVE_SETRESUGID */ } else if ((f == FPOSIX || f == FSH) && newval) { /* Turning on -o posix or -o sh? */ @@ -304,6 +304,11 @@ change_flag(enum sh_flag f, int what, bool newset) void change_xtrace(unsigned char newval, bool dosnapshot) { + static bool in_xtrace; + + if (in_xtrace) + return; + if (!dosnapshot && newval == Flag(FXTRACE)) return; @@ -328,8 +333,13 @@ change_xtrace(unsigned char newval, bool dosnapshot) shl_xtrace->fd = 2; changed_xtrace: - if ((Flag(FXTRACE) = newval) == 2) + if ((Flag(FXTRACE) = newval) == 2) { + in_xtrace = true; + Flag(FXTRACE) = 0; shf_puts(substitute(str_val(global("PS4")), 0), shl_xtrace); + Flag(FXTRACE) = 2; + in_xtrace = false; + } } /* @@ -485,7 +495,6 @@ parse_args(const char **argv, if (arrayset) { const char *ccp = NULL; - mkssert(array != NULL); if (*array) ccp = skip_varname(array, false); if (!ccp || !(!ccp[0] || (ccp[0] == '+' && !ccp[1]))) { @@ -1384,8 +1393,7 @@ do_realpath(const char *upath) { char *xp, *ip, *tp, *ipath, *ldest = NULL; XString xs; - ptrdiff_t pos; - size_t len; + size_t pos, len; int llen; struct stat sb; #ifdef MKSH__NO_PATH_MAX diff --git a/src/mksh.1 b/src/mksh.1 index 480184e..5ad143c 100644 --- a/src/mksh.1 +++ b/src/mksh.1 @@ -1,9 +1,9 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.344 2014/10/07 15:30:12 tg Exp $ -.\" $OpenBSD: ksh.1,v 1.153 2014/08/17 07:15:41 jmc Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.344.2.3 2015/03/01 15:43:03 tg Exp $ +.\" $OpenBSD: ksh.1,v 1.156 2015/01/16 15:32:32 schwarze Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, -.\" 2010, 2011, 2012, 2013, 2014 -.\" Thorsten Glaser +.\" 2010, 2011, 2012, 2013, 2014, 2015 +.\" Thorsten “mirabilos” Glaser .\" .\" Provided that these terms and disclaimer and all copyright notices .\" are retained or reproduced in an accompanying document, permission @@ -74,7 +74,7 @@ .\" with -mandoc, it might implement .Mx itself, but we want to .\" use our own definition. And .Dd must come *first*, always. .\" -.Dd $Mdocdate: October 7 2014 $ +.Dd $Mdocdate: March 1 2015 $ .\" .\" Check which macro package we use, and do other -mdoc setup. .\" @@ -673,11 +673,11 @@ are reserved words, not meta-characters. .It Xo case Ar word No in .Oo Op \&( .Ar pattern -.Op \*(Ba Ar pat +.Op \*(Ba Ar pattern .No ... Ns ) .Ar list -.Op ;; \*(Ba ;&\& \*(Ba ;\*(Ba\ \& -.Oc ... esac +.Ic terminator +.Oc No ... esac .Xc The .Ic case @@ -707,9 +707,11 @@ For historical reasons, open and close braces may be used instead of and .Ic esac e.g.\& -.Ic case $foo { *) echo bar;; } . +.Ic case $foo { *) echo bar ;; } . .Pp -The list terminators are: +The list +.Ic terminator Ns s +are: .Bl -tag -width 4n .It Ql ;; Terminate after the list. @@ -2923,6 +2925,10 @@ trapped) will have their default effect in a function. .It The EXIT trap, if set in a function, will be executed after the function returns. +.It +Shell options +.Pq Ic set Fl o +have local scope, i.e. changes inside a function are reset upon its exit. .El .Ss Command execution After evaluation of command-line arguments, redirections, and parameter @@ -3370,9 +3376,25 @@ string which the shell then parses and executes in the current environment. .Pp .It Xo .Ic exec +.Op Fl a Ar argv0 +.Op Fl c .Op Ar command Op Ar arg ... .Xc The command is executed without forking, replacing the shell process. +This is currently absolute, i.e.\& +.Ic exec +never returns, even if the +.Ar command +is not found. +The +.Fl a +option permits setting a different +.Li argv[0] +value, and +.Fl c +clears the environment before executing the child process, except for the +.Ev _ +variable and direct assignments. .Pp If no command is given except for I/O redirection, the I/O redirection is permanent and the shell is @@ -6457,6 +6479,17 @@ If you require 64-bit integer arithmetics, use 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. +.Pp +.Nm mksh +provides a consistent, clear interface normally. +This may deviate from POSIX in optional or opinionated places, such +as whether leading-digit-zero numbers should be interpreted as octal. +.Ic set \-o posix +will cause the shell (either +.Nm mksh +or +.Nm lksh ) +to behave more like the standard expects. .Sh BUGS Suspending (using \*(haZ) pipelines like the one below will only suspend the currently running part of the pipeline; in this example, @@ -6468,16 +6501,19 @@ $ /bin/sleep 666 && echo fubar .Ed .Pp This document attempts to describe -.Nm mksh\ R50 +.Nm mksh\ R50e and up, compiled without any options impacting functionality, such as .Dv MKSH_SMALL , when not called as .Pa /bin/sh which, on some systems only, enables +.Ic set \-o posix +or .Ic set \-o sh automatically (whose behaviour differs across targets), for an operating environment supporting all of its advanced needs. +.Pp Please report bugs in .Nm to the diff --git a/src/sh.h b/src/sh.h index b3d1c0b..d053ed2 100644 --- a/src/sh.h +++ b/src/sh.h @@ -10,7 +10,7 @@ /*- * Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014 + * 2011, 2012, 2013, 2014, 2015 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -169,9 +169,9 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.697 2014/10/07 15:22:17 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.701.2.4 2015/03/01 15:43:05 tg Exp $"); #endif -#define MKSH_VERSION "R50 2014/10/07" +#define MKSH_VERSION "R50 2015/03/01" /* arithmetic types: C implementation */ #if !HAVE_CAN_INTTYPES @@ -312,9 +312,13 @@ struct rusage { #undef PATH_MAX #else #ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else #define PATH_MAX 1024 #endif #endif +#endif #ifndef SIZE_MAX #ifdef SIZE_T_MAX #define SIZE_MAX SIZE_T_MAX @@ -533,7 +537,7 @@ char *ucstrstr(char *, const char *); #define mkssert(e) do { } while (/* CONSTCOND */ 0) #endif -#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 504) +#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 505) #error Must run Build.sh to compile this. extern void thiswillneverbedefinedIhope(void); int @@ -992,8 +996,8 @@ EXTERN sigset_t sm_default, sm_sigchld; /* name of called builtin function (used by error functions) */ EXTERN const char *builtin_argv0; -/* flags of called builtin (SPEC_BI, etc.) */ -EXTERN uint32_t builtin_flag; +/* is called builtin SPEC_BI? */ +EXTERN bool builtin_spec; /* current working directory */ EXTERN char *current_wd; @@ -1233,6 +1237,7 @@ struct block { /* Values for struct block.flags */ #define BF_DOGETOPTS BIT(0) /* save/restore getopts state */ +#define BF_STOPENV BIT(1) /* do not export further */ /* * Used by ktwalk() and ktnext() routines. @@ -1396,7 +1401,8 @@ struct ioword { #define DOVACHECK BIT(9) /* var assign check (for typeset, set, etc) */ #define DOMARKDIRS BIT(10) /* force markdirs behaviour */ #define DOTCOMEXEC BIT(11) /* not an eval flag, used by sh -c hack */ -#define DOASNFIELD BIT(12) /* is assignment, change field handling */ +#define DOSCALAR BIT(12) /* change field handling to non-list context */ +#define DOHEREDOC BIT(13) /* change scalar handling to heredoc body */ #define X_EXTRA 20 /* this many extra bytes in X string */ @@ -1645,7 +1651,7 @@ char *evalonestr(const char *cp, int); char *debunk(char *, const char *, size_t); void expand(const char *, XPtrV *, int); int glob_str(char *, XPtrV *, bool); -char *tilde(char *); +char *do_tilde(char *); /* exec.c */ int execute(struct op * volatile, volatile int, volatile int * volatile); int shcomexec(const char **); diff --git a/src/shf.c b/src/shf.c index 33e89bd..cc30442 100644 --- a/src/shf.c +++ b/src/shf.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, - * 2012, 2013 + * 2012, 2013, 2015 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -25,7 +25,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.62 2013/10/09 11:59:30 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.62.2.2 2015/03/01 15:43:07 tg Exp $"); /* flags to shf_emptybuf() */ #define EB_READSW 0x01 /* about to switch to reading */ @@ -232,7 +232,7 @@ shf_close(struct shf *shf) if (shf->fd >= 0) { ret = shf_flush(shf); if (close(shf->fd) < 0) - ret = EOF; + ret = -1; } if (shf->flags & SHF_ALLOCS) afree(shf, shf->areap); @@ -251,7 +251,7 @@ shf_fdclose(struct shf *shf) if (shf->fd >= 0) { ret = shf_flush(shf); if (close(shf->fd) < 0) - ret = EOF; + ret = -1; shf->rnleft = 0; shf->rp = shf->buf; shf->wnleft = 0; @@ -283,20 +283,20 @@ shf_sclose(struct shf *shf) /* * Un-read what has been read but not examined, or write what has been - * buffered. Returns 0 for success, EOF for (write) error. + * buffered. Returns 0 for success, -1 for (write) error. */ int shf_flush(struct shf *shf) { if (shf->flags & SHF_STRING) - return ((shf->flags & SHF_WR) ? EOF : 0); + return ((shf->flags & SHF_WR) ? -1 : 0); if (shf->fd < 0) internal_errorf("%s: %s", "shf_flush", "no fd"); if (shf->flags & SHF_ERROR) { errno = shf->errnosv; - return (EOF); + return (-1); } if (shf->flags & SHF_READING) { @@ -315,7 +315,7 @@ shf_flush(struct shf *shf) /* * Write out any buffered data. If currently reading, flushes the read - * buffer. Returns 0 for success, EOF for (write) error. + * buffer. Returns 0 for success, -1 for (write) error. */ static int shf_emptybuf(struct shf *shf, int flags) @@ -327,7 +327,7 @@ shf_emptybuf(struct shf *shf, int flags) if (shf->flags & SHF_ERROR) { errno = shf->errnosv; - return (EOF); + return (-1); } if (shf->flags & SHF_READING) { @@ -347,7 +347,7 @@ shf_emptybuf(struct shf *shf, int flags) */ if (!(flags & EB_GROW) || !(shf->flags & SHF_DYNAMIC) || !(shf->flags & SHF_ALLOCB)) - return (EOF); + return (-1); /* allocate more space for buffer */ nbuf = aresize2(shf->buf, 2, shf->wbsize, shf->areap); shf->rp = nbuf + (shf->rp - shf->buf); @@ -379,7 +379,7 @@ shf_emptybuf(struct shf *shf, int flags) ntowrite); shf->wp = shf->buf + ntowrite; } - return (EOF); + return (-1); } buf += n; ntowrite -= n; @@ -399,7 +399,7 @@ shf_emptybuf(struct shf *shf, int flags) return (ret); } -/* Fill up a read buffer. Returns EOF for a read error, 0 otherwise. */ +/* Fill up a read buffer. Returns -1 for a read error, 0 otherwise. */ static int shf_fillbuf(struct shf *shf) { @@ -414,11 +414,11 @@ shf_fillbuf(struct shf *shf) if (shf->flags & (SHF_EOF | SHF_ERROR)) { if (shf->flags & SHF_ERROR) errno = shf->errnosv; - return (EOF); + return (-1); } - if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) - return (EOF); + if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1) + return (-1); shf->flags |= SHF_READING; @@ -434,7 +434,7 @@ shf_fillbuf(struct shf *shf) shf->errnosv = errno; shf->rnleft = 0; shf->rp = shf->buf; - return (EOF); + return (-1); } if ((shf->rnleft = n) == 0) shf->flags |= SHF_EOF; @@ -443,7 +443,7 @@ shf_fillbuf(struct shf *shf) /* * Read a buffer from shf. Returns the number of bytes read into buf, if - * no bytes were read, returns 0 if end of file was seen, EOF if a read + * no bytes were read, returns 0 if end of file was seen, -1 if a read * error occurred. */ ssize_t @@ -459,7 +459,7 @@ shf_read(char *buf, ssize_t bsize, struct shf *shf) while (bsize > 0) { if (shf->rnleft == 0 && - (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) + (shf_fillbuf(shf) == -1 || shf->rnleft == 0)) break; ncopy = shf->rnleft; if (ncopy > bsize) @@ -471,12 +471,12 @@ shf_read(char *buf, ssize_t bsize, struct shf *shf) shf->rnleft -= ncopy; } /* Note: fread(3S) returns 0 for errors - this doesn't */ - return (orig_bsize == bsize ? (shf_error(shf) ? EOF : 0) : + return (orig_bsize == bsize ? (shf_error(shf) ? -1 : 0) : orig_bsize - bsize); } /* - * Read up to a newline or EOF. The newline is put in buf; buf is always + * Read up to a newline or -1. The newline is put in buf; buf is always * NUL terminated. Returns NULL on read error or if nothing was read * before end of file, returns a pointer to the NUL byte in buf * otherwise. @@ -498,7 +498,7 @@ shf_getse(char *buf, ssize_t bsize, struct shf *shf) --bsize; do { if (shf->rnleft == 0) { - if (shf_fillbuf(shf) == EOF) + if (shf_fillbuf(shf) == -1) return (NULL); if (shf->rnleft == 0) { *buf = '\0'; @@ -520,22 +520,22 @@ shf_getse(char *buf, ssize_t bsize, struct shf *shf) return (buf); } -/* Returns the char read. Returns EOF for error and end of file. */ +/* Returns the char read. Returns -1 for error and end of file. */ int shf_getchar(struct shf *shf) { if (!(shf->flags & SHF_RD)) internal_errorf("%s: flags 0x%X", "shf_getchar", shf->flags); - if (shf->rnleft == 0 && (shf_fillbuf(shf) == EOF || shf->rnleft == 0)) - return (EOF); + if (shf->rnleft == 0 && (shf_fillbuf(shf) == -1 || shf->rnleft == 0)) + return (-1); --shf->rnleft; return (*shf->rp++); } /* * Put a character back in the input stream. Returns the character if - * successful, EOF if there is no room. + * successful, -1 if there is no room. */ int shf_ungetc(int c, struct shf *shf) @@ -543,12 +543,12 @@ shf_ungetc(int c, struct shf *shf) if (!(shf->flags & SHF_RD)) internal_errorf("%s: flags 0x%X", "shf_ungetc", shf->flags); - if ((shf->flags & SHF_ERROR) || c == EOF || + if ((shf->flags & SHF_ERROR) || c == -1 || (shf->rp == shf->buf && shf->rnleft)) - return (EOF); + return (-1); - if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == EOF) - return (EOF); + if ((shf->flags & SHF_WRITING) && shf_emptybuf(shf, EB_READSW) == -1) + return (-1); if (shf->rp == shf->buf) shf->rp = shf->buf + shf->rbsize; @@ -558,7 +558,7 @@ shf_ungetc(int c, struct shf *shf) * we don't want to modify a string. */ if ((int)(shf->rp[-1]) != c) - return (EOF); + return (-1); shf->flags &= ~SHF_EOF; shf->rp--; shf->rnleft++; @@ -571,7 +571,7 @@ shf_ungetc(int c, struct shf *shf) } /* - * Write a character. Returns the character if successful, EOF if the + * Write a character. Returns the character if successful, -1 if the * char could not be written. */ int @@ -580,8 +580,8 @@ shf_putchar(int c, struct shf *shf) if (!(shf->flags & SHF_WR)) internal_errorf("%s: flags 0x%X", "shf_putchar", shf->flags); - if (c == EOF) - return (EOF); + if (c == -1) + return (-1); if (shf->flags & SHF_UNBUF) { unsigned char cc = (unsigned char)c; @@ -591,7 +591,7 @@ shf_putchar(int c, struct shf *shf) internal_errorf("%s: %s", "shf_putchar", "no fd"); if (shf->flags & SHF_ERROR) { errno = shf->errnosv; - return (EOF); + return (-1); } while ((n = write(shf->fd, &cc, 1)) != 1) if (n < 0) { @@ -600,12 +600,12 @@ shf_putchar(int c, struct shf *shf) continue; shf->flags |= SHF_ERROR; shf->errnosv = errno; - return (EOF); + return (-1); } } else { /* Flush deals with strings and sticky errors */ - if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == EOF) - return (EOF); + if (shf->wnleft == 0 && shf_emptybuf(shf, EB_GROW) == -1) + return (-1); shf->wnleft--; *shf->wp++ = c; } @@ -614,19 +614,19 @@ shf_putchar(int c, struct shf *shf) } /* - * Write a string. Returns the length of the string if successful, EOF + * Write a string. Returns the length of the string if successful, -1 * if the string could not be written. */ ssize_t shf_puts(const char *s, struct shf *shf) { if (!s) - return (EOF); + return (-1); return (shf_write(s, strlen(s), shf)); } -/* Write a buffer. Returns nbytes if successful, EOF if there is an error. */ +/* Write a buffer. Returns nbytes if successful, -1 if there is an error. */ ssize_t shf_write(const char *buf, ssize_t nbytes, struct shf *shf) { @@ -653,13 +653,13 @@ shf_write(const char *buf, ssize_t nbytes, struct shf *shf) if (shf->flags & SHF_STRING) { /* resize buffer until there's enough space left */ while (nbytes > shf->wnleft) - if (shf_emptybuf(shf, EB_GROW) == EOF) - return (EOF); + if (shf_emptybuf(shf, EB_GROW) == -1) + return (-1); /* then write everything into the buffer */ } else { /* flush deals with sticky errors */ - if (shf_emptybuf(shf, EB_GROW) == EOF) - return (EOF); + if (shf_emptybuf(shf, EB_GROW) == -1) + return (-1); /* write chunks larger than window size directly */ if (nbytes > shf->wbsize) { ncopy = nbytes; @@ -679,7 +679,7 @@ shf_write(const char *buf, ssize_t nbytes, struct shf *shf) * Note: fwrite(3) returns 0 * for errors - this doesn't */ - return (EOF); + return (-1); } buf += n; ncopy -= n; @@ -767,12 +767,7 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) ssize_t field, precision, len; unsigned long lnum; /* %#o produces the longest output */ - char numbuf[(8 * sizeof(long) + 2) / 3 + 1 -#ifdef DEBUG - /* a NUL for LLVM/Clang scan-build */ - + 1 -#endif - ]; + char numbuf[(8 * sizeof(long) + 2) / 3 + 1]; /* this stuff for dealing with the buffer */ ssize_t nwritten = 0; @@ -910,16 +905,6 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) integral: flags |= FL_NUMBER; cp = numbuf + sizeof(numbuf); -#ifdef DEBUG - /* - * this is necessary so Clang 3.2 realises - * utf_skipcols/shf_putc in the output loop - * terminate; these values are always ASCII - * so an out-of-bounds access cannot happen - * but Clang doesn't know that - */ - *--cp = '\0'; -#endif switch (c) { case 'd': @@ -971,10 +956,6 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) } } len = numbuf + sizeof(numbuf) - (s = cp); -#ifdef DEBUG - /* see above comment for Clang 3.2 */ - --len; -#endif if (flags & FL_DOT) { if (precision > len) { field = precision; @@ -1068,7 +1049,7 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args) } } - return (shf_error(shf) ? EOF : nwritten); + return (shf_error(shf) ? -1 : nwritten); } #if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST) diff --git a/src/syn.c b/src/syn.c index 6a544df..0e6e677 100644 --- a/src/syn.c +++ b/src/syn.c @@ -23,7 +23,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.94 2014/01/05 21:57:29 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.94.2.1 2015/01/25 15:35:54 tg Exp $"); struct nesting_state { int start_token; /* token than began nesting (eg, FOR) */ @@ -196,10 +196,11 @@ synio(int cf) musthave(LWORD, ishere ? HEREDELIM : 0); if (ishere) { iop->delim = yylval.cp; - if (*ident != 0) + if (*ident != 0) { /* unquoted */ gotnulldelim: iop->flag |= IOEVAL; + } if (herep > &heres[HERES - 1]) yyerror("too many %ss\n", "<<"); *herep++ = iop; diff --git a/src/var.c b/src/var.c index 9f05ec1..452b6e2 100644 --- a/src/var.c +++ b/src/var.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - * 2011, 2012, 2013, 2014 + * 2011, 2012, 2013, 2014, 2015 * Thorsten Glaser * * Provided that these terms and disclaimer and all copyright notices @@ -28,7 +28,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/var.c,v 1.183 2014/10/04 11:47:19 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/var.c,v 1.183.2.2 2015/03/01 15:43:07 tg Exp $"); /*- * Variables @@ -308,7 +308,6 @@ local(const char *n, bool copy) * dereference namerefs; must come first */ n = array_index_calc(n, &array, &val); - mkssert(n != NULL); h = hash(n); if (!ksh_isalphx(*n)) { vp = &vtemp; @@ -679,8 +678,6 @@ exportprep(struct tbl *vp, const char *val) char *op = (vp->flag&ALLOC) ? vp->val.s : NULL; size_t namelen, vallen; - mkssert(val != NULL); - namelen = strlen(vp->name); vallen = strlen(val) + 1; @@ -1114,6 +1111,8 @@ makenv(void) } XPput(denv, vp->val.s); } + if (l->flags & BF_STOPENV) + break; } XPput(denv, NULL); return ((char **)XPclose(denv));