-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=541
+ -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=551
include $(BUILD_EXECUTABLE)
#!/bin/sh
-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.707 2016/11/11 23:31:29 tg Exp $'
+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.716 2017/04/12 18:33:22 tg Exp $'
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-# 2011, 2012, 2013, 2014, 2015, 2016
+# 2011, 2012, 2013, 2014, 2015, 2016, 2017
# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
last=
tfn=
legacy=0
+textmode=0
for i
do
:-r)
r=1
;;
+ :-T)
+ textmode=1
+ ;;
+ :+T)
+ textmode=0
+ ;;
:-t)
last=t
;;
rmf a.exe* a.out* conftest.c conftest.exe* *core core.* ${tfn}* *.bc *.dbg \
*.ll *.o *.gen *.cat1 Rebuild.sh lft no signames.inc test.sh x vv.out
-SRCS="lalloc.c eval.c exec.c expr.c funcs.c histrap.c jobs.c"
+SRCS="lalloc.c edit.c eval.c exec.c expr.c funcs.c histrap.c jobs.c"
SRCS="$SRCS lex.c main.c misc.c shf.c syn.c tree.c var.c"
if test $legacy = 0; then
- SRCS="$SRCS edit.c"
check_categories="$check_categories shell:legacy-no int:32"
else
check_categories="$check_categories shell:legacy-yes"
add_cppflags -DMKSH_LEGACY_MODE
- HAVE_PERSISTENT_HISTORY=0
+fi
+
+if test $textmode = 0; then
+ check_categories="$check_categories shell:textmode-no shell:binmode-yes"
+else
+ check_categories="$check_categories shell:textmode-yes shell:binmode-no"
+ add_cppflags -DMKSH_WITH_TEXTMODE
fi
if test x"$srcdir" = x"."; then
add_cppflags -DMKSH__NO_SETEUGID
oswarn=' and will currently not work'
add_cppflags -DMKSH_UNEMPLOYED
- add_cppflags -DMKSH_NOPROSPECTOFWORK
# these taken from Harvey-OS github and need re-checking
add_cppflags -D_setjmp=setjmp -D_longjmp=longjmp
: "${HAVE_CAN_NO_EH_FRAME=0}"
: "${HAVE_SETLOCALE_CTYPE=0}"
;;
OS/2)
+ add_cppflags -DMKSH_ASSUME_UTF8=0; HAVE_ISSET_MKSH_ASSUME_UTF8=1
HAVE_TERMIOS_H=0
HAVE_MKNOD=0 # setmode() incompatible
- oswarn="; it is currently being ported, get it from"
- oswarn="$oswarn${nl}https://github.com/komh/mksh-os2 in the meanwhile"
+ oswarn="; it is being ported"
check_categories="$check_categories nosymlink"
: "${CC=gcc}"
: "${SIZE=: size}"
+ SRCS="$SRCS os2.c"
add_cppflags -DMKSH_UNEMPLOYED
add_cppflags -DMKSH_NOPROSPECTOFWORK
add_cppflags -DMKSH_NO_LIMITS
+ add_cppflags -DMKSH_DOSPATH
+ if test $textmode = 0; then
+ x='dis'
+ y='standard OS/2 tools'
+ else
+ x='en'
+ y='standard Unix mksh and other tools'
+ fi
+ echo >&2 "
+OS/2 Note: mksh can be built with or without 'textmode'.
+Without 'textmode' it will behave like a standard Unix utility,
+compatible to mksh on all other platforms, using only ASCII LF
+(0x0A) as line ending character. This is supported by the mksh
+upstream developer.
+With 'textmode', mksh will be modified to behave more like other
+OS/2 utilities, supporting ASCII CR+LF (0x0D 0x0A) as line ending
+at the cost of deviation from standard mksh. This is supported by
+the mksh-os2 porter.
+
+] You are currently compiling with textmode ${x}abled, introducing
+] incompatibilities with $y.
+"
;;
OSF1)
HAVE_SIG_T=0 # incompatible
ac_testdone
ac_cppflags
-save_CFLAGS=$CFLAGS
-ac_testn compile_time_asserts_$$ '' 'whether compile-time assertions pass' <<-'EOF'
- #define MKSH_INCLUDES_ONLY
- #include "sh.h"
- #ifndef CHAR_BIT
- #define CHAR_BIT 8 /* defuse this test on really legacy systems */
- #endif
- struct ctasserts {
- #define cta(name, assertion) char name[(assertion) ? 1 : -1]
-/* this one should be defined by the standard */
-cta(char_is_1_char, (sizeof(char) == 1) && (sizeof(signed char) == 1) &&
- (sizeof(unsigned char) == 1));
-cta(char_is_8_bits, ((CHAR_BIT) == 8) && ((int)(unsigned char)0xFF == 0xFF) &&
- ((int)(unsigned char)0x100 == 0) && ((int)(unsigned char)(int)-1 == 0xFF));
-/* the next assertion is probably not really needed */
-cta(short_is_2_char, sizeof(short) == 2);
-cta(short_size_no_matter_of_signedness, sizeof(short) == sizeof(unsigned short));
-/* the next assertion is probably not really needed */
-cta(int_is_4_char, sizeof(int) == 4);
-cta(int_size_no_matter_of_signedness, sizeof(int) == sizeof(unsigned int));
-
-cta(long_ge_int, sizeof(long) >= sizeof(int));
-cta(long_size_no_matter_of_signedness, sizeof(long) == sizeof(unsigned long));
-
-#ifndef MKSH_LEGACY_MODE
-/* the next assertion is probably not really needed */
-cta(ari_is_4_char, sizeof(mksh_ari_t) == 4);
-/* but this is */
-cta(ari_has_31_bit, 0 < (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1));
-/* the next assertion is probably not really needed */
-cta(uari_is_4_char, sizeof(mksh_uari_t) == 4);
-/* but the next three are; we REQUIRE unsigned integer wraparound */
-cta(uari_has_31_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 2 + 1));
-cta(uari_has_32_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3));
-cta(uari_wrap_32_bit,
- (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) >
- (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4));
-#define NUM 22
-#else
-#define NUM 16
-#endif
-/* these are always required */
-cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0);
-cta(uari_is_unsigned, (mksh_uari_t)-1 > (mksh_uari_t)0);
-/* we require these to have the precisely same size and assume 2s complement */
-cta(ari_size_no_matter_of_signedness, sizeof(mksh_ari_t) == sizeof(mksh_uari_t));
-
-cta(sizet_size_no_matter_of_signedness, sizeof(ssize_t) == sizeof(size_t));
-cta(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(size_t) <= sizeof(long));
-cta(ari_fits_in_long, sizeof(mksh_ari_t) <= sizeof(long));
-/* for struct alignment people */
- char padding[64 - NUM];
- };
-char ctasserts_dblcheck[sizeof(struct ctasserts) == 64 ? 1 : -1];
- int main(void) { return (sizeof(ctasserts_dblcheck) + isatty(0)); }
-EOF
-CFLAGS=$save_CFLAGS
-eval test 1 = \$HAVE_COMPILE_TIME_ASSERTS_$$ || exit 1
-
#
# extra checks for legacy mksh
#
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=541
+add_cppflags -DMKSH_BUILD_R=551
$e $bi$me: Finished configuration testing, now producing output.$ao
-# $MirOS: src/bin/mksh/check.t,v 1.756 2016/11/11 23:31:31 tg Exp $
+# $MirOS: src/bin/mksh/check.t,v 1.775 2017/04/12 17:38:41 tg Exp $
# -*- mode: sh -*-
#-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-# 2011, 2012, 2013, 2014, 2015, 2016
+# 2011, 2012, 2013, 2014, 2015, 2016, 2017
# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
expected-stdout:
- @(#)MIRBSD KSH R54 2016/11/11
+ @(#)MIRBSD KSH R55 2017/04/12
description:
Check version of shell.
stdin:
echo $KSH_VERSION
name: KSH_VERSION
-category: shell:legacy-no
+category: !shell:legacy-yes,!shell:textmode-yes
---
expected-stdout:
- @(#)LEGACY KSH R54 2016/11/11
+ @(#)LEGACY KSH R55 2017/04/12
description:
Check version of legacy shell.
stdin:
echo $KSH_VERSION
name: KSH_VERSION-legacy
-category: shell:legacy-yes
+category: !shell:legacy-no,!shell:textmode-yes
+---
+expected-stdout:
+ @(#)MIRBSD KSH R55 2017/04/12 +TEXTMODE
+description:
+ Check version of shell.
+stdin:
+ echo $KSH_VERSION
+name: KSH_VERSION-textmode
+category: !shell:legacy-yes,!shell:textmode-no
+---
+expected-stdout:
+ @(#)LEGACY KSH R55 2017/04/12 +TEXTMODE
+description:
+ Check version of legacy shell.
+stdin:
+ echo $KSH_VERSION
+name: KSH_VERSION-legacy-textmode
+category: !shell:legacy-no,!shell:textmode-no
---
name: selftest-1
description:
stdin:
set
---
-name: selftest-legacy
-description:
- Check some things in the LEGACY KSH
-category: shell:legacy-yes
-stdin:
- set +o emacs
- set +o vi
- [[ "$(set +o) -o" = *"-o emacs -o"* ]] && echo 1=emacs
- [[ "$(set +o) -o" = *"-o vi -o"* ]] && echo 1=vi
- set -o emacs
- set -o vi
- [[ "$(set +o) -o" = *"-o emacs -o"* ]] && echo 2=emacs
- [[ "$(set +o) -o" = *"-o vi -o"* ]] && echo 2=vi
-expected-stdout:
- 2=emacs
- 2=vi
----
name: selftest-direct-builtin-call
description:
Check that direct builtin calls work
expected-stdout:
-c echo foo
---
+name: selftest-pathsep-unix
+description:
+ Check that $PATHSEP is set correctly.
+category: !os:os2
+stdin:
+ PATHSEP=.; export PATHSEP
+ "$__progname" -c 'print -r -- $PATHSEP'
+expected-stdout:
+ :
+---
+name: selftest-pathsep-dospath
+description:
+ Check that $PATHSEP is set correctly.
+category: os:os2
+stdin:
+ PATHSEP=.; export PATHSEP
+ "$__progname" -c 'print -r -- $PATHSEP'
+expected-stdout:
+ ;
+---
name: alias-1
description:
Check that recursion is detected/avoided in aliases.
description:
Check that special argument handling still applies with escaped aliases
stdin:
- alias local='\typeset'
- function foo {
- local x=$1 y=z
+ alias local1='\typeset'
+ alias local2='\\builtin typeset'
+ function fooa {
+ local1 x=$1 y=z
+ print -r -- "$x,$y"
+ }
+ function foob {
+ local2 x=$1 y=z
print -r -- "$x,$y"
}
- foo 'bar - baz'
+ x=1 y=2; fooa 'bar - baz'
+ x=1 y=2; foob 'bar - baz'
expected-stdout:
bar - baz,z
+ bar - baz,z
+---
+name: alias-12
+description:
+ Something weird from Martijn Dekker
+stdin:
+ alias echo=print
+ x() { echo a; (echo b); x=$(echo c); }
+ typeset -f x
+ alias OPEN='{' CLOSE='};'
+ { OPEN echo hi1; CLOSE }
+ var=`{ OPEN echo hi2; CLOSE }` && echo "$var"
+ var=$({ OPEN echo hi3; CLOSE }) && echo "$var"
+expected-stdout:
+ x() {
+ \print a
+ ( \print b )
+ x=$(\print c )
+ }
+ hi1
+ hi2
+ hi3
---
name: arith-compound
description:
echo end-$i
done
echo end-3
+ for i in a b c; do echo $i; eval break; echo bad-$i; done
+ echo end-4
expected-stdout:
a
end-1
c:x
end-c
end-3
+ a
+ end-4
---
name: break-2
description:
echo end-$i
done
echo end-3
+ for i in a b c; do echo $i; eval continue; echo bad-$i ; done
+ echo end-4
expected-stdout:
a
b
c:z
end-c
end-3
+ a
+ b
+ c
+ end-4
---
name: continue-2
description:
expected-stdout:
0
bar() {
- foo 4<<-a <<-b 5<<-c
+ \foo 4<<-a <<-b 5<<-c
four
a
zero
8 ok
<9> <ab> <a b> .
---
+name: IFS-subst-10
+description:
+ Scalar context in ${var=$subst}
+stdin:
+ showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
+ set -- one "two three" four
+ unset -v var
+ save_IFS=$IFS
+ IFS=
+ set -- ${var=$*}
+ IFS=$save_IFS
+ echo "var=$var"
+ showargs "$@"
+expected-stdout:
+ var=onetwo threefour
+ <onetwo threefour> .
+---
name: IFS-arith-1
description:
http://austingroupbugs.net/view.php?id=832
line <6>
expected-exit: 1
---
+name: lineno-eval-alias
+description:
+ Check if LINENO is trapped in eval and aliases
+stdin:
+ ${ZSH_VERSION+false} || emulate sh; echo $LINENO
+ echo $LINENO
+ eval ' echo $LINENO
+ echo $LINENO
+ echo $LINENO'
+ echo $LINENO
+expected-stdout:
+ 1
+ 2
+ 3
+ 3
+ 3
+ 6
+---
name: unknown-trap
description:
Ensure unknown traps are not a syntax error
description:
Check if test -nt/-ot succeeds if second(first) file is missing.
stdin:
- touch a
+ :>a
test a -nt b && echo nt OK || echo nt BAD
test b -ot a && echo ot OK || echo ot BAD
expected-stdout:
Check tilde expansion works
env-setup: !HOME=/sweet!
stdin:
+ :>'c=a'
+ typeset c=[ab]
+ :>'d=a'
+ x=typeset; $x d=[ab]
+ echo "<$c>" "<$d>"
wd=$PWD
cd /
plus=$(print -r -- ~+)
[[ $minus = "$wd" ]]; echo two $? .
[[ $nix = /sweet ]]; echo nix $? .
expected-stdout:
+ <[ab]> <a>
one 0 .
two 0 .
nix 0 .
---
+name: tilde-expand-3
+description:
+ Check mostly Austin 351 stuff
+stdin:
+ showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
+ set "1 b=2" "3 d=4"
+ export a=$1 \c=$2
+ showargs 1 "$a" "$b" "$c" "$d"
+ unset a b c d
+ HOME=/tmp
+ export \a=~ b=~
+ command export c=~
+ builtin export d=~
+ \\builtin export e=~
+ showargs 2 "$a" "$b" "$c" "$d" "$e" ksh
+ unset a b c d e
+ set -o posix
+ export \a=~ b=~
+ command export c=~
+ builtin export d=~
+ \\builtin export e=~
+ showargs 3 "$a" "$b" "$c" "$d" "$e" posix
+ unset a b c d e
+ set +o posix
+ export a=$1
+ showargs 4 "$a" "$b" ksh
+ unset a b
+ showargs 5 a=$1 ksh
+ export \a=$1
+ showargs 6 "$a" "$b" ksh
+ unset a b
+ set -o posix
+ export a=$1
+ showargs 7 "$a" "$b" posix
+ unset a b
+ showargs 8 a=$1 posix
+ export \a=$1
+ showargs 9 "$a" "$b" posix
+ unset a b
+ set +o posix
+ command echo 10 ksh a=~
+ command command export a=~
+ showargs 11 "$a"
+ unset a
+ set -o posix
+ command echo 12 posix a=~
+ command command export a=~
+ showargs 13 "$a"
+ unset a
+ # unspecified whether /tmp or ~
+ var=export; command $var a=~
+ showargs 14 "$a"
+ echo 'echo "<$foo>"' >bar
+ "$__progname" bar
+ var=foo
+ export $var=1
+ "$__progname" bar
+ export $var=~
+ "$__progname" bar
+ # unspecified
+ command -- export a=~
+ showargs 18 "$a"
+ set -A bla
+ typeset bla[1]=~:~
+ global gbl=~ g2=$1
+ local lcl=~ l2=$1
+ readonly ro=~ r2=$1
+ showargs 19 "${bla[1]}" a=~ "$gbl" "$lcl" "$ro" "$g2" "$l2" "$r2"
+ set +o posix
+ echo "20 some arbitrary stuff "=~
+ set -o posix
+ echo "21 some arbitrary stuff "=~
+expected-stdout:
+ <1> <1 b=2> <> <3> <4> .
+ <2> </tmp> </tmp> </tmp> </tmp> </tmp> <ksh> .
+ <3> <~> </tmp> </tmp> <~> </tmp> <posix> .
+ <4> <1 b=2> <> <ksh> .
+ <5> <a=1> <b=2> <ksh> .
+ <6> <1> <2> <ksh> .
+ <7> <1 b=2> <> <posix> .
+ <8> <a=1> <b=2> <posix> .
+ <9> <1> <2> <posix> .
+ 10 ksh a=/tmp
+ <11> </tmp> .
+ 12 posix a=~
+ <13> </tmp> .
+ <14> <~> .
+ <>
+ <1>
+ <~>
+ <18> <~> .
+ <19> </tmp:/tmp> <a=~> </tmp> </tmp> </tmp> <1 b=2> <1 b=2> <1 b=2> .
+ 20 some arbitrary stuff =/tmp
+ 21 some arbitrary stuff =~
+---
name: exit-err-1
description:
Check some "exit on error" conditions
After error 2
Exit trap
expected-stderr-pattern:
- /syntax error: 'newline' unexpected/
+ /syntax error: unexpected 'newline'/
---
name: test-stlt-1
description:
2- 1 1 1 =
3- 0 0 0 =
---
+name: test-varset-1
+description:
+ Test the test -v operator
+stdin:
+ [[ -v a ]]
+ rv=$?; echo $((++i)) $rv
+ a=
+ [[ -v a ]]
+ rv=$?; echo $((++i)) $rv
+ unset a
+ [[ -v a ]]
+ rv=$?; echo $((++i)) $rv
+ a=x
+ [[ -v a ]]
+ rv=$?; echo $((++i)) $rv
+ nameref b=a
+ [[ -v b ]]
+ rv=$?; echo $((++i)) $rv
+ unset a
+ [[ -v b ]]
+ rv=$?; echo $((++i)) $rv
+ x[1]=y
+ [[ -v x ]]
+ rv=$?; echo $((++i)) $rv
+ [[ -v x[0] ]]
+ rv=$?; echo $((++i)) $rv
+ [[ -v x[1] ]]
+ rv=$?; echo $((++i)) $rv
+ [[ -v x[2] ]]
+ rv=$?; echo $((++i)) $rv
+expected-stdout:
+ 1 1
+ 2 0
+ 3 1
+ 4 0
+ 5 0
+ 6 1
+ 7 1
+ 8 1
+ 9 0
+ 10 1
+---
+name: test-varset-2
+description:
+ test -v works only on scalars
+stdin:
+ [[ -v x[*] ]]
+ echo ok
+expected-exit: e != 0
+expected-stderr-pattern:
+ /unexpected '\*'/
+---
name: test-stnze-1
description:
Check that the short form [ $x ] works
---
name: typeset-1
description:
- Check that global does what typeset is supposed to do
+ Check that typeset -g works correctly
stdin:
set -A arrfoo 65
foo() {
- global -Uui16 arrfoo[*]
+ typeset -g -Uui16 arrfoo[*]
}
echo before ${arrfoo[0]} .
foo
echo inside before ${arrbar[0]} .
arrbar[0]=97
echo inside changed ${arrbar[0]} .
- global -Uui16 arrbar[*]
+ typeset -g -Uui16 arrbar[*]
echo inside typeset ${arrbar[0]} .
arrbar[0]=48
echo inside changed ${arrbar[0]} .
inside changed 16#30 .
after 16#30 .
---
+name: typeset-2
+description:
+ Check that typeset -p on arrays works correctly
+stdin:
+ set -A x -- a b c
+ echo =
+ typeset -p x
+ echo =
+ typeset -p x[1]
+expected-stdout:
+ =
+ set -A x
+ typeset x[0]=a
+ typeset x[1]=b
+ typeset x[2]=c
+ =
+ typeset x[1]=b
+---
name: typeset-padding-1
description:
Check if left/right justification works as per TFM
-UMKSH_ASSUME_UTF8 => not expected, but if your OS is old,
try passing HAVE_SETLOCALE_CTYPE=0 to Build.sh
need-pass: no
-category: !os:hpux,!os:msys
+category: !os:hpux,!os:msys,!os:os2
need-ctty: yes
arguments: !-i!
env-setup: !PS1=!PS2=!LC_CTYPE=en_US.UTF-8!
alias
typeset -f
expected-stdout:
- autoload='\typeset -fu'
- functions='\typeset -f'
- hash='\builtin alias -t'
- history='\builtin fc -l'
- integer='\typeset -i'
- local='\typeset'
- login='\exec login'
- nameref='\typeset -n'
+ autoload='\\builtin typeset -fu'
+ functions='\\builtin typeset -f'
+ hash='\\builtin alias -t'
+ history='\\builtin fc -l'
+ integer='\\builtin typeset -i'
+ local='\\builtin typeset'
+ login='\\builtin exec login'
+ nameref='\\builtin typeset -n'
nohup='nohup '
- r='\builtin fc -e -'
- type='\builtin whence -v'
+ r='\\builtin fc -e -'
+ type='\\builtin whence -v'
---
name: aliases-2b
description:
alias
typeset -f
expected-stdout:
- autoload='\typeset -fu'
- functions='\typeset -f'
- hash='\builtin alias -t'
- history='\builtin fc -l'
- integer='\typeset -i'
- local='\typeset'
- login='\exec login'
- nameref='\typeset -n'
+ autoload='\\builtin typeset -fu'
+ functions='\\builtin typeset -f'
+ hash='\\builtin alias -t'
+ history='\\builtin fc -l'
+ integer='\\builtin typeset -i'
+ local='\\builtin typeset'
+ login='\\builtin exec login'
+ nameref='\\builtin typeset -n'
nohup='nohup '
- r='\builtin fc -e -'
- type='\builtin whence -v'
+ r='\\builtin fc -e -'
+ type='\\builtin whence -v'
---
name: aliases-3b
description:
./sh -c 'alias; typeset -f'
rm -f sh
expected-stdout:
- autoload='\typeset -fu'
- functions='\typeset -f'
- hash='\builtin alias -t'
- history='\builtin fc -l'
- integer='\typeset -i'
- local='\typeset'
- login='\exec login'
- nameref='\typeset -n'
+ autoload='\\builtin typeset -fu'
+ functions='\\builtin typeset -f'
+ hash='\\builtin alias -t'
+ history='\\builtin fc -l'
+ integer='\\builtin typeset -i'
+ local='\\builtin typeset'
+ login='\\builtin exec login'
+ nameref='\\builtin typeset -n'
nohup='nohup '
- r='\builtin fc -e -'
- type='\builtin whence -v'
+ r='\\builtin fc -e -'
+ type='\\builtin whence -v'
---
name: aliases-cmdline
description:
:|| local() { :; }
alias local
expected-stdout:
- local='\typeset'
- local='\typeset'
+ local='\\builtin typeset'
+ local='\\builtin typeset'
---
name: arrays-1
description:
name: arrassign-fnc-global
description:
Check locality of array access inside a function
- with the mksh-specific global keyword
+ with the bash4/mksh/yash/zsh typeset -g keyword
stdin:
function fn {
- global x
+ typeset -g x
x+=(f)
echo ".fn:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
}
function rfn {
set -A y
- global y
+ typeset -g y
y+=(f)
echo ".rfn:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
}
function fnr {
- global z
+ typeset -g z
set -A z
z+=(f)
echo ".fnr:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
name: strassign-fnc-global
description:
Check locality of string access inside a function
- with the mksh-specific global keyword
+ with the bash4/mksh/yash/zsh typeset -g keyword
stdin:
function fn {
- global x
+ typeset -g x
x+=f
echo ".fn:$x:"
}
function rfn {
y=
- global y
+ typeset -g y
y+=f
echo ".rfn:$y:"
}
function fnr {
- global z
+ typeset -g z
z=
z+=f
echo ".fnr:$z:"
while (( i < ${#line[*]} )); do
hv=${line[i++]}
if (( (pos & 15) == 0 )); then
- (( pos )) && print "$dasc|"
+ (( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- '
done
- (( hv == 2147483647 )) || print "$dasc|"
+ (( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 3C 64 E4 DB C3 9B E2 82 - AC C3 9B 40 3E 0A 3C 00 |<d.........@>.<.|
name: print-crlf
description:
Check that CR+LF is shown and read as-is
+category: shell:textmode-no
stdin:
cat >foo <<-'EOF'
x='bar\r
{.5}
{<bar\r}
---
+name: print-crlf-textmode
+description:
+ Check that CR+LF is treated as newline
+category: shell:textmode-yes
+stdin:
+ cat >foo <<-'EOF'
+ x='bar\r
+ ' #\r
+ echo .${#x} #\r
+ if test x"$KSH_VERSION" = x""; then #\r
+ printf '<%s>' "$x" #\r
+ else #\r
+ print -nr -- "<$x>" #\r
+ fi #\r
+ EOF
+ echo "[$("$__progname" foo)]"
+ "$__progname" foo | while IFS= read -r line; do
+ print -r -- "{$line}"
+ done
+expected-stdout:
+ [.4
+ <bar
+ >]
+ {.4}
+ {<bar}
+---
name: print-lf
description:
Check that LF-only is shown and read as-is
while [[ -n $line ]]; do
hv=1#${line::1}
if (( (pos & 15) == 0 )); then
- (( pos )) && print "$dasc|"
+ (( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- '
done
- (( hv == 2147483647 )) || print "$dasc|"
+ (( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 5C 20 5C 21 5C 22 5C 23 - 5C 24 5C 25 5C 26 5C 27 |\ \!\"\#\$\%\&\'|
00000030 20 5C 39 5C 3A 5C 3B 5C - 3C 5C 3D 5C 3E 5C 3F 5C | \9\:\;\<\=\>\?\|
00000040 40 5C 41 5C 42 5C 43 5C - 44 1B 5C 46 5C 47 5C 48 |@\A\B\C\D.\F\G\H|
00000050 5C 49 5C 4A 5C 4B 5C 4C - 5C 4D 5C 4E 5C 4F 5C 50 |\I\J\K\L\M\N\O\P|
- 00000060 5C 51 5C 52 5C 53 5C 54 - 20 5C 56 5C 57 5C 58 5C |\Q\R\S\T \V\W\X\|
- 00000070 59 5C 5A 5C 5B 5C 5C 5D - 5C 5E 5C 5F 5C 60 07 08 |Y\Z\[\]\^\_\`..|
- 00000080 20 20 5C 64 1B 0C 5C 67 - 5C 68 5C 69 5C 6A 5C 6B | \d..\g\h\i\j\k|
- 00000090 5C 6C 5C 6D 0A 5C 6F 5C - 70 20 5C 71 0D 5C 73 09 |\l\m.\o\p \q.\s.|
- 000000A0 0B 5C 77 5C 79 5C 7A 5C - 7B 5C 7C 5C 7D 5C 7E 20 |.\w\y\z\{\|\}\~ |
- 000000B0 E2 82 AC 64 20 EF BF BD - 20 12 33 20 78 20 53 20 |...d ... .3 x S |
- 000000C0 53 34 0A - |S4.|
+ 00000060 5C 51 5C 52 5C 53 5C 54 - 20 5C 55 5C 56 5C 57 5C |\Q\R\S\T \U\V\W\|
+ 00000070 58 5C 59 5C 5A 5C 5B 5C - 5C 5D 5C 5E 5C 5F 5C 60 |X\Y\Z\[\\]\^\_\`|
+ 00000080 07 08 20 20 5C 64 1B 0C - 5C 67 5C 68 5C 69 5C 6A |.. \d..\g\h\i\j|
+ 00000090 5C 6B 5C 6C 5C 6D 0A 5C - 6F 5C 70 20 5C 71 0D 5C |\k\l\m.\o\p \q.\|
+ 000000A0 73 09 5C 75 0B 5C 77 5C - 78 5C 79 5C 7A 5C 7B 5C |s.\u.\w\x\y\z\{\|
+ 000000B0 7C 5C 7D 5C 7E 20 E2 82 - AC 64 20 EF BF BD 20 12 ||\}\~ ...d ... .|
+ 000000C0 33 20 78 20 53 20 53 34 - 0A |3 x S S4.|
---
name: dollar-doublequoted-strings
description:
while [[ -n $line ]]; do
hv=1#${line::1}
if (( (pos & 15) == 0 )); then
- (( pos )) && print "$dasc|"
+ (( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- '
done
- (( hv == 2147483647 )) || print "$dasc|"
+ (( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 20 21 22 23 24 25 26 27 - 28 29 2A 2B 2C 2D 2E 2F | !"#$%&'()*+,-./|
while [[ -n $line ]]; do
hv=1#${line::1}
if (( (pos & 15) == 0 )); then
- (( pos )) && print "$dasc|"
+ (( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- '
done
- (( hv == 2147483647 )) || print "$dasc|"
+ (( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 48 65 6C 6C 6F 2C 20 57 - 6F 72 6C 64 21 5C 0A E3 |Hello, World!\..|
dasc=$dasc$dch
dch=
elif (( (pos & 7) == 0 )); then
- (( pos )) && print "$dasc|"
+ (( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
print -n ' '
(( (pos++ & 7) == 3 )) && print -n -- '- '
done
- (( hv == 2147483647 )) || print "$dasc|"
+ (( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 0048 0065 006C 006C - 006F 002C 0020 0057 |Hello, W|
while (( i < ${#line[*]} )); do
hv=${line[i++]}
if (( (pos & 15) == 0 )); then
- (( pos )) && print "$dasc|"
+ (( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- '
done
- (( hv == 2147483647 )) || print "$dasc|"
+ (( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 48 65 6C 6C 6F 2C 20 57 - 6F 72 6C 64 21 5C 0A E3 |Hello, World!\..|
dasc=$dasc$dch
dch=
elif (( (pos & 7) == 0 )); then
- (( pos )) && print "$dasc|"
+ (( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
print -n ' '
(( (pos++ & 7) == 3 )) && print -n -- '- '
done
- (( hv == 2147483647 )) || print "$dasc|"
+ (( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 0048 0065 006C 006C - 006F 002C 0020 0057 |Hello, W|
---
name: ulimit-1
description:
+ Check that ulimit as used in dot.mksh works or is stubbed
+stdin:
+ ulimit -c 0
+---
+name: ulimit-2
+description:
Check if we can use a specific syntax idiom for ulimit
-category: !os:syllable
+ XXX Haiku works, but only for -n and -V
+category: !os:haiku,!os:syllable
stdin:
if ! x=$(ulimit -d) || [[ $x = unknown ]]; then
#echo expected to fail on this OS
description:
Check if GNU bash-like I/O redirection works
Part 1: this is also supported by GNU bash
-category: shell:legacy-no
stdin:
exec 3>&1
function threeout {
description:
Check if GNU bash-like I/O redirection works
Part 2: this is *not* supported by GNU bash
-category: shell:legacy-no
stdin:
exec 3>&1
function threeout {
description:
Check if GNU bash-like I/O redirection works
Part 2: this is *not* supported by GNU bash
-category: shell:legacy-no
stdin:
exec 3>&1
function threeout {
description:
Check if GNU bash-like I/O redirection works
Part 2: this is supported by GNU bash 4 only
-category: shell:legacy-no
stdin:
echo mir >foo
set -o noclobber
description:
Check if GNU bash-like I/O redirection fails correctly
Part 1: this is also supported by GNU bash
-category: shell:legacy-no
stdin:
echo mir >foo
set -o noclobber
description:
Check if GNU bash-like I/O redirection fails correctly
Part 2: this is *not* supported by GNU bash
-category: shell:legacy-no
stdin:
echo mir >foo
set -o noclobber
Check if GNU bash-like I/O redirection works
Part 4: this is also supported by GNU bash,
but failed in some mksh versions
-category: shell:legacy-no
stdin:
exec 3>&1
function threeout {
ras
dwa
---
-name: bashiop-5-normal
+name: bashiop-5
description:
Check if GNU bash-like I/O redirection is only supported
in !POSIX !sh mode as it breaks existing scripts' syntax
-category: shell:legacy-no
stdin:
:>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
:>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
2 = bar .
3 = bar .
---
-name: bashiop-5-legacy
-description:
- Check if GNU bash-like I/O redirection is not parsed
- in lksh as it breaks existing scripts' syntax
-category: shell:legacy-yes
-stdin:
- :>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
- :>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
- :>x; echo 3 "$("$__progname" -o sh -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
-expected-stdout:
- 1 = bar .
- 2 = bar .
- 3 = bar .
----
name: oksh-eval
description:
Check expansions.
AT&T ksh93 does this still, which means we must keep it as well
XXX fails on some old Perl installations
need-pass: no
-category: shell:legacy-no
stdin:
cat >cld <<-EOF
#!$__perlname
expected-stdout:
Fowl
---
-name: fd-cloexec-3
-description:
- Verify that file descriptors > 2 are not private for LEGACY KSH
-category: shell:legacy-yes
-stdin:
- cat >cld <<-EOF
- #!$__perlname
- open(my \$fh, ">&", 9) or die "E: open \$!";
- syswrite(\$fh, "Fowl\\n", 5) or die "E: write \$!";
- EOF
- chmod +x cld
- exec 9>&1
- ./cld
-expected-stdout:
- Fowl
----
name: comsub-1a
description:
COMSUB are now parsed recursively, so this works
x() {
case $1 in
(u)
- echo x
+ \echo x
;|
(*)
- echo $1
+ \echo $1
;;
esac
}
name: comsub-5
description:
Check COMSUB works with aliases (does not expand them twice)
+ and reentrancy safety
stdin:
print '#!'"$__progname"'\nfor x in "$@"; do print -r -- "$x"; done' >pfn
chmod +x pfn
alias echo='echo a'
foo() {
+ echo moo
./pfn "$(echo foo)"
}
./pfn "$(echo b)"
+ typeset -f foo >x
+ cat x
+ foo
+ . ./x
typeset -f foo
+ foo
expected-stdout:
a b
foo() {
- ./pfn "$(echo foo )"
+ \echo a moo
+ ./pfn "$(\echo a foo )"
+ }
+ a moo
+ a foo
+ foo() {
+ \echo a moo
+ ./pfn "$(\echo a foo )"
}
+ a moo
+ a foo
---
name: comsub-torture
description:
vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4"
}
inline_TCOM() {
- vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4"
+ vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4"
}
function comsub_TCOM { x=$(
vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4"
); }
function comsub_TCOM {
- x=$(vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" )
+ x=$(vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4" )
}
function reread_TCOM { x=$((
vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4"
)|tr u x); }
function reread_TCOM {
- x=$(( vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" ) | tr u x )
+ x=$( ( vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4" ) | \tr u x )
}
inline_TPAREN_TPIPE_TLIST() {
(echo $foo | tr -dc 0-9; echo)
}
inline_TPAREN_TPIPE_TLIST() {
- ( echo $foo | tr -dc 0-9
- echo )
+ ( \echo $foo | \tr -dc 0-9
+ \echo )
}
function comsub_TPAREN_TPIPE_TLIST { x=$(
(echo $foo | tr -dc 0-9; echo)
); }
function comsub_TPAREN_TPIPE_TLIST {
- x=$(( echo $foo | tr -dc 0-9 ; echo ) )
+ x=$( ( \echo $foo | \tr -dc 0-9 ; \echo ) )
}
function reread_TPAREN_TPIPE_TLIST { x=$((
(echo $foo | tr -dc 0-9; echo)
)|tr u x); }
function reread_TPAREN_TPIPE_TLIST {
- x=$(( ( echo $foo | tr -dc 0-9 ; echo ) ) | tr u x )
+ x=$( ( ( \echo $foo | \tr -dc 0-9 ; \echo ) ) | \tr u x )
}
inline_TAND_TOR() {
cmd && echo ja || echo nein
}
inline_TAND_TOR() {
- cmd && echo ja || echo nein
+ \cmd && \echo ja || \echo nein
}
function comsub_TAND_TOR { x=$(
cmd && echo ja || echo nein
); }
function comsub_TAND_TOR {
- x=$(cmd && echo ja || echo nein )
+ x=$(\cmd && \echo ja || \echo nein )
}
function reread_TAND_TOR { x=$((
cmd && echo ja || echo nein
)|tr u x); }
function reread_TAND_TOR {
- x=$(( cmd && echo ja || echo nein ) | tr u x )
+ x=$( ( \cmd && \echo ja || \echo nein ) | \tr u x )
}
inline_TSELECT() {
select file in *; do echo "<$file>" ; break ; done
inline_TSELECT() {
select file in *
do
- echo "<$file>"
- break
+ \echo "<$file>"
+ \break
done
}
function comsub_TSELECT { x=$(
select file in *; do echo "<$file>" ; break ; done
); }
function comsub_TSELECT {
- x=$(select file in * ; do echo "<$file>" ; break ; done )
+ x=$(select file in * ; do \echo "<$file>" ; \break ; done )
}
function reread_TSELECT { x=$((
select file in *; do echo "<$file>" ; break ; done
)|tr u x); }
function reread_TSELECT {
- x=$(( select file in * ; do echo "<$file>" ; break ; done ) | tr u x )
+ x=$( ( select file in * ; do \echo "<$file>" ; \break ; done ) | \tr u x )
}
inline_TFOR_TTIME() {
time for i in {1,2,3} ; do echo $i ; done
inline_TFOR_TTIME() {
time for i in {1,2,3}
do
- echo $i
+ \echo $i
done
}
function comsub_TFOR_TTIME { x=$(
time for i in {1,2,3} ; do echo $i ; done
); }
function comsub_TFOR_TTIME {
- x=$(time for i in {1,2,3} ; do echo $i ; done )
+ x=$(time for i in {1,2,3} ; do \echo $i ; done )
}
function reread_TFOR_TTIME { x=$((
time for i in {1,2,3} ; do echo $i ; done
)|tr u x); }
function reread_TFOR_TTIME {
- x=$(( time for i in {1,2,3} ; do echo $i ; done ) | tr u x )
+ x=$( ( time for i in {1,2,3} ; do \echo $i ; done ) | \tr u x )
}
inline_TCASE() {
case $foo in 1) echo eins;& 2) echo zwei ;| *) echo kann net bis drei zählen;; esac
inline_TCASE() {
case $foo in
(1)
- echo eins
+ \echo eins
;&
(2)
- echo zwei
+ \echo zwei
;|
(*)
- echo kann net bis drei zählen
+ \echo kann net bis drei zählen
;;
esac
}
case $foo in 1) echo eins;& 2) echo zwei ;| *) echo kann net bis drei zählen;; esac
); }
function comsub_TCASE {
- x=$(case $foo in (1) echo eins ;& (2) echo zwei ;| (*) echo kann net bis drei zählen ;; esac )
+ x=$(case $foo in (1) \echo eins ;& (2) \echo zwei ;| (*) \echo kann net bis drei zählen ;; esac )
}
function reread_TCASE { x=$((
case $foo in 1) echo eins;& 2) echo zwei ;| *) echo kann net bis drei zählen;; esac
)|tr u x); }
function reread_TCASE {
- x=$(( case $foo in (1) echo eins ;& (2) echo zwei ;| (*) echo kann net bis drei zählen ;; esac ) | tr u x )
+ x=$( ( case $foo in (1) \echo eins ;& (2) \echo zwei ;| (*) \echo kann net bis drei zählen ;; esac ) | \tr u x )
}
inline_TIF_TBANG_TDBRACKET_TELIF() {
if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi
inline_TIF_TBANG_TDBRACKET_TELIF() {
if ! [[ 1 = 1 ]]
then
- echo eins
+ \echo eins
elif [[ 1 = 2 ]]
then
- echo zwei
+ \echo zwei
else
- echo drei
+ \echo drei
fi
}
function comsub_TIF_TBANG_TDBRACKET_TELIF { x=$(
if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi
); }
function comsub_TIF_TBANG_TDBRACKET_TELIF {
- x=$(if ! [[ 1 = 1 ]] ; then echo eins ; elif [[ 1 = 2 ]] ; then echo zwei ; else echo drei ; fi )
+ x=$(if ! [[ 1 = 1 ]] ; then \echo eins ; elif [[ 1 = 2 ]] ; then \echo zwei ; else \echo drei ; fi )
}
function reread_TIF_TBANG_TDBRACKET_TELIF { x=$((
if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi
)|tr u x); }
function reread_TIF_TBANG_TDBRACKET_TELIF {
- x=$(( if ! [[ 1 = 1 ]] ; then echo eins ; elif [[ 1 = 2 ]] ; then echo zwei ; else echo drei ; fi ) | tr u x )
+ x=$( ( if ! [[ 1 = 1 ]] ; then \echo eins ; elif [[ 1 = 2 ]] ; then \echo zwei ; else \echo drei ; fi ) | \tr u x )
}
inline_TWHILE() {
i=1; while (( i < 10 )); do echo $i; let ++i; done
inline_TWHILE() {
i=1
while {
- \let] " i < 10 "
+ \\builtin let " i < 10 "
}
do
- echo $i
- let ++i
+ \echo $i
+ \let ++i
done
}
function comsub_TWHILE { x=$(
i=1; while (( i < 10 )); do echo $i; let ++i; done
); }
function comsub_TWHILE {
- x=$(i=1 ; while { \let] " i < 10 " ; } ; do echo $i ; let ++i ; done )
+ x=$(i=1 ; while { \\builtin let " i < 10 " ; } ; do \echo $i ; \let ++i ; done )
}
function reread_TWHILE { x=$((
i=1; while (( i < 10 )); do echo $i; let ++i; done
)|tr u x); }
function reread_TWHILE {
- x=$(( i=1 ; while { \let] " i < 10 " ; } ; do echo $i ; let ++i ; done ) | tr u x )
+ x=$( ( i=1 ; while { \\builtin let " i < 10 " ; } ; do \echo $i ; \let ++i ; done ) | \tr u x )
}
inline_TUNTIL() {
i=10; until (( !--i )) ; do echo $i; done
inline_TUNTIL() {
i=10
until {
- \let] " !--i "
+ \\builtin let " !--i "
}
do
- echo $i
+ \echo $i
done
}
function comsub_TUNTIL { x=$(
i=10; until (( !--i )) ; do echo $i; done
); }
function comsub_TUNTIL {
- x=$(i=10 ; until { \let] " !--i " ; } ; do echo $i ; done )
+ x=$(i=10 ; until { \\builtin let " !--i " ; } ; do \echo $i ; done )
}
function reread_TUNTIL { x=$((
i=10; until (( !--i )) ; do echo $i; done
)|tr u x); }
function reread_TUNTIL {
- x=$(( i=10 ; until { \let] " !--i " ; } ; do echo $i ; done ) | tr u x )
+ x=$( ( i=10 ; until { \\builtin let " !--i " ; } ; do \echo $i ; done ) | \tr u x )
}
inline_TCOPROC() {
cat * |& ls
}
inline_TCOPROC() {
- cat * |&
- ls
+ \cat * |&
+ \ls
}
function comsub_TCOPROC { x=$(
cat * |& ls
); }
function comsub_TCOPROC {
- x=$(cat * |& ls )
+ x=$(\cat * |& \ls )
}
function reread_TCOPROC { x=$((
cat * |& ls
)|tr u x); }
function reread_TCOPROC {
- x=$(( cat * |& ls ) | tr u x )
+ x=$( ( \cat * |& \ls ) | \tr u x )
}
inline_TFUNCT_TBRACE_TASYNC() {
function korn { echo eins; echo zwei ; }
}
inline_TFUNCT_TBRACE_TASYNC() {
function korn {
- echo eins
- echo zwei
+ \echo eins
+ \echo zwei
}
bourne() {
- logger * &
+ \logger * &
}
}
function comsub_TFUNCT_TBRACE_TASYNC { x=$(
bourne () { logger * & }
); }
function comsub_TFUNCT_TBRACE_TASYNC {
- x=$(function korn { echo eins ; echo zwei ; } ; bourne() { logger * & } )
+ x=$(function korn { \echo eins ; \echo zwei ; } ; bourne() { \logger * & } )
}
function reread_TFUNCT_TBRACE_TASYNC { x=$((
function korn { echo eins; echo zwei ; }
bourne () { logger * & }
)|tr u x); }
function reread_TFUNCT_TBRACE_TASYNC {
- x=$(( function korn { echo eins ; echo zwei ; } ; bourne() { logger * & } ) | tr u x )
+ x=$( ( function korn { \echo eins ; \echo zwei ; } ; bourne() { \logger * & } ) | \tr u x )
}
inline_IOREAD_IOCAT() {
tr x u 0<foo >>bar
}
inline_IOREAD_IOCAT() {
- tr x u <foo >>bar
+ \tr x u <foo >>bar
}
function comsub_IOREAD_IOCAT { x=$(
tr x u 0<foo >>bar
); }
function comsub_IOREAD_IOCAT {
- x=$(tr x u <foo >>bar )
+ x=$(\tr x u <foo >>bar )
}
function reread_IOREAD_IOCAT { x=$((
tr x u 0<foo >>bar
)|tr u x); }
function reread_IOREAD_IOCAT {
- x=$(( tr x u <foo >>bar ) | tr u x )
+ x=$( ( \tr x u <foo >>bar ) | \tr u x )
}
inline_IOWRITE_IOCLOB_IOHERE_noIOSKIP() {
cat >|bar <<'EOFN'
EOFN
}
inline_IOWRITE_IOCLOB_IOHERE_noIOSKIP() {
- cat >|bar <<"EOFN"
+ \cat >|bar <<"EOFN"
foo
EOFN
EOFN
); }
function comsub_IOWRITE_IOCLOB_IOHERE_noIOSKIP {
- x=$(cat >|bar <<"EOFN"
+ x=$(\cat >|bar <<"EOFN"
foo
EOFN
)
EOFN
)|tr u x); }
function reread_IOWRITE_IOCLOB_IOHERE_noIOSKIP {
- x=$(( cat >|bar <<"EOFN"
+ x=$( ( \cat >|bar <<"EOFN"
foo
EOFN
- ) | tr u x )
+ ) | \tr u x )
}
inline_IOWRITE_noIOCLOB_IOHERE_IOSKIP() {
cat 1>bar <<-EOFI
EOFI
}
inline_IOWRITE_noIOCLOB_IOHERE_IOSKIP() {
- cat >bar <<-EOFI
+ \cat >bar <<-EOFI
foo
EOFI
EOFI
); }
function comsub_IOWRITE_noIOCLOB_IOHERE_IOSKIP {
- x=$(cat >bar <<-EOFI
+ x=$(\cat >bar <<-EOFI
foo
EOFI
)
EOFI
)|tr u x); }
function reread_IOWRITE_noIOCLOB_IOHERE_IOSKIP {
- x=$(( cat >bar <<-EOFI
+ x=$( ( \cat >bar <<-EOFI
foo
EOFI
- ) | tr u x )
+ ) | \tr u x )
}
inline_IORDWR_IODUP() {
sh 1<>/dev/console 0<&1 2>&1
}
inline_IORDWR_IODUP() {
- sh 1<>/dev/console <&1 2>&1
+ \sh 1<>/dev/console <&1 2>&1
}
function comsub_IORDWR_IODUP { x=$(
sh 1<>/dev/console 0<&1 2>&1
); }
function comsub_IORDWR_IODUP {
- x=$(sh 1<>/dev/console <&1 2>&1 )
+ x=$(\sh 1<>/dev/console <&1 2>&1 )
}
function reread_IORDWR_IODUP { x=$((
sh 1<>/dev/console 0<&1 2>&1
)|tr u x); }
function reread_IORDWR_IODUP {
- x=$(( sh 1<>/dev/console <&1 2>&1 ) | tr u x )
+ x=$( ( \sh 1<>/dev/console <&1 2>&1 ) | \tr u x )
}
inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
}
inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
- echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;}
+ \echo $(\true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;}
}
function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$(
echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
); }
function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB {
- x=$(echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} )
+ x=$(\echo $(\true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} )
}
function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$((
echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
)|tr u x); }
function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB {
- x=$(( echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} ) | tr u x )
+ x=$( ( \echo $(\true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} ) | \tr u x )
}
inline_QCHAR_OQUOTE_CQUOTE() {
echo fo\ob\"a\`r\'b\$az
echo 'fo\ob\"a\`r'\''b\$az'
}
inline_QCHAR_OQUOTE_CQUOTE() {
- echo fo\ob\"a\`r\'b\$az
- echo "fo\ob\"a\`r\'b\$az"
- echo "fo\\ob\\\"a\\\`r"\'"b\\\$az"
+ \echo fo\ob\"a\`r\'b\$az
+ \echo "fo\ob\"a\`r\'b\$az"
+ \echo "fo\\ob\\\"a\\\`r"\'"b\\\$az"
}
function comsub_QCHAR_OQUOTE_CQUOTE { x=$(
echo fo\ob\"a\`r\'b\$az
echo 'fo\ob\"a\`r'\''b\$az'
); }
function comsub_QCHAR_OQUOTE_CQUOTE {
- x=$(echo fo\ob\"a\`r\'b\$az ; echo "fo\ob\"a\`r\'b\$az" ; echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" )
+ x=$(\echo fo\ob\"a\`r\'b\$az ; \echo "fo\ob\"a\`r\'b\$az" ; \echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" )
}
function reread_QCHAR_OQUOTE_CQUOTE { x=$((
echo fo\ob\"a\`r\'b\$az
echo 'fo\ob\"a\`r'\''b\$az'
)|tr u x); }
function reread_QCHAR_OQUOTE_CQUOTE {
- x=$(( echo fo\ob\"a\`r\'b\$az ; echo "fo\ob\"a\`r\'b\$az" ; echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" ) | tr u x )
+ x=$( ( \echo fo\ob\"a\`r\'b\$az ; \echo "fo\ob\"a\`r\'b\$az" ; \echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" ) | \tr u x )
}
inline_OSUBST_CSUBST_OPAT_SPAT_CPAT() {
[[ ${foo#bl\(u\)b} = @(bar|baz) ]]
[[ ${foo#bl\(u\)b} = @(bar|baz) ]]
)|tr u x); }
function reread_OSUBST_CSUBST_OPAT_SPAT_CPAT {
- x=$(( [[ ${foo#bl\(u\)b} = @(bar|baz) ]] ) | tr u x )
+ x=$( ( [[ ${foo#bl\(u\)b} = @(bar|baz) ]] ) | \tr u x )
}
inline_heredoc_closed() {
x=$(cat <<EOFN
EOFN); echo $x
}
inline_heredoc_closed() {
- x=$(cat <<EOFN
+ x=$(\cat <<EOFN
note there must be no space between EOFN and )
EOFN
)
- echo $x
+ \echo $x
}
function comsub_heredoc_closed { x=$(
x=$(cat <<EOFN
EOFN); echo $x
); }
function comsub_heredoc_closed {
- x=$(x=$(cat <<EOFN
+ x=$(x=$(\cat <<EOFN
note there must be no space between EOFN and )
EOFN
- ) ; echo $x )
+ ) ; \echo $x )
}
function reread_heredoc_closed { x=$((
x=$(cat <<EOFN
EOFN); echo $x
)|tr u x); }
function reread_heredoc_closed {
- x=$(( x=$(cat <<EOFN
+ x=$( ( x=$(\cat <<EOFN
note there must be no space between EOFN and )
EOFN
- ) ; echo $x ) | tr u x )
+ ) ; \echo $x ) | \tr u x )
}
inline_heredoc_space() {
x=$(cat <<EOFN\
EOFN ); echo $x
}
inline_heredoc_space() {
- x=$(cat <<EOFN\
+ x=$(\cat <<EOFN\
note the space between EOFN and ) is actually part of the here document marker
EOFN
)
- echo $x
+ \echo $x
}
function comsub_heredoc_space { x=$(
x=$(cat <<EOFN\
EOFN ); echo $x
); }
function comsub_heredoc_space {
- x=$(x=$(cat <<EOFN\
+ x=$(x=$(\cat <<EOFN\
note the space between EOFN and ) is actually part of the here document marker
EOFN
- ) ; echo $x )
+ ) ; \echo $x )
}
function reread_heredoc_space { x=$((
x=$(cat <<EOFN\
EOFN ); echo $x
)|tr u x); }
function reread_heredoc_space {
- x=$(( x=$(cat <<EOFN\
+ x=$( ( x=$(\cat <<EOFN\
note the space between EOFN and ) is actually part of the here document marker
EOFN
- ) ; echo $x ) | tr u x )
+ ) ; \echo $x ) | \tr u x )
}
inline_patch_motd() {
x=$(sysctl -n kern.version | sed 1q)
fi
}
inline_patch_motd() {
- x=$(sysctl -n kern.version | sed 1q )
- [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
+ x=$(\sysctl -n kern.version | \sed 1q )
+ [[ -s /etc/motd && "$([[ "$(\head -1 /etc/motd )" != $x ]] && \ed -s /etc/motd 2>&1 <<-EOF
1,/^\$/d
0a
$x
.
wq
EOF
- )" = @(?) ]] && rm -f /etc/motd
+ )" = @(?) ]] && \rm -f /etc/motd
if [[ ! -s /etc/motd ]]
then
- install -c -o root -g wheel -m 664 /dev/null /etc/motd
- print -- "$x\n" >/etc/motd
+ \install -c -o root -g wheel -m 664 /dev/null /etc/motd
+ \print -- "$x\n" >/etc/motd
fi
}
function comsub_patch_motd { x=$(
fi
); }
function comsub_patch_motd {
- x=$(x=$(sysctl -n kern.version | sed 1q ) ; [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
+ x=$(x=$(\sysctl -n kern.version | \sed 1q ) ; [[ -s /etc/motd && "$([[ "$(\head -1 /etc/motd )" != $x ]] && \ed -s /etc/motd 2>&1 <<-EOF
1,/^\$/d
0a
$x
.
wq
EOF
- )" = @(?) ]] && rm -f /etc/motd ; if [[ ! -s /etc/motd ]] ; then install -c -o root -g wheel -m 664 /dev/null /etc/motd ; print -- "$x\n" >/etc/motd ; fi )
+ )" = @(?) ]] && \rm -f /etc/motd ; if [[ ! -s /etc/motd ]] ; then \install -c -o root -g wheel -m 664 /dev/null /etc/motd ; \print -- "$x\n" >/etc/motd ; fi )
}
function reread_patch_motd { x=$((
x=$(sysctl -n kern.version | sed 1q)
fi
)|tr u x); }
function reread_patch_motd {
- x=$(( x=$(sysctl -n kern.version | sed 1q ) ; [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
+ x=$( ( x=$(\sysctl -n kern.version | \sed 1q ) ; [[ -s /etc/motd && "$([[ "$(\head -1 /etc/motd )" != $x ]] && \ed -s /etc/motd 2>&1 <<-EOF
1,/^\$/d
0a
$x
.
wq
EOF
- )" = @(?) ]] && rm -f /etc/motd ; if [[ ! -s /etc/motd ]] ; then install -c -o root -g wheel -m 664 /dev/null /etc/motd ; print -- "$x\n" >/etc/motd ; fi ) | tr u x )
+ )" = @(?) ]] && \rm -f /etc/motd ; if [[ ! -s /etc/motd ]] ; then \install -c -o root -g wheel -m 664 /dev/null /etc/motd ; \print -- "$x\n" >/etc/motd ; fi ) | \tr u x )
}
inline_wdarrassign() {
case x in
case x in
(x)
a+=b
- \set -A c+ -- d e
+ \\builtin set -A c+ -- d e
;;
esac
}
esac
); }
function comsub_wdarrassign {
- x=$(case x in (x) a+=b ; \set -A c+ -- d e ;; esac )
+ x=$(case x in (x) a+=b ; \\builtin set -A c+ -- d e ;; esac )
}
function reread_wdarrassign { x=$((
case x in
esac
)|tr u x); }
function reread_wdarrassign {
- x=$(( case x in (x) a+=b ; \set -A c+ -- d e ;; esac ) | tr u x )
+ x=$( ( case x in (x) a+=b ; \\builtin set -A c+ -- d e ;; esac ) | \tr u x )
}
---
name: comsub-torture-io
vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4" >&3
}
inline_TCOM() {
- vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" >&3
+ vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4" >&3
}
function comsub_TCOM { x=$(
vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4" >&3
); }
function comsub_TCOM {
- x=$(vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" >&3 )
+ x=$(vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4" >&3 )
}
function reread_TCOM { x=$((
vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4" >&3
)|tr u x); }
function reread_TCOM {
- x=$(( vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" >&3 ) | tr u x )
+ x=$( ( vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4" >&3 ) | \tr u x )
}
inline_TPAREN_TPIPE_TLIST() {
(echo $foo | tr -dc 0-9 >&3; echo >&3) >&3
}
inline_TPAREN_TPIPE_TLIST() {
- ( echo $foo | tr -dc 0-9 >&3
- echo >&3 ) >&3
+ ( \echo $foo | \tr -dc 0-9 >&3
+ \echo >&3 ) >&3
}
function comsub_TPAREN_TPIPE_TLIST { x=$(
(echo $foo | tr -dc 0-9 >&3; echo >&3) >&3
); }
function comsub_TPAREN_TPIPE_TLIST {
- x=$(( echo $foo | tr -dc 0-9 >&3 ; echo >&3 ) >&3 )
+ x=$( ( \echo $foo | \tr -dc 0-9 >&3 ; \echo >&3 ) >&3 )
}
function reread_TPAREN_TPIPE_TLIST { x=$((
(echo $foo | tr -dc 0-9 >&3; echo >&3) >&3
)|tr u x); }
function reread_TPAREN_TPIPE_TLIST {
- x=$(( ( echo $foo | tr -dc 0-9 >&3 ; echo >&3 ) >&3 ) | tr u x )
+ x=$( ( ( \echo $foo | \tr -dc 0-9 >&3 ; \echo >&3 ) >&3 ) | \tr u x )
}
inline_TAND_TOR() {
cmd >&3 && >&3 echo ja || echo >&3 nein
}
inline_TAND_TOR() {
- cmd >&3 && echo ja >&3 || echo nein >&3
+ \cmd >&3 && \echo ja >&3 || \echo nein >&3
}
function comsub_TAND_TOR { x=$(
cmd >&3 && >&3 echo ja || echo >&3 nein
); }
function comsub_TAND_TOR {
- x=$(cmd >&3 && echo ja >&3 || echo nein >&3 )
+ x=$(\cmd >&3 && \echo ja >&3 || \echo nein >&3 )
}
function reread_TAND_TOR { x=$((
cmd >&3 && >&3 echo ja || echo >&3 nein
)|tr u x); }
function reread_TAND_TOR {
- x=$(( cmd >&3 && echo ja >&3 || echo nein >&3 ) | tr u x )
+ x=$( ( \cmd >&3 && \echo ja >&3 || \echo nein >&3 ) | \tr u x )
}
inline_TSELECT() {
select file in *; do echo "<$file>" ; break >&3 ; done >&3
inline_TSELECT() {
select file in *
do
- echo "<$file>"
- break >&3
+ \echo "<$file>"
+ \break >&3
done >&3
}
function comsub_TSELECT { x=$(
select file in *; do echo "<$file>" ; break >&3 ; done >&3
); }
function comsub_TSELECT {
- x=$(select file in * ; do echo "<$file>" ; break >&3 ; done >&3 )
+ x=$(select file in * ; do \echo "<$file>" ; \break >&3 ; done >&3 )
}
function reread_TSELECT { x=$((
select file in *; do echo "<$file>" ; break >&3 ; done >&3
)|tr u x); }
function reread_TSELECT {
- x=$(( select file in * ; do echo "<$file>" ; break >&3 ; done >&3 ) | tr u x )
+ x=$( ( select file in * ; do \echo "<$file>" ; \break >&3 ; done >&3 ) | \tr u x )
}
inline_TFOR_TTIME() {
for i in {1,2,3} ; do time >&3 echo $i ; done >&3
inline_TFOR_TTIME() {
for i in {1,2,3}
do
- time echo $i >&3
+ time \echo $i >&3
done >&3
}
function comsub_TFOR_TTIME { x=$(
for i in {1,2,3} ; do time >&3 echo $i ; done >&3
); }
function comsub_TFOR_TTIME {
- x=$(for i in {1,2,3} ; do time echo $i >&3 ; done >&3 )
+ x=$(for i in {1,2,3} ; do time \echo $i >&3 ; done >&3 )
}
function reread_TFOR_TTIME { x=$((
for i in {1,2,3} ; do time >&3 echo $i ; done >&3
)|tr u x); }
function reread_TFOR_TTIME {
- x=$(( for i in {1,2,3} ; do time echo $i >&3 ; done >&3 ) | tr u x )
+ x=$( ( for i in {1,2,3} ; do time \echo $i >&3 ; done >&3 ) | \tr u x )
}
inline_TCASE() {
case $foo in 1) echo eins >&3;& 2) echo zwei >&3 ;| *) echo kann net bis drei zählen >&3;; esac >&3
inline_TCASE() {
case $foo in
(1)
- echo eins >&3
+ \echo eins >&3
;&
(2)
- echo zwei >&3
+ \echo zwei >&3
;|
(*)
- echo kann net bis drei zählen >&3
+ \echo kann net bis drei zählen >&3
;;
esac >&3
}
case $foo in 1) echo eins >&3;& 2) echo zwei >&3 ;| *) echo kann net bis drei zählen >&3;; esac >&3
); }
function comsub_TCASE {
- x=$(case $foo in (1) echo eins >&3 ;& (2) echo zwei >&3 ;| (*) echo kann net bis drei zählen >&3 ;; esac >&3 )
+ x=$(case $foo in (1) \echo eins >&3 ;& (2) \echo zwei >&3 ;| (*) \echo kann net bis drei zählen >&3 ;; esac >&3 )
}
function reread_TCASE { x=$((
case $foo in 1) echo eins >&3;& 2) echo zwei >&3 ;| *) echo kann net bis drei zählen >&3;; esac >&3
)|tr u x); }
function reread_TCASE {
- x=$(( case $foo in (1) echo eins >&3 ;& (2) echo zwei >&3 ;| (*) echo kann net bis drei zählen >&3 ;; esac >&3 ) | tr u x )
+ x=$( ( case $foo in (1) \echo eins >&3 ;& (2) \echo zwei >&3 ;| (*) \echo kann net bis drei zählen >&3 ;; esac >&3 ) | \tr u x )
}
inline_TIF_TBANG_TDBRACKET_TELIF() {
if ! [[ 1 = 1 ]] >&3 ; then echo eins; elif [[ 1 = 2 ]] >&3; then echo zwei ;else echo drei; fi >&3
inline_TIF_TBANG_TDBRACKET_TELIF() {
if ! [[ 1 = 1 ]] >&3
then
- echo eins
+ \echo eins
elif [[ 1 = 2 ]] >&3
then
- echo zwei
+ \echo zwei
else
- echo drei
+ \echo drei
fi >&3
}
function comsub_TIF_TBANG_TDBRACKET_TELIF { x=$(
if ! [[ 1 = 1 ]] >&3 ; then echo eins; elif [[ 1 = 2 ]] >&3; then echo zwei ;else echo drei; fi >&3
); }
function comsub_TIF_TBANG_TDBRACKET_TELIF {
- x=$(if ! [[ 1 = 1 ]] >&3 ; then echo eins ; elif [[ 1 = 2 ]] >&3 ; then echo zwei ; else echo drei ; fi >&3 )
+ x=$(if ! [[ 1 = 1 ]] >&3 ; then \echo eins ; elif [[ 1 = 2 ]] >&3 ; then \echo zwei ; else \echo drei ; fi >&3 )
}
function reread_TIF_TBANG_TDBRACKET_TELIF { x=$((
if ! [[ 1 = 1 ]] >&3 ; then echo eins; elif [[ 1 = 2 ]] >&3; then echo zwei ;else echo drei; fi >&3
)|tr u x); }
function reread_TIF_TBANG_TDBRACKET_TELIF {
- x=$(( if ! [[ 1 = 1 ]] >&3 ; then echo eins ; elif [[ 1 = 2 ]] >&3 ; then echo zwei ; else echo drei ; fi >&3 ) | tr u x )
+ x=$( ( if ! [[ 1 = 1 ]] >&3 ; then \echo eins ; elif [[ 1 = 2 ]] >&3 ; then \echo zwei ; else \echo drei ; fi >&3 ) | \tr u x )
}
inline_TWHILE() {
i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
inline_TWHILE() {
i=1
while {
- \let] " i < 10 "
+ \\builtin let " i < 10 "
} >&3
do
- echo $i
- let ++i
+ \echo $i
+ \let ++i
done >&3
}
function comsub_TWHILE { x=$(
i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
); }
function comsub_TWHILE {
- x=$(i=1 ; while { \let] " i < 10 " ; } >&3 ; do echo $i ; let ++i ; done >&3 )
+ x=$(i=1 ; while { \\builtin let " i < 10 " ; } >&3 ; do \echo $i ; \let ++i ; done >&3 )
}
function reread_TWHILE { x=$((
i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
)|tr u x); }
function reread_TWHILE {
- x=$(( i=1 ; while { \let] " i < 10 " ; } >&3 ; do echo $i ; let ++i ; done >&3 ) | tr u x )
+ x=$( ( i=1 ; while { \\builtin let " i < 10 " ; } >&3 ; do \echo $i ; \let ++i ; done >&3 ) | \tr u x )
}
inline_TUNTIL() {
i=10; until (( !--i )) >&3 ; do echo $i; done >&3
inline_TUNTIL() {
i=10
until {
- \let] " !--i "
+ \\builtin let " !--i "
} >&3
do
- echo $i
+ \echo $i
done >&3
}
function comsub_TUNTIL { x=$(
i=10; until (( !--i )) >&3 ; do echo $i; done >&3
); }
function comsub_TUNTIL {
- x=$(i=10 ; until { \let] " !--i " ; } >&3 ; do echo $i ; done >&3 )
+ x=$(i=10 ; until { \\builtin let " !--i " ; } >&3 ; do \echo $i ; done >&3 )
}
function reread_TUNTIL { x=$((
i=10; until (( !--i )) >&3 ; do echo $i; done >&3
)|tr u x); }
function reread_TUNTIL {
- x=$(( i=10 ; until { \let] " !--i " ; } >&3 ; do echo $i ; done >&3 ) | tr u x )
+ x=$( ( i=10 ; until { \\builtin let " !--i " ; } >&3 ; do \echo $i ; done >&3 ) | \tr u x )
}
inline_TCOPROC() {
cat * >&3 |& >&3 ls
}
inline_TCOPROC() {
- cat * >&3 |&
- ls >&3
+ \cat * >&3 |&
+ \ls >&3
}
function comsub_TCOPROC { x=$(
cat * >&3 |& >&3 ls
); }
function comsub_TCOPROC {
- x=$(cat * >&3 |& ls >&3 )
+ x=$(\cat * >&3 |& \ls >&3 )
}
function reread_TCOPROC { x=$((
cat * >&3 |& >&3 ls
)|tr u x); }
function reread_TCOPROC {
- x=$(( cat * >&3 |& ls >&3 ) | tr u x )
+ x=$( ( \cat * >&3 |& \ls >&3 ) | \tr u x )
}
inline_TFUNCT_TBRACE_TASYNC() {
function korn { echo eins; echo >&3 zwei ; }
}
inline_TFUNCT_TBRACE_TASYNC() {
function korn {
- echo eins
- echo zwei >&3
+ \echo eins
+ \echo zwei >&3
}
bourne() {
- logger * >&3 &
+ \logger * >&3 &
}
}
function comsub_TFUNCT_TBRACE_TASYNC { x=$(
bourne () { logger * >&3 & }
); }
function comsub_TFUNCT_TBRACE_TASYNC {
- x=$(function korn { echo eins ; echo zwei >&3 ; } ; bourne() { logger * >&3 & } )
+ x=$(function korn { \echo eins ; \echo zwei >&3 ; } ; bourne() { \logger * >&3 & } )
}
function reread_TFUNCT_TBRACE_TASYNC { x=$((
function korn { echo eins; echo >&3 zwei ; }
bourne () { logger * >&3 & }
)|tr u x); }
function reread_TFUNCT_TBRACE_TASYNC {
- x=$(( function korn { echo eins ; echo zwei >&3 ; } ; bourne() { logger * >&3 & } ) | tr u x )
+ x=$( ( function korn { \echo eins ; \echo zwei >&3 ; } ; bourne() { \logger * >&3 & } ) | \tr u x )
}
inline_COMSUB_EXPRSUB() {
echo $(true >&3) $((1+ 2))
}
inline_COMSUB_EXPRSUB() {
- echo $(true >&3 ) $((1+ 2))
+ \echo $(\true >&3 ) $((1+ 2))
}
function comsub_COMSUB_EXPRSUB { x=$(
echo $(true >&3) $((1+ 2))
); }
function comsub_COMSUB_EXPRSUB {
- x=$(echo $(true >&3 ) $((1+ 2)) )
+ x=$(\echo $(\true >&3 ) $((1+ 2)) )
}
function reread_COMSUB_EXPRSUB { x=$((
echo $(true >&3) $((1+ 2))
)|tr u x); }
function reread_COMSUB_EXPRSUB {
- x=$(( echo $(true >&3 ) $((1+ 2)) ) | tr u x )
+ x=$( ( \echo $(\true >&3 ) $((1+ 2)) ) | \tr u x )
}
---
name: funsub-1
# $Id$
-# $MirOS: src/bin/mksh/dot.mkshrc,v 1.108 2016/07/26 22:03:41 tg Exp $
+# $MirOS: src/bin/mksh/dot.mkshrc,v 1.114 2017/03/19 22:31:26 tg Exp $
#-
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
-# 2011, 2012, 2013, 2014, 2015, 2016
+# 2011, 2012, 2013, 2014, 2015, 2016, 2017
# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
#-
# ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells
-# catch non-mksh (including lksh) trying to run this file
+# catch non-mksh, non-lksh, trying to run this file
case ${KSH_VERSION:-} in
-*MIRBSD\ KSH*) ;;
-*) return 0 ;;
+*LEGACY\ KSH*|*MIRBSD\ KSH*) ;;
+*) \return 0 ;;
esac
-PS1='#'; (( USER_ID )) && PS1='$'; \: "${TERM:=vt100}${HOSTNAME:=$(\ulimit -c \
- 0; hostname 2>/dev/null)}${EDITOR:=/bin/ed}${USER:=$(\ulimit -c 0; id -un \
- 2>/dev/null || \echo \?)}${MKSH:=$(\builtin whence -p mksh)}"
-HOSTNAME=${HOSTNAME%%*([ ]).*}; HOSTNAME=${HOSTNAME##*([ ])}
-[[ $HOSTNAME = ?(ip6-)localhost?(6) ]] && HOSTNAME=
-\: "${HOSTNAME:=nil}${MKSH:=/bin/mksh}"; \export EDITOR HOSTNAME MKSH TERM USER
-PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
- \typeset e=$?
+# give MidnightBSD's laffer1 a bit of csh feeling
+function setenv {
+ if (( $# )); then
+ \\builtin eval '\\builtin export "$1"="${2:-}"'
+ else
+ \\builtin typeset -x
+ fi
+}
+
+# pager (not control character safe)
+smores() (
+ \\builtin set +m
+ \\builtin cat "$@" |&
+ \\builtin trap "rv=\$?; \\\\builtin kill $! >/dev/null 2>&1; \\\\builtin exit \$rv" EXIT
+ while IFS= \\builtin read -pr line; do
+ llen=${%line}
+ (( llen == -1 )) && llen=${#line}
+ (( llen = llen ? (llen + COLUMNS - 1) / COLUMNS : 1 ))
+ if (( (curlin += llen) >= LINES )); then
+ \\builtin print -nr -- $'\e[7m--more--\e[0m'
+ \\builtin read -u1 || \\builtin exit $?
+ [[ $REPLY = [Qq]* ]] && \\builtin exit 0
+ curlin=$llen
+ fi
+ \\builtin print -r -- "$line"
+ done
+)
+
+\\builtin alias ls=ls l='ls -F' la='l -a' ll='l -l' lo='l -alo'
+\: "${HOSTNAME:=$(\\builtin ulimit -c 0; \\builtin print -r -- $(hostname \
+ 2>/dev/null))}${EDITOR:=/bin/ed}${TERM:=vt100}${USER:=$(\\builtin ulimit \
+ -c 0; id -un 2>/dev/null)}${USER:=?}"
+[[ $HOSTNAME = ?(?(ip6-)localhost?(6)) ]] && HOSTNAME=nil; \\builtin unalias ls
+\\builtin export EDITOR HOSTNAME TERM USER
+
+# minimal support for lksh users
+if [[ $KSH_VERSION = *LEGACY\ KSH* ]]; then
+ PS1='$USER@${HOSTNAME%%.*}:$PWD>'
+ \\builtin return 0
+fi
+
+# mksh-specific from here
+\: "${MKSH:=$(\\builtin whence -p mksh)}${MKSH:=/bin/mksh}"
+\\builtin export MKSH
+
+PS4='[$EPOCHREALTIME] '; PS1='#'; (( USER_ID )) && PS1='$'; PS1=$'\001\r''${|
+ \\builtin typeset e=$?
(( e )) && REPLY+="$e|"
REPLY+=${USER}@${HOSTNAME%%.*}:
- \typeset d=${PWD:-?}/ p=~; [[ $p = ?(*/) ]] || d=${d/#$p\//\~/}
- d=${d%/}; \typeset m=${%d} n p=...; (( m > 0 )) || m=${#d}
+ \\builtin typeset d=${PWD:-?}/ p=~; [[ $p = ?(*/) ]] || d=${d/#$p\//\~/}
+ d=${d%/}; \\builtin typeset m=${%d} n p=...; (( m > 0 )) || m=${#d}
(( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
REPLY+=$p$d
- \return $e
+ \\builtin return $e
} '"$PS1 "
-\alias ls=ls
-\unalias ls
-\alias l='ls -F'
-\alias la='l -a'
-\alias ll='l -l'
-\alias lo='l -alo'
-\alias doch='sudo mksh -c "$(\builtin fc -ln -1)"'
-\command -v rot13 >/dev/null || \alias rot13='tr \
+\\builtin alias doch='sudo mksh -c "$(\\builtin fc -ln -1)"'
+\\builtin command -v rot13 >/dev/null || \\builtin alias rot13='tr \
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
-if \command -v hd >/dev/null; then \:; elif \command -v hexdump >/dev/null; then
+if \\builtin command -v hd >/dev/null; then
+ \:
+elif \\builtin command -v hexdump >/dev/null; then
function hd {
hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \
-e '" |" "%_p"' -e '"|\n"' "$@"
}
else
function hd {
- \typeset -Uui16 -Z11 pos=0
- \typeset -Uui16 -Z5 hv=2147483647
- \typeset dasc line i
- \set +U
+ \\builtin typeset -Uui16 -Z11 pos=0
+ \\builtin typeset -Uui16 -Z5 hv=2147483647
+ \\builtin typeset dasc line i
+ \\builtin set +U
- \cat "$@" | if \read -arN -1 line; then
- \typeset -i1 'line[*]'
+ \\builtin cat "$@" | if \\builtin read -arN -1 line; then
+ \\builtin typeset -i1 'line[*]'
i=0
while (( i < ${#line[*]} )); do
hv=${line[i++]}
if (( (pos & 15) == 0 )); then
(( pos )) && \
- \builtin print -r -- "$dasc|"
- \builtin print -n "${pos#16#} "
+ \\builtin print -r -- "$dasc|"
+ \\builtin print -nr "${pos#16#} "
dasc=' |'
fi
- \builtin print -n "${hv#16#} "
+ \\builtin print -nr "${hv#16#} "
#XXX EBCDIC, but we need [[:print:]] to fix this
if (( (hv < 32) || (hv > 126) )); then
dasc+=.
dasc+=${line[i-1]#1#}
fi
(( (pos++ & 15) == 7 )) && \
- \builtin print -n -- '- '
+ \\builtin print -nr -- '- '
done
while (( pos & 15 )); do
- \builtin print -n ' '
+ \\builtin print -nr ' '
(( (pos++ & 15) == 7 )) && \
- \builtin print -n -- '- '
+ \\builtin print -nr -- '- '
done
- (( hv == 2147483647 )) || \builtin print -r -- "$dasc|"
+ (( hv == 2147483647 )) || \\builtin print -r -- "$dasc|"
fi
}
fi
# Berkeley C shell compatible dirs, popd, and pushd functions
# Z shell compatible chpwd() hook, used to update DIRSTACK[0]
-DIRSTACKBASE=$(\builtin realpath ~/. 2>/dev/null || \
- \builtin print -nr -- "${HOME:-/}")
-set -A DIRSTACK
+DIRSTACKBASE=$(\\builtin realpath ~/. 2>/dev/null || \
+ \\builtin print -nr -- "${HOME:-/}")
+\\builtin set -A DIRSTACK
function chpwd {
- DIRSTACK[0]=$(\builtin realpath . 2>/dev/null || \
- \builtin print -r -- "$PWD")
+ DIRSTACK[0]=$(\\builtin realpath . 2>/dev/null || \
+ \\builtin print -nr -- "$PWD")
[[ $DIRSTACKBASE = ?(*/) ]] || \
DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/\~}
\:
}
\chpwd .
cd() {
- \builtin cd "$@" || \return $?
+ \\builtin cd "$@" || \\builtin return $?
\chpwd "$@"
}
function cd_csh {
- \typeset d t=${1/#\~/$DIRSTACKBASE}
+ \\builtin typeset d t=${1/#\~/$DIRSTACKBASE}
- if ! d=$(\builtin cd "$t" 2>&1); then
- \builtin print -u2 "${1}: ${d##*cd: $t: }."
- \return 1
+ if ! d=$(\\builtin cd "$t" 2>&1); then
+ \\builtin print -ru2 "${1}: ${d##*cd: $t: }."
+ \\builtin return 1
fi
\cd "$t"
}
function dirs {
- \typeset d dwidth
- \typeset -i fl=0 fv=0 fn=0 cpos=0
+ \\builtin typeset d dwidth
+ \\builtin typeset -i fl=0 fv=0 fn=0 cpos=0
- while \getopts ":lvn" d; do
+ while \\builtin getopts ":lvn" d; do
case $d {
(l) fl=1 ;;
(v) fv=1 ;;
(n) fn=1 ;;
- (*) \builtin print -u2 'Usage: dirs [-lvn].'
- \return 1 ;;
+ (*) \\builtin print -ru2 'Usage: dirs [-lvn].'
+ \\builtin return 1 ;;
}
done
- \shift $((OPTIND - 1))
+ \\builtin shift $((OPTIND - 1))
if (( $# > 0 )); then
- \builtin print -u2 'Usage: dirs [-lvn].'
- \return 1
+ \\builtin print -ru2 'Usage: dirs [-lvn].'
+ \\builtin return 1
fi
if (( fv )); then
fv=0
while (( fv < ${#DIRSTACK[*]} )); do
d=${DIRSTACK[fv]}
(( fl )) && d=${d/#\~/$DIRSTACKBASE}
- \builtin print -r -- "$fv $d"
- \builtin let fv++
+ \\builtin print -r -- "$fv $d"
+ (( ++fv ))
done
else
fv=0
(( dwidth = (${%d} > 0 ? ${%d} : ${#d}) ))
if (( fn && (cpos += dwidth + 1) >= 79 && \
dwidth < 80 )); then
- \builtin print
+ \\builtin print
(( cpos = dwidth + 1 ))
fi
- \builtin print -nr -- "$d "
- \builtin let fv++
+ \\builtin print -nr -- "$d "
+ (( ++fv ))
done
- \builtin print
+ \\builtin print
fi
- \return 0
+ \\builtin return 0
}
function popd {
- \typeset d fa
- \typeset -i n=1
+ \\builtin typeset d fa
+ \\builtin typeset -i n=1
- while \getopts ":0123456789lvn" d; do
+ while \\builtin getopts ":0123456789lvn" d; do
case $d {
(l|v|n) fa+=" -$d" ;;
(+*) n=2
- \break ;;
- (*) \builtin print -u2 'Usage: popd [-lvn] [+<n>].'
- \return 1 ;;
+ \\builtin break ;;
+ (*) \\builtin print -ru2 'Usage: popd [-lvn] [+<n>].'
+ \\builtin return 1 ;;
}
done
- \shift $((OPTIND - n))
+ \\builtin shift $((OPTIND - n))
n=0
if (( $# > 1 )); then
- \builtin print -u2 popd: Too many arguments.
- \return 1
+ \\builtin print -ru2 popd: Too many arguments.
+ \\builtin return 1
elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then
if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then
- \builtin print -u2 popd: Directory stack not that deep.
- \return 1
+ \\builtin print -ru2 popd: Directory stack not that deep.
+ \\builtin return 1
fi
elif [[ -n $1 ]]; then
- \builtin print -u2 popd: Bad directory.
- \return 1
+ \\builtin print -ru2 popd: Bad directory.
+ \\builtin return 1
fi
if (( ${#DIRSTACK[*]} < 2 )); then
- \builtin print -u2 popd: Directory stack empty.
- \return 1
+ \\builtin print -ru2 popd: Directory stack empty.
+ \\builtin return 1
fi
- \unset DIRSTACK[n]
- \set -A DIRSTACK -- "${DIRSTACK[@]}"
- \cd_csh "${DIRSTACK[0]}" || \return 1
+ \\builtin unset DIRSTACK[n]
+ \\builtin set -A DIRSTACK -- "${DIRSTACK[@]}"
+ \cd_csh "${DIRSTACK[0]}" || \\builtin return 1
\dirs $fa
}
function pushd {
- \typeset d fa
- \typeset -i n=1
+ \\builtin typeset d fa
+ \\builtin typeset -i n=1
- while \getopts ":0123456789lvn" d; do
+ while \\builtin getopts ":0123456789lvn" d; do
case $d {
(l|v|n) fa+=" -$d" ;;
(+*) n=2
- \break ;;
- (*) \builtin print -u2 'Usage: pushd [-lvn] [<dir>|+<n>].'
- \return 1 ;;
+ \\builtin break ;;
+ (*) \\builtin print -ru2 'Usage: pushd [-lvn] [<dir>|+<n>].'
+ \\builtin return 1 ;;
}
done
- \shift $((OPTIND - n))
+ \\builtin shift $((OPTIND - n))
if (( $# == 0 )); then
if (( ${#DIRSTACK[*]} < 2 )); then
- \builtin print -u2 pushd: No other directory.
- \return 1
+ \\builtin print -ru2 pushd: No other directory.
+ \\builtin return 1
fi
d=${DIRSTACK[1]}
DIRSTACK[1]=${DIRSTACK[0]}
- \cd_csh "$d" || \return 1
+ \cd_csh "$d" || \\builtin return 1
elif (( $# > 1 )); then
- \builtin print -u2 pushd: Too many arguments.
- \return 1
+ \\builtin print -ru2 pushd: Too many arguments.
+ \\builtin return 1
elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then
if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then
- \builtin print -u2 pushd: Directory stack not that deep.
- \return 1
+ \\builtin print -ru2 pushd: Directory stack not that deep.
+ \\builtin return 1
fi
while (( n-- )); do
d=${DIRSTACK[0]}
- \unset DIRSTACK[0]
- \set -A DIRSTACK -- "${DIRSTACK[@]}" "$d"
+ \\builtin unset DIRSTACK[0]
+ \\builtin set -A DIRSTACK -- "${DIRSTACK[@]}" "$d"
done
- \cd_csh "${DIRSTACK[0]}" || \return 1
+ \cd_csh "${DIRSTACK[0]}" || \\builtin return 1
else
- \set -A DIRSTACK -- placeholder "${DIRSTACK[@]}"
- \cd_csh "$1" || \return 1
+ \\builtin set -A DIRSTACK -- placeholder "${DIRSTACK[@]}"
+ \cd_csh "$1" || \\builtin return 1
fi
\dirs $fa
}
-# pager (not control character safe)
-smores() (
- \set +m
- \cat "$@" |&
- \trap "rv=\$?; 'kill' $! >/dev/null 2>&1; 'exit' \$rv" EXIT
- while IFS= \read -pr line; do
- llen=${%line}
- (( llen == -1 )) && llen=${#line}
- (( llen = llen ? (llen + COLUMNS - 1) / COLUMNS : 1 ))
- if (( (curlin += llen) >= LINES )); then
- \builtin print -n -- '\e[7m--more--\e[0m'
- \read -u1 || \exit $?
- [[ $REPLY = [Qq]* ]] && \exit 0
- curlin=$llen
- fi
- \builtin print -r -- "$line"
- done
-)
-
# base64 encoder and decoder, RFC compliant, NUL safe, not EBCDIC safe
function Lb64decode {
- \set +U
- \typeset c s="$*" t
- [[ -n $s ]] || { s=$(\cat; \builtin print x); s=${s%x}; }
- \typeset -i i=0 j=0 n=${#s} p=0 v x
- \typeset -i16 o
+ \\builtin set +U
+ \\builtin typeset c s="$*" t
+ [[ -n $s ]] || { s=$(\\builtin cat; \\builtin print x); s=${s%x}; }
+ \\builtin typeset -i i=0 j=0 n=${#s} p=0 v x
+ \\builtin typeset -i16 o
while (( i < n )); do
c=${s:(i++):1}
case $c {
- (=) \break ;;
+ (=) \\builtin break ;;
([A-Z]) (( v = 1#$c - 65 )) ;;
([a-z]) (( v = 1#$c - 71 )) ;;
([0-9]) (( v = 1#$c + 4 )) ;;
(+) v=62 ;;
(/) v=63 ;;
- (*) \continue ;;
+ (*) \\builtin continue ;;
}
(( x = (x << 6) | v ))
case $((p++)) {
- (0) \continue ;;
+ (0) \\builtin continue ;;
(1) (( o = (x >> 4) & 255 )) ;;
(2) (( o = (x >> 2) & 255 )) ;;
(3) (( o = x & 255 ))
;;
}
t+=\\x${o#16#}
- (( ++j & 4095 )) && \continue
- \builtin print -n $t
+ (( ++j & 4095 )) && \\builtin continue
+ \\builtin print -n $t
t=
done
- \builtin print -n $t
+ \\builtin print -n $t
}
-
-\set -A Lb64encode_tbl -- 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 {
- \set +U
- \typeset c s t
+ \\builtin set +U
+ \\builtin typeset c s t table
+ \\builtin set -A table -- 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 + /
if (( $# )); then
- \read -raN-1 s <<<"$*"
- \unset s[${#s[*]}-1]
+ \\builtin read -raN-1 s <<<"$*"
+ \\builtin unset s[${#s[*]}-1]
else
- \read -raN-1 s
+ \\builtin read -raN-1 s
fi
- \typeset -i i=0 n=${#s[*]} j v
+ \\builtin typeset -i i=0 n=${#s[*]} v
while (( i < n )); do
(( v = s[i++] << 16 ))
- (( j = i < n ? s[i++] : 0 ))
- (( v |= j << 8 ))
- (( j = i < n ? s[i++] : 0 ))
- (( v |= j ))
- t+=${Lb64encode_tbl[v >> 18]}${Lb64encode_tbl[v >> 12 & 63]}
- c=${Lb64encode_tbl[v >> 6 & 63]}
+ (( v |= s[i++] << 8 ))
+ (( v |= s[i++] ))
+ t+=${table[v >> 18]}${table[v >> 12 & 63]}
+ c=${table[v >> 6 & 63]}
if (( i <= n )); then
- t+=$c${Lb64encode_tbl[v & 63]}
+ t+=$c${table[v & 63]}
elif (( i == n + 1 )); then
t+=$c=
else
t+===
fi
if (( ${#t} == 76 || i >= n )); then
- \builtin print $t
+ \\builtin print -r $t
t=
fi
done
}
# Better Avalanche for the Jenkins Hash
-\typeset -Z11 -Uui16 Lbafh_v
+\\builtin typeset -Z11 -Uui16 Lbafh_v
function Lbafh_init {
Lbafh_v=0
}
function Lbafh_add {
- \set +U
- \typeset s
+ \\builtin set +U
+ \\builtin typeset s
if (( $# )); then
- \read -raN-1 s <<<"$*"
- \unset s[${#s[*]}-1]
+ \\builtin read -raN-1 s <<<"$*"
+ \\builtin unset s[${#s[*]}-1]
else
- \read -raN-1 s
+ \\builtin read -raN-1 s
fi
- \typeset -i i=0 n=${#s[*]}
+ \\builtin typeset -i i=0 n=${#s[*]}
while (( i < n )); do
((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 ))
done
}
function Lbafh_finish {
- \typeset -Ui t
+ \\builtin typeset -Ui t
((# t = (((Lbafh_v >> 7) & 0x01010101) * 0x1B) ^ \
((Lbafh_v << 1) & 0xFEFEFEFE) ))
# strip comments (and leading/trailing whitespace if IFS is set) from
# any file(s) given as argument, or stdin if none, and spew to stdout
function Lstripcom {
- \set -o noglob
- \cat "$@" | while \read _line; do
+ \\builtin set -o noglob
+ \\builtin cat "$@" | while \\builtin read _line; do
_line=${_line%%#*}
- [[ -n $_line ]] && \builtin print -r -- $_line
+ [[ -n $_line ]] && \\builtin print -r -- $_line
done
}
-# give MidnightBSD's laffer1 a bit of csh feeling
-function setenv {
- if (( $# )); then
- \eval '\export "$1"="${2:-}"'
- else
- \typeset -x
- fi
-}
-
# toggle built-in aliases and utilities, and aliases and functions from mkshrc
function enable {
- \typeset doprnt=0 mode=1 x y z rv=0
- \typeset b_alias i_alias i_func nalias=0 nfunc=0 i_all
- \set -A b_alias
- \set -A i_alias
- \set -A i_func
+ \\builtin typeset doprnt=0 mode=1 x y z rv=0
+ \\builtin typeset b_alias i_alias i_func nalias=0 nfunc=0 i_all
+ \\builtin set -A b_alias
+ \\builtin set -A i_alias
+ \\builtin set -A i_func
# accumulate mksh built-in aliases, in ASCIIbetical order
- i_alias[nalias]=autoload; b_alias[nalias++]='\typeset -fu'
- i_alias[nalias]=functions; b_alias[nalias++]='\typeset -f'
- i_alias[nalias]=hash; b_alias[nalias++]='\builtin alias -t'
- i_alias[nalias]=history; b_alias[nalias++]='\builtin fc -l'
- i_alias[nalias]=integer; b_alias[nalias++]='\typeset -i'
- i_alias[nalias]=local; b_alias[nalias++]='\typeset'
- i_alias[nalias]=login; b_alias[nalias++]='\exec login'
- i_alias[nalias]=nameref; b_alias[nalias++]='\typeset -n'
+ i_alias[nalias]=autoload; b_alias[nalias++]='\\builtin typeset -fu'
+ i_alias[nalias]=functions; b_alias[nalias++]='\\builtin typeset -f'
+ i_alias[nalias]=hash; b_alias[nalias++]='\\builtin alias -t'
+ i_alias[nalias]=history; b_alias[nalias++]='\\builtin fc -l'
+ i_alias[nalias]=integer; b_alias[nalias++]='\\builtin typeset -i'
+ i_alias[nalias]=local; b_alias[nalias++]='\\builtin typeset'
+ i_alias[nalias]=login; b_alias[nalias++]='\\builtin exec login'
+ i_alias[nalias]=nameref; b_alias[nalias++]='\\builtin typeset -n'
i_alias[nalias]=nohup; b_alias[nalias++]='nohup '
- i_alias[nalias]=r; b_alias[nalias++]='\builtin fc -e -'
- i_alias[nalias]=type; b_alias[nalias++]='\builtin whence -v'
+ i_alias[nalias]=r; b_alias[nalias++]='\\builtin fc -e -'
+ i_alias[nalias]=type; b_alias[nalias++]='\\builtin whence -v'
# accumulate mksh built-in utilities, in definition order, even ifndef
i_func[nfunc++]=.
i_func[nfunc++]='['
i_func[nfunc++]=alias
i_func[nfunc++]=break
+ # \\builtin cannot, by design, be overridden
i_func[nfunc++]=builtin
i_func[nfunc++]=cat
i_func[nfunc++]=cd
i_func[nfunc++]=jobs
i_func[nfunc++]=kill
i_func[nfunc++]=let
- i_func[nfunc++]='let]'
i_func[nfunc++]=print
i_func[nfunc++]=pwd
i_func[nfunc++]=read
i_alias[nalias]=la; b_alias[nalias++]='l -a'
i_alias[nalias]=ll; b_alias[nalias++]='l -l'
i_alias[nalias]=lo; b_alias[nalias++]='l -alo'
- i_alias[nalias]=doch; b_alias[nalias++]='sudo mksh -c "$(\builtin fc -ln -1)"'
+ i_alias[nalias]=doch; b_alias[nalias++]='sudo mksh -c "$(\\builtin fc -ln -1)"'
i_alias[nalias]=rot13; b_alias[nalias++]='tr abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
- i_alias[nalias]=cls; b_alias[nalias++]='\builtin print -n \\ec'
+ i_alias[nalias]=cls; b_alias[nalias++]='\\builtin print -n \\ec'
# accumulate functions from dot.mkshrc, in definition order
+ i_func[nfunc++]=setenv
+ i_func[nfunc++]=smores
i_func[nfunc++]=hd
i_func[nfunc++]=chpwd
i_func[nfunc++]=cd
i_func[nfunc++]=dirs
i_func[nfunc++]=popd
i_func[nfunc++]=pushd
- i_func[nfunc++]=smores
i_func[nfunc++]=Lb64decode
i_func[nfunc++]=Lb64encode
i_func[nfunc++]=Lbafh_init
i_func[nfunc++]=Lbafh_add
i_func[nfunc++]=Lbafh_finish
i_func[nfunc++]=Lstripcom
- i_func[nfunc++]=setenv
i_func[nfunc++]=enable
# collect all identifiers, sorted ASCIIbetically
- \set -sA i_all -- "${i_alias[@]}" "${i_func[@]}"
+ \\builtin set -sA i_all -- "${i_alias[@]}" "${i_func[@]}"
# handle options, we don't do dynamic loading
- while \getopts "adf:nps" x; do
+ while \\builtin getopts "adf:nps" x; do
case $x {
(a)
mode=-1
# deliberately causing an error, like bash-static
;|
(f)
- \builtin print -u2 enable: dynamic loading not available
- \return 2
+ \\builtin print -ru2 enable: dynamic loading not available
+ \\builtin return 2
;;
(n)
mode=0
doprnt=1
;;
(s)
- \set -sA i_all -- . : break continue eval exec exit \
- export readonly return set shift times trap unset
+ \\builtin set -sA i_all -- . : break continue eval \
+ exec exit export readonly return set shift times \
+ trap unset
;;
(*)
- \builtin print -u2 enable: usage: \
+ \\builtin print -ru2 enable: usage: \
"enable [-adnps] [-f filename] [name ...]"
return 2
;;
}
done
- \shift $((OPTIND - 1))
+ \\builtin shift $((OPTIND - 1))
# display builtins enabled/disabled/all/special?
if (( doprnt || ($# == 0) )); then
for x in "${i_all[@]}"; do
- y=$(\alias "$x") || y=
- [[ $y = "$x='\\builtin whence -p $x >/dev/null || (\\builtin print mksh: $x: not found; exit 127) && \$(\\builtin whence -p $x)'" ]]; z=$?
+ y=$(\\builtin alias "$x") || y=
+ [[ $y = "$x='\\\\builtin whence -p $x >/dev/null || (\\\\builtin print -r mksh: $x: not found; \\\\builtin exit 127) && \$(\\\\builtin whence -p $x)'" ]]; z=$?
case $mode:$z {
(-1:0|0:0)
- \print -r -- "enable -n $x"
+ \\builtin print -r -- "enable -n $x"
;;
(-1:1|1:1)
- \print -r -- "enable $x"
+ \\builtin print -r -- "enable $x"
;;
}
done
- \return 0
+ \\builtin return 0
fi
for x in "$@"; do
z=0
for y in "${i_alias[@]}" "${i_func[@]}"; do
- [[ $x = "$y" ]] || \continue
+ [[ $x = "$y" ]] || \\builtin continue
z=1
- \break
+ \\builtin break
done
if (( !z )); then
- \builtin print -ru2 enable: "$x": not a shell builtin
+ \\builtin print -ru2 enable: "$x": not a shell builtin
rv=1
- \continue
+ \\builtin continue
fi
if (( !mode )); then
# disable this
- \alias "$x=\\builtin whence -p $x >/dev/null || (\\builtin print mksh: $x: not found; exit 127) && \$(\\builtin whence -p $x)"
+ \\builtin alias "$x=\\\\builtin whence -p $x >/dev/null || (\\\\builtin print -r mksh: $x: not found; \\\\builtin exit 127) && \$(\\\\builtin whence -p $x)"
else
# find out if this is an alias or not, first
z=0
y=-1
while (( ++y < nalias )); do
- [[ $x = "${i_alias[y]}" ]] || \continue
+ [[ $x = "${i_alias[y]}" ]] || \\builtin continue
z=1
- \break
+ \\builtin break
done
if (( z )); then
# re-enable the original alias body
- \alias "$x=${b_alias[y]}"
+ \\builtin alias "$x=${b_alias[y]}"
else
# re-enable the original utility/function
- \unalias "$x"
+ \\builtin unalias "$x"
fi
fi
done
- \return $rv
+ \\builtin return $rv
}
\: place customisations below this line
for p in ~/.etc/bin ~/bin; do
- [[ -d $p/. ]] || \continue
- #XXX OS/2
- [[ :$PATH: = *:$p:* ]] || PATH=$p:$PATH
+ [[ -d $p/. ]] || \\builtin continue
+ [[ $PATHSEP$PATH$PATHSEP = *"$PATHSEP$p$PATHSEP"* ]] || \
+ PATH=$p$PATHSEP$PATH
done
-\export SHELL=$MKSH MANWIDTH=80 LESSHISTFILE=-
-\alias cls='\builtin print -n \\ec'
+\\builtin export SHELL=$MKSH MANWIDTH=80 LESSHISTFILE=-
+\\builtin alias cls='\\builtin print -n \\ec'
-#\unset LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_IDENTIFICATION LC_MONETARY \
+#\\builtin unset LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_IDENTIFICATION LC_MONETARY \
# LC_NAME LC_NUMERIC LC_TELEPHONE LC_TIME
#p=en_GB.UTF-8
-#\export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
-#\set -U
+#\\builtin export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
+#\\builtin set -U
-\unset p
+\\builtin unset p
\: place customisations above this line
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015, 2016
+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#ifndef MKSH_NO_CMDLINE_EDITING
-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.312 2016/11/11 23:48:28 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.321 2017/04/12 16:46:20 tg Exp $");
/*
* in later versions we might use libtermcap for this, but since external
static int
x_getc(void)
{
+#ifdef __OS2__
+ return (_read_kbd(0, 1, 0));
+#else
char c;
ssize_t n;
x_mode(true);
}
return ((n == 1) ? (int)(unsigned char)c : -1);
+#endif
}
static void
* and if so, discern "~foo/bar" and "~/baz" from "~blah";
* if we have a directory part (the former), try to expand
*/
- if (*s == '~' && (cp = mksh_sdirsep(s)) != NULL) {
+ if (*s == '~' && (cp = /* not sdirsep */ strchr(s, '/')) != NULL) {
/* ok, so split into "~foo"/"bar" or "~"/"baz" */
*cp++ = 0;
/* try to expand the tilde */
}
}
- if (*toglob == '~' && !mksh_vdirsep(toglob)) {
+ if (*toglob == '~' && /* not vdirsep */ !vstrchr(toglob, '/')) {
/* neither for '~foo' (but '~foo/bar') */
*flagsp |= XCF_IS_NOSPACE;
goto dont_add_glob;
static char **x_histp; /* history position */
static int x_nextcmd; /* for newline-and-next */
static char **x_histncp; /* saved x_histp for " */
+static char **x_histmcp; /* saved x_histp for " */
static char *xmp; /* mark pointer */
static unsigned char x_last_command;
static unsigned char (*x_tab)[X_TABSZ]; /* key definition */
x_modified(void)
{
if (!modified) {
+ x_histmcp = x_histp;
x_histp = histptr + 1;
modified = 1;
}
xlp_valid = true;
xmp = NULL;
x_curprefix = 0;
- x_histp = histptr + 1;
+ x_histmcp = x_histp = histptr + 1;
x_last_command = XFUNC_error;
x_init_prompt(true);
static int
x_end_of_text(int c MKSH_A_UNUSED)
{
- unsigned char tmp;
- char *cp = (void *)&tmp;
+ unsigned char tmp[1], *cp = tmp;
- tmp = isedchar(edchars.eof) ? (unsigned char)edchars.eof :
+ *tmp = isedchar(edchars.eof) ? (unsigned char)edchars.eof :
(unsigned char)CTRL('D');
- x_zotc3(&cp);
+ x_zotc3((char **)&cp);
x_putc('\r');
x_putc('\n');
x_flush();
static int
x_nl_next_com(int c MKSH_A_UNUSED)
{
- if (!x_histncp || (x_histp != x_histncp && x_histp != histptr + 1))
+ if (!modified)
+ x_histmcp = x_histp;
+ if (!x_histncp || (x_histmcp != x_histncp && x_histmcp != histptr + 1))
/* fresh start of ^O */
- x_histncp = x_histp;
+ x_histncp = x_histmcp;
x_nextcmd = source->line - (histptr - x_histncp) + 1;
return (x_newline('\n'));
}
offset = -1;
break;
}
- if (p > pat)
- *--p = '\0';
+ if (p > pat) {
+ p = x_bs0(p - 1, pat);
+ *p = '\0';
+ }
if (p == pat)
offset = -1;
else
char *cp2;
width = utf_widthadj(*cp, (const char **)&cp2);
- while (*cp < cp2)
- x_putcf(*(*cp)++);
+ if (cp2 == *cp + 1) {
+ (*cp)++;
+ shf_puts("\xEF\xBF\xBD", shl_out);
+ } else
+ while (*cp < cp2)
+ x_putcf(*(*cp)++);
} else {
(*cp)++;
x_putc(c);
x_ins(cp);
*rcp = ch;
}
+ if (!modified)
+ x_histmcp = x_histp;
modified = m + 1;
return (KSTD);
}
static struct edstate ebuf;
static struct edstate undobuf;
-static struct edstate *es; /* current editor state */
+static struct edstate *vs; /* current Vi editing mode state */
static struct edstate *undo;
static char *ibuf; /* input buffer */
undobuf.linelen = ebuf.linelen = 0;
undobuf.cursor = ebuf.cursor = 0;
undobuf.winleft = ebuf.winleft = 0;
- es = &ebuf;
+ vs = &ebuf;
undo = &undobuf;
x_init_prompt(true);
unwind(LSHELL);
} else if (isched(c, edchars.eof) &&
state != VVERSION) {
- if (es->linelen == 0) {
+ if (vs->linelen == 0) {
x_vi_zotc(c);
c = -1;
break;
x_putc('\n');
x_flush();
- if (c == -1 || (ssize_t)LINE <= es->linelen)
+ if (c == -1 || (ssize_t)LINE <= vs->linelen)
return (-1);
- if (es->cbuf != buf)
- memcpy(buf, es->cbuf, es->linelen);
+ if (vs->cbuf != buf)
+ memcpy(buf, vs->cbuf, vs->linelen);
- buf[es->linelen++] = '\n';
+ buf[vs->linelen++] = '\n';
- return (es->linelen);
+ return (vs->linelen);
}
static int
break;
case 0:
if (state == VLIT) {
- es->cursor--;
+ vs->cursor--;
refresh(0);
} else
refresh(insert != 0);
state = nextstate(ch);
if (state == VSEARCH) {
save_cbuf();
- es->cursor = 0;
- es->linelen = 0;
+ vs->cursor = 0;
+ vs->linelen = 0;
if (putbuf(ch == '/' ? "/" : "?", 1,
false) != 0)
return (-1);
}
if (state == VVERSION) {
save_cbuf();
- es->cursor = 0;
- es->linelen = 0;
+ vs->cursor = 0;
+ vs->linelen = 0;
putbuf(KSH_VERSION,
strlen(KSH_VERSION), false);
refresh(0);
case VLIT:
if (is_bad(ch)) {
- del_range(es->cursor, es->cursor + 1);
+ del_range(vs->cursor, vs->cursor + 1);
vi_error();
} else
- es->cbuf[es->cursor++] = ch;
+ vs->cbuf[vs->cursor++] = ch;
refresh(1);
state = VNORMAL;
break;
} else if (isched(ch, edchars.erase) || ch == CTRL('h')) {
if (srchlen != 0) {
srchlen--;
- es->linelen -= char_len(locpat[srchlen]);
- es->cursor = es->linelen;
+ vs->linelen -= char_len(locpat[srchlen]);
+ vs->cursor = vs->linelen;
refresh(0);
return (0);
}
refresh(0);
} else if (isched(ch, edchars.kill)) {
srchlen = 0;
- es->linelen = 1;
- es->cursor = 1;
+ vs->linelen = 1;
+ vs->cursor = 1;
refresh(0);
return (0);
} else if (isched(ch, edchars.werase)) {
new_es.cursor = srchlen;
new_es.cbuf = locpat;
- save_es = es;
- es = &new_es;
+ save_es = vs;
+ vs = &new_es;
n = backword(1);
- es = save_es;
+ vs = save_es;
i = (unsigned)srchlen;
while (--i >= n)
- es->linelen -= char_len(locpat[i]);
+ vs->linelen -= char_len(locpat[i]);
srchlen = (int)n;
- es->cursor = es->linelen;
+ vs->cursor = vs->linelen;
refresh(0);
return (0);
} else {
else {
locpat[srchlen++] = ch;
if (ISCTRL(ch) && /* but not C1 */ ch < 0x80) {
- if ((size_t)es->linelen + 2 >
- (size_t)es->cbufsize)
+ if ((size_t)vs->linelen + 2 >
+ (size_t)vs->cbufsize)
vi_error();
- es->cbuf[es->linelen++] = '^';
- es->cbuf[es->linelen++] = UNCTRL(ch);
+ vs->cbuf[vs->linelen++] = '^';
+ vs->cbuf[vs->linelen++] = UNCTRL(ch);
} else {
- if (es->linelen >= es->cbufsize)
+ if (vs->linelen >= vs->cbufsize)
vi_error();
- es->cbuf[es->linelen++] = ch;
+ vs->cbuf[vs->linelen++] = ch;
}
- es->cursor = es->linelen;
+ vs->cursor = vs->linelen;
refresh(0);
}
return (0);
switch (ch) {
case 'A':
/* the cursor may not be at the BOL */
- if (!es->cursor)
+ if (!vs->cursor)
break;
/* nor further in the line than we can search for */
- if ((size_t)es->cursor >= sizeof(srchpat) - 1)
- es->cursor = sizeof(srchpat) - 2;
+ if ((size_t)vs->cursor >= sizeof(srchpat) - 1)
+ vs->cursor = sizeof(srchpat) - 2;
/* anchor the search pattern */
srchpat[0] = '^';
/* take the current line up to the cursor */
- memmove(srchpat + 1, es->cbuf, es->cursor);
- srchpat[es->cursor + 1] = '\0';
+ memmove(srchpat + 1, vs->cbuf, vs->cursor);
+ srchpat[vs->cursor + 1] = '\0';
/* set a magic flag */
- argc1 = 2 + (int)es->cursor;
+ argc1 = 2 + (int)vs->cursor;
/* and emulate a backwards history search */
lastsearch = '/';
*curcmd = 'n';
if (isched(ch, edchars.erase) || ch == CTRL('h')) {
if (insert == REPLACE) {
- if (es->cursor == undo->cursor) {
+ if (vs->cursor == undo->cursor) {
vi_error();
return (0);
}
if (inslen > 0)
inslen--;
- es->cursor--;
- if (es->cursor >= undo->linelen)
- es->linelen--;
+ vs->cursor--;
+ if (vs->cursor >= undo->linelen)
+ vs->linelen--;
else
- es->cbuf[es->cursor] = undo->cbuf[es->cursor];
+ vs->cbuf[vs->cursor] = undo->cbuf[vs->cursor];
} else {
- if (es->cursor == 0)
+ if (vs->cursor == 0)
return (0);
if (inslen > 0)
inslen--;
- es->cursor--;
- es->linelen--;
- memmove(&es->cbuf[es->cursor], &es->cbuf[es->cursor + 1],
- es->linelen - es->cursor + 1);
+ vs->cursor--;
+ vs->linelen--;
+ memmove(&vs->cbuf[vs->cursor], &vs->cbuf[vs->cursor + 1],
+ vs->linelen - vs->cursor + 1);
}
expanded = NONE;
return (0);
}
if (isched(ch, edchars.kill)) {
- if (es->cursor != 0) {
+ if (vs->cursor != 0) {
inslen = 0;
- memmove(es->cbuf, &es->cbuf[es->cursor],
- es->linelen - es->cursor);
- es->linelen -= es->cursor;
- es->cursor = 0;
+ memmove(vs->cbuf, &vs->cbuf[vs->cursor],
+ vs->linelen - vs->cursor);
+ vs->linelen -= vs->cursor;
+ vs->cursor = 0;
}
expanded = NONE;
return (0);
}
if (isched(ch, edchars.werase)) {
- if (es->cursor != 0) {
+ if (vs->cursor != 0) {
tcursor = backword(1);
- memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor],
- es->linelen - es->cursor);
- es->linelen -= es->cursor - tcursor;
- if (inslen < es->cursor - tcursor)
+ memmove(&vs->cbuf[tcursor], &vs->cbuf[vs->cursor],
+ vs->linelen - vs->cursor);
+ vs->linelen -= vs->cursor - tcursor;
+ if (inslen < vs->cursor - tcursor)
inslen = 0;
else
- inslen -= es->cursor - tcursor;
- es->cursor = tcursor;
+ inslen -= vs->cursor - tcursor;
+ vs->cursor = tcursor;
}
expanded = NONE;
return (0);
break;
case CTRL('e'):
- print_expansions(es, 0);
+ print_expansions(vs, 0);
break;
case CTRL('i'):
/* end nonstandard vi commands } */
default:
- if (es->linelen >= es->cbufsize - 1)
+ if (vs->linelen >= vs->cbufsize - 1)
return (-1);
ibuf[inslen++] = ch;
if (insert == INSERT) {
- memmove(&es->cbuf[es->cursor + 1], &es->cbuf[es->cursor],
- es->linelen - es->cursor);
- es->linelen++;
+ memmove(&vs->cbuf[vs->cursor + 1], &vs->cbuf[vs->cursor],
+ vs->linelen - vs->cursor);
+ vs->linelen++;
}
- es->cbuf[es->cursor++] = ch;
- if (insert == REPLACE && es->cursor > es->linelen)
- es->linelen++;
+ vs->cbuf[vs->cursor++] = ch;
+ if (insert == REPLACE && vs->cursor > vs->linelen)
+ vs->linelen++;
expanded = NONE;
}
return (0);
if (is_move(*cmd)) {
if ((cur = domove(argcnt, cmd, 0)) >= 0) {
- if (cur == es->linelen && cur != 0)
+ if (cur == vs->linelen && cur != 0)
cur--;
- es->cursor = cur;
+ vs->cursor = cur;
} else
return (-1);
} else {
/* Don't save state in middle of macro.. */
if (is_undoable(*cmd) && !macro.p) {
- undo->winleft = es->winleft;
- memmove(undo->cbuf, es->cbuf, es->linelen);
- undo->linelen = es->linelen;
- undo->cursor = es->cursor;
+ undo->winleft = vs->winleft;
+ memmove(undo->cbuf, vs->cbuf, vs->linelen);
+ undo->linelen = vs->linelen;
+ undo->cursor = vs->cursor;
lastac = argcnt;
memmove(lastcmd, cmd, MAXVICMD);
}
case 'a':
modified = 1;
hnum = hlast;
- if (es->linelen != 0)
- es->cursor++;
+ if (vs->linelen != 0)
+ vs->cursor++;
insert = INSERT;
break;
modified = 1;
hnum = hlast;
del_range(0, 0);
- es->cursor = es->linelen;
+ vs->cursor = vs->linelen;
insert = INSERT;
break;
case 'S':
- es->cursor = domove(1, "^", 1);
- del_range(es->cursor, es->linelen);
+ vs->cursor = domove(1, "^", 1);
+ del_range(vs->cursor, vs->linelen);
modified = 1;
hnum = hlast;
insert = INSERT;
case 'y':
if (*cmd == cmd[1]) {
c1 = *cmd == 'c' ? domove(1, "^", 1) : 0;
- c2 = es->linelen;
+ c2 = vs->linelen;
} else if (!is_move(cmd[1]))
return (-1);
else {
return (-1);
if (*cmd == 'c' &&
(cmd[1] == 'w' || cmd[1] == 'W') &&
- !ksh_isspace(es->cbuf[es->cursor])) {
+ !ksh_isspace(vs->cbuf[vs->cursor])) {
do {
--ncursor;
- } while (ksh_isspace(es->cbuf[ncursor]));
+ } while (ksh_isspace(vs->cbuf[ncursor]));
ncursor++;
}
- if (ncursor > es->cursor) {
- c1 = es->cursor;
+ if (ncursor > vs->cursor) {
+ c1 = vs->cursor;
c2 = ncursor;
} else {
c1 = ncursor;
- c2 = es->cursor;
+ c2 = vs->cursor;
if (cmd[1] == '%')
c2++;
}
yank_range(c1, c2);
if (*cmd != 'y') {
del_range(c1, c2);
- es->cursor = c1;
+ vs->cursor = c1;
}
if (*cmd == 'c') {
modified = 1;
case 'p':
modified = 1;
hnum = hlast;
- if (es->linelen != 0)
- es->cursor++;
+ if (vs->linelen != 0)
+ vs->cursor++;
while (putbuf(ybuf, yanklen, false) == 0 &&
--argcnt > 0)
;
- if (es->cursor != 0)
- es->cursor--;
+ if (vs->cursor != 0)
+ vs->cursor--;
if (argcnt != 0)
return (-1);
break;
while (putbuf(ybuf, yanklen, false) == 0 &&
--argcnt > 0)
any = 1;
- if (any && es->cursor != 0)
- es->cursor--;
+ if (any && vs->cursor != 0)
+ vs->cursor--;
if (argcnt != 0)
return (-1);
break;
case 'C':
modified = 1;
hnum = hlast;
- del_range(es->cursor, es->linelen);
+ del_range(vs->cursor, vs->linelen);
insert = INSERT;
break;
case 'D':
- yank_range(es->cursor, es->linelen);
- del_range(es->cursor, es->linelen);
- if (es->cursor != 0)
- es->cursor--;
+ yank_range(vs->cursor, vs->linelen);
+ del_range(vs->cursor, vs->linelen);
+ if (vs->cursor != 0)
+ vs->cursor--;
break;
case 'g':
case 'I':
modified = 1;
hnum = hlast;
- es->cursor = domove(1, "^", 1);
+ vs->cursor = domove(1, "^", 1);
insert = INSERT;
break;
break;
case 'r':
- if (es->linelen == 0)
+ if (vs->linelen == 0)
return (-1);
modified = 1;
hnum = hlast;
else {
int n;
- if (es->cursor + argcnt > es->linelen)
+ if (vs->cursor + argcnt > vs->linelen)
return (-1);
for (n = 0; n < argcnt; ++n)
- es->cbuf[es->cursor + n] = cmd[1];
- es->cursor += n - 1;
+ vs->cbuf[vs->cursor + n] = cmd[1];
+ vs->cursor += n - 1;
}
break;
break;
case 's':
- if (es->linelen == 0)
+ if (vs->linelen == 0)
return (-1);
modified = 1;
hnum = hlast;
- if (es->cursor + argcnt > es->linelen)
- argcnt = es->linelen - es->cursor;
- del_range(es->cursor, es->cursor + argcnt);
+ if (vs->cursor + argcnt > vs->linelen)
+ argcnt = vs->linelen - vs->cursor;
+ del_range(vs->cursor, vs->cursor + argcnt);
insert = INSERT;
break;
case 'v':
if (!argcnt) {
- if (es->linelen == 0)
+ if (vs->linelen == 0)
return (-1);
if (modified) {
- es->cbuf[es->linelen] = '\0';
- histsave(&source->line, es->cbuf,
+ vs->cbuf[vs->linelen] = '\0';
+ histsave(&source->line, vs->cbuf,
HIST_STORE, true);
} else
argcnt = source->line + 1 -
(hlast - hnum);
}
if (argcnt)
- shf_snprintf(es->cbuf, es->cbufsize, Tf_sd,
+ shf_snprintf(vs->cbuf, vs->cbufsize, Tf_sd,
"fc -e ${VISUAL:-${EDITOR:-vi}} --",
argcnt);
else
- strlcpy(es->cbuf,
+ strlcpy(vs->cbuf,
"fc -e ${VISUAL:-${EDITOR:-vi}} --",
- es->cbufsize);
- es->linelen = strlen(es->cbuf);
+ vs->cbufsize);
+ vs->linelen = strlen(vs->cbuf);
return (2);
case 'x':
- if (es->linelen == 0)
+ if (vs->linelen == 0)
return (-1);
modified = 1;
hnum = hlast;
- if (es->cursor + argcnt > es->linelen)
- argcnt = es->linelen - es->cursor;
- yank_range(es->cursor, es->cursor + argcnt);
- del_range(es->cursor, es->cursor + argcnt);
+ if (vs->cursor + argcnt > vs->linelen)
+ argcnt = vs->linelen - vs->cursor;
+ yank_range(vs->cursor, vs->cursor + argcnt);
+ del_range(vs->cursor, vs->cursor + argcnt);
break;
case 'X':
- if (es->cursor > 0) {
+ if (vs->cursor > 0) {
modified = 1;
hnum = hlast;
- if (es->cursor < argcnt)
- argcnt = es->cursor;
- yank_range(es->cursor - argcnt, es->cursor);
- del_range(es->cursor - argcnt, es->cursor);
- es->cursor -= argcnt;
+ if (vs->cursor < argcnt)
+ argcnt = vs->cursor;
+ yank_range(vs->cursor - argcnt, vs->cursor);
+ del_range(vs->cursor - argcnt, vs->cursor);
+ vs->cursor -= argcnt;
} else
return (-1);
break;
case 'u':
- t = es;
- es = undo;
+ t = vs;
+ vs = undo;
undo = t;
break;
}
if (argcnt >= 2) {
/* flag from cursor-up command */
- es->cursor = argcnt - 2;
+ vs->cursor = argcnt - 2;
return (0);
}
break;
}
modified = 1;
hnum = hlast;
- if (es->cursor != es->linelen)
- es->cursor++;
+ if (vs->cursor != vs->linelen)
+ vs->cursor++;
while (*p && !issp(*p)) {
argcnt++;
p++;
}
if (putbuf(T1space, 1, false) != 0 ||
putbuf(sp, argcnt, false) != 0) {
- if (es->cursor != 0)
- es->cursor--;
+ if (vs->cursor != 0)
+ vs->cursor--;
return (-1);
}
insert = INSERT;
char *p;
int i;
- if (es->linelen == 0)
+ if (vs->linelen == 0)
return (-1);
for (i = 0; i < argcnt; i++) {
- p = &es->cbuf[es->cursor];
+ p = &vs->cbuf[vs->cursor];
if (ksh_islower(*p)) {
modified = 1;
hnum = hlast;
hnum = hlast;
*p = ksh_tolower(*p);
}
- if (es->cursor < es->linelen - 1)
- es->cursor++;
+ if (vs->cursor < vs->linelen - 1)
+ vs->cursor++;
}
break;
}
case '#':
{
- int ret = x_do_comment(es->cbuf, es->cbufsize,
- &es->linelen);
+ int ret = x_do_comment(vs->cbuf, vs->cbufsize,
+ &vs->linelen);
if (ret >= 0)
- es->cursor = 0;
+ vs->cursor = 0;
return (ret);
}
case '=':
/* Nonstandard vi/ksh */
case CTRL('e'):
- print_expansions(es, 1);
+ print_expansions(vs, 1);
break;
case '[':
case 'O':
state = VPREFIX2;
- if (es->linelen != 0)
- es->cursor++;
+ if (vs->linelen != 0)
+ vs->cursor++;
insert = INSERT;
return (0);
}
- if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
- es->cursor--;
+ if (insert == 0 && vs->cursor != 0 && vs->cursor >= vs->linelen)
+ vs->cursor--;
}
return (0);
}
switch (*cmd) {
case 'b':
- if (!sub && es->cursor == 0)
+ if (!sub && vs->cursor == 0)
return (-1);
ncursor = backword(argcnt);
break;
case 'B':
- if (!sub && es->cursor == 0)
+ if (!sub && vs->cursor == 0)
return (-1);
ncursor = Backword(argcnt);
break;
case 'e':
- if (!sub && es->cursor + 1 >= es->linelen)
+ if (!sub && vs->cursor + 1 >= vs->linelen)
return (-1);
ncursor = endword(argcnt);
- if (sub && ncursor < es->linelen)
+ if (sub && ncursor < vs->linelen)
ncursor++;
break;
case 'E':
- if (!sub && es->cursor + 1 >= es->linelen)
+ if (!sub && vs->cursor + 1 >= vs->linelen)
return (-1);
ncursor = Endword(argcnt);
- if (sub && ncursor < es->linelen)
+ if (sub && ncursor < vs->linelen)
ncursor++;
break;
case 'h':
case CTRL('h'):
- if (!sub && es->cursor == 0)
+ if (!sub && vs->cursor == 0)
return (-1);
- ncursor = es->cursor - argcnt;
+ ncursor = vs->cursor - argcnt;
if (ncursor < 0)
ncursor = 0;
break;
case ' ':
case 'l':
- if (!sub && es->cursor + 1 >= es->linelen)
+ if (!sub && vs->cursor + 1 >= vs->linelen)
return (-1);
- if (es->linelen != 0) {
- ncursor = es->cursor + argcnt;
- if (ncursor > es->linelen)
- ncursor = es->linelen;
+ if (vs->linelen != 0) {
+ ncursor = vs->cursor + argcnt;
+ if (ncursor > vs->linelen)
+ ncursor = vs->linelen;
}
break;
case 'w':
- if (!sub && es->cursor + 1 >= es->linelen)
+ if (!sub && vs->cursor + 1 >= vs->linelen)
return (-1);
ncursor = forwword(argcnt);
break;
case 'W':
- if (!sub && es->cursor + 1 >= es->linelen)
+ if (!sub && vs->cursor + 1 >= vs->linelen)
return (-1);
ncursor = Forwword(argcnt);
break;
case '^':
ncursor = 0;
- while (ncursor < es->linelen - 1 &&
- ksh_isspace(es->cbuf[ncursor]))
+ while (ncursor < vs->linelen - 1 &&
+ ksh_isspace(vs->cbuf[ncursor]))
ncursor++;
break;
case '|':
ncursor = argcnt;
- if (ncursor > es->linelen)
- ncursor = es->linelen;
+ if (ncursor > vs->linelen)
+ ncursor = vs->linelen;
if (ncursor)
ncursor--;
break;
case '$':
- if (es->linelen != 0)
- ncursor = es->linelen;
+ if (vs->linelen != 0)
+ ncursor = vs->linelen;
else
ncursor = 0;
break;
case '%':
- ncursor = es->cursor;
- while (ncursor < es->linelen &&
- (i = bracktype(es->cbuf[ncursor])) == 0)
+ ncursor = vs->cursor;
+ while (ncursor < vs->linelen &&
+ (i = bracktype(vs->cbuf[ncursor])) == 0)
ncursor++;
- if (ncursor == es->linelen)
+ if (ncursor == vs->linelen)
return (-1);
bcount = 1;
do {
if (i > 0) {
- if (++ncursor >= es->linelen)
+ if (++ncursor >= vs->linelen)
return (-1);
} else {
if (--ncursor < 0)
return (-1);
}
- t = bracktype(es->cbuf[ncursor]);
+ t = bracktype(vs->cbuf[ncursor]);
if (t == i)
bcount++;
else if (t == -i)
while (count-- > 0)
if (putbuf(ibuf, inslen, tobool(insert == REPLACE)) != 0)
return (-1);
- if (es->cursor > 0)
- es->cursor--;
+ if (vs->cursor > 0)
+ vs->cursor--;
insert = 0;
return (0);
}
{
yanklen = b - a;
if (yanklen != 0)
- memmove(ybuf, &es->cbuf[a], yanklen);
+ memmove(ybuf, &vs->cbuf[a], yanklen);
}
static int
static void
save_cbuf(void)
{
- memmove(holdbufp, es->cbuf, es->linelen);
- holdlen = es->linelen;
+ memmove(holdbufp, vs->cbuf, vs->linelen);
+ holdlen = vs->linelen;
holdbufp[holdlen] = '\0';
}
static void
restore_cbuf(void)
{
- es->cursor = 0;
- es->linelen = holdlen;
- memmove(es->cbuf, holdbufp, holdlen);
+ vs->cursor = 0;
+ vs->linelen = holdlen;
+ memmove(vs->cbuf, holdbufp, holdlen);
}
/* return a new edstate */
if (len == 0)
return (0);
if (repl) {
- if (es->cursor + len >= es->cbufsize)
+ if (vs->cursor + len >= vs->cbufsize)
return (-1);
- if (es->cursor + len > es->linelen)
- es->linelen = es->cursor + len;
+ if (vs->cursor + len > vs->linelen)
+ vs->linelen = vs->cursor + len;
} else {
- if (es->linelen + len >= es->cbufsize)
+ if (vs->linelen + len >= vs->cbufsize)
return (-1);
- memmove(&es->cbuf[es->cursor + len], &es->cbuf[es->cursor],
- es->linelen - es->cursor);
- es->linelen += len;
+ memmove(&vs->cbuf[vs->cursor + len], &vs->cbuf[vs->cursor],
+ vs->linelen - vs->cursor);
+ vs->linelen += len;
}
- memmove(&es->cbuf[es->cursor], buf, len);
- es->cursor += len;
+ memmove(&vs->cbuf[vs->cursor], buf, len);
+ vs->cursor += len;
return (0);
}
static void
del_range(int a, int b)
{
- if (es->linelen != b)
- memmove(&es->cbuf[a], &es->cbuf[b], es->linelen - b);
- es->linelen -= b - a;
+ if (vs->linelen != b)
+ memmove(&vs->cbuf[a], &vs->cbuf[b], vs->linelen - b);
+ vs->linelen -= b - a;
}
static int
{
int ncursor;
- if (es->linelen == 0)
+ if (vs->linelen == 0)
return (-1);
- ncursor = es->cursor;
+ ncursor = vs->cursor;
while (cnt--) {
do {
if (forw) {
- if (++ncursor == es->linelen)
+ if (++ncursor == vs->linelen)
return (-1);
} else {
if (--ncursor < 0)
return (-1);
}
- } while (es->cbuf[ncursor] != ch);
+ } while (vs->cbuf[ncursor] != ch);
}
if (!incl) {
if (forw)
{
int ncursor;
- ncursor = es->cursor;
- while (ncursor < es->linelen && argcnt--) {
- if (ksh_isalnux(es->cbuf[ncursor]))
- while (ncursor < es->linelen &&
- ksh_isalnux(es->cbuf[ncursor]))
+ ncursor = vs->cursor;
+ while (ncursor < vs->linelen && argcnt--) {
+ if (ksh_isalnux(vs->cbuf[ncursor]))
+ while (ncursor < vs->linelen &&
+ ksh_isalnux(vs->cbuf[ncursor]))
ncursor++;
- else if (!ksh_isspace(es->cbuf[ncursor]))
- while (ncursor < es->linelen &&
- !ksh_isalnux(es->cbuf[ncursor]) &&
- !ksh_isspace(es->cbuf[ncursor]))
+ else if (!ksh_isspace(vs->cbuf[ncursor]))
+ while (ncursor < vs->linelen &&
+ !ksh_isalnux(vs->cbuf[ncursor]) &&
+ !ksh_isspace(vs->cbuf[ncursor]))
ncursor++;
- while (ncursor < es->linelen &&
- ksh_isspace(es->cbuf[ncursor]))
+ while (ncursor < vs->linelen &&
+ ksh_isspace(vs->cbuf[ncursor]))
ncursor++;
}
return (ncursor);
{
int ncursor;
- ncursor = es->cursor;
+ ncursor = vs->cursor;
while (ncursor > 0 && argcnt--) {
- while (--ncursor > 0 && ksh_isspace(es->cbuf[ncursor]))
+ while (--ncursor > 0 && ksh_isspace(vs->cbuf[ncursor]))
;
if (ncursor > 0) {
- if (ksh_isalnux(es->cbuf[ncursor]))
+ if (ksh_isalnux(vs->cbuf[ncursor]))
while (--ncursor >= 0 &&
- ksh_isalnux(es->cbuf[ncursor]))
+ ksh_isalnux(vs->cbuf[ncursor]))
;
else
while (--ncursor >= 0 &&
- !ksh_isalnux(es->cbuf[ncursor]) &&
- !ksh_isspace(es->cbuf[ncursor]))
+ !ksh_isalnux(vs->cbuf[ncursor]) &&
+ !ksh_isspace(vs->cbuf[ncursor]))
;
ncursor++;
}
{
int ncursor;
- ncursor = es->cursor;
- while (ncursor < es->linelen && argcnt--) {
- while (++ncursor < es->linelen - 1 &&
- ksh_isspace(es->cbuf[ncursor]))
+ ncursor = vs->cursor;
+ while (ncursor < vs->linelen && argcnt--) {
+ while (++ncursor < vs->linelen - 1 &&
+ ksh_isspace(vs->cbuf[ncursor]))
;
- if (ncursor < es->linelen - 1) {
- if (ksh_isalnux(es->cbuf[ncursor]))
- while (++ncursor < es->linelen &&
- ksh_isalnux(es->cbuf[ncursor]))
+ if (ncursor < vs->linelen - 1) {
+ if (ksh_isalnux(vs->cbuf[ncursor]))
+ while (++ncursor < vs->linelen &&
+ ksh_isalnux(vs->cbuf[ncursor]))
;
else
- while (++ncursor < es->linelen &&
- !ksh_isalnux(es->cbuf[ncursor]) &&
- !ksh_isspace(es->cbuf[ncursor]))
+ while (++ncursor < vs->linelen &&
+ !ksh_isalnux(vs->cbuf[ncursor]) &&
+ !ksh_isspace(vs->cbuf[ncursor]))
;
ncursor--;
}
{
int ncursor;
- ncursor = es->cursor;
- while (ncursor < es->linelen && argcnt--) {
- while (ncursor < es->linelen &&
- !ksh_isspace(es->cbuf[ncursor]))
+ ncursor = vs->cursor;
+ while (ncursor < vs->linelen && argcnt--) {
+ while (ncursor < vs->linelen &&
+ !ksh_isspace(vs->cbuf[ncursor]))
ncursor++;
- while (ncursor < es->linelen &&
- ksh_isspace(es->cbuf[ncursor]))
+ while (ncursor < vs->linelen &&
+ ksh_isspace(vs->cbuf[ncursor]))
ncursor++;
}
return (ncursor);
{
int ncursor;
- ncursor = es->cursor;
+ ncursor = vs->cursor;
while (ncursor > 0 && argcnt--) {
- while (--ncursor >= 0 && ksh_isspace(es->cbuf[ncursor]))
+ while (--ncursor >= 0 && ksh_isspace(vs->cbuf[ncursor]))
;
- while (ncursor >= 0 && !ksh_isspace(es->cbuf[ncursor]))
+ while (ncursor >= 0 && !ksh_isspace(vs->cbuf[ncursor]))
ncursor--;
ncursor++;
}
{
int ncursor;
- ncursor = es->cursor;
- while (ncursor < es->linelen - 1 && argcnt--) {
- while (++ncursor < es->linelen - 1 &&
- ksh_isspace(es->cbuf[ncursor]))
+ ncursor = vs->cursor;
+ while (ncursor < vs->linelen - 1 && argcnt--) {
+ while (++ncursor < vs->linelen - 1 &&
+ ksh_isspace(vs->cbuf[ncursor]))
;
- if (ncursor < es->linelen - 1) {
- while (++ncursor < es->linelen &&
- !ksh_isspace(es->cbuf[ncursor]))
+ if (ncursor < vs->linelen - 1) {
+ while (++ncursor < vs->linelen &&
+ !ksh_isspace(vs->cbuf[ncursor]))
;
ncursor--;
}
}
if (save)
save_cbuf();
- if ((es->linelen = strlen(hptr)) >= es->cbufsize)
- es->linelen = es->cbufsize - 1;
- memmove(es->cbuf, hptr, es->linelen);
- es->cursor = 0;
+ if ((vs->linelen = strlen(hptr)) >= vs->cbufsize)
+ vs->linelen = vs->cbufsize - 1;
+ memmove(vs->cbuf, hptr, vs->linelen);
+ vs->cursor = 0;
ohnum = n;
return (0);
}
save_cbuf();
histnum(hist);
hptr = *histpos();
- if ((es->linelen = strlen(hptr)) >= es->cbufsize)
- es->linelen = es->cbufsize - 1;
- memmove(es->cbuf, hptr, es->linelen);
- es->cursor = 0;
+ if ((vs->linelen = strlen(hptr)) >= vs->cbufsize)
+ vs->linelen = vs->cbufsize - 1;
+ memmove(vs->cbuf, hptr, vs->linelen);
+ vs->cursor = 0;
return (hist);
}
{
int cur, col;
- if (es->cursor < es->winleft)
+ if (vs->cursor < vs->winleft)
return (1);
col = 0;
- cur = es->winleft;
- while (cur < es->cursor)
- col = newcol((unsigned char)es->cbuf[cur++], col);
+ cur = vs->winleft;
+ while (cur < vs->cursor)
+ col = newcol((unsigned char)vs->cbuf[cur++], col);
if (col >= winwidth)
return (1);
return (0);
holdcur1 = holdcur2 = tcur = 0;
holdcol1 = holdcol2 = tcol = 0;
- while (tcur < es->cursor) {
+ while (tcur < vs->cursor) {
if (tcol - holdcol2 > winwidth / 2) {
holdcur1 = holdcur2;
holdcol1 = holdcol2;
holdcur2 = tcur;
holdcol2 = tcol;
}
- tcol = newcol((unsigned char)es->cbuf[tcur++], tcol);
+ tcol = newcol((unsigned char)vs->cbuf[tcur++], tcol);
}
while (tcol - holdcol1 > winwidth / 2)
- holdcol1 = newcol((unsigned char)es->cbuf[holdcur1++],
+ holdcol1 = newcol((unsigned char)vs->cbuf[holdcur1++],
holdcol1);
- es->winleft = holdcur1;
+ vs->winleft = holdcur1;
}
static int
int moreright;
col = 0;
- cur = es->winleft;
+ cur = vs->winleft;
moreright = 0;
twb1 = wb1;
- while (col < winwidth && cur < es->linelen) {
- if (cur == es->cursor && leftside)
+ while (col < winwidth && cur < vs->linelen) {
+ if (cur == vs->cursor && leftside)
ncol = col + pwidth;
- if ((ch = es->cbuf[cur]) == '\t')
+ if ((ch = vs->cbuf[cur]) == '\t')
do {
*twb1++ = ' ';
} while (++col < winwidth && (col & 7) != 0);
col++;
}
}
- if (cur == es->cursor && !leftside)
+ if (cur == vs->cursor && !leftside)
ncol = col + pwidth - 1;
cur++;
}
- if (cur == es->cursor)
+ if (cur == vs->cursor)
ncol = col + pwidth;
if (col < winwidth) {
while (col < winwidth) {
twb2++;
col++;
}
- if (es->winleft > 0 && moreright)
+ if (vs->winleft > 0 && moreright)
/*
* POSIX says to use * for this but that is a globbing
* character and may confuse people; + is more innocuous
*/
mc = '+';
- else if (es->winleft > 0)
+ else if (vs->winleft > 0)
mc = '<';
else if (moreright)
mc = '>';
/* Undo previous expansion */
if (cmd == 0 && expanded == EXPAND && buf) {
- restore_edstate(es, buf);
+ restore_edstate(vs, buf);
buf = 0;
expanded = NONE;
return (0);
}
i = XCF_COMMAND_FILE | XCF_FULLPATH;
- nwords = x_cf_glob(&i, es->cbuf, es->linelen, es->cursor,
+ nwords = x_cf_glob(&i, vs->cbuf, vs->linelen, vs->cursor,
&start, &end, &words);
if (nwords == 0) {
vi_error();
return (-1);
}
- buf = save_edstate(es);
+ buf = save_edstate(vs);
expanded = EXPAND;
del_range(start, end);
- es->cursor = start;
+ vs->cursor = start;
i = 0;
while (i < nwords) {
if (x_escape(words[i], strlen(words[i]), x_vi_putbuf) != 0) {
}
i = buf->cursor - end;
if (rval == 0 && i > 0)
- es->cursor += i;
+ vs->cursor += i;
modified = 1;
hnum = hlast;
insert = INSERT;
return (0);
}
if (cmd == 0 && expanded == PRINT && buf) {
- restore_edstate(es, buf);
+ restore_edstate(vs, buf);
buf = 0;
expanded = NONE;
return (0);
flags = XCF_COMMAND_FILE;
if (count)
flags |= XCF_FULLPATH;
- nwords = x_cf_glob(&flags, es->cbuf, es->linelen, es->cursor,
+ nwords = x_cf_glob(&flags, vs->cbuf, vs->linelen, vs->cursor,
&start, &end, &words);
if (nwords == 0) {
vi_error();
is_unique = nwords == 1;
}
- buf = save_edstate(es);
+ buf = save_edstate(vs);
del_range(start, end);
- es->cursor = start;
+ vs->cursor = start;
/*
* escape all shell-sensitive characters and put the result into
if (!kshsetjmp(e->jbuf)) {
char *wds = alloc(len + 3, ATEMP);
- wds[0] = FUNSUB;
+ wds[0] = FUNASUB;
memcpy(wds + 1, cmd, len);
wds[len + 1] = '\0';
wds[len + 2] = EOS;
cp = evalstr(wds, DOSCALAR);
+ afree(wds, ATEMP);
strdupx(cp, cp, AEDIT);
} else
cp = NULL;
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015, 2016
+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.194 2016/11/11 23:31:34 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.201 2017/04/06 01:59:54 tg Exp $");
/*
* string expansion
word = IFS_WORD;
quote = st->quotew;
continue;
+ case COMASUB:
case COMSUB:
+ case FUNASUB:
case FUNSUB:
case VALSUB:
tilde_ok = 0;
if (f & DONTRUNCOMMAND) {
word = IFS_WORD;
*dp++ = '$';
- *dp++ = c == COMSUB ? '(' : '{';
- if (c != COMSUB)
- *dp++ = c == FUNSUB ? ' ' : '|';
+ switch (c) {
+ case COMASUB:
+ case COMSUB:
+ *dp++ = '(';
+ c = ')';
+ break;
+ case FUNASUB:
+ case FUNSUB:
+ case VALSUB:
+ *dp++ = '{';
+ *dp++ = c == VALSUB ? '|' : ' ';
+ c = '}';
+ break;
+ }
while (*sp != '\0') {
Xcheck(ds, dp);
*dp++ = *sp++;
}
- if (c != COMSUB) {
+ if (c == '}')
*dp++ = ';';
- *dp++ = '}';
- } else
- *dp++ = ')';
+ *dp++ = c;
} else {
type = comsub(&x, sp, c);
if (type != XBASE && (f & DOBLANK))
break;
case '=':
/*
- * Enabling tilde expansion
- * after :s here is
- * non-standard ksh, but is
- * consistent with rules for
- * other assignments. Not
- * sure what POSIX thinks of
- * this.
+ * Tilde expansion for string
+ * variables in POSIX mode is
+ * governed by Austinbug 351.
+ * In non-POSIX mode historic
+ * ksh behaviour (enable it!)
+ * us followed.
* Not doing tilde expansion
* for integer variables is a
* non-POSIX thing - makes
*/
if (!(x.var->flag & INTEGER))
f |= DOASNTILDE | DOTILDE;
- f |= DOTEMP;
+ f |= DOTEMP | DOSCALAR;
/*
* These will be done after the
* value has been assigned.
c = '\n';
--newlines;
} else {
- while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
+ while ((c = shf_getc(x.u.shf)) == 0 ||
+#ifdef MKSH_WITH_TEXTMODE
+ c == '\r' ||
+#endif
+ c == '\n') {
+#ifdef MKSH_WITH_TEXTMODE
+ if (c == '\r') {
+ c = shf_getc(x.u.shf);
+ switch (c) {
+ case '\n':
+ break;
+ default:
+ shf_ungetc(c, x.u.shf);
+ /* FALLTHROUGH */
+ case -1:
+ c = '\r';
+ break;
+ }
+ }
+#endif
if (c == '\n')
/* save newlines */
newlines++;
+ }
if (newlines && c != -1) {
shf_ungetc(c, x.u.shf);
c = '\n';
} else if (ctype(c, C_SUBOP1)) {
slen += 2;
stype |= c;
- } else if (ctype(c, C_SUBOP2)) {
+ } else if (ksh_issubop2(c)) {
/* Note: ksh88 allows :%, :%%, etc */
slen += 2;
stype = c;
}
} else if (c == '@') {
/* @x where x is command char */
- slen += 2;
- stype |= 0x100;
- if (word[slen] == CHAR) {
- stype |= word[slen + 1];
- slen += 2;
+ switch (c = word[slen + 2] == CHAR ? word[slen + 3] : 0) {
+ case '#':
+ case '/':
+ case 'Q':
+ break;
+ default:
+ return (-1);
}
+ stype |= 0x100 | c;
+ slen += 4;
} else if (stype)
/* : is not ok */
return (-1);
c = stype & 0x7F;
/* test the compiler's code generator */
- if (((stype < 0x100) && (ctype(c, C_SUBOP2) ||
+ if (((stype < 0x100) && (ksh_issubop2(c) ||
(((stype & 0x80) ? *xp->str == '\0' : xp->str == null) &&
(state != XARG || (ifs0 || xp->split ?
(xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ?
/* expand word instead of variable value */
state = XBASE;
if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
- (ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
+ (ksh_issubop2(c) || (state != XBASE && c != '+')))
errorf(Tf_parm, sp);
*stypep = stype;
*slenp = slen;
* Run the command in $(...) and read its output.
*/
static int
-comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
+comsub(Expand *xp, const char *cp, int fn)
{
Source *s, *sold;
struct op *t;
struct shf *shf;
+ bool doalias = false;
uint8_t old_utfmode = UTFMODE;
+ switch (fn) {
+ case COMASUB:
+ fn = COMSUB;
+ if (0)
+ /* FALLTHROUGH */
+ case FUNASUB:
+ fn = FUNSUB;
+ doalias = true;
+ }
+
s = pushs(SSTRING, ATEMP);
s->start = s->str = cp;
sold = source;
- t = compile(s, true);
+ t = compile(s, true, doalias);
afree(s, ATEMP);
source = sold;
Xinit(ts, tp, 16, ATEMP);
/* : only for DOASNTILDE form */
- while (p[0] == CHAR && !mksh_cdirsep(p[1]) &&
+ while (p[0] == CHAR && /* not cdirsep */ p[1] != '/' &&
(!isassign || p[1] != ':')) {
Xcheck(ts, tp);
*tp++ = p[1];
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015, 2016
+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.186 2016/11/11 23:31:34 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.196 2017/04/12 16:46:21 tg Exp $");
#ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
if (t->right == NULL)
/* should be error */
break;
- rv = execute(t->left, XERROK, NULL) == 0 ?
- execute(t->right->left, flags & XERROK, xerrok) :
- execute(t->right->right, flags & XERROK, xerrok);
+ rv = execute(execute(t->left, XERROK, NULL) == 0 ?
+ t->right->left : t->right->right, flags & XERROK, xerrok);
break;
case TCASE:
/* NOTREACHED */
default:
quitenv(NULL);
- internal_errorf(Tf_sd, "CFUNC", i);
+ internal_errorf(Tunexpected_type, Tunwind, Tfunction, i);
}
break;
}
unsigned short m;
ssize_t n;
+#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
+ setmode(fd, O_TEXT);
+#endif
/* read first couple of octets from file */
n = read(fd, buf, sizeof(buf) - 1);
close(fd);
if (*cp)
*tp->args-- = (char *)cp;
}
+#ifdef __OS2__
+ /*
+ * Search shell/interpreter name without directory in PATH
+ * if specified path does not exist
+ */
+ if (mksh_vdirsep(sh) && !search_path(sh, path, X_OK, NULL)) {
+ cp = search_path(_getname(sh), path, X_OK, NULL);
+ if (cp)
+ sh = cp;
+ }
+#endif
goto nomagic;
noshebang:
m = buf[0] << 8 | buf[1];
buf[4] == 'Z') || (m == /* 7zip */ 0x377A) ||
(m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D))
errorf("%s: not executable: magic %04X", tp->str, m);
+#ifdef __OS2__
+ cp = _getext(tp->str);
+ if (cp && (!stricmp(cp, ".cmd") || !stricmp(cp, ".bat"))) {
+ /* execute .cmd and .bat with OS2_SHELL, usually CMD.EXE */
+ sh = str_val(global("OS2_SHELL"));
+ *tp->args-- = "/c";
+ /* convert slahes to backslashes */
+ for (cp = tp->str; *cp; cp++) {
+ if (*cp == '/')
+ *cp = '\\';
+ }
+ }
+#endif
nomagic:
;
}
errorf(Tf_sD_sD_s, tp->str, sh, cstrerror(errno));
}
+/* actual 'builtin' built-in utility call is handled in comexec() */
int
-shcomexec(const char **wp)
+c_builtin(const char **wp)
{
- struct tbl *tp;
+ return (call_builtin(get_builtin(*wp), wp, Tbuiltin, false));
+}
- tp = ktsearch(&builtins, *wp, hash(*wp));
- return (call_builtin(tp, wp, "shcomexec", false));
+struct tbl *
+get_builtin(const char *s)
+{
+ return (s && *s ? ktsearch(&builtins, s, hash(s)) : NULL);
}
/*
/* external utility overrides built-in utility, with flags */
flag |= LOW_BI;
break;
+ case '-':
+ /* is declaration utility if argv[1] is one (POSIX: command) */
+ flag |= DECL_FWDR;
+ break;
+ case '^':
+ /* is declaration utility (POSIX: export, readonly) */
+ flag |= DECL_UTIL;
+ break;
default:
goto flags_seen;
}
char *fpath;
union mksh_cchack npath;
- if (mksh_vdirsep(name)) {
+ if (mksh_vdirsep(name)
+#ifdef MKSH_DOSPATH
+ && (strcmp(name, T_builtin) != 0)
+#endif
+ ) {
insert = 0;
/* prevent FPATH search below */
flags &= ~FC_FUNC;
}
#ifdef __OS2__
/* treat all files as executable on OS/2 */
- sb.st_mode &= S_IXUSR | S_IXGRP | S_IXOTH;
+ sb.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
#endif
if (mode == X_OK && (!S_ISREG(sb.st_mode) ||
!(sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
return (0);
}
+#ifdef __OS2__
+/* check if path is something we want to find, adding executable extensions */
+#define search_access(fn, mode) access_ex((search_access), (fn), (mode))
+#else
+#define search_access(fn, mode) (search_access)((fn), (mode))
+#endif
+
/*
* search for command with PATH
*/
search_path_ok:
if (errnop)
*errnop = 0;
+#ifndef __OS2__
return (name);
+#else
+ return (real_exec_name(name));
+#endif
}
goto search_path_err;
}
XcheckN(xs, xp, p - sp);
memcpy(xp, sp, p - sp);
xp += p - sp;
+#ifdef __OS2__
+ if (xp > Xstring(xs, xp) && mksh_cdirsep(xp[-1]))
+ xp--;
+#endif
*xp++ = '/';
}
sp = p;
if (!tp)
internal_errorf(Tf_sD_s, where, wp[0]);
builtin_argv0 = wp[0];
- builtin_spec = tobool(!resetspec &&
- /*XXX odd use of KEEPASN */
- ((tp->flag & SPEC_BI) || (Flag(FPOSIX) && (tp->flag & KEEPASN))));
+ 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);
/* herein() may already have printed message */
if (u == -1) {
u = errno;
- warningf(true, Tf_cant,
+ warningf(true, Tf_cant_ss_s,
+#if 0
+ /* can't happen */
iotype == IODUP ? "dup" :
+#endif
(iotype == IOREAD || iotype == IOHERE) ?
Topen : Tcreate, cp, cstrerror(u));
}
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2016
+ * 2011, 2012, 2013, 2014, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.90 2016/11/07 16:58:48 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.93 2017/04/02 16:47:41 tg Exp $");
#define EXPRTOK_DEFNS
#include "exprtok.h"
case ET_BADLIT:
warningf(true, Tf_sD_s_qs, es->expression,
- "bad number", str);
+ Tbadnum, str);
break;
case ET_RECURSIVE:
if (c == '\0')
es->tok = END;
else if (ksh_isalphx(c)) {
- for (; ksh_isalnux(c); c = *cp)
- cp++;
+ do {
+ c = *++cp;
+ } while (ksh_isalnux(c));
if (c == '[') {
size_t len;
int
ksh_access(const char *fn, int mode)
{
+#ifdef __OS2__
+ return (access_ex(access, fn, mode));
+#else
int rv;
struct stat sb;
rv = -1;
return (rv);
+#endif
}
#ifndef MIRBSD_BOOTFLOPPY
/*-
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- * 2010, 2011, 2012, 2013, 2014, 2015, 2016
+ * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#endif
#endif
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.319 2016/11/11 23:48:29 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.340 2017/04/12 17:46:29 tg Exp $");
#if HAVE_KILLPG
/*
int rv;
if (!(rv = getn(as, ai)))
- bi_errorf(Tf_sD_s, as, "bad number");
+ bi_errorf(Tf_sD_s, Tbadnum, as);
return (rv);
}
/*
* A leading = means assignments before command are kept.
* A leading * means a POSIX special builtin.
+ * A leading ^ means declaration utility, - forwarder.
*/
const struct builtin mkshbuiltins[] = {
{Tsgdot, c_dot},
{Tbracket, c_test},
/* no =: AT&T manual wrong */
{Talias, c_alias},
- {"*=break", c_brkcont},
- {Tgbuiltin, c_builtin},
+ {Tsgbreak, c_brkcont},
+ {T__builtin, c_builtin},
+ {Tbuiltin, c_builtin},
#if !defined(__ANDROID__)
{Tbcat, c_cat},
#endif
{Tcd, c_cd},
/* dash compatibility hack */
{"chdir", c_cd},
- {Tcommand, c_command},
- {"*=continue", c_brkcont},
+ {T_command, c_command},
+ {Tsgcontinue, c_brkcont},
{"echo", c_print},
{"*=eval", c_eval},
{"*=exec", c_exec},
{"*=exit", c_exitreturn},
- {Tsgexport, c_typeset},
+ {Tdsgexport, c_typeset},
{Tfalse, c_false},
{"fc", c_fc},
{Tgetopts, c_getopts},
- {"=global", c_typeset},
+ /* deprecated, replaced by typeset -g */
+ {"^=global", c_typeset},
{Tjobs, c_jobs},
{"kill", c_kill},
{"let", c_let},
- {"let]", c_let},
{"print", c_print},
{"pwd", c_pwd},
{Tread, c_read},
- {Tsgreadonly, c_typeset},
+ {Tdsgreadonly, c_typeset},
#if !defined(__ANDROID__)
{"!realpath", c_realpath},
#endif
{"*=return", c_exitreturn},
{Tsgset, c_set},
{"*=shift", c_shift},
- {"=source", c_dot},
+ {Tgsource, c_dot},
#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
{Tsuspend, c_suspend},
#endif
{"*=times", c_times},
{"*=trap", c_trap},
{Ttrue, c_true},
- {Tgtypeset, c_typeset},
+ {Tdgtypeset, c_typeset},
{"ulimit", c_ulimit},
{"umask", c_umask},
{Tunalias, c_unalias},
{"*=unset", c_unset},
- {"=wait", c_wait},
+ {"wait", c_wait},
{"whence", c_whence},
#ifndef MKSH_UNEMPLOYED
{Tbg, c_fgbg},
{"-f", TO_FILREG },
{"-G", TO_FILGID },
{"-g", TO_FILSETG },
- {"-h", TO_FILSYM },
{"-H", TO_FILCDF },
+ {"-h", TO_FILSYM },
{"-k", TO_FILSTCK },
{"-L", TO_FILSYM },
{"-n", TO_STNZE },
{"-o", TO_OPTION },
{"-p", TO_FILFIFO },
{"-r", TO_FILRD },
- {"-s", TO_FILGZ },
{"-S", TO_FILSOCK },
+ {"-s", TO_FILGZ },
{"-t", TO_FILTT },
{"-u", TO_FILSETU },
+ {"-v", TO_ISSET },
{"-w", TO_FILWR },
{"-x", TO_FILEX },
{"-z", TO_STZER },
bool hist;
/* print words as wide characters? */
bool chars;
- /* print a "--" argument? */
- bool pminusminus;
/* writing to a coprocess (SIGPIPE blocked)? */
bool coproc;
bool copipe;
po.ws = ' ';
po.ls = '\n';
po.nl = true;
- po.exp = true;
if (wp[0][0] == 'e') {
/* "echo" builtin */
- ++wp;
-#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
- if (Flag(FSH)) {
- /*
- * MidnightBSD /bin/sh needs a BSD echo, that is,
- * one that supports -e but does not enable it by
- * default
- */
- po.exp = false;
- }
-#endif
if (Flag(FPOSIX) ||
#ifndef MKSH_MIDNIGHTBSD01ASH_COMPAT
Flag(FSH) ||
#endif
Flag(FAS_BUILTIN)) {
- /* Debian Policy 10.4 compliant "echo" builtin */
+ /* BSD "echo" cmd, Debian Policy 10.4 compliant */
+ ++wp;
+ bsd_echo:
if (*wp && !strcmp(*wp, "-n")) {
- /* recognise "-n" only as the first arg */
po.nl = false;
++wp;
}
- /* print everything as-is */
po.exp = false;
} else {
- bool new_exp = po.exp, new_nl = po.nl;
-
- /**
- * a compromise between sysV and BSD echo commands:
- * escape sequences are enabled by default, and -n,
- * -e and -E are recognised if they appear in argu-
- * ments with no illegal options (ie, echo -nq will
- * print -nq).
- * Different from sysV echo since options are reco-
- * gnised, different from BSD echo since escape se-
- * quences are enabled by default.
+ bool new_exp, new_nl = true;
+
+ /*-
+ * compromise between various historic echos: only
+ * recognise -Een if they appear in arguments with
+ * no illegal options; e.g. echo -nq outputs '-nq'
*/
+#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
+ /* MidnightBSD /bin/sh needs -e supported but off */
+ if (Flag(FSH))
+ new_exp = false;
+ else
+#endif
+ /* otherwise compromise on -e enabled by default */
+ new_exp = true;
+ goto print_tradparse_beg;
print_tradparse_arg:
if ((s = *wp) && *s++ == '-' && *s) {
new_nl = false;
goto print_tradparse_ch;
case '\0':
+ print_tradparse_beg:
po.exp = new_exp;
po.nl = new_nl;
++wp;
}
} else {
/* "print" builtin */
- const char *opts = "AclNnpRrsu,";
+ const char *opts = "AcelNnpRrsu,";
const char *emsg;
- po.pminusminus = false;
+ po.exp = true;
while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1)
switch (c) {
}
break;
case 'R':
- /* fake BSD echo command */
- po.pminusminus = true;
- po.exp = false;
- opts = "en";
- break;
+ /* fake BSD echo but don't reset other flags */
+ wp += builtin_opt.optind;
+ goto bsd_echo;
case 'r':
po.exp = false;
break;
if (wp[builtin_opt.optind] &&
ksh_isdash(wp[builtin_opt.optind]))
builtin_opt.optind++;
- } else if (po.pminusminus)
- builtin_opt.optind--;
+ }
wp += builtin_opt.optind;
}
break;
#ifndef MKSH_SMALL
default:
- bi_errorf("%s is of unknown type %d", id, tp->type);
+ bi_errorf(Tunexpected_type, id, Tcommand, tp->type);
return (1);
#endif
}
return (rv);
}
-/* typeset, global, export, and readonly */
-static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool);
-static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool,
- bool);
-int
-c_typeset(const char **wp)
-{
- struct tbl *vp, **p;
- uint32_t fset = 0, fclr = 0, flag;
- int thing = 0, field = 0, base = 0, i;
- struct block *l;
- const char *opts;
- const char *fieldstr = NULL, *basestr = NULL;
- bool localv = false, func = false, pflag = false, istset = true;
- enum namerefflag new_refflag = SRF_NOP;
-
- switch (**wp) {
-
- /* export */
- case 'e':
- fset |= EXPORT;
- istset = false;
- break;
-
- /* readonly */
- case 'r':
- fset |= RDONLY;
- istset = false;
- break;
-
- /* set */
- case 's':
- /* called with 'typeset -' */
- break;
-
- /* typeset */
- case 't':
- localv = true;
- break;
- }
-
- /* see comment below regarding possible opions */
- opts = istset ? "L#R#UZ#afi#lnprtux" : "p";
-
- builtin_opt.flags |= GF_PLUSOPT;
- /*
- * AT&T ksh seems to have 0-9 as options which are multiplied
- * to get a number that is used with -L, -R, -Z or -i (eg, -1R2
- * sets right justify in a field of 12). This allows options
- * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and
- * does not allow the number to be specified as a separate argument
- * Here, the number must follow the RLZi option, but is optional
- * (see the # kludge in ksh_getopt()).
- */
- while ((i = ksh_getopt(wp, &builtin_opt, opts)) != -1) {
- flag = 0;
- switch (i) {
- case 'L':
- flag = LJUST;
- fieldstr = builtin_opt.optarg;
- break;
- case 'R':
- flag = RJUST;
- fieldstr = builtin_opt.optarg;
- break;
- case 'U':
- /*
- * AT&T ksh uses u, but this conflicts with
- * upper/lower case. If this option is changed,
- * need to change the -U below as well
- */
- flag = INT_U;
- break;
- case 'Z':
- flag = ZEROFIL;
- fieldstr = builtin_opt.optarg;
- break;
- case 'a':
- /*
- * this is supposed to set (-a) or unset (+a) the
- * indexed array attribute; it does nothing on an
- * existing regular string or indexed array though
- */
- break;
- case 'f':
- func = true;
- break;
- case 'i':
- flag = INTEGER;
- basestr = builtin_opt.optarg;
- break;
- case 'l':
- flag = LCASEV;
- break;
- case 'n':
- new_refflag = (builtin_opt.info & GI_PLUS) ?
- SRF_DISABLE : SRF_ENABLE;
- break;
- /* export, readonly: POSIX -p flag */
- case 'p':
- /* typeset: show values as well */
- pflag = true;
- if (istset)
- continue;
- break;
- case 'r':
- flag = RDONLY;
- break;
- case 't':
- flag = TRACE;
- break;
- case 'u':
- /* upper case / autoload */
- flag = UCASEV_AL;
- break;
- case 'x':
- flag = EXPORT;
- break;
- case '?':
- return (1);
- }
- if (builtin_opt.info & GI_PLUS) {
- fclr |= flag;
- fset &= ~flag;
- thing = '+';
- } else {
- fset |= flag;
- fclr &= ~flag;
- thing = '-';
- }
- }
-
- if (fieldstr && !bi_getn(fieldstr, &field))
- return (1);
- if (basestr) {
- if (!getn(basestr, &base)) {
- bi_errorf(Tf_sD_s, "bad integer base", basestr);
- return (1);
- }
- if (base < 1 || base > 36)
- base = 10;
- }
-
- if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] &&
- (wp[builtin_opt.optind][0] == '-' ||
- wp[builtin_opt.optind][0] == '+') &&
- wp[builtin_opt.optind][1] == '\0') {
- thing = wp[builtin_opt.optind][0];
- builtin_opt.optind++;
- }
-
- if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) ||
- new_refflag != SRF_NOP)) {
- bi_errorf("only -t, -u and -x options may be used with -f");
- return (1);
- }
- if (wp[builtin_opt.optind]) {
- /*
- * Take care of exclusions.
- * At this point, flags in fset are cleared in fclr and vice
- * versa. This property should be preserved.
- */
- if (fset & LCASEV)
- /* LCASEV has priority over UCASEV_AL */
- fset &= ~UCASEV_AL;
- if (fset & LJUST)
- /* LJUST has priority over RJUST */
- fset &= ~RJUST;
- if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) {
- /* -Z implies -ZR */
- fset |= RJUST;
- fclr &= ~RJUST;
- }
- /*
- * Setting these attributes clears the others, unless they
- * are also set in this command
- */
- if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV |
- INTEGER | INT_U | INT_L)) || new_refflag != SRF_NOP)
- fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL |
- LCASEV | INTEGER | INT_U | INT_L);
- }
- if (new_refflag != SRF_NOP) {
- fclr &= ~(ARRAY | ASSOC);
- fset &= ~(ARRAY | ASSOC);
- fclr |= EXPORT;
- fset |= ASSOC;
- if (new_refflag == SRF_DISABLE)
- fclr |= ASSOC;
- }
-
- /* set variables and attributes */
- if (wp[builtin_opt.optind] &&
- /* not "typeset -p varname" */
- !(!func && pflag && !(fset | fclr))) {
- int rv = 0;
- struct tbl *f;
-
- if (localv && !func)
- fset |= LOCAL;
- for (i = builtin_opt.optind; wp[i]; i++) {
- if (func) {
- f = findfunc(wp[i], hash(wp[i]),
- tobool(fset & UCASEV_AL));
- if (!f) {
- /* AT&T ksh does ++rv: bogus */
- rv = 1;
- continue;
- }
- if (fset | fclr) {
- f->flag |= fset;
- f->flag &= ~fclr;
- } else {
- fpFUNCTf(shl_stdout, 0,
- tobool(f->flag & FKSH),
- wp[i], f->val.t);
- shf_putc('\n', shl_stdout);
- }
- } else if (!typeset(wp[i], fset, fclr, field, base)) {
- bi_errorf(Tf_sD_s, wp[i], Tnot_ident);
- return (1);
- }
- }
- return (rv);
- }
-
- /* list variables and attributes */
-
- /* no difference at this point.. */
- flag = fset | fclr;
- if (func) {
- for (l = e->loc; l; l = l->next) {
- for (p = ktsort(&l->funs); (vp = *p++); ) {
- if (flag && (vp->flag & flag) == 0)
- continue;
- if (thing == '-')
- fpFUNCTf(shl_stdout, 0,
- tobool(vp->flag & FKSH),
- vp->name, vp->val.t);
- else
- shf_puts(vp->name, shl_stdout);
- shf_putc('\n', shl_stdout);
- }
- }
- } else if (wp[builtin_opt.optind]) {
- for (i = builtin_opt.optind; wp[i]; i++) {
- varsearch(e->loc, &vp, wp[i], hash(wp[i]));
- c_typeset_vardump(vp, flag, thing, pflag, istset);
- }
- } else
- c_typeset_vardump_recursive(e->loc, flag, thing, pflag, istset);
- return (0);
-}
-
-static void
-c_typeset_vardump_recursive(struct block *l, uint32_t flag, int thing,
- bool pflag, bool istset)
+bool
+valid_alias_name(const char *cp)
{
- struct tbl **blockvars, *vp;
-
- if (l->next)
- c_typeset_vardump_recursive(l->next, flag, thing, pflag, istset);
- blockvars = ktsort(&l->vars);
- while ((vp = *blockvars++))
- c_typeset_vardump(vp, flag, thing, pflag, istset);
- /*XXX doesn’t this leak? */
-}
-
-static void
-c_typeset_vardump(struct tbl *vp, uint32_t flag, int thing, bool pflag,
- bool istset)
-{
- struct tbl *tvp;
- int any_set = 0;
- char *s;
-
- if (!vp)
- return;
-
- /*
- * See if the parameter is set (for arrays, if any
- * element is set).
- */
- for (tvp = vp; tvp; tvp = tvp->u.array)
- if (tvp->flag & ISSET) {
- any_set = 1;
- break;
- }
-
- /*
- * Check attributes - note that all array elements
- * have (should have?) the same attributes, so checking
- * the first is sufficient.
- *
- * Report an unset param only if the user has
- * explicitly given it some attribute (like export);
- * otherwise, after "echo $FOO", we would report FOO...
- */
- if (!any_set && !(vp->flag & USERATTRIB))
- return;
- if (flag && (vp->flag & flag) == 0)
- return;
- if (!(vp->flag & ARRAY))
- /* optimise later conditionals */
- any_set = 0;
- do {
- /*
- * Ignore array elements that aren't set unless there
- * are no set elements, in which case the first is
- * reported on
- */
- if (any_set && !(vp->flag & ISSET))
- continue;
- /* no arguments */
- if (!thing && !flag) {
- if (any_set == 1) {
- shprintf(Tf_s_s_sN, Tset, "-A", vp->name);
- any_set = 2;
- }
- /*
- * AT&T ksh prints things like export, integer,
- * leftadj, zerofill, etc., but POSIX says must
- * be suitable for re-entry...
- */
- shprintf(Tf_s_s, Ttypeset, "");
- if (((vp->flag & (ARRAY | ASSOC)) == ASSOC))
- shprintf(Tf__c_, 'n');
- if ((vp->flag & INTEGER))
- shprintf(Tf__c_, 'i');
- if ((vp->flag & EXPORT))
- shprintf(Tf__c_, 'x');
- if ((vp->flag & RDONLY))
- shprintf(Tf__c_, 'r');
- if ((vp->flag & TRACE))
- shprintf(Tf__c_, 't');
- if ((vp->flag & LJUST))
- shprintf("-L%d ", vp->u2.field);
- if ((vp->flag & RJUST))
- shprintf("-R%d ", vp->u2.field);
- if ((vp->flag & ZEROFIL))
- shprintf(Tf__c_, 'Z');
- if ((vp->flag & LCASEV))
- shprintf(Tf__c_, 'l');
- if ((vp->flag & UCASEV_AL))
- shprintf(Tf__c_, 'u');
- if ((vp->flag & INT_U))
- shprintf(Tf__c_, 'U');
- } else if (pflag) {
- shprintf(Tf_s_s, istset ? Ttypeset :
- (flag & EXPORT) ? Texport : Treadonly, "");
- }
- if (any_set)
- shprintf("%s[%lu]", vp->name, arrayindex(vp));
+ while (*cp)
+ if (!ksh_isalias(*cp))
+ return (false);
else
- shf_puts(vp->name, shl_stdout);
- if ((!thing && !flag && pflag) ||
- (thing == '-' && (vp->flag & ISSET))) {
- s = str_val(vp);
- shf_putc('=', shl_stdout);
- /* AT&T ksh can't have justified integers... */
- if ((vp->flag & (INTEGER | LJUST | RJUST)) == INTEGER)
- shf_puts(s, shl_stdout);
- else
- print_value_quoted(shl_stdout, s);
- }
- shf_putc('\n', shl_stdout);
-
- /*
- * Only report first 'element' of an array with
- * no set elements.
- */
- if (!any_set)
- return;
- } while ((vp = vp->u.array));
+ ++cp;
+ return (true);
}
int
strndupx(xalias, alias, val++ - alias, ATEMP);
alias = xalias;
}
+ if (!valid_alias_name(alias) || *alias == '-') {
+ bi_errorf(Tinvname, alias, Talias);
+ afree(xalias, ATEMP);
+ return (1);
+ }
h = hash(alias);
if (val == NULL && !tflag && !xflag) {
ap = ktsearch(t, alias, h);
if (user_opt.optarg == NULL)
unset(voptarg, 1);
else
- /* This can't fail (have cleared readonly/integer) */
+ /* this can't fail (haing cleared readonly/integer) */
setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR);
rv = 0;
/* nothing to do */
return (0);
} else if (n < 0) {
- bi_errorf(Tf_sD_s, arg, "bad number");
+ bi_errorf(Tf_sD_s, Tbadnum, arg);
return (1);
}
if (l->argc < n) {
++cp;
}
if (*cp) {
- bi_errorf("bad number");
+ bi_errorf(Tbadnum);
return (1);
}
} else {
#else
#define c_read_opts "Aad:N:n:prsu,"
#endif
+#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
+ int saved_mode;
+ int saved_errno;
+#endif
while ((c = ksh_getopt(wp, &builtin_opt, c_read_opts)) != -1)
switch (c) {
}
#endif
+#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
+ saved_mode = setmode(fd, O_TEXT);
+#endif
if ((bytesread = blocking_read(fd, xp, bytesleft)) == (size_t)-1) {
+#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
+ saved_errno = errno;
+ setmode(fd, saved_mode);
+ errno = saved_errno;
+#endif
if (errno == EINTR) {
/* check whether the signal would normally kill */
if (!fatal_trap_check()) {
rv = 2;
goto c_read_out;
}
+#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
+ setmode(fd, saved_mode);
+#endif
switch (readmode) {
case READALL:
return (1);
s = pushs(SWORDS, ATEMP);
s->u.strv = wp + builtin_opt.optind;
+ s->line = current_lineno;
/*-
* The following code handles the case where the command is
savef = Flag(FERREXIT);
Flag(FERREXIT) |= 0x80;
- rv = shell(s, false);
+ rv = shell(s, 2);
Flag(FERREXIT) = savef;
source = saves;
afree(s, ATEMP);
* scripts, but don't generate an error (ie, keep going).
*/
if ((unsigned int)n == quit) {
- warningf(true, "%s: can't %s", wp[0], wp[0]);
+ warningf(true, Tf_cant_s, wp[0], wp[0]);
return (0);
}
/*
for (i = 0; i < NUFILE; i++) {
if (e->savefd[i] > 0)
close(e->savefd[i]);
-#ifndef MKSH_LEGACY_MODE
/*
* keep all file descriptors > 2 private for ksh,
* but not for POSIX or legacy/kludge sh
if (!Flag(FPOSIX) && !Flag(FSH) && i > 2 &&
e->savefd[i])
fcntl(i, F_SETFD, FD_CLOEXEC);
-#endif
}
e->savefd = NULL;
}
return (0);
}
-#if HAVE_MKNOD
+#if HAVE_MKNOD && !defined(__OS2__)
int
c_mknod(const char **wp)
{
| "(" oexpr ")"
;
- unary-operator ::= "-a"|"-r"|"-w"|"-x"|"-e"|"-f"|"-d"|"-c"|"-b"|"-p"|
- "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|
- "-L"|"-h"|"-S"|"-H";
+ unary-operator ::= "-a"|"-b"|"-c"|"-d"|"-e"|"-f"|"-G"|"-g"|"-H"|"-h"|
+ "-k"|"-L"|"-n"|"-O"|"-o"|"-p"|"-r"|"-S"|"-s"|"-t"|
+ "-u"|"-v"|"-w"|"-x"|"-z";
+
+ binary-operator ::= "="|"=="|"!="|"<"|">"|"-eq"|"-ne"|"-gt"|"-ge"|
+ "-lt"|"-le"|"-ef"|"-nt"|"-ot";
- binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
- "-nt"|"-ot"|"-ef"|
- "<"|">" # rules used for [[ ... ]] expressions
- ;
operand ::= <anything>
*/
return (TO_NONOP);
}
+#ifdef __OS2__
+#define test_access(name, mode) access_ex(access, (name), (mode))
+#define test_stat(name, buffer) stat_ex((name), (buffer))
+#else
+#define test_access(name, mode) access((name), (mode))
+#define test_stat(name, buffer) stat((name), (buffer))
+#endif
+
int
test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
bool do_eval)
size_t k;
struct stat b1, b2;
mksh_ari_t v1, v2;
+ struct tbl *vp;
if (!do_eval)
return (0);
case TO_STZER:
return (*opnd1 == '\0');
+ /* -v */
+ case TO_ISSET:
+ return ((vp = isglobal(opnd1, false)) && (vp->flag & ISSET));
+
/* -o */
case TO_OPTION:
if ((i = *opnd1) == '!' || i == '?')
/* -r */
case TO_FILRD:
/* LINTED use of access */
- return (access(opnd1, R_OK) == 0);
+ return (test_access(opnd1, R_OK) == 0);
/* -w */
case TO_FILWR:
/* LINTED use of access */
- return (access(opnd1, W_OK) == 0);
+ return (test_access(opnd1, W_OK) == 0);
/* -x */
case TO_FILEX:
case TO_FILAXST:
/* -e */
case TO_FILEXST:
- return (stat(opnd1, &b1) == 0);
+ return (test_stat(opnd1, &b1) == 0);
- /* -r */
+ /* -f */
case TO_FILREG:
- return (stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode));
+ return (test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode));
/* -d */
case TO_FILID:
* Binary Operators
*/
- /* = */
+ /* =, == */
case TO_STEQL:
if (te->flags & TEF_DBRACKET) {
if ((i = gmatchx(opnd1, opnd2, false)))
if (!all)
print_ulimit(rlimits[i], how);
else for (i = 0; i < NELEM(rlimits); ++i) {
- shprintf("%-20s ", rlimits[i]->name);
+ shprintf("-%c: %-20s ", rlimits[i]->optchar, rlimits[i]->name);
print_ulimit(rlimits[i], how);
}
return (0);
#include <sys/file.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.159 2016/11/11 18:44:32 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.160 2017/04/08 01:07:16 tg Exp $");
Trap sigtraps[ksh_NSIG + 1];
static struct sigaction Sigact_ign;
goto retry;
}
if (hs != hist_init_retry)
- bi_errorf(Tf_cant,
+ bi_errorf(Tf_cant_ss_s,
"unlink HISTFILE", hname, cstrerror(errno));
histfsize = 0;
return;
if (!strcmp(sigtraps[i].name, "EXIT") ||
!strcmp(sigtraps[i].name, "ERR")) {
#ifndef MKSH_SMALL
- internal_warningf("ignoring invalid signal name %s",
- sigtraps[i].name);
+ internal_warningf(Tinvname, sigtraps[i].name,
+ "signal");
#endif
sigtraps[i].name = null;
}
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015, 2016
+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.228 2016/08/01 21:38:03 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.234 2017/04/06 01:59:55 tg Exp $");
/*
* states while lexing word
* If this is a trim operation,
* treat (,|,) specially in STBRACE.
*/
- if (ctype(c, C_SUBOP2)) {
+ if (ksh_issubop2(c)) {
ungetsc(c);
if (Flag(FSH))
PUSH_STATE(STBRACEBOURNE);
case '`':
subst_gravis:
PUSH_STATE(SBQUOTE);
- *wp++ = COMSUB;
+ *wp++ = COMASUB;
/*
* We need to know whether we are within double
* quotes in order to translate \" to " within
Xcheck(ws, wp);
if (statep != &states[1])
/* XXX figure out what is missing */
- yyerror("no closing quote\n");
+ yyerror("no closing quote");
/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
if (state == SHEREDELIM)
dp = Xstring(ws, wp);
if (state == SBASE && (
-#ifndef MKSH_LEGACY_MODE
(c == '&' && !Flag(FSH) && !Flag(FPOSIX)) ||
-#endif
c == '<' || c == '>') && ((c2 = Xlength(ws, wp)) == 0 ||
(c2 == 2 && dp[0] == CHAR && ksh_isdigit(dp[1])))) {
struct ioword *iop = alloc(sizeof(struct ioword), ATEMP);
while ((dp - ident) < IDENT && (c = *sp++) == CHAR)
*dp++ = *sp++;
if (c != EOS)
- /* word is not unquoted */
+ /* word is not unquoted, or space ran out */
dp = ident;
/* make sure the ident array stays NUL padded */
memset(dp, 0, (ident + IDENT) - dp + 1);
- if (!(cf & (KEYWORD | ALIAS)))
- return (LWORD);
-
- if (*ident != '\0') {
+ if (*ident != '\0' && (cf & (KEYWORD | ALIAS))) {
struct tbl *p;
uint32_t h = hash(ident);
s->start = s->str = p->val.s;
s->u.tblp = p;
s->flags |= SF_HASALIAS;
+ s->line = source->line;
s->next = source;
if (source->type == SEOF) {
/* prevent infinite recursion at EOS */
goto Again;
}
}
- } else if (cf & ALIAS) {
+ } else if (*ident == '\0') {
/* retain typeset et al. even when quoted */
- if (assign_command((dp = wdstrip(yylval.cp, 0)), true))
+ struct tbl *tt = get_builtin((dp = wdstrip(yylval.cp, 0)));
+ uint32_t flag = tt ? tt->flag : 0;
+
+ if (flag & (DECL_UTIL | DECL_FWDR))
strlcpy(ident, dp, sizeof(ident));
afree(dp, ATEMP);
}
error_prefix(true);
va_start(va, fmt);
shf_vfprintf(shl_out, fmt, va);
+ shf_putc('\n', shl_out);
va_end(va);
errorfz();
}
char *tmp, *p;
if (!arraysub(&tmp))
- yyerror("missing ]\n");
+ yyerror("missing ]");
*wp++ = c;
for (p = tmp; *p; ) {
Xcheck(*wsp, wp);
-.\" $MirOS: src/bin/mksh/lksh.1,v 1.20 2016/11/11 23:31:35 tg Exp $
+.\" $MirOS: src/bin/mksh/lksh.1,v 1.23 2017/04/02 13:38:02 tg Exp $
.\"-
-.\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016
+.\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016, 2017
.\" mirabilos <m@mirbsd.org>
.\"
.\" Provided that these terms and disclaimer and all copyright notices
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
-.Dd $Mdocdate: November 11 2016 $
+.Dd $Mdocdate: April 2 2017 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
refer to its manual page for details on the scripting language.
It is recommended to port scripts to
.Nm mksh
-instead of relying on legacy or idiotic POSIX-mandated behaviour,
+instead of relying on legacy or objectionable POSIX-mandated behaviour,
since the MirBSD Korn Shell scripting language is much more consistent.
.Pp
+Do not use
+.Nm
+as an interactive or login shell; use
+.Nm mksh
+instead.
+.Pp
Note that it's strongly recommended to invoke
.Nm
-with at least the
+with
.Fl o Ic posix
-option, if not both that
-.Em and Fl o Ic sh ,
to fully enjoy better compatibility to the
.Tn POSIX
standard (which is probably why you use
.Nm
over
.Nm mksh
-in the first place) or legacy scripts, respectively.
+in the first place);
+.Fl o Ic sh
+(possibly additionally to the above) may be needed for some legacy scripts.
.Sh LEGACY MODE
.Nm
currently has the following differences from
.Nm mksh :
.Bl -bullet
.It
-.\"XXX TODO: remove (some systems may wish to have lksh as ksh)
-There is no explicit support for interactive use,
-nor any command line editing or history code.
-Hence,
-.Nm
-is not suitable as a user's login shell, either; use
-.Nm mksh
-instead.
-.It
The
.Ev KSH_VERSION
string identifies
The compiler is permitted to delete all data and crash the system
if Undefined Behaviour occurs (see above for an example).
.It
-.\"XXX TODO: move this to FPOSIX
The rotation arithmetic operators are not available.
.It
The shift arithmetic operators take all bits of the second operand into
account; if they exceed permitted precision, the result is unspecified.
.It
-.\"XXX TODO: move this to FPOSIX
-The
-.Tn GNU
-.Nm bash
-extension &\*(Gt to redirect stdout and stderr in one go is not parsed.
-.It
-.\"XXX TODO: drop along with allowing interactivity
-The
-.Nm mksh
-command line option
-.Fl T
-is not available.
-.It
Unless
.Ic set -o posix
is active,
.Xr getopt 1
command.
.It
-.\"XXX TODO: move to FPOSIX/FSH
-Unlike
-.At
-.Nm ksh ,
-.Nm mksh
-in
-.Fl o Ic posix
-or
-.Fl o Ic sh
-mode and
-.Nm lksh
-do not keep file descriptors \*(Gt 2 private from sub-processes.
-.It
Functions defined with the
.Ic function
reserved word share the shell options
.Sh SEE ALSO
.Xr mksh 1
.Pp
-.Pa https://www.mirbsd.org/mksh.htm
+.Pa http://www.mirbsd.org/mksh.htm
.Pp
-.Pa https://www.mirbsd.org/ksh\-chan.htm
+.Pa http://www.mirbsd.org/ksh\-chan.htm
.Sh CAVEATS
-The distinction between the shell variants
-.Pq Nm lksh / Nm mksh
-and shell flags
-.Pq Fl o Ic posix / Ic sh
-will be reworked for an upcoming release.
-.Pp
To use
.Nm
as
.Ic set -o posix
by default if called as
.Nm sh
+.Pq adding Dv \-DMKSH_BINSHPOSIX to Dv CPPFLAGS
is highly recommended for better standards compliance.
+.Pp
For better compatibility with legacy scripts, such as many
.Tn Debian
maintainer scripts, Upstart and SYSV init scripts, and other
-unfixed scripts, using the compile-time options for enabling
+unfixed scripts, also adding the
+.Dv \-DMKSH_BINSHREDUCED
+compile-time option to enable
.Em both
.Ic set -o posix -o sh
when the shell is run as
-.Nm sh
-is recommended.
+.Nm sh ,
+as well as integrating the optional disrecommended
+.Xr printf 1
+builtin, might be necessary.
.Pp
.Nm
tries to make a cross between a legacy bourne/posix compatibl-ish
.Dq legacy
is not exactly specified.
.Pp
-The
-.Ic set
-built-in command does not currently have all options one would expect
-from a full-blown
-.Nm mksh
-or
-.Nm pdksh .
-.Pp
Talk to the
.Mx
development team using the mailing list at
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015, 2016
+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include <locale.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.322 2016/11/11 23:48:30 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.332 2017/04/12 16:01:45 tg Exp $");
extern char **environ;
static void x_sigwinch(int);
#endif
-static const char initifs[] = "IFS= \t\n";
-
static const char initsubs[] =
"${PS2=> }"
"${PS3=#? }"
Ttypeset, "-x", "HOME", TPATH, TSHELL, NULL,
Ttypeset, "-i10", "COLUMNS", "LINES", "SECONDS", "TMOUT", NULL,
Talias,
- "integer=\\typeset -i",
- "local=\\typeset",
+ "integer=\\\\builtin typeset -i",
+ "local=\\\\builtin typeset",
/* not "alias -t --": hash -r needs to work */
- "hash=\\builtin alias -t",
- "type=\\builtin whence -v",
- "autoload=\\typeset -fu",
- "functions=\\typeset -f",
- "history=\\builtin fc -l",
- "nameref=\\typeset -n",
+ "hash=\\\\builtin alias -t",
+ "type=\\\\builtin whence -v",
+ "autoload=\\\\builtin typeset -fu",
+ "functions=\\\\builtin typeset -f",
+ "history=\\\\builtin fc -l",
+ "nameref=\\\\builtin typeset -n",
"nohup=nohup ",
- "r=\\builtin fc -e -",
- "login=\\exec login",
+ "r=\\\\builtin fc -e -",
+ "login=\\\\builtin exec login",
NULL,
/* this is what AT&T ksh seems to track, with the addition of emacs */
Talias, "-tU",
static struct env env;
struct env *e = &env;
+/* compile-time assertions */
+#define cta(name, expr) struct cta_ ## name { char t[(expr) ? 1 : -1]; }
+
+/* this one should be defined by the standard */
+cta(char_is_1_char, (sizeof(char) == 1) && (sizeof(signed char) == 1) &&
+ (sizeof(unsigned char) == 1));
+cta(char_is_8_bits, ((CHAR_BIT) == 8) && ((int)(unsigned char)0xFF == 0xFF) &&
+ ((int)(unsigned char)0x100 == 0) && ((int)(unsigned char)(int)-1 == 0xFF));
+/* the next assertion is probably not really needed */
+cta(short_is_2_char, sizeof(short) == 2);
+cta(short_size_no_matter_of_signedness, sizeof(short) == sizeof(unsigned short));
+/* the next assertion is probably not really needed */
+cta(int_is_4_char, sizeof(int) == 4);
+cta(int_size_no_matter_of_signedness, sizeof(int) == sizeof(unsigned int));
+
+cta(long_ge_int, sizeof(long) >= sizeof(int));
+cta(long_size_no_matter_of_signedness, sizeof(long) == sizeof(unsigned long));
+
+#ifndef MKSH_LEGACY_MODE
+/* the next assertion is probably not really needed */
+cta(ari_is_4_char, sizeof(mksh_ari_t) == 4);
+/* but this is */
+cta(ari_has_31_bit, 0 < (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1));
+/* the next assertion is probably not really needed */
+cta(uari_is_4_char, sizeof(mksh_uari_t) == 4);
+/* but the next three are; we REQUIRE unsigned integer wraparound */
+cta(uari_has_31_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 2 + 1));
+cta(uari_has_32_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3));
+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));
+#endif
+/* these are always required */
+cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0);
+cta(uari_is_unsigned, (mksh_uari_t)-1 > (mksh_uari_t)0);
+/* we require these to have the precisely same size and assume 2s complement */
+cta(ari_size_no_matter_of_signedness, sizeof(mksh_ari_t) == sizeof(mksh_uari_t));
+
+cta(sizet_size_no_matter_of_signedness, sizeof(ssize_t) == sizeof(size_t));
+cta(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(size_t) <= sizeof(long));
+cta(ari_fits_in_long, sizeof(mksh_ari_t) <= sizeof(long));
+
static mksh_uari_t
rndsetup(void)
{
for (i = 0; i < 3; ++i)
if (!isatty(i))
setmode(i, O_BINARY);
+
+ os2_init(&argc, &argv);
#endif
/* do things like getpgrp() et al. */
}
/* for security */
- typeset(initifs, 0, 0, 0, 0);
+ typeset("IFS= \t\n", 0, 0, 0, 0);
/* assign default shell variable values */
+ typeset("PATHSEP=" MKSH_PATHSEPS, 0, 0, 0, 0);
substitute(initsubs, 0);
/* Figure out the current working directory and set $PWD */
setstr(vp, current_wd, KSH_RETURN_ERROR);
for (wp = initcoms; *wp != NULL; wp++) {
- shcomexec(wp);
+ c_builtin(wp);
while (*wp != NULL)
wp++;
}
* to search for it. This changes the behaviour of a
* simple "mksh foo", but can't be helped.
*/
- s->file = search_path(argv[argi++], path, X_OK, NULL);
+ s->file = argv[argi++];
+ if (search_access(s->file, X_OK) != 0)
+ s->file = search_path(s->file, path, X_OK, NULL);
if (!s->file || !*s->file)
s->file = argv[argi - 1];
#else
}
if (restricted_shell) {
- shcomexec(restr_com);
+ c_builtin(restr_com);
/* After typeset command... */
Flag(FRESTRICTED) = 1;
}
if ((rv = main_init(argc, argv, &s, &l)) == 0) {
if (Flag(FAS_BUILTIN)) {
- rv = shcomexec(l->argv);
+ rv = c_builtin(l->argv);
} else {
- shell(s, true);
+ shell(s, 0);
/* NOTREACHED */
}
}
unwind(i);
/* NOTREACHED */
default:
- internal_errorf("include %d", i);
+ internal_errorf(Tunexpected_type, Tunwind, Tsource, i);
/* NOTREACHED */
}
}
s = pushs(SFILE, ATEMP);
s->u.shf = shf;
strdupx(s->file, name, ATEMP);
- i = shell(s, false);
+ i = shell(s, 1);
quitenv(s->u.shf);
if (old_argv) {
e->loc->argv = old_argv;
s = pushs(SSTRING, ATEMP);
s->start = s->str = comm;
s->line = line;
- rv = shell(s, false);
+ rv = shell(s, 1);
source = sold;
return (rv);
}
* run the commands from the input source, returning status.
*/
int
-shell(Source * volatile s, volatile bool toplevel)
+shell(Source * volatile s, volatile int level)
{
struct op *t;
volatile bool wastty = tobool(s->flags & SF_TTY);
volatile uint8_t attempts = 13;
- volatile bool interactive = Flag(FTALKING) && toplevel;
+ volatile bool interactive = (level == 0) && Flag(FTALKING);
volatile bool sfirst = true;
Source *volatile old_source = source;
int i;
- newenv(E_PARSE);
+ newenv(level == 2 ? E_EVAL : E_PARSE);
if (interactive)
really_exit = false;
switch ((i = kshsetjmp(e->jbuf))) {
case 0:
break;
+ case LBREAK:
+ case LCONTIN:
+ if (level != 2) {
+ source = old_source;
+ quitenv(NULL);
+ internal_errorf(Tf_cant_s, Tshell,
+ i == LBREAK ? Tbreak : Tcontinue);
+ /* NOTREACHED */
+ }
+ /* assert: interactive == false */
+ /* FALLTHROUGH */
case LINTR:
/* we get here if SIGINT not caught or ignored */
case LERROR:
default:
source = old_source;
quitenv(NULL);
- internal_errorf("shell %d", i);
+ internal_errorf(Tunexpected_type, Tunwind, Tshell, i);
/* NOTREACHED */
}
while (/* CONSTCOND */ 1) {
j_notify();
set_prompt(PS1, s);
}
- t = compile(s, sfirst);
+ t = compile(s, sfirst, true);
if (interactive)
histsave(&s->line, NULL, HIST_FLUSH, true);
sfirst = false;
* immediately after the last command
* executed.
*/
- if (toplevel)
+ if (level == 0)
unwind(LEXIT);
break;
}
case E_INCL:
case E_LOOP:
case E_ERRH:
+ case E_EVAL:
kshlongjmp(e->jbuf, i);
/* NOTREACHED */
case E_NONE:
VWARNINGF_BUILTIN, fmt, va);
va_end(va);
- /*
- * POSIX special builtins and ksh special builtins cause
- * non-interactive shells to exit. XXX may not want LERROR here
- */
+ /* POSIX special builtins cause non-interactive shells to exit */
if (builtin_spec) {
builtin_argv0 = NULL;
+ /* may not want to use LERROR here */
unwind(LERROR);
}
}
#ifdef DF
if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
if ((lfp = getenv("HOME")) == NULL || !mksh_abspath(lfp))
- errorf("cannot get home directory");
+ errorf("can't get home directory");
lfp = shf_smprintf(Tf_sSs, lfp, "mksh-dbg.txt");
}
if ((shl_dbg_fd = open(lfp, O_WRONLY | O_APPEND | O_CREAT, 0600)) < 0)
- errorf("cannot open debug output file %s", lfp);
+ errorf("can't open debug output file %s", lfp);
if (shl_dbg_fd < FDBASE) {
int nfd;
nfd = fcntl(shl_dbg_fd, F_DUPFD, FDBASE);
close(shl_dbg_fd);
if ((shl_dbg_fd = nfd) == -1)
- errorf("cannot dup debug output file");
+ errorf("can't dup debug output file");
}
fcntl(shl_dbg_fd, F_SETFD, FD_CLOEXEC);
shf_fdopen(shl_dbg_fd, SHF_WR, shl_dbg);
int rv;
if (((rv = dup2(ofd, nfd)) < 0) && !errok && (errno != EBADF))
- errorf("too many files open in shell");
+ errorf(Ttoo_many_files);
#ifdef __ultrix
/*XXX imake style */
(errno == EBADF || errno == EPERM))
return (-1);
if (nfd < 0 || nfd > SHRT_MAX)
- errorf("too many files open in shell");
+ errorf(Ttoo_many_files);
fcntl(nfd, F_SETFD, FD_CLOEXEC);
return ((short)nfd);
}
pv[1] = savefd(lpv[1]);
if (pv[1] != lpv[1])
close(lpv[1]);
+#ifdef __OS2__
+ setmode(pv[0], O_BINARY);
+ setmode(pv[1], O_BINARY);
+#endif
}
void
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015, 2016
+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include <grp.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.249 2016/11/11 23:31:35 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.255 2017/04/12 16:46:22 tg Exp $");
#define KSH_CHVT_FLAG
#ifdef MKSH_SMALL
#define KSH_CHVT_CODE
#define KSH_CHVT_FLAG
#endif
-#ifdef MKSH_LEGACY_MODE
-#undef KSH_CHVT_CODE
-#undef KSH_CHVT_FLAG
-#endif
/* type bits for unsigned char */
unsigned char chtypes[UCHAR_MAX + 1];
void
initctypes(void)
{
- setctypes(letters_uc, C_ALPHA);
- setctypes(letters_lc, C_ALPHA);
- chtypes['_'] |= C_ALPHA;
+ setctypes(letters_uc, C_ALPHX);
+ setctypes(letters_lc, C_ALPHX);
+ chtypes['_'] |= C_ALPHX;
setctypes("0123456789", C_DIGIT);
- /* \0 added automatically */
setctypes(TC_LEX1, C_LEX1);
setctypes("*@#!$-?", C_VAR1);
setctypes(TC_IFSWS, C_IFSWS);
if (arrayset) {
const char *ccp = NULL;
- if (*array)
+ if (array && *array)
ccp = skip_varname(array, false);
if (!ccp || !(!ccp[0] || (ccp[0] == '+' && !ccp[1]))) {
bi_errorf(Tf_sD_s, array, Tnot_ident);
/* symlink target is an absolute path */
xp = Xstring(xs, xp);
beginning_of_a_pathname:
- /* assert: (ip == ipath)[0] == '/' */
+ /* assert: mksh_cdirsep((ip == ipath)[0]) */
/* assert: xp == xs.beg => start of path */
/* exactly two leading slashes? (SUSv4 3.266) */
- /* @komh do NOT use mksh_cdirsep() here */
- if (ip[1] == '/' && ip[2] != '/') {
+ if (ip[1] == ip[0] && !mksh_cdirsep(ip[2])) {
/* keep them, e.g. for UNC pathnames */
Xput(xs, xp, '/');
}
case 0:
return;
case '/':
+#ifdef MKSH_DOSPATH
+ case '\\':
+#endif
/* exactly two leading slashes? (SUSv4 3.266) */
- /* @komh no mksh_cdirsep() here! */
- if (p[1] == '/' && p[2] != '/')
+ if (p[1] == p[0] && !mksh_cdirsep(p[2]))
/* keep them, e.g. for UNC pathnames */
++p;
-#ifdef __OS2__
- /* FALLTHROUGH */
- case '\\':
-#endif
needslash = true;
break;
default:
int
unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
{
- int wc, i, c, fc;
+ int wc, i, c, fc, n;
fc = (*fg)();
switch (fc) {
* four (U: eight) digits; convert to Unicode
*/
wc = 0;
- while (i--) {
+ n = 0;
+ while (n < i || i == -1) {
wc <<= 4;
if ((c = (*fg)()) >= ord('0') && c <= ord('9'))
wc += ksh_numdig(c);
(*fp)(c);
break;
}
+ ++n;
}
+ if (!n)
+ goto unknown_escape;
if ((cstyle && wc > 0xFF) || fc != 'x')
/* Unicode marker */
wc += 0x100;
-.\" $MirOS: src/bin/mksh/mksh.1,v 1.420 2016/11/11 23:31:36 tg Exp $
+.\" $MirOS: src/bin/mksh/mksh.1,v 1.442 2017/04/12 18:30:58 tg Exp $
.\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-.\" 2010, 2011, 2012, 2013, 2014, 2015, 2016
+.\" 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
.\" mirabilos <m@mirbsd.org>
.\"
.\" Provided that these terms and disclaimer and all copyright notices
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
-.Dd $Mdocdate: November 11 2016 $
+.Dd $Mdocdate: April 12 2017 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
into account all information is first and foremost presented with
.Nm
in mind and should be taken as such.
-.Ss I'm an Android user, so what's mksh?
-.Nm mksh
-is a
-.Ux
-shell / command interpreter, similar to
-.Nm COMMAND.COM
-or
-.Nm CMD.EXE ,
-which has been included with
-.Tn Android Open Source Project
-for a while now.
-Basically, it's a program that runs in a terminal (console window),
-takes user input and runs commands or scripts, which it can also
-be asked to do by other programs, even in the background.
-Any privilege pop-ups you might be encountering are thus not
-.Nm mksh
-issues but questions by some other program utilising it.
+.Ss I use Android, OS/2, etc. so what...?
+Please see the FAQ at the end of this document.
.Ss Invocation
Most builtins can be called directly, for example if a link points from its
name to the shell; not all make sense, have been tested or work at all though.
.Pp
The following command aliases are defined automatically by the shell:
.Bd -literal -offset indent
-autoload=\*(aq\etypeset \-fu\*(aq
-functions=\*(aq\etypeset \-f\*(aq
-hash=\*(aq\ebuiltin alias \-t\*(aq
-history=\*(aq\ebuiltin fc \-l\*(aq
-integer=\*(aq\etypeset \-i\*(aq
-local=\*(aq\etypeset\*(aq
-login=\*(aq\eexec login\*(aq
-nameref=\*(aq\etypeset \-n\*(aq
+autoload=\*(aq\e\ebuiltin typeset \-fu\*(aq
+functions=\*(aq\e\ebuiltin typeset \-f\*(aq
+hash=\*(aq\e\ebuiltin alias \-t\*(aq
+history=\*(aq\e\ebuiltin fc \-l\*(aq
+integer=\*(aq\e\ebuiltin typeset \-i\*(aq
+local=\*(aq\e\ebuiltin typeset\*(aq
+login=\*(aq\e\ebuiltin exec login\*(aq
+nameref=\*(aq\e\ebuiltin typeset \-n\*(aq
nohup=\*(aqnohup \*(aq
-r=\*(aq\ebuiltin fc \-e \-\*(aq
-type=\*(aq\ebuiltin whence \-v\*(aq
+r=\*(aq\e\ebuiltin fc \-e \-\*(aq
+type=\*(aq\e\ebuiltin whence \-v\*(aq
.Ed
.Pp
Tracked aliases allow the shell to remember where it found a particular
.Dq Li \&.
command (see below).
An empty string resulting from a leading or trailing
-colon, or two adjacent colons, is treated as a
+(semi)colon, or two adjacent ones, is treated as a
.Dq Li \&.
(the current directory).
+.It Ev PATHSEP
+A colon (semicolon on OS/2), for the user's convenience.
.It Ev PGRP
The process ID of the shell's process group leader.
.It Ev PIPESTATUS
.Nm
now also supports the following form:
.Bd -literal -offset indent
-PS1=$'\e1\er\e1\ee[7m\e1$PWD\e1\ee[0m\e1\*(Gt '
+PS1=$\*(aq\e1\er\e1\ee[7m\e1$PWD\e1\ee[0m\e1\*(Gt \*(aq
.Ed
.It Ev PS2
Secondary prompt string, by default
The effective user id of the shell.
.El
.Ss Tilde expansion
-Tilde expansion which is done in parallel with parameter substitution, is done
-on words starting with an unquoted
+Tilde expansion, which is done in parallel with parameter substitution,
+is applied to words starting with an unquoted
.Ql \*(TI .
+In parameter assignments (such as those preceding a simple-command or those
+occurring in the arguments of a declaration utility), tilde expansion is done
+after any assignment (i.e. after the equals sign) or after an unquoted colon
+.Pq Ql \&: ;
+login names are also delimited by colons.
+The Korn shell, except in POSIX mode, always expands tildes after unquoted
+equals signs, not just in assignment context (see below), and enables tab
+completion for tildes after all unquoted colons during command line editing.
+.Pp
The characters following the tilde, up to the first
.Ql / ,
if any, are assumed to be a login name.
if any quoting or parameter substitution occurs in the login name, no
substitution is performed.
.Pp
-In parameter assignments
-(such as those preceding a simple-command or those occurring
-in the arguments of
-.Ic alias ,
-.Ic export ,
-.Ic global ,
-.Ic readonly
-and
-.Ic typeset ) ,
-tilde expansion is done after any assignment
-(i.e. after the equals sign)
-or after an unquoted colon
-.Pq Ql \&: ;
-login names are also delimited by colons.
-.Pp
The home directory of previously expanded login names are cached and re-used.
The
.Ic alias Fl d
pipelines are created and in the order they are given, so the following
will print an error with a line number prepended to it:
.Pp
-.D1 $ cat /foo/bar 2\*(Gt&1 \*(Gt/dev/null \*(Ba pr \-n \-t
+.Dl $ cat /foo/bar 2\*(Gt&1 \*(Gt/dev/null \*(Ba pr \-n \-t
.Pp
File descriptors created by I/O redirections are private to the shell.
.Ss Arithmetic expressions
A function can be made to finish immediately using the
.Ic return
command; this may also be used to explicitly specify the exit status.
+Note that when called in a subshell,
+.Ic return
+will only exit that subshell and will not cause the original shell to exit
+a running function (see the
+.Ic while Ns Li \&... Ns Ic read
+loop FAQ below).
.Pp
Functions defined with the
.Ic function
.Nm
commands keeping assignments:
.Pp
-.Ic builtin , global , source , typeset ,
-.Ic wait
+.Ic global , source , typeset
.Pp
Builtins that are not special:
.Pp
.Ic [ , alias , bg , bind ,
-.Ic cat , cd , command , echo ,
-.Ic false , fc , fg , getopts ,
-.Ic jobs , kill , let , print ,
-.Ic pwd , read , realpath , rename ,
-.Ic sleep , suspend , test , true ,
-.Ic ulimit , umask , unalias , whence
+.Ic builtin , cat , cd , command ,
+.Ic echo , false , fc , fg ,
+.Ic getopts , jobs , kill , let ,
+.Ic print , pwd , read , realpath ,
+.Ic rename , sleep , suspend , test ,
+.Ic true , ulimit , umask , unalias ,
+.Ic wait , whence
.Pp
Once the type of command has been determined, any command-line parameter
assignments are performed and exported for the duration of the command.
Any name with a value defines an alias (see
.Sx Aliases
above).
+.Li \&[A\-Za\-z0\-9_!%,@\-]
+are valid in names except they may not begin with a hyphen-minus.
.Pp
When listing aliases, one of two formats is used.
Normally, aliases are listed as
.Ar command .
.Pp
.It Xo
+.Ic \ebuiltin
+.Ar command Op Ar arg ...
+.Xc
+Same as
+.Ic builtin .
+Additionally acts as declaration utility forwarder, i.e. this is a
+declaration utility (see
+.Sx Tilde expansion )
+.No iff Ar command
+is a declaration utility.
+.Pp
+.It Xo
.Ic cat
.Op Fl u
.Op Ar
and secondly, special built-in commands lose their specialness
(i.e. redirection and utility errors do not cause the shell to
exit, and command assignments are not permanent).
+The declaration utility property is not reset.
.Pp
If the
.Fl p
.Ic posix
or
.Ic sh
-option is set or this is a direct builtin call, only the first argument
-is treated as an option, and only if it is exactly
+option is set or this is a direct builtin call or
+.Ic print
+.Fl R ,
+only the first argument is treated as an option, and only if it is exactly
.Dq Li \-n .
Backslash interpretation is disabled.
.Pp
it does pass these file descriptors on.
.Pp
.It Ic exit Op Ar status
-The shell exits with the specified exit status.
+The shell or subshell exits with the specified exit status.
If
.Ar status
is not specified, the exit status is the current value of the
Sets the export attribute of the named parameters.
Exported parameters are passed in the environment to executed commands.
If values are specified, the named parameters are also assigned.
+This is a declaration utility.
.Pp
If no parameters are specified, all parameters with the export attribute
set are printed one per line; either their names, or, if a
.Ev OPTIND
may lead to unexpected results.
.Pp
-.It global Ar ...
+.It Xo
+.Ic global
+.Op Ic +\-aglpnrtUux
+.Oo Fl L Ns Op Ar n
+.No \*(Ba Fl R Ns Op Ar n
+.No \*(Ba Fl Z Ns Op Ar n Oc
+.Op Fl i Ns Op Ar n
+.Oo Ar name
+.Op Ns = Ns Ar value
+.Ar ... Oc
+.Xc
See
-.Ic typeset .
+.Ic typeset Fl g .
+.No Deprecated , Em will
+be removed from a future version of
+.Nm .
.Pp
.It Xo
.Ic hash
the parsing or evaluation of an expression, the exit status is greater than 1.
Since expressions may need to be quoted,
.No \&(( Ar expr No ))
-is syntactic sugar for
-.No "{ let '" Ns Ar expr Ns "'; }" .
-.Pp
-.It Ic let]
-Internally used alias for
-.Ic let .
+is syntactic sugar for:
+.Dl "{ \e\ebuiltin let \*(aq" Ns Ar expr Ns "\*(aq; }"
.Pp
.It Xo
.Ic mknod
.Pp
.It Xo
.Ic print
-.Oo Fl AclNnprsu Ns Oo Ar n Oc \*(Ba
-.Fl R Op Fl en Oc
+.Oo Fl AcelNnprsu Ns Oo Ar n Oc \*(Ba
+.Fl R Op Fl n Oc
.Op Ar argument ...
.Xc
Print the specified argument(s) on the standard output,
separated by spaces, terminated with a newline.
-The C escapes mentioned in
+The escapes mentioned in
.Sx Backslash expansion
above, as well as
.Dq Li \ec ,
built-in utility and the
.Ic select
statement do.
+.It Fl e
+Restore backslash expansion after a previous
+.Fl r .
.It Fl l
Change the output word separator to newline.
.It Fl N
Inhibit backslash expansion.
.It Fl s
Print to the history file instead of standard output.
-.It Fl u Op Ar n
+.It Fl u Ns Op Ar n
Print to the file descriptor
.Ar n Pq defaults to 1 if omitted
instead of standard output.
.Pp
The
.Fl R
-option is used to emulate, to some degree, the
+option mostly emulates the
.Bx
.Xr echo 1
-command which does not process
-.Ql \e
-sequences unless the
-.Fl e
-option is given.
-As above, the
-.Fl n
-option suppresses the trailing newline.
-.Pp
-.It Ic printf Ar format Op Ar arguments ...
-Formatted output.
-Approximately the same as the
-.Xr printf 1 ,
-utility, except it uses the same
-.Sx Backslash expansion
-and I/O code and does not handle floating point as the rest of
-.Nm mksh .
-An external utility is preferred over the builtin.
-This is not normally part of
-.Nm mksh ;
-however, distributors may have added this as builtin as a speed hack.
-Do not use in new code.
+command which does not expand backslashes and interprets
+its first argument as option only if it is exactly
+.Dq Li \-n
+.Pq to suppress the trailing newline .
.Pp
.It Ic pwd Op Fl LP
Print the present working directory.
.Ic read
exits with a non-zero status.
.Pp
-Another handy set of tricks:
-If
-.Ic read
-is run in a loop such as
-.Ic while read foo; do ...; done
-then leading whitespace will be removed (IFS) and backslashes processed.
-You might want to use
-.Ic while IFS= read \-r foo; do ...; done
-for pristine I/O.
-Similarly, when using the
-.Fl a
-option, use of the
-.Fl r
-option might be prudent; the same applies for:
-.Bd -literal -offset indent
-find . \-type f \-print0 \*(Ba& \e
- while IFS= read \-d \*(aq\*(aq \-pr filename; do
- print \-r \-\- "found \*(Lt${filename#./}\*(Gt"
-done
-.Ed
-.Pp
-The inner loop will be executed in a subshell and variable changes
-cannot be propagated if executed in a pipeline:
-.Bd -literal -offset indent
-bar \*(Ba baz \*(Ba while read foo; do ...; done
-.Ed
-.Pp
-Use co-processes instead:
-.Bd -literal -offset indent
-bar \*(Ba baz \*(Ba&
-while read \-p foo; do ...; done
-exec 3\*(Gt&p; exec 3\*(Gt&\-
-.Ed
-.Pp
.It Xo
.Ic readonly
.Op Fl p
.Ar ... Oc
.Xc
Sets the read-only attribute of the named parameters.
+This is a declaration utility.
If values are given,
parameters are set to them before setting the attribute.
Once a parameter is
.It Fl o Ic braceexpand
Enable brace expansion (a.k.a. alternation).
This is enabled by default.
-If disabled, tilde expansion after an equals sign is disabled as a side effect.
.It Fl o Ic emacs
Enable BRL emacs-like command-line editing (interactive shells only); see
.Sx Emacs editing mode .
.It Fl O Ar file
.Ar file Ns 's
owner is the shell's effective user ID.
-.It Fl o Ar option
-Shell
-.Ar option
-is set (see the
-.Ic set
-command above for a list of options).
-As a non-standard extension, if the option starts with a
-.Ql \&! ,
-the test is negated; the test always fails if
-.Ar option
-doesn't exist (so [ \-o foo \-o \-o !foo ] returns true if and only if option
-.Ar foo
-exists).
-The same can be achieved with [ \-o ?foo ] like in
-.At
-.Nm ksh93 .
-.Ar option
-can also be the short flag led by either
-.Ql \-
-or
-.Ql +
-.Pq no logical negation ,
-for example
-.Dq Li \-x
-or
-.Dq Li +x
-instead of
-.Dq Li xtrace .
.It Fl p Ar file
.Ar file
is a named pipe
.It Fl z Ar string
.Ar string
is empty.
+.It Fl v Ar name
+The shell parameter
+.Ar name
+is set.
+.It Fl o Ar option
+Shell
+.Ar option
+is set (see the
+.Ic set
+command above for a list of options).
+As a non-standard extension, if the option starts with a
+.Ql \&! ,
+the test is negated; the test always fails if
+.Ar option
+doesn't exist (so [ \-o foo \-o \-o !foo ] returns true if and only if option
+.Ar foo
+exists).
+The same can be achieved with [ \-o ?foo ] like in
+.At
+.Nm ksh93 .
+.Ar option
+can also be the short flag led by either
+.Ql \-
+or
+.Ql +
+.Pq no logical negation ,
+for example
+.Dq Li \-x
+or
+.Dq Li +x
+instead of
+.Dq Li xtrace .
.It Ar string No = Ar string
Strings are equal.
.It Ar string No == Ar string
A command that exits with a zero value.
.Pp
.It Xo
-.Ic global
-.Oo Op Ic +\-alpnrtUux
-.Op Fl L Ns Op Ar n
-.Op Fl R Ns Op Ar n
-.Op Fl Z Ns Op Ar n
+.Ic typeset
+.Op Ic +\-aglpnrtUux
+.Oo Fl L Ns Op Ar n
+.No \*(Ba Fl R Ns Op Ar n
+.No \*(Ba Fl Z Ns Op Ar n Oc
.Op Fl i Ns Op Ar n
-.No \*(Ba Fl f Op Fl tux Oc
.Oo Ar name
.Op Ns = Ns Ar value
.Ar ... Oc
.Xc
.It Xo
.Ic typeset
-.Oo Op Ic +\-alpnrtUux
-.Op Fl LRZ Ns Op Ar n
-.Op Fl i Ns Op Ar n
-.No \*(Ba Fl f Op Fl tux Oc
-.Oo Ar name
-.Op Ns = Ns Ar value
-.Ar ... Oc
+.Fl f Op Fl tux
+.Op Ar name ...
.Xc
Display or set parameter attributes.
+This is a declaration utility.
With no
.Ar name
arguments, parameter attributes are displayed; if no options are used, the
If
.Ar name
arguments are given, the attributes of the named parameters are set
-.Pq Ic \-
+.Pq Ic \&\-
or cleared
-.Pq Ic + .
+.Pq Ic \&+ ;
+inside a function, this will cause the parameters to be created
+(with no value) in the local scope (but see
+.Fl g ) .
Values for parameters may optionally be specified.
For
.Ar name Ns \&[*] ,
-the change affects the entire array, and no value may be specified.
-.Pp
-If
-.Ic typeset
-is used inside a function, any parameters specified are localised.
-This is not done by the otherwise identical
-.Ic global .
-.Em Note :
-This means that
-.Nm No 's Ic global
-command is
-.Em not
-equivalent to other programming languages' as it does not allow a
-function called from another function to access a parameter at truly
-global scope, but only prevents putting an accessed one into local scope.
+the change affects all elements of the array, and no value may be specified.
.Pp
When
.Fl f
.It Fl f
Function mode.
Display or set functions and their attributes, instead of parameters.
+.It Fl g
+Do not cause named parameters to be created in
+the local scope when called inside a function.
.It Fl i Ns Op Ar n
Integer attribute.
.Ar n
Also note that the types of limits available are system
dependent \*(en some systems have only the
.Fl f
-limit.
+limit, or not even that, or can set only the soft limits
.Bl -tag -width 5n
.It Fl a
Display all limits; unless
or opinionated differences can be disabled by using this mode; these are:
.Bl -bullet
.It
-The GNU
+The incompatible GNU
.Nm bash
I/O redirection
.Ic &\*(Gt Ns Ar file
-is no longer supported.
+is not supported.
.It
File descriptors created by I/O redirections are inherited by
child processes.
The
.Nm echo
builtin does not interpret backslashes and only supports the exact option
-.Dq Li \-n .
+.Fl n .
+.It
+Alias expansion with a trailing space only reruns on command words.
+.It
+Tilde expansion follows POSIX instead of Korn shell rules.
.It
-\&... (list is incomplete and may change for R54)
+The exit status of
+.Ic fg
+is always 0.
+.It
+.Ic kill
+.Fl l
+only lists signal names, all in one line.
+.It
+.Ic getopts
+does not accept options with a leading
+.Ql + .
.El
.Ss SH mode
Compatibility mode; intended for use with legacy scripts that
cannot easily be fixed; the changes are as follows:
.Bl -bullet
.It
-The GNU
+The incompatible GNU
.Nm bash
I/O redirection
.Ic &\*(Gt Ns Ar file
-is no longer supported.
+is not supported.
.It
File descriptors created by I/O redirections are inherited by
child processes.
The
.Nm echo
builtin does not interpret backslashes and only supports the exact option
-.Dq Li \-n .
+.Fl n ,
+unless built with
+.Ev \-DMKSH_MIDNIGHTBSD01ASH_COMPAT .
.It
The substitution operations
.Sm off
.Xc
wrongly do not require a parenthesis to be escaped and do not parse extglobs.
.It
-\&... (list is incomplete and may change for R54)
+The getopt construct from
+.Xr lksh 1
+passes through the errorlevel.
+.It
+.Nm sh
+.Fl c
+eats a leading
+.Fl \-
+if built with
+.Ev \-DMKSH_MIDNIGHTBSD01ASH_COMPAT .
.El
.Ss Interactive input line editing
The shell supports three modes of reading command lines from a
.No KILL Pq \*(haU
.Xc
Deletes the entire input line.
-If Ctrl-U should only delete the line up to the cursor, use:
-.Pp
-.D1 $ bind \-m \*(haU='\*(ha[0\*(haK'
.It kill\-region: \*(haW
Deletes the input between the cursor and the mark.
.It Xo kill\-to\-eol:
.Xr utf\-8 7 ,
.Xr mknod 8
.Pp
-.Pa https://www.mirbsd.org/ksh\-chan.htm
+.Pa http://www.mirbsd.org/ksh\-chan.htm
.Rs
.%A Morris Bolsky
.%B "The KornShell Command and Programming Language"
contributors including our users, to improve the shell is appreciated.
See the documentation, web site and CVS for details.
.Pp
+.Nm mksh\-os2
+is developed by
+.An KO Myung-Hun Aq Mt komh@chollian.net .
+.Pp
+.Nm mksh\-w32
+is developed by
+.An Michael Langguth Aq Mt lan@scalaris.com .
+.Pp
The BSD daemon is Copyright \(co Marshall Kirk McKusick.
The complete legalese is at:
-.Pa https://www.mirbsd.org/TaC\-mksh.txt
+.Pa http://www.mirbsd.org/TaC\-mksh.txt
.\"
.\" This boils down to: feel free to use mksh.ico as application icon
.\" or shortcut for mksh or mksh/Win32 or OS/2; distro patches are ok
.\" to protect it or lose it, which McKusick almost did.
.\"
.Sh CAVEATS
-.Nm
-has a different scope model from
-.At
-.Nm ksh ,
-which leads to subtle differences in semantics for identical builtins.
-This can cause issues with a
-.Ic nameref
-to suddenly point to a local variable by accident; fixing this is hard.
-.Pp
-The parts of a pipeline, like below, are executed in subshells.
-Thus, variable assignments inside them are not visible in the
-surrounding execution environment.
-Use co-processes instead.
-.Bd -literal -offset indent
-foo \*(Ba bar \*(Ba read baz # will not change $baz
-foo \*(Ba bar \*(Ba& read \-p baz # will, however, do so
-.Ed
-.Pp
.Nm mksh
provides a consistent 32-bit integer arithmetic implementation, both
signed and unsigned, with sign of the result of a remainder operation
esac
.Ed
In near future, (Unicode) locale tracking will be implemented though.
+.Pp
+See also the FAQ below.
.Sh BUGS
Suspending (using \*(haZ) pipelines like the one below will only suspend
the currently running part of the pipeline; in this example,
.Xr memmove 3 .
.Pp
This document attempts to describe
-.Nm mksh\ R54
+.Nm mksh\ R55
and up,
.\" with vendor patches from insert-your-name-here,
compiled without any options impacting functionality, such as
Please report bugs in
.Nm
to the
-.Mx
-mailing list at
.Aq Mt miros\-mksh@mirbsd.org
+mailing list
or in the
.Li \&#\&!/bin/mksh
.Pq or Li \&#ksh
.Pq Port 6697 SSL, 6667 unencrypted ,
or at:
.Pa https://launchpad.net/mksh
+.Sh FREQUENTLY ASKED QUESTIONS
+This FAQ attempts to document some of the questions users of
+.Nm
+or readers of this manual page may encounter.
+.Ss I'm an Android user, so what's mksh?
+.Nm mksh
+is a
+.Ux
+shell / command interpreter, similar to
+.Nm COMMAND.COM
+or
+.Nm CMD.EXE ,
+which has been included with
+.Tn Android Open Source Project
+for a while now.
+Basically, it's a program that runs in a terminal (console window),
+takes user input and runs commands or scripts, which it can also
+be asked to do by other programs, even in the background.
+Any privilege pop-ups you might be encountering are thus not
+.Nm mksh
+issues but questions by some other program utilising it.
+.Ss "I'm an OS/2 user, what do I need to know?"
+Unlike the native command prompt, the current working directory is,
+for security reasons common on Unix systems which the shell is designed for,
+not in the search path at all; if you really need this, run the command
+.Li PATH=.$PATHSEP$PATH
+or add that to a suitable initialisation file.
+.Pp
+There are two different newline modes for mksh-os2: standard (Unix) mode,
+in which only LF (0A hex) is supported as line separator, and "textmode",
+which also accepts ASCII newlines (CR+LF), like most other tools on OS/2,
+but creating an incompatibility with standard
+.Nm .
+If you compiled mksh from source, you will get the standard Unix mode unless
+.Fl T
+is added during compilation; you will most likely have gotten this shell
+through komh's port on Hobbes, or from his OS/2 Factory on eComStation
+Korea, which uses "textmode", though.
+Most OS/2 users will want to use "textmode" unless they need absolute
+compatibility with Unix
+.Nm .
+.Ss "How do I start mksh on a specific terminal?"
+Normally:
+.Dl mksh \-T/dev/tty2
+.Pp
+However, if you want for it to return (e.g. for an embedded
+system rescue shell), use this on your real console device instead:
+.Dl mksh \-T!/dev/ttyACM0
+.Pp
+.Nm
+can also daemonise (send to the background):
+.Dl mksh \-T\- \-c \*(aqexec cdio lock\*(aq
+.Ss "POSIX says..."
+Run the shell in POSIX mode (and possibly
+.Nm lksh
+instead of
+.Nm mksh ) :
+.Dl set \-o posix
+.Ss "My prompt from <some other shell> does not work!"
+Contact us on the mailing list or on IRC, we'll convert it for you.
+.Ss "Something is going wrong with my while...read loop"
+Most likely, you've encountered the problem in which the shell runs
+all parts of a pipeline as subshell.
+The inner loop will be executed in a subshell and variable changes
+cannot be propagated if run in a pipeline:
+.Bd -literal -offset indent
+bar \*(Ba baz \*(Ba while read foo; do ...; done
+.Ed
+.Pp
+Note that
+.Ic exit
+in the inner loop will only exit the subshell and not the original shell.
+Likewise, if the code is inside a function,
+.Ic return
+in the inner loop will only exit the subshell and won't terminate the function.
+.Pp
+Use co-processes instead:
+.Bd -literal -offset indent
+bar \*(Ba baz \*(Ba&
+while read \-p foo; do ...; done
+exec 3\*(Gt&p; exec 3\*(Gt&\-
+.Ed
+.Pp
+If
+.Ic read
+is run in a loop such as
+.Ic while read foo; do ...; done
+then leading whitespace will be removed (IFS) and backslashes processed.
+You might want to use
+.Ic while IFS= read \-r foo; do ...; done
+for pristine I/O.
+Similarly, when using the
+.Fl a
+option, use of the
+.Fl r
+option might be prudent
+.Pq Dq Li read \-raN\-1 arr \*(Ltfile ;
+the same applies for NUL-terminated lines:
+.Bd -literal -offset indent
+find . \-type f \-print0 \*(Ba& \e
+ while IFS= read \-d \*(aq\*(aq \-pr filename; do
+ print \-r \-\- "found \*(Lt${filename#./}\*(Gt"
+done
+.Ed
+.Pp
+.Ss "What differences in function-local scopes are there?"
+.Nm
+has a different scope model from
+.At
+.Nm ksh ,
+which leads to subtle differences in semantics for identical builtins.
+This can cause issues with a
+.Ic nameref
+to suddenly point to a local variable by accident.
+.Pp
+.Tn GNU
+.Nm bash
+allows unsetting local variables; in
+.Nm ,
+doing so in a function allows back access to the global variable
+(actually the one in the next scope up) with the same name.
+The following code, when run before the function definitions, changes
+the behaviour of
+.Ic unset
+to behave like other shells (the alias can be removed after the definitions):
+.Bd -literal -offset indent
+case ${KSH_VERSION:\-} in
+*MIRBSD\ KSH*\*(Ba*LEGACY\ KSH*)
+ function unset_compat {
+ \e\ebuiltin typeset unset_compat_x
+
+ for unset_compat_x in "$@"; do
+ eval "\e\e\e\ebuiltin unset $unset_compat_x[*]"
+ done
+ }
+ \e\ebuiltin alias unset=unset_compat
+ ;;
+esac
+.Ed
+.Pp
+When a local variable is created (e.g. using
+.Ic local ,
+.Ic typeset ,
+.Ic integer ,
+.Ic \e\ebuiltin typeset )
+it does not, like in other shells, inherit the value from the global
+(next scope up) variable with the same name; it is rather created
+without any value (unset but defined).
+.Ss "I get an error in this regex comparison"
+Use extglobs instead of regexes:
+.Dl "[[ foo =~ (foo\*(Babar).*baz ]] # becomes"
+.Dl "[[ foo = *@(foo\*(Babar)*baz* ]] # instead"
+.Ss "Are there any extensions to avoid?"
+.Tn GNU
+.Nm bash
+supports
+.Dq Li &\*(Gt
+.Pq and Dq Li \*(Ba&
+to redirect both stdout and stderr in one go, but this breaks POSIX
+and Korn Shell syntax; use POSIX redirections instead:
+.Dl "foo \*(Ba& bar \*(Ba& baz &\*(Gtlog # GNU bash"
+.Dl "foo 2\*(Gt&1 \*(Ba bar 2\*(Gt&1 \*(Ba baz \*(Gtlog 2\*(Gt&1 # POSIX"
+.Ss "\*(haL (Ctrl-L) does not clear the screen"
+Use \*(ha[\*(haL (Escape+Ctrl-L) or rebind it:
+.Dl bind \*(aq\*(haL=clear-screen\*(aq
+.Ss "\*(haU (Ctrl-U) clears the entire line"
+If it should only delete the line up to the cursor, use:
+.Dl bind \-m \*(haU=\*(aq\*(ha[0\*(haK\*(aq
+.Ss "Cursor Up behaves differently from zsh"
+Some shells make Cursor Up search in the history only for
+commands starting with what was already entered.
+.Nm
+separates the shortcuts: Cursor Up goes up one command
+and PgUp searches the history as described above.
--- /dev/null
+/*-
+ * Copyright (c) 2015
+ * KO Myung-Hun <komh@chollian.net>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
+#define INCL_DOS
+#include <os2.h>
+
+#include "sh.h"
+
+#include <klibc/startup.h>
+#include <io.h>
+#include <unistd.h>
+#include <process.h>
+
+__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.1 2017/04/02 15:00:44 tg Exp $");
+
+static char *remove_trailing_dots(char *);
+static int access_stat_ex(int (*)(), const char *, void *);
+static int test_exec_exist(const char *, char *);
+static void response(int *, const char ***);
+static char *make_response_file(char * const *);
+static void env_slashify(void);
+static void add_temp(const char *);
+static void cleanup_temps(void);
+static void cleanup(void);
+
+#define RPUT(x) do { \
+ if (new_argc >= new_alloc) { \
+ new_alloc += 20; \
+ if (!(new_argv = realloc(new_argv, \
+ new_alloc * sizeof(char *)))) \
+ goto exit_out_of_memory; \
+ } \
+ new_argv[new_argc++] = (x); \
+} while (/* CONSTCOND */ 0)
+
+#define KLIBC_ARG_RESPONSE_EXCLUDE \
+ (__KLIBC_ARG_DQUOTE | __KLIBC_ARG_WILDCARD | __KLIBC_ARG_SHELL)
+
+static void
+response(int *argcp, const char ***argvp)
+{
+ int i, old_argc, new_argc, new_alloc = 0;
+ const char **old_argv, **new_argv;
+ char *line, *l, *p;
+ FILE *f;
+
+ old_argc = *argcp;
+ old_argv = *argvp;
+ for (i = 1; i < old_argc; ++i)
+ if (old_argv[i] &&
+ !(old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) &&
+ old_argv[i][0] == '@')
+ break;
+
+ if (i >= old_argc)
+ /* do nothing */
+ return;
+
+ new_argv = NULL;
+ new_argc = 0;
+ for (i = 0; i < old_argc; ++i) {
+ if (i == 0 || !old_argv[i] ||
+ (old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) ||
+ old_argv[i][0] != '@' ||
+ !(f = fopen(old_argv[i] + 1, "rt")))
+ RPUT(old_argv[i]);
+ else {
+ long filesize;
+
+ fseek(f, 0, SEEK_END);
+ filesize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ line = malloc(filesize + /* type */ 1 + /* NUL */ 1);
+ if (!line) {
+ exit_out_of_memory:
+ fputs("Out of memory while reading response file\n", stderr);
+ exit(255);
+ }
+
+ line[0] = __KLIBC_ARG_NONZERO | __KLIBC_ARG_RESPONSE;
+ l = line + 1;
+ while (fgets(l, (filesize + 1) - (l - (line + 1)), f)) {
+ p = strchr(l, '\n');
+ if (p) {
+ /*
+ * if a line ends with a backslash,
+ * concatenate with the next line
+ */
+ if (p > l && p[-1] == '\\') {
+ char *p1;
+ int count = 0;
+
+ for (p1 = p - 1; p1 >= l &&
+ *p1 == '\\'; p1--)
+ count++;
+
+ if (count & 1) {
+ l = p + 1;
+
+ continue;
+ }
+ }
+
+ *p = 0;
+ }
+ p = strdup(line);
+ if (!p)
+ goto exit_out_of_memory;
+
+ RPUT(p + 1);
+
+ l = line + 1;
+ }
+
+ free(line);
+
+ if (ferror(f)) {
+ fputs("Cannot read response file\n", stderr);
+ exit(255);
+ }
+
+ fclose(f);
+ }
+ }
+
+ RPUT(NULL);
+ --new_argc;
+
+ *argcp = new_argc;
+ *argvp = new_argv;
+}
+
+static void
+init_extlibpath(void)
+{
+ const char *vars[] = {
+ "BEGINLIBPATH",
+ "ENDLIBPATH",
+ "LIBPATHSTRICT",
+ NULL
+ };
+ char val[512];
+ int flag;
+
+ for (flag = 0; vars[flag]; flag++) {
+ DosQueryExtLIBPATH(val, flag + 1);
+ if (val[0])
+ setenv(vars[flag], val, 1);
+ }
+}
+
+/*
+ * Convert backslashes of environmental variables to forward slahes.
+ * A backslash may be used as an escaped character when doing 'echo'.
+ * This leads to an unexpected behavior.
+ */
+static void
+env_slashify(void)
+{
+ /*
+ * PATH and TMPDIR are used by OS/2 as well. That is, they may
+ * have backslashes as a directory separator.
+ * BEGINLIBPATH and ENDLIBPATH are special variables on OS/2.
+ */
+ const char *var_list[] = {
+ "PATH",
+ "TMPDIR",
+ "BEGINLIBPATH",
+ "ENDLIBPATH",
+ NULL
+ };
+ const char **var;
+ char *value;
+
+ for (var = var_list; *var; var++) {
+ value = getenv(*var);
+
+ if (value)
+ _fnslashify(value);
+ }
+}
+
+void
+os2_init(int *argcp, const char ***argvp)
+{
+ response(argcp, argvp);
+
+ init_extlibpath();
+ env_slashify();
+
+ if (!isatty(STDIN_FILENO))
+ setmode(STDIN_FILENO, O_BINARY);
+ if (!isatty(STDOUT_FILENO))
+ setmode(STDOUT_FILENO, O_BINARY);
+ if (!isatty(STDERR_FILENO))
+ setmode(STDERR_FILENO, O_BINARY);
+
+ atexit(cleanup);
+}
+
+void
+setextlibpath(const char *name, const char *val)
+{
+ int flag;
+ char *p, *cp;
+
+ if (!strcmp(name, "BEGINLIBPATH"))
+ flag = BEGIN_LIBPATH;
+ else if (!strcmp(name, "ENDLIBPATH"))
+ flag = END_LIBPATH;
+ else if (!strcmp(name, "LIBPATHSTRICT"))
+ flag = LIBPATHSTRICT;
+ else
+ return;
+
+ /* convert slashes to backslashes */
+ strdupx(cp, val, ATEMP);
+ for (p = cp; *p; p++) {
+ if (*p == '/')
+ *p = '\\';
+ }
+
+ DosSetExtLIBPATH(cp, flag);
+
+ afree(cp, ATEMP);
+}
+
+/* remove trailing dots */
+static char *
+remove_trailing_dots(char *name)
+{
+ char *p;
+
+ for (p = name + strlen(name); --p > name && *p == '.'; )
+ /* nothing */;
+
+ if (*p != '.' && *p != '/' && *p != '\\' && *p != ':')
+ p[1] = '\0';
+
+ return (name);
+}
+
+#define REMOVE_TRAILING_DOTS(name) \
+ remove_trailing_dots(memcpy(alloca(strlen(name) + 1), name, strlen(name) + 1))
+
+/* alias of stat() */
+extern int _std_stat(const char *, struct stat *);
+
+/* replacement for stat() of kLIBC which fails if there are trailing dots */
+int
+stat(const char *name, struct stat *buffer)
+{
+ return (_std_stat(REMOVE_TRAILING_DOTS(name), buffer));
+}
+
+/* alias of access() */
+extern int _std_access(const char *, int);
+
+/* replacement for access() of kLIBC which fails if there are trailing dots */
+int
+access(const char *name, int mode)
+{
+ /*
+ * On OS/2 kLIBC, X_OK is set only for executable files.
+ * This prevents scripts from being executed.
+ */
+ if (mode & X_OK)
+ mode = (mode & ~X_OK) | R_OK;
+
+ return (_std_access(REMOVE_TRAILING_DOTS(name), mode));
+}
+
+#define MAX_X_SUFFIX_LEN 4
+
+static const char *x_suffix_list[] =
+ { "", ".ksh", ".exe", ".sh", ".cmd", ".com", ".bat", NULL };
+
+/* call fn() by appending executable extensions */
+static int
+access_stat_ex(int (*fn)(), const char *name, void *arg)
+{
+ char *x_name;
+ const char **x_suffix;
+ int rc = -1;
+ size_t x_namelen = strlen(name) + MAX_X_SUFFIX_LEN + 1;
+
+ /* otherwise, try to append executable suffixes */
+ x_name = alloc(x_namelen, ATEMP);
+
+ for (x_suffix = x_suffix_list; rc && *x_suffix; x_suffix++) {
+ strlcpy(x_name, name, x_namelen);
+ strlcat(x_name, *x_suffix, x_namelen);
+
+ rc = fn(x_name, arg);
+ }
+
+ afree(x_name, ATEMP);
+
+ return (rc);
+}
+
+/* access()/search_access() version */
+int
+access_ex(int (*fn)(const char *, int), const char *name, int mode)
+{
+ /*XXX this smells fishy --mirabilos */
+ return (access_stat_ex(fn, name, (void *)mode));
+}
+
+/* stat() version */
+int
+stat_ex(const char *name, struct stat *buffer)
+{
+ return (access_stat_ex(stat, name, buffer));
+}
+
+static int
+test_exec_exist(const char *name, char *real_name)
+{
+ struct stat sb;
+
+ if (stat(name, &sb) < 0 || !S_ISREG(sb.st_mode))
+ return (-1);
+
+ /* safe due to calculations in real_exec_name() */
+ memcpy(real_name, name, strlen(name) + 1);
+
+ return (0);
+}
+
+const char *
+real_exec_name(const char *name)
+{
+ char x_name[strlen(name) + MAX_X_SUFFIX_LEN + 1];
+ const char *real_name = name;
+
+ if (access_stat_ex(test_exec_exist, real_name, x_name) != -1)
+ /*XXX memory leak */
+ strdupx(real_name, x_name, ATEMP);
+
+ return (real_name);
+}
+
+/* OS/2 can process a command line up to 32 KiB */
+#define MAX_CMD_LINE_LEN 32768
+
+/* make a response file to pass a very long command line */
+static char *
+make_response_file(char * const *argv)
+{
+ char rsp_name_arg[] = "@mksh-rsp-XXXXXX";
+ char *rsp_name = &rsp_name_arg[1];
+ int arg_len = 0;
+ int i;
+
+ for (i = 0; argv[i]; i++)
+ arg_len += strlen(argv[i]) + 1;
+
+ /*
+ * If a length of command line is longer than MAX_CMD_LINE_LEN, then
+ * use a response file. OS/2 cannot process a command line longer
+ * than 32K. Of course, a response file cannot be recognised by a
+ * normal OS/2 program, that is, neither non-EMX or non-kLIBC. But
+ * it cannot accept a command line longer than 32K in itself. So
+ * using a response file in this case, is an acceptable solution.
+ */
+ if (arg_len > MAX_CMD_LINE_LEN) {
+ int fd;
+ char *result;
+
+ if ((fd = mkstemp(rsp_name)) == -1)
+ return (NULL);
+
+ /* write all the arguments except a 0th program name */
+ for (i = 1; argv[i]; i++) {
+ write(fd, argv[i], strlen(argv[i]));
+ write(fd, "\n", 1);
+ }
+
+ close(fd);
+ add_temp(rsp_name);
+ strdupx(result, rsp_name_arg, ATEMP);
+ return (result);
+ }
+
+ return (NULL);
+}
+
+/* alias of execve() */
+extern int _std_execve(const char *, char * const *, char * const *);
+
+/* replacement for execve() of kLIBC */
+int
+execve(const char *name, char * const *argv, char * const *envp)
+{
+ const char *exec_name;
+ FILE *fp;
+ char sign[2];
+ char *rsp_argv[3];
+ char *rsp_name_arg;
+ int pid;
+ int status;
+ int fd;
+ int rc;
+
+ /*
+ * #! /bin/sh : append .exe
+ * extproc sh : search sh.exe in PATH
+ */
+ exec_name = search_path(name, path, X_OK, NULL);
+ if (!exec_name) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /*-
+ * kLIBC execve() has problems when executing scripts.
+ * 1. it fails to execute a script if a directory whose name
+ * is same as an interpreter exists in a current directory.
+ * 2. it fails to execute a script not starting with sharpbang.
+ * 3. it fails to execute a batch file if COMSPEC is set to a shell
+ * incompatible with cmd.exe, such as /bin/sh.
+ * And ksh process scripts more well, so let ksh process scripts.
+ */
+ errno = 0;
+ if (!(fp = fopen(exec_name, "rb")))
+ errno = ENOEXEC;
+
+ if (!errno && fread(sign, 1, sizeof(sign), fp) != sizeof(sign))
+ errno = ENOEXEC;
+
+ if (fp && fclose(fp))
+ errno = ENOEXEC;
+
+ if (!errno &&
+ !((sign[0] == 'M' && sign[1] == 'Z') ||
+ (sign[0] == 'N' && sign[1] == 'E') ||
+ (sign[0] == 'L' && sign[1] == 'X')))
+ errno = ENOEXEC;
+
+ if (errno == ENOEXEC)
+ return (-1);
+
+ rsp_name_arg = make_response_file(argv);
+
+ if (rsp_name_arg) {
+ rsp_argv[0] = argv[0];
+ rsp_argv[1] = rsp_name_arg;
+ rsp_argv[2] = NULL;
+
+ argv = rsp_argv;
+ }
+
+ pid = spawnve(P_NOWAIT, exec_name, argv, envp);
+
+ afree(rsp_name_arg, ATEMP);
+
+ if (pid == -1) {
+ cleanup_temps();
+
+ return (-1);
+ }
+
+ /* close all opened handles */
+ for (fd = 0; fd < NUFILE; fd++) {
+ if (fcntl(fd, F_GETFD) == -1)
+ continue;
+
+ close(fd);
+ }
+
+ while ((rc = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
+ /* nothing */;
+
+ cleanup_temps();
+
+ /* Is this possible? And is this right? */
+ if (rc == -1)
+ return (-1);
+
+ if (WIFSIGNALED(status))
+ _exit(ksh_sigmask(WTERMSIG(status)));
+
+ _exit(WEXITSTATUS(status));
+}
+
+static struct temp *templist = NULL;
+
+static void
+add_temp(const char *name)
+{
+ struct temp *tp;
+
+ tp = alloc(offsetof(struct temp, tffn[0]) + strlen(name) + 1, APERM);
+ memcpy(tp->tffn, name, strlen(name) + 1);
+ tp->next = templist;
+ templist = tp;
+}
+
+/* alias of unlink() */
+extern int _std_unlink(const char *);
+
+/*
+ * Replacement for unlink() of kLIBC not supporting to remove files used by
+ * another processes.
+ */
+int
+unlink(const char *name)
+{
+ int rc;
+
+ rc = _std_unlink(name);
+ if (rc == -1 && errno != ENOENT)
+ add_temp(name);
+
+ return (rc);
+}
+
+static void
+cleanup_temps(void)
+{
+ struct temp *tp;
+ struct temp **tpnext;
+
+ for (tpnext = &templist, tp = templist; tp; tp = *tpnext) {
+ if (_std_unlink(tp->tffn) == 0 || errno == ENOENT) {
+ *tpnext = tp->next;
+ afree(tp, APERM);
+ } else {
+ tpnext = &tp->next;
+ }
+ }
+}
+
+static void
+cleanup(void)
+{
+ cleanup_temps();
+}
/*-
* Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015, 2016
+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#endif
#ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.791 2016/11/11 23:31:38 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.808 2017/04/12 17:38:46 tg Exp $");
#endif
-#define MKSH_VERSION "R54 2016/11/11"
+#define MKSH_VERSION "R55 2017/04/12"
/* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES
#endif
#ifdef __OS2__
+#define MKSH_UNIXROOT "/@unixroot"
+#else
+#define MKSH_UNIXROOT ""
+#endif
+
+#ifdef MKSH_DOSPATH
+#ifndef __GNUC__
+# error GCC extensions needed later on
+#endif
#define MKSH_PATHSEPS ";"
#define MKSH_PATHSEPC ';'
-#define MKSH_UNIXROOT "/@unixroot"
#else
#define MKSH_PATHSEPS ":"
#define MKSH_PATHSEPC ':'
-#define MKSH_UNIXROOT ""
#endif
#if !HAVE_FLOCK_DECL
EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
#ifdef MKSH_LEGACY_MODE
-#define KSH_VERSIONNAME "LEGACY"
+#define KSH_VERSIONNAME_ISLEGACY "LEGACY"
+#else
+#define KSH_VERSIONNAME_ISLEGACY "MIRBSD"
+#endif
+#ifdef MKSH_WITH_TEXTMODE
+#define KSH_VERSIONNAME_TEXTMODE " +TEXTMODE"
#else
-#define KSH_VERSIONNAME "MIRBSD"
+#define KSH_VERSIONNAME_TEXTMODE ""
+#endif
+#ifndef KSH_VERSIONNAME_VENDOR_EXT
+#define KSH_VERSIONNAME_VENDOR_EXT ""
#endif
-EXTERN const char initvsn[] E_INIT("KSH_VERSION=@(#)" KSH_VERSIONNAME \
- " KSH " MKSH_VERSION);
+EXTERN const char initvsn[] E_INIT("KSH_VERSION=@(#)" KSH_VERSIONNAME_ISLEGACY \
+ " KSH " MKSH_VERSION KSH_VERSIONNAME_TEXTMODE KSH_VERSIONNAME_VENDOR_EXT);
#define KSH_VERSION (initvsn + /* "KSH_VERSION=@(#)" */ 16)
EXTERN const char digits_uc[] E_INIT("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
#define mkssert(e) do { } while (/* CONSTCOND */ 0)
#endif
-#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 541)
+#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 551)
#error Must run Build.sh to compile this.
extern void thiswillneverbedefinedIhope(void);
int
} while (/* CONSTCOND */ 0)
#endif
-#ifdef MKSH_LEGACY_MODE
-#ifndef MKSH_NO_CMDLINE_EDITING
-#define MKSH_NO_CMDLINE_EDITING /* defined */
-#endif
-#undef MKSH_S_NOVI
-#define MKSH_S_NOVI 1
-#endif
-
#ifdef MKSH_SMALL
#ifndef MKSH_NOPWNAM
#define MKSH_NOPWNAM /* defined */
#define E_LOOP 5 /* executing for/while # */
#define E_ERRH 6 /* general error handler # */
#define E_GONE 7 /* hidden in child */
+#define E_EVAL 8 /* running eval # */
/* # indicates env has valid jbuf (see unwind()) */
/* struct env.flag values */
#ifndef HAVE_STRING_POOLING /* helpers for pooled strings */
EXTERN const char T4spaces[] E_INIT(" ");
-#define T1space (T4spaces + 3)
-EXTERN const char Tcolsp[] E_INIT(": ");
+#define T1space (Treal_sp2 + 5)
+#define Tcolsp (Tf_sD_ + 2)
EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n");
#define TC_IFSWS (TC_LEX1 + 7)
EXTERN const char TFCEDIT_dollaru[] E_INIT("${FCEDIT:-/bin/ed} $_");
EXTERN const char Taugo[] E_INIT("augo");
EXTERN const char Tbracket[] E_INIT("[");
#define Tdot (Tsgdot + 2)
-EXTERN const char Talias[] E_INIT("alias");
-EXTERN const char Tbadsubst[] E_INIT("bad substitution");
+#define Talias (Tunalias + 2)
+EXTERN const char Tbadnum[] E_INIT("bad number");
+#define Tbadsubst (Tfg_badsubst + 10)
EXTERN const char Tbg[] E_INIT("bg");
EXTERN const char Tbad_bsize[] E_INIT("bad shf/buf/bsize");
#define Tbsize (Tbad_bsize + 12)
EXTERN const char Tbad_sig_ss[] E_INIT("%s: bad signal '%s'");
#define Tbad_sig_s (Tbad_sig_ss + 4)
-EXTERN const char Tgbuiltin[] E_INIT("=builtin");
-#define Tbuiltin (Tgbuiltin + 1)
+EXTERN const char Tsgbreak[] E_INIT("*=break");
+#define Tbreak (Tsgbreak + 2)
+EXTERN const char T__builtin[] E_INIT("-\\builtin");
+#define T_builtin (T__builtin + 1)
+#define Tbuiltin (T__builtin + 2)
EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes");
EXTERN const char Tcant_cd[] E_INIT("restricted shell - can't cd");
EXTERN const char Tcant_find[] E_INIT("can't find");
EXTERN const char Tbcat[] E_INIT("!cat");
#define Tcat (Tbcat + 1)
#define Tcd (Tcant_cd + 25)
-EXTERN const char Tcommand[] E_INIT("command");
+#define T_command (T_funny_command + 9)
+#define Tcommand (T_funny_command + 10)
+EXTERN const char Tsgcontinue[] E_INIT("*=continue");
+#define Tcontinue (Tsgcontinue + 2)
EXTERN const char Tcreate[] E_INIT("create");
EXTERN const char TELIF_unexpected[] E_INIT("TELIF unexpected");
EXTERN const char TEXECSHELL[] E_INIT("EXECSHELL");
-EXTERN const char Tsgexport[] E_INIT("*=export");
-#define Texport (Tsgexport + 2)
+EXTERN const char Tdsgexport[] E_INIT("^*=export");
+#define Texport (Tdsgexport + 3)
#ifdef __OS2__
EXTERN const char Textproc[] E_INIT("extproc");
#endif
EXTERN const char Tfalse[] E_INIT("false");
EXTERN const char Tfg[] E_INIT("fg");
EXTERN const char Tfg_badsubst[] E_INIT("fileglob: bad substitution");
-EXTERN const char Tfile[] E_INIT("file");
+#define Tfile (Tfile_fd + 20)
EXTERN const char Tfile_fd[] E_INIT("function definition file");
EXTERN const char TFPATH[] E_INIT("FPATH");
EXTERN const char T_function[] E_INIT(" function");
#define Tfunction (T_function + 1)
-EXTERN const char T_funny_command[] E_INIT("funny $() command");
+EXTERN const char T_funny_command[] E_INIT("funny $()-command");
EXTERN const char Tgetopts[] E_INIT("getopts");
-EXTERN const char Thistory[] E_INIT("history");
+#define Thistory (Tnot_in_history + 7)
EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented");
+EXTERN const char Tinvname[] E_INIT("%s: invalid %s name");
EXTERN const char Tjobs[] E_INIT("jobs");
EXTERN const char Tjob_not_started[] E_INIT("job not started");
EXTERN const char Tmksh[] E_INIT("mksh");
-EXTERN const char Tname[] E_INIT("name");
+#define Tname (Tinvname + 15)
EXTERN const char Tno_args[] E_INIT("missing argument");
EXTERN const char Tno_OLDPWD[] E_INIT("no OLDPWD");
EXTERN const char Tnot_ident[] E_INIT("is not an identifier");
#define TOLDPWD (Tno_OLDPWD + 3)
#define Topen (Tcant_open + 6)
#define TPATH (TFPATH + 1)
-EXTERN const char Tpv[] E_INIT("pv");
+#define Tpv (TpVv + 1)
EXTERN const char TpVv[] E_INIT("Vpv");
#define TPWD (Tno_OLDPWD + 6)
-EXTERN const char Tread[] E_INIT("read");
-EXTERN const char Tsgreadonly[] E_INIT("*=readonly");
-#define Treadonly (Tsgreadonly + 2)
+#define Tread (Tshf_read + 4)
+EXTERN const char Tdsgreadonly[] E_INIT("^*=readonly");
+#define Treadonly (Tdsgreadonly + 3)
EXTERN const char Tredirection_dup[] E_INIT("can't finish (dup) redirection");
#define Tredirection (Tredirection_dup + 19)
-EXTERN const char Treal_sp1[] E_INIT("real ");
+#define Treal_sp1 (Treal_sp2 + 1)
EXTERN const char Treal_sp2[] E_INIT(" real ");
EXTERN const char Treq_arg[] E_INIT("requires an argument");
EXTERN const char Tselect[] E_INIT("select");
EXTERN const char Tsgset[] E_INIT("*=set");
-#define Tset (Tsgset + 2)
+#define Tset (Tf_parm + 18)
#define Tsh (Tmksh + 2)
#define TSHELL (TEXECSHELL + 4)
+#define Tshell (Ttoo_many_files + 23)
EXTERN const char Tshf_read[] E_INIT("shf_read");
EXTERN const char Tshf_write[] E_INIT("shf_write");
+EXTERN const char Tgsource[] E_INIT("=source");
+#define Tsource (Tgsource + 1)
EXTERN const char Tj_suspend[] E_INIT("j_suspend");
#define Tsuspend (Tj_suspend + 2)
EXTERN const char Tsynerr[] E_INIT("syntax error");
EXTERN const char Ttime[] E_INIT("time");
EXTERN const char Ttoo_many_args[] E_INIT("too many arguments");
+EXTERN const char Ttoo_many_files[] E_INIT("too many open files in shell");
EXTERN const char Ttrue[] E_INIT("true");
EXTERN const char Ttty_fd_dupof[] E_INIT("dup of tty fd");
#define Ttty_fd (Ttty_fd_dupof + 7)
-EXTERN const char Tgtypeset[] E_INIT("=typeset");
-#define Ttypeset (Tgtypeset + 1)
+EXTERN const char Tdgtypeset[] E_INIT("^=typeset");
+#define Ttypeset (Tdgtypeset + 2)
#define Tugo (Taugo + 1)
EXTERN const char Tunalias[] E_INIT("unalias");
#define Tunexpected (TELIF_unexpected + 6)
+EXTERN const char Tunexpected_type[] E_INIT("%s: unexpected %s type %d");
EXTERN const char Tunknown_option[] E_INIT("unknown option");
-EXTERN const char Tuser_sp1[] E_INIT("user ");
+EXTERN const char Tunwind[] E_INIT("unwind");
+#define Tuser_sp1 (Tuser_sp2 + 1)
EXTERN const char Tuser_sp2[] E_INIT(" user ");
#define Twrite (Tshf_write + 4)
EXTERN const char Tf__S[] E_INIT(" %S");
-EXTERN const char Tf__d[] E_INIT(" %d");
+#define Tf__d (Tunexpected_type + 22)
EXTERN const char Tf__ss[] E_INIT(" %s%s");
-EXTERN const char Tf__sN[] E_INIT(" %s\n");
+#define Tf__sN (Tf_s_s_sN + 5)
EXTERN const char Tf_sSs[] E_INIT("%s/%s");
-EXTERN const char Tf_T[] E_INIT("%T");
+#define Tf_T (Tf_s_T + 3)
EXTERN const char Tf_dN[] E_INIT("%d\n");
EXTERN const char Tf_s_[] E_INIT("%s ");
EXTERN const char Tf_s_T[] E_INIT("%s %T");
EXTERN const char Tf_s_s_sN[] E_INIT("%s %s %s\n");
-EXTERN const char Tf_s_s[] E_INIT("%s %s");
-EXTERN const char Tf_s_sD_s[] E_INIT("%s %s: %s");
+#define Tf_s_s (Tf_sD_s_s + 4)
+#define Tf_s_sD_s (Tf_cant_ss_s + 6)
EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s");
EXTERN const char Tf_sD_[] E_INIT("%s: ");
EXTERN const char Tf_szs[] E_INIT("%s: %zd %s");
EXTERN const char Tf_parm[] E_INIT("%s: parameter not set");
EXTERN const char Tf_coproc[] E_INIT("-p: %s");
-EXTERN const char Tf_cant[] E_INIT("can't %s %s: %s");
-EXTERN const char Tf_heredoc[] E_INIT("here document '%s' unclosed\n");
+EXTERN const char Tf_cant_s[] E_INIT("%s: can't %s");
+EXTERN const char Tf_cant_ss_s[] E_INIT("can't %s %s: %s");
+EXTERN const char Tf_heredoc[] E_INIT("here document '%s' unclosed");
#if HAVE_MKNOD
EXTERN const char Tf_nonnum[] E_INIT("non-numeric %s %s '%s'");
#endif
EXTERN const char Tf_S_[] E_INIT("%S ");
#define Tf_S (Tf__S + 1)
-EXTERN const char Tf_lu[] E_INIT("%lu");
+#define Tf_lu (Tf_toolarge + 17)
EXTERN const char Tf_toolarge[] E_INIT("%s %s too large: %lu");
EXTERN const char Tf_ldfailed[] E_INIT("%s %s(%d, %ld) failed: %s");
-#define Tf_ss (Tf__ss + 1)
+#define Tf_ss (Tf_sss + 2)
EXTERN const char Tf_sss[] E_INIT("%s%s%s");
EXTERN const char Tf_sD_s_sD_s[] E_INIT("%s: %s %s: %s");
-EXTERN const char Tf_toomany[] E_INIT("too many %ss\n");
+EXTERN const char Tf_toomany[] E_INIT("too many %ss");
EXTERN const char Tf_sd[] E_INIT("%s %d");
-#define Tf_s (Tf__ss + 3)
+#define Tf_s (Tf_temp + 28)
EXTERN const char Tft_end[] E_INIT("%;");
EXTERN const char Tft_R[] E_INIT("%R");
-#define Tf_d (Tf__d + 1)
+#define Tf_d (Tunexpected_type + 23)
EXTERN const char Tf_sD_s_qs[] E_INIT("%s: %s '%s'");
EXTERN const char Tf_ro[] E_INIT("read-only: %s");
EXTERN const char Tf_flags[] E_INIT("%s: flags 0x%X");
EXTERN const char Tf_sD_sD_s[] E_INIT("%s: %s: %s");
EXTERN const char Tf__c_[] E_INIT("-%c ");
EXTERN const char Tf_sD_s_s[] E_INIT("%s: %s %s");
-#define Tf_sN (Tf__sN + 1)
-#define Tf_sD_s (Tf_s_sD_s + 3)
+#define Tf_sN (Tf_s_s_sN + 6)
+#define Tf_sD_s (Tf_temp + 24)
EXTERN const char T_devtty[] E_INIT("/dev/tty");
#else /* helpers for string pooling */
#define T4spaces " "
#define Tbracket "["
#define Tdot "."
#define Talias "alias"
+#define Tbadnum "bad number"
#define Tbadsubst "bad substitution"
#define Tbg "bg"
#define Tbad_bsize "bad shf/buf/bsize"
#define Tbsize "bsize"
#define Tbad_sig_ss "%s: bad signal '%s'"
#define Tbad_sig_s "bad signal '%s'"
-#define Tgbuiltin "=builtin"
+#define Tsgbreak "*=break"
+#define Tbreak "break"
+#define T__builtin "-\\builtin"
+#define T_builtin "\\builtin"
#define Tbuiltin "builtin"
#define Toomem "can't allocate %zu data bytes"
#define Tcant_cd "restricted shell - can't cd"
#define Tbcat "!cat"
#define Tcat "cat"
#define Tcd "cd"
+#define T_command "-command"
#define Tcommand "command"
+#define Tsgcontinue "*=continue"
+#define Tcontinue "continue"
#define Tcreate "create"
#define TELIF_unexpected "TELIF unexpected"
#define TEXECSHELL "EXECSHELL"
-#define Tsgexport "*=export"
+#define Tdsgexport "^*=export"
#define Texport "export"
#ifdef __OS2__
#define Textproc "extproc"
#define TFPATH "FPATH"
#define T_function " function"
#define Tfunction "function"
-#define T_funny_command "funny $() command"
+#define T_funny_command "funny $()-command"
#define Tgetopts "getopts"
#define Thistory "history"
#define Tintovfl "integer overflow %zu %c %zu prevented"
+#define Tinvname "%s: invalid %s name"
#define Tjobs "jobs"
#define Tjob_not_started "job not started"
#define Tmksh "mksh"
#define TpVv "Vpv"
#define TPWD "PWD"
#define Tread "read"
-#define Tsgreadonly "*=readonly"
+#define Tdsgreadonly "^*=readonly"
#define Treadonly "readonly"
#define Tredirection_dup "can't finish (dup) redirection"
#define Tredirection "redirection"
#define Tset "set"
#define Tsh "sh"
#define TSHELL "SHELL"
+#define Tshell "shell"
#define Tshf_read "shf_read"
#define Tshf_write "shf_write"
+#define Tgsource "=source"
+#define Tsource "source"
#define Tj_suspend "j_suspend"
#define Tsuspend "suspend"
#define Tsynerr "syntax error"
#define Ttime "time"
#define Ttoo_many_args "too many arguments"
+#define Ttoo_many_files "too many open files in shell"
#define Ttrue "true"
#define Ttty_fd_dupof "dup of tty fd"
#define Ttty_fd "tty fd"
-#define Tgtypeset "=typeset"
+#define Tdgtypeset "^=typeset"
#define Ttypeset "typeset"
#define Tugo "ugo"
#define Tunalias "unalias"
#define Tunexpected "unexpected"
+#define Tunexpected_type "%s: unexpected %s type %d"
#define Tunknown_option "unknown option"
+#define Tunwind "unwind"
#define Tuser_sp1 "user "
#define Tuser_sp2 " user "
#define Twrite "write"
#define Tf_szs "%s: %zd %s"
#define Tf_parm "%s: parameter not set"
#define Tf_coproc "-p: %s"
-#define Tf_cant "can't %s %s: %s"
-#define Tf_heredoc "here document '%s' unclosed\n"
+#define Tf_cant_s "%s: can't %s"
+#define Tf_cant_ss_s "can't %s %s: %s"
+#define Tf_heredoc "here document '%s' unclosed"
#if HAVE_MKNOD
#define Tf_nonnum "non-numeric %s %s '%s'"
#endif
#define Tf_ss "%s%s"
#define Tf_sss "%s%s%s"
#define Tf_sD_s_sD_s "%s: %s %s: %s"
-#define Tf_toomany "too many %ss\n"
+#define Tf_toomany "too many %ss"
#define Tf_sd "%s %d"
#define Tf_s "%s"
#define Tft_end "%;"
/*
* fast character classes
*/
-#define C_ALPHA BIT(0) /* a-z_A-Z */
+#define C_ALPHX BIT(0) /* A-Za-z_ */
#define C_DIGIT BIT(1) /* 0-9 */
#define C_LEX1 BIT(2) /* \t \n\0|&;<>() */
#define C_VAR1 BIT(3) /* *@#!$-? */
#define C_SUBOP1 BIT(5) /* "=-+?" */
#define C_QUOTE BIT(6) /* \t\n "#$&'()*;<=>?[\]`| (needing quoting) */
#define C_IFS BIT(7) /* $IFS */
-#define C_SUBOP2 BIT(8) /* "#%" (magic, see below) */
extern unsigned char chtypes[];
-#define ctype(c, t) tobool( ((t) == C_SUBOP2) ? \
- (((c) == '#' || (c) == '%') ? 1 : 0) : \
- (chtypes[(unsigned char)(c)] & (t)) )
+#define ctype(c, t) tobool(chtypes[(unsigned char)(c)] & (t))
#define ord(c) ((int)(unsigned char)(c))
-#define ksh_isalphx(c) ctype((c), C_ALPHA)
-#define ksh_isalnux(c) ctype((c), C_ALPHA | C_DIGIT)
-#define ksh_isdigit(c) (((c) >= '0') && ((c) <= '9'))
+#define ksh_issubop2(c) tobool((c) == ord('#') || (c) == ord('%'))
+#define ksh_isalias(c) (ctype((c), C_ALPHX | C_DIGIT) || (c) == ord('!') || \
+ (c) == ord('%') || (c) == ord(',') || \
+ (c) == ord('@') || (c) == ord('-'))
+#define ksh_isalpha(c) (ctype((c), C_ALPHX) && (c) != ord('_'))
+#define ksh_isalphx(c) ctype((c), C_ALPHX)
+#define ksh_isalnux(c) ctype((c), C_ALPHX | C_DIGIT)
+#define ksh_isdigit(c) ctype((c), C_DIGIT)
#define ksh_islower(c) (((c) >= 'a') && ((c) <= 'z'))
#define ksh_isupper(c) (((c) >= 'A') && ((c) <= 'Z'))
#define ksh_tolower(c) (ksh_isupper(c) ? (c) - 'A' + 'a' : (c))
/* name of called builtin function (used by error functions) */
EXTERN const char *builtin_argv0;
-/* is called builtin SPEC_BI? (also KEEPASN, odd use though) */
+/* is called builtin a POSIX special builtin? (error functions only) */
EXTERN bool builtin_spec;
/* current working directory */
};
EXTERN struct tbl *vtemp;
-/* set by global() and local() */
+/* set by isglobal(), global() and local() */
EXTERN bool last_lookup_was_array;
/* common flag bits */
#define SPEC_BI BIT(12) /* a POSIX special builtin */
#define LOWER_BI BIT(13) /* (with LOW_BI) override even w/o flags */
#define LOW_BI BIT(14) /* external utility overrides built-in one */
+#define DECL_UTIL BIT(15) /* is declaration utility */
+#define DECL_FWDR BIT(16) /* is declaration utility forwarder */
/*
* Attributes that can be set by the user (used to decide if an unset
#define ADELIM 12 /* arbitrary delimiter: ${foo:2:3} ${foo/bar/baz} */
#define FUNSUB 14 /* ${ foo;} substitution (NUL terminated) */
#define VALSUB 15 /* ${|foo;} substitution (NUL terminated) */
+#define COMASUB 16 /* `…` substitution (COMSUB but expand aliases) */
+#define FUNASUB 17 /* function substitution but expand aliases */
/*
* IO redirection
char *do_tilde(char *);
/* exec.c */
int execute(struct op * volatile, volatile int, volatile int * volatile);
-int shcomexec(const char **);
+int c_builtin(const char **);
+struct tbl *get_builtin(const char *);
struct tbl *findfunc(const char *, uint32_t, bool);
int define(const char *, struct op *);
const char *builtin(const char *, int (*)(const char **));
int c_whence(const char **);
int c_command(const char **);
int c_typeset(const char **);
+bool valid_alias_name(const char *);
int c_alias(const char **);
int c_unalias(const char **);
int c_let(const char **);
int timex(struct op *, int, volatile int *);
void timex_hook(struct op *, char ** volatile *);
int c_exec(const char **);
-/* dummy function (just need pointer value), special case in comexec() */
-#define c_builtin shcomexec
int c_test(const char **);
#if HAVE_MKNOD
int c_mknod(const char **);
/* main.c */
int include(const char *, int, const char **, bool);
int command(const char *, int);
-int shell(Source * volatile, volatile bool);
+int shell(Source * volatile, volatile int);
/* argument MUST NOT be 0 */
void unwind(int) MKSH_A_NORETURN;
void newenv(int);
char *strndup_i(const char *, size_t, Area *);
#endif
int unbksl(bool, int (*)(void), void (*)(int));
+#ifdef __OS2__
+/* os2.c */
+void os2_init(int *, const char ***);
+void setextlibpath(const char *, const char *);
+int access_ex(int (*)(const char *, int), const char *, int);
+int stat_ex(const char *, struct stat *);
+const char *real_exec_name(const char *);
+#endif
/* shf.c */
struct shf *shf_open(const char *, int, int, int);
struct shf *shf_fdopen(int, int, struct shf *);
ssize_t shf_vfprintf(struct shf *, const char *, va_list)
MKSH_A_FORMAT(__printf__, 2, 0);
/* syn.c */
-int assign_command(const char *, bool) MKSH_A_PURE;
void initkeywords(void);
-struct op *compile(Source *, bool);
+struct op *compile(Source *, bool, bool);
bool parse_usec(const char *, struct timeval *);
char *yyrecursive(int);
void yyrecursive_pop(bool);
void initvar(void);
struct block *varsearch(struct block *, struct tbl **, const char *, uint32_t);
struct tbl *global(const char *);
+struct tbl *isglobal(const char *, bool);
struct tbl *local(const char *, bool);
char *str_val(struct tbl *);
int setstr(struct tbl *, const char *, int);
/* non-operator */
TO_NONOP = 0,
/* unary operators */
- TO_STNZE, TO_STZER, TO_OPTION,
+ TO_STNZE, TO_STZER, TO_ISSET, TO_OPTION,
TO_FILAXST,
TO_FILEXST,
TO_FILREG, TO_FILBDEV, TO_FILCDEV, TO_FILSYM, TO_FILFIFO, TO_FILSOCK,
extern int tty_init_fd(void); /* initialise tty_fd, tty_devtty */
#ifdef __OS2__
-#ifndef __GNUC__
-# error oops?
-#endif
#define binopen2(path,flags) __extension__({ \
int binopen2_fd = open((path), (flags) | O_BINARY); \
if (binopen2_fd >= 0) \
setmode(binopen3_fd, O_BINARY); \
(binopen3_fd); \
})
+#else
+#define binopen2(path,flags) open((path), (flags) | O_BINARY)
+#define binopen3(path,flags,mode) open((path), (flags) | O_BINARY, (mode))
+#endif
+
+#ifdef MKSH_DOSPATH
#define mksh_abspath(s) __extension__({ \
const char *mksh_abspath_s = (s); \
(mksh_cdirsep(mksh_abspath_s[0]) || \
- (ksh_isalphx(mksh_abspath_s[0]) && \
+ (ksh_isalpha(mksh_abspath_s[0]) && \
mksh_abspath_s[1] == ':')); \
})
#define mksh_cdirsep(c) __extension__({ \
char mksh_cdirsep_c = (c); \
(mksh_cdirsep_c == '/' || mksh_cdirsep_c == '\\'); \
})
-/*
- * I've seen mksh_sdirsep(s) and mksh_vdirsep(s) but need to think
- * more about the OS/2 port (and, possibly, toy with it) before I
- * can merge this upstream, but good job so far @komh, thanks!
- */
+#define mksh_sdirsep(s) __extension__({ \
+ const char *mksh_sdirsep_s = (s); \
+ ((char *)((ksh_isalphx(mksh_sdirsep_s[0]) && \
+ mksh_sdirsep_s[1] == ':' && \
+ !mksh_cdirsep(mksh_sdirsep_s[2])) ? \
+ (mksh_sdirsep_s + 1) : strpbrk(mksh_sdirsep_s, "/\\"))); \
+})
+#define mksh_vdirsep(s) (mksh_sdirsep((s)) != NULL)
#else
-#define binopen2(path,flags) open((path), (flags) | O_BINARY)
-#define binopen3(path,flags,mode) open((path), (flags) | O_BINARY, (mode))
#define mksh_abspath(s) ((s)[0] == '/')
#define mksh_cdirsep(c) ((c) == '/')
#define mksh_sdirsep(s) strchr((s), '/')
/* +++ GENERATED FILE +++ DO NOT EDIT +++ */
/*-
- * Copyright (c) 2013, 2014, 2015
+ * Copyright (c) 2013, 2014, 2015, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#ifndef SHFLAGS_OPTCS
#if defined(SHFLAGS_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.4 2015/12/12 21:08:44 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.5 2017/02/18 02:33:15 tg Exp $");
#elif defined(SHFLAGS_ENUMS)
#define FN(sname,cname,flags,ochar) cname,
#define F0(sname,cname,flags,ochar) cname = 0,
FN("bgnice", FBGNICE, OF_ANY, 0)
#endif
FN("braceexpand", FBRACEEXPAND, OF_ANY, 0)
-#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+#ifndef MKSH_NO_CMDLINE_EDITING
FN("emacs", FEMACS, OF_ANY, 0)
#endif
FN("errexit", FERREXIT, OF_ANY, 'e')
-#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+#ifndef MKSH_NO_CMDLINE_EDITING
FN("gmacs", FGMACS, OF_ANY, 0)
#endif
FN("ignoreeof", FIGNOREEOF, OF_ANY, 0)
FN("trackall", FTRACKALL, OF_ANY, 'h')
FN("utf8-mode", FUNICODE, OF_ANY, 'U')
FN("verbose", FVERBOSE, OF_ANY, 'v')
-#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+#ifndef MKSH_NO_CMDLINE_EDITING
FN("vi", FVI, OF_ANY, 0)
#endif
-#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+#ifndef MKSH_NO_CMDLINE_EDITING
FN("vi-esccomplete", FVIESCCOMPLETE, OF_ANY, 0)
#endif
-#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+#ifndef MKSH_NO_CMDLINE_EDITING
FN("vi-tabcomplete", FVITABCOMPLETE, OF_ANY, 0)
#endif
-#if !defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+#ifndef MKSH_NO_CMDLINE_EDITING
FN("viraw", FVIRAW, OF_ANY, 0)
#endif
FN("xtrace", FXTRACE, OF_ANY, 'x')
/*-
- * Copyright (c) 2013, 2014, 2015
+ * Copyright (c) 2013, 2014, 2015, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
*/
@SHFLAGS_DEFNS
-__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.4 2015/12/12 21:08:44 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.5 2017/02/18 02:33:15 tg Exp $");
@SHFLAGS_ENUMS
#define FN(sname,cname,flags,ochar) cname,
#define F0(sname,cname,flags,ochar) cname = 0,
FN("braceexpand", FBRACEEXPAND, OF_ANY
/* ./. Emacs command line editing mode */
->|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+>|!MKSH_NO_CMDLINE_EDITING
FN("emacs", FEMACS, OF_ANY
/* -e quit on error */
FN("errexit", FERREXIT, OF_ANY
/* ./. Emacs command line editing mode, gmacs variant */
->|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+>|!MKSH_NO_CMDLINE_EDITING
FN("gmacs", FGMACS, OF_ANY
/* ./. reading EOF does not exit */
FN("verbose", FVERBOSE, OF_ANY
/* ./. Vi command line editing mode */
->|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+>|!MKSH_NO_CMDLINE_EDITING
FN("vi", FVI, OF_ANY
/* ./. enable ESC as file name completion character (non-standard) */
->|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+>|!MKSH_NO_CMDLINE_EDITING
FN("vi-esccomplete", FVIESCCOMPLETE, OF_ANY
/* ./. enable Tab as file name completion character (non-standard) */
->|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+>|!MKSH_NO_CMDLINE_EDITING
FN("vi-tabcomplete", FVITABCOMPLETE, OF_ANY
/* ./. always read in raw mode (no effect) */
->|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
+>|!MKSH_NO_CMDLINE_EDITING
FN("viraw", FVIRAW, OF_ANY
/* -x execution trace (display commands as they are run) */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
- * 2012, 2013, 2015, 2016
+ * 2012, 2013, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.76 2016/07/25 00:04:47 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.79 2017/04/12 17:08:49 tg Exp $");
/* flags to shf_emptybuf() */
#define EB_READSW 0x01 /* about to switch to reading */
int
shf_flush(struct shf *shf)
{
- if (shf->flags & SHF_STRING)
- return ((shf->flags & SHF_WR) ? -1 : 0);
+ int rv = 0;
- if (shf->fd < 0)
+ if (shf->flags & SHF_STRING)
+ rv = (shf->flags & SHF_WR) ? -1 : 0;
+ else if (shf->fd < 0)
internal_errorf(Tf_sD_s, "shf_flush", "no fd");
-
- if (shf->flags & SHF_ERROR) {
+ else if (shf->flags & SHF_ERROR) {
errno = shf->errnosv;
- return (-1);
- }
-
- if (shf->flags & SHF_READING) {
+ rv = -1;
+ } else if (shf->flags & SHF_READING) {
shf->flags &= ~(SHF_EOF | SHF_READING);
if (shf->rnleft > 0) {
- lseek(shf->fd, (off_t)-shf->rnleft, SEEK_CUR);
+ if (lseek(shf->fd, (off_t)-shf->rnleft,
+ SEEK_CUR) == -1) {
+ shf->flags |= SHF_ERROR;
+ shf->errnosv = errno;
+ rv = -1;
+ }
shf->rnleft = 0;
shf->rp = shf->buf;
}
- return (0);
} else if (shf->flags & SHF_WRITING)
- return (shf_emptybuf(shf, 0));
+ rv = shf_emptybuf(shf, 0);
- return (0);
+ return (rv);
}
/*
shf->rnleft -= ncopy;
buf += ncopy;
bsize -= ncopy;
+#ifdef MKSH_WITH_TEXTMODE
+ if (end && buf > orig_buf + 1 && buf[-2] == '\r') {
+ buf--;
+ bsize++;
+ buf[-1] = '\n';
+ }
+#endif
} while (!end && bsize);
+#ifdef MKSH_WITH_TEXTMODE
+ if (!bsize && buf[-1] == '\r') {
+ int c = shf_getc(shf);
+ if (c == '\n')
+ buf[-1] = '\n';
+ else if (c != -1)
+ shf_ungetc(c, shf);
+ }
+#endif
*buf = '\0';
return (buf);
}
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- * 2011, 2012, 2013, 2014, 2015, 2016
+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.115 2016/09/01 12:59:12 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.120 2017/04/06 01:59:57 tg Exp $");
struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */
struct yyrecursive_state *next;
struct ioword **old_herep;
int old_symbol;
- int old_salias;
int old_nesting_type;
bool old_reject;
};
-static void yyparse(void);
-static struct op *pipeline(int);
-static struct op *andor(void);
-static struct op *c_list(bool);
+static void yyparse(bool);
+static struct op *pipeline(int, int);
+static struct op *andor(int);
+static struct op *c_list(int, bool);
static struct ioword *synio(int);
-static struct op *nested(int, int, int);
-static struct op *get_command(int);
-static struct op *dogroup(void);
-static struct op *thenpart(void);
-static struct op *elsepart(void);
-static struct op *caselist(void);
-static struct op *casepart(int);
-static struct op *function_body(char *, bool);
-static char **wordlist(void);
+static struct op *nested(int, int, int, int);
+static struct op *get_command(int, int);
+static struct op *dogroup(int);
+static struct op *thenpart(int);
+static struct op *elsepart(int);
+static struct op *caselist(int);
+static struct op *casepart(int, int);
+static struct op *function_body(char *, int, bool);
+static char **wordlist(int);
static struct op *block(int, struct op *, struct op *);
static struct op *newtp(int);
static void syntaxerr(const char *) MKSH_A_NORETURN;
static bool reject; /* token(cf) gets symbol again */
static int symbol; /* yylex value */
-static int sALIAS = ALIAS; /* 0 in yyrecursive */
#define REJECT (reject = true)
#define ACCEPT (reject = false)
static const char Tesac[] = "esac";
static void
-yyparse(void)
+yyparse(bool doalias)
{
int c;
ACCEPT;
- outtree = c_list(source->type == SSTRING);
+ outtree = c_list(doalias ? ALIAS : 0, source->type == SSTRING);
c = tpeek(0);
if (c == 0 && !outtree)
outtree = newtp(TEOF);
}
static struct op *
-pipeline(int cf)
+pipeline(int cf, int sALIAS)
{
struct op *t, *p, *tl = NULL;
- t = get_command(cf);
+ t = get_command(cf, sALIAS);
if (t != NULL) {
while (token(0) == '|') {
- if ((p = get_command(CONTIN)) == NULL)
+ if ((p = get_command(CONTIN, sALIAS)) == NULL)
syntaxerr(NULL);
if (tl == NULL)
t = tl = block(TPIPE, t, p);
}
static struct op *
-andor(void)
+andor(int sALIAS)
{
struct op *t, *p;
int c;
- t = pipeline(0);
+ t = pipeline(0, sALIAS);
if (t != NULL) {
while ((c = token(0)) == LOGAND || c == LOGOR) {
- if ((p = pipeline(CONTIN)) == NULL)
+ if ((p = pipeline(CONTIN, sALIAS)) == NULL)
syntaxerr(NULL);
t = block(c == LOGAND? TAND: TOR, t, p);
}
}
static struct op *
-c_list(bool multi)
+c_list(int sALIAS, bool multi)
{
struct op *t = NULL, *p, *tl = NULL;
int c;
bool have_sep;
while (/* CONSTCOND */ 1) {
- p = andor();
+ p = andor(sALIAS);
/*
* Token has always been read/rejected at this point, so
* we don't worry about what flags to pass token()
}
static struct op *
-nested(int type, int smark, int emark)
+nested(int type, int smark, int emark, int sALIAS)
{
struct op *t;
struct nesting_state old_nesting;
nesting_push(&old_nesting, smark);
- t = c_list(true);
+ t = c_list(sALIAS, true);
musthave(emark, KEYWORD|sALIAS);
nesting_pop(&old_nesting);
return (block(type, t, NULL));
}
+static const char builtin_cmd[] = {
+ QCHAR, '\\', CHAR, 'b', CHAR, 'u', CHAR, 'i',
+ CHAR, 'l', CHAR, 't', CHAR, 'i', CHAR, 'n', EOS
+};
static const char let_cmd[] = {
- QCHAR, 'l', CHAR, 'e', CHAR, 't', CHAR, ']', EOS
+ CHAR, 'l', CHAR, 'e', CHAR, 't', EOS
};
static const char setA_cmd0[] = {
- QCHAR, 's', CHAR, 'e', CHAR, 't', EOS
+ CHAR, 's', CHAR, 'e', CHAR, 't', EOS
};
static const char setA_cmd1[] = {
CHAR, '-', CHAR, 'A', EOS
};
static struct op *
-get_command(int cf)
+get_command(int cf, int sALIAS)
{
struct op *t;
int c, iopn = 0, syniocf, lno;
t->lineno = source->line;
goto get_command_start;
while (/* CONSTCOND */ 1) {
- bool check_assign_cmd;
+ bool check_decl_utility;
if (XPsize(args) == 0) {
get_command_start:
- check_assign_cmd = true;
+ check_decl_utility = true;
cf = sALIAS | CMDASN;
} else if (t->u.evalflags)
cf = CMDWORD | CMDASN;
case LWORD:
ACCEPT;
- /*
- * the iopn == 0 and XPsize(vars) == 0 are
- * dubious but AT&T ksh acts this way
- */
- if (iopn == 0 && XPsize(vars) == 0 &&
- check_assign_cmd) {
- if (assign_command(ident, false))
+ if (check_decl_utility) {
+ struct tbl *tt = get_builtin(ident);
+ uint32_t flag;
+
+ flag = tt ? tt->flag : 0;
+ if (flag & DECL_UTIL)
t->u.evalflags = DOVACHECK;
- else if (strcmp(ident, Tcommand) != 0)
- check_assign_cmd = false;
+ if (!(flag & DECL_FWDR))
+ check_decl_utility = false;
}
if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
is_wdvarassign(yylval.cp))
tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
/* construct new args strings */
+ XPput(args, wdcopy(builtin_cmd, ATEMP));
XPput(args, wdcopy(setA_cmd0, ATEMP));
XPput(args, wdcopy(setA_cmd1, ATEMP));
XPput(args, tcp);
syntaxerr(NULL);
ACCEPT;
musthave(/*(*/')', 0);
- t = function_body(XPptrv(args)[0], false);
+ t = function_body(XPptrv(args)[0],
+ sALIAS, false);
}
goto Leave;
Subshell:
subshell_nesting_type_saved = subshell_nesting_type;
subshell_nesting_type = ')';
- t = nested(TPAREN, '(', ')');
+ t = nested(TPAREN, '(', ')', sALIAS);
subshell_nesting_type = subshell_nesting_type_saved;
break;
}
case '{': /*}*/
- t = nested(TBRACE, '{', '}');
+ t = nested(TBRACE, '{', '}', sALIAS);
break;
case MDPAREN:
}
t = newtp(TCOM);
t->lineno = lno;
+ XPput(args, wdcopy(builtin_cmd, ATEMP));
XPput(args, wdcopy(let_cmd, ATEMP));
XPput(args, yylval.cp);
break;
t = newtp((c == FOR) ? TFOR : TSELECT);
musthave(LWORD, CMDASN);
if (!is_wdvarname(yylval.cp, true))
- yyerror("%s: bad identifier\n",
+ yyerror("%s: bad identifier",
c == FOR ? "for" : Tselect);
strdupx(t->str, ident, ATEMP);
nesting_push(&old_nesting, c);
- t->vars = wordlist();
- t->left = dogroup();
+ t->vars = wordlist(sALIAS);
+ t->left = dogroup(sALIAS);
nesting_pop(&old_nesting);
break;
case UNTIL:
nesting_push(&old_nesting, c);
t = newtp((c == WHILE) ? TWHILE : TUNTIL);
- t->left = c_list(true);
- t->right = dogroup();
+ t->left = c_list(sALIAS, true);
+ t->right = dogroup(sALIAS);
nesting_pop(&old_nesting);
break;
musthave(LWORD, 0);
t->str = yylval.cp;
nesting_push(&old_nesting, c);
- t->left = caselist();
+ t->left = caselist(sALIAS);
nesting_pop(&old_nesting);
break;
case IF:
nesting_push(&old_nesting, c);
t = newtp(TIF);
- t->left = c_list(true);
- t->right = thenpart();
+ t->left = c_list(sALIAS, true);
+ t->right = thenpart(sALIAS);
musthave(FI, KEYWORD|sALIAS);
nesting_pop(&old_nesting);
break;
case BANG:
syniocf &= ~(KEYWORD|sALIAS);
- t = pipeline(0);
+ t = pipeline(0, sALIAS);
if (t == NULL)
syntaxerr(NULL);
t = block(TBANG, NULL, t);
case TIME:
syniocf &= ~(KEYWORD|sALIAS);
- t = pipeline(0);
+ t = pipeline(0, sALIAS);
if (t && t->type == TCOM) {
t->str = alloc(2, ATEMP);
/* TF_* flags */
case FUNCTION:
musthave(LWORD, 0);
- t = function_body(yylval.cp, true);
+ t = function_body(yylval.cp, sALIAS, true);
break;
}
}
static struct op *
-dogroup(void)
+dogroup(int sALIAS)
{
int c;
struct op *list;
c = '}';
else
syntaxerr(NULL);
- list = c_list(true);
+ list = c_list(sALIAS, true);
musthave(c, KEYWORD|sALIAS);
return (list);
}
static struct op *
-thenpart(void)
+thenpart(int sALIAS)
{
struct op *t;
musthave(THEN, KEYWORD|sALIAS);
t = newtp(0);
- t->left = c_list(true);
+ t->left = c_list(sALIAS, true);
if (t->left == NULL)
syntaxerr(NULL);
- t->right = elsepart();
+ t->right = elsepart(sALIAS);
return (t);
}
static struct op *
-elsepart(void)
+elsepart(int sALIAS)
{
struct op *t;
switch (token(KEYWORD|sALIAS|CMDASN)) {
case ELSE:
- if ((t = c_list(true)) == NULL)
+ if ((t = c_list(sALIAS, true)) == NULL)
syntaxerr(NULL);
return (t);
case ELIF:
t = newtp(TELIF);
- t->left = c_list(true);
- t->right = thenpart();
+ t->left = c_list(sALIAS, true);
+ t->right = thenpart(sALIAS);
return (t);
default:
}
static struct op *
-caselist(void)
+caselist(int sALIAS)
{
struct op *t, *tl;
int c;
t = tl = NULL;
/* no ALIAS here */
while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) {
- struct op *tc = casepart(c);
+ struct op *tc = casepart(c, sALIAS);
if (tl == NULL)
t = tl = tc, tl->right = NULL;
else
}
static struct op *
-casepart(int endtok)
+casepart(int endtok, int sALIAS)
{
struct op *t;
XPtrV ptns;
t->vars = (char **)XPclose(ptns);
musthave(')', 0);
- t->left = c_list(true);
+ t->left = c_list(sALIAS, true);
/* initialise to default for ;; or omitted */
t->u.charflag = ';';
}
static struct op *
-function_body(char *name,
+function_body(char *name, int sALIAS,
/* function foo { ... } vs foo() { .. } */
bool ksh_func)
{
*/
for (p = sname; *p; p++)
if (ctype(*p, C_QUOTE))
- yyerror("%s: invalid function name\n", sname);
+ yyerror(Tinvname, sname, Tfunction);
/*
* Note that POSIX allows only compound statements after foo(),
t->u.ksh_func = tobool(ksh_func);
t->lineno = source->line;
- if ((t->left = get_command(CONTIN)) == NULL) {
+ if ((t->left = get_command(CONTIN, sALIAS)) == NULL) {
char *tv;
/*
* Probably something like foo() followed by EOF or ';'.
}
static char **
-wordlist(void)
+wordlist(int sALIAS)
{
int c;
XPtrV args;
goto Again;
}
/* don't quote the EOF */
- yyerror("%s: unexpected EOF\n", Tsynerr);
+ yyerror("%s: unexpected EOF", Tsynerr);
/* NOTREACHED */
case LWORD:
s = redir;
}
}
- yyerror("%s: '%s' %s\n", Tsynerr, s, what);
+ yyerror(Tf_sD_s_qs, Tsynerr, what, s);
}
static void
}
struct op *
-compile(Source *s, bool skiputf8bom)
+compile(Source *s, bool skiputf8bom, bool doalias)
{
nesting.start_token = 0;
nesting.start_line = 0;
source = s;
if (skiputf8bom)
yyskiputf8bom();
- yyparse();
+ yyparse(doalias);
return (outtree);
}
-/*-
- * This kludge exists to take care of sh/AT&T ksh oddity in which
- * the arguments of alias/export/readonly/typeset have no field
- * splitting, file globbing, or (normal) tilde expansion done.
- * AT&T ksh seems to do something similar to this since
- * $ touch a=a; typeset a=[ab]; echo "$a"
- * a=[ab]
- * $ x=typeset; $x a=[ab]; echo "$a"
- * a=a
- * $
- */
-int
-assign_command(const char *s, bool docommand)
-{
- if (!*s)
- return (0);
- return ((strcmp(s, Talias) == 0) ||
- (strcmp(s, Texport) == 0) ||
- (strcmp(s, Treadonly) == 0) ||
- (docommand && (strcmp(s, Tcommand) == 0)) ||
- (strcmp(s, Ttypeset) == 0));
-}
-
/* Check if we are in the middle of reading an alias */
static int
inalias(struct source *s)
* a COMSUB recursively using the main shell parser and lexer
*/
char *
-yyrecursive(int subtype MKSH_A_UNUSED)
+yyrecursive(int subtype)
{
struct op *t;
char *cp;
memcpy(ys->old_heres, heres, sizeof(heres));
ys->old_herep = herep;
herep = heres;
- ys->old_salias = sALIAS;
- sALIAS = 0;
ys->next = e->yyrecursive_statep;
e->yyrecursive_statep = ys;
/* we use TPAREN as a helper container here */
- t = nested(TPAREN, stok, etok);
+ t = nested(TPAREN, stok, etok, ALIAS);
yyrecursive_pop(false);
/* t->left because nested(TPAREN, ...) hides our goodies there */
return;
e->yyrecursive_statep = ys->next;
- sALIAS = ys->old_salias;
memcpy(heres, ys->old_heres, sizeof(heres));
herep = ys->old_herep;
reject = ys->old_reject;
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2015, 2016
+ * 2011, 2012, 2013, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.86 2016/07/25 00:04:48 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.89 2017/04/12 16:46:23 tg Exp $");
#define INDENT 8
case TCOM:
prevent_semicolon = false;
/* special-case 'var=<<EOF' (cf. exec.c:execute) */
- if (
+ if (t->args &&
/* we have zero arguments, i.e. no program to run */
t->args[0] == NULL &&
/* we have exactly one variable assignment */
shf_puts("#no-vars# ", shf);
if (t->args) {
w = t->args;
+ if (*w && **w == CHAR) {
+ char *cp = wdstrip(*w++, WDS_TPUTS);
+
+ if (valid_alias_name(cp))
+ shf_putc('\\', shf);
+ shf_puts(cp, shf);
+ shf_putc(' ', shf);
+ afree(cp, ATEMP);
+ }
while (*w)
fptreef(shf, indent, Tf_S_, *w++);
} else
}
shf_putc(c, shf);
break;
+ case COMASUB:
case COMSUB:
shf_puts("$(", shf);
cs = ")";
+ if (*wp == '(' /*)*/)
+ shf_putc(' ', shf);
pSUB:
while ((c = *wp++) != 0)
shf_putc(c, shf);
shf_puts(cs, shf);
break;
+ case FUNASUB:
case FUNSUB:
c = ' ';
if (0)
case SPAT:
c = '|';
if (0)
+ /* FALLTHROUGH */
case CPAT:
- c = /*(*/ ')';
+ c = /*(*/ ')';
shf_putc(c, shf);
break;
}
case QCHAR:
wp++;
break;
+ case COMASUB:
case COMSUB:
+ case FUNASUB:
case FUNSUB:
case VALSUB:
case EXPRSUB:
}
shf_puts("ADELIM=", shf);
if (0)
+ /* FALLTHROUGH */
case CHAR:
- shf_puts("CHAR=", shf);
+ shf_puts("CHAR=", shf);
dumpchar(shf, *wp++);
break;
case QCHAR:
shf_putc('\\', shf);
dumpchar(shf, c);
goto closeandout;
+ case COMASUB:
+ shf_puts("COMASUB<", shf);
+ goto dumpsub;
case COMSUB:
shf_puts("COMSUB<", shf);
dumpsub:
closeandout:
shf_putc('>', shf);
break;
+ case FUNASUB:
+ shf_puts("FUNASUB<", shf);
+ goto dumpsub;
case FUNSUB:
shf_puts("FUNSUB<", shf);
goto dumpsub;
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015, 2016
+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include <sys/sysctl.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.209 2016/11/11 23:31:39 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.214 2017/04/02 16:47:43 tg Exp $");
/*-
* Variables
/* may only be set by typeset() just before call to array_index_calc() */
static enum namerefflag innermost_refflag = SRF_NOP;
+static void c_typeset_vardump(struct tbl *, uint32_t, int, int, bool, bool);
+static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool,
+ bool);
static char *formatstr(struct tbl *, const char *);
static void exportprep(struct tbl *, const char *);
static int special(const char *);
struct tbl *
global(const char *n)
{
+ return (isglobal(n, true));
+}
+
+/* search for variable; if not found, return NULL or create globally */
+struct tbl *
+isglobal(const char *n, bool docreate)
+{
struct tbl *vp;
union mksh_cchack vname;
struct block *l = e->loc;
goto out;
}
l = varsearch(e->loc, &vp, vn, h);
+ if (vp == NULL && docreate)
+ vp = ktenter(&l->vars, vn, h);
+ else
+ docreate = false;
if (vp != NULL) {
if (array)
vp = arraysearch(vp, val);
- goto out;
+ if (docreate) {
+ vp->flag |= DEFINED;
+ if (special(vn))
+ vp->flag |= SPECIAL;
+ }
}
- vp = ktenter(&l->vars, vn, h);
- if (array)
- vp = arraysearch(vp, val);
- vp->flag |= DEFINED;
- if (special(vn))
- vp->flag |= SPECIAL;
out:
last_lookup_was_array = array;
if (vn != n)
size_t alen;
if (s && ksh_isalphx(*s)) {
- while (*++s && ksh_isalnux(*s))
- ;
+ do {
+ ++s;
+ } while (ksh_isalnux(*s));
if (aok && *s == '[' && (alen = array_ref_len(s)))
s += alen;
}
if (getint(vp, &num, false) == -1) {
s = str_val(vp);
if (st != V_RANDOM)
- errorf(Tf_sD_sD_s, vp->name, "bad number", s);
+ errorf(Tf_sD_sD_s, vp->name, Tbadnum, s);
num.u = hash(s);
}
vp->flag |= SPECIAL;
vp->flag = DEFINED | RDONLY;
setstr(vp, istr, 0x4);
}
+
+/* typeset, global(deprecated), export, and readonly */
+int
+c_typeset(const char **wp)
+{
+ struct tbl *vp, **p;
+ uint32_t fset = 0, fclr = 0, flag;
+ int thing = 0, field = 0, base = 0, i;
+ struct block *l;
+ const char *opts;
+ const char *fieldstr = NULL, *basestr = NULL;
+ bool localv = false, func = false, pflag = false, istset = true;
+ enum namerefflag new_refflag = SRF_NOP;
+
+ switch (**wp) {
+
+ /* export */
+ case 'e':
+ fset |= EXPORT;
+ istset = false;
+ break;
+
+ /* readonly */
+ case 'r':
+ fset |= RDONLY;
+ istset = false;
+ break;
+
+ /* set */
+ case 's':
+ /* called with 'typeset -' */
+ break;
+
+ /* typeset */
+ case 't':
+ localv = true;
+ break;
+ }
+
+ /* see comment below regarding possible opions */
+ opts = istset ? "L#R#UZ#afgi#lnprtux" : "p";
+
+ builtin_opt.flags |= GF_PLUSOPT;
+ /*
+ * AT&T ksh seems to have 0-9 as options which are multiplied
+ * to get a number that is used with -L, -R, -Z or -i (eg, -1R2
+ * sets right justify in a field of 12). This allows options
+ * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and
+ * does not allow the number to be specified as a separate argument
+ * Here, the number must follow the RLZi option, but is optional
+ * (see the # kludge in ksh_getopt()).
+ */
+ while ((i = ksh_getopt(wp, &builtin_opt, opts)) != -1) {
+ flag = 0;
+ switch (i) {
+ case 'L':
+ flag = LJUST;
+ fieldstr = builtin_opt.optarg;
+ break;
+ case 'R':
+ flag = RJUST;
+ fieldstr = builtin_opt.optarg;
+ break;
+ case 'U':
+ /*
+ * AT&T ksh uses u, but this conflicts with
+ * upper/lower case. If this option is changed,
+ * need to change the -U below as well
+ */
+ flag = INT_U;
+ break;
+ case 'Z':
+ flag = ZEROFIL;
+ fieldstr = builtin_opt.optarg;
+ break;
+ case 'a':
+ /*
+ * this is supposed to set (-a) or unset (+a) the
+ * indexed array attribute; it does nothing on an
+ * existing regular string or indexed array though
+ */
+ break;
+ case 'f':
+ func = true;
+ break;
+ case 'g':
+ localv = (builtin_opt.info & GI_PLUS) ? true : false;
+ break;
+ case 'i':
+ flag = INTEGER;
+ basestr = builtin_opt.optarg;
+ break;
+ case 'l':
+ flag = LCASEV;
+ break;
+ case 'n':
+ new_refflag = (builtin_opt.info & GI_PLUS) ?
+ SRF_DISABLE : SRF_ENABLE;
+ break;
+ /* export, readonly: POSIX -p flag */
+ case 'p':
+ /* typeset: show values as well */
+ pflag = true;
+ if (istset)
+ continue;
+ break;
+ case 'r':
+ flag = RDONLY;
+ break;
+ case 't':
+ flag = TRACE;
+ break;
+ case 'u':
+ /* upper case / autoload */
+ flag = UCASEV_AL;
+ break;
+ case 'x':
+ flag = EXPORT;
+ break;
+ case '?':
+ return (1);
+ }
+ if (builtin_opt.info & GI_PLUS) {
+ fclr |= flag;
+ fset &= ~flag;
+ thing = '+';
+ } else {
+ fset |= flag;
+ fclr &= ~flag;
+ thing = '-';
+ }
+ }
+
+ if (fieldstr && !getn(fieldstr, &field)) {
+ bi_errorf(Tf_sD_s, Tbadnum, fieldstr);
+ return (1);
+ }
+ if (basestr) {
+ if (!getn(basestr, &base)) {
+ bi_errorf(Tf_sD_s, "bad integer base", basestr);
+ return (1);
+ }
+ if (base < 1 || base > 36)
+ base = 10;
+ }
+
+ if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] &&
+ (wp[builtin_opt.optind][0] == '-' ||
+ wp[builtin_opt.optind][0] == '+') &&
+ wp[builtin_opt.optind][1] == '\0') {
+ thing = wp[builtin_opt.optind][0];
+ builtin_opt.optind++;
+ }
+
+ if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) ||
+ new_refflag != SRF_NOP)) {
+ bi_errorf("only -t, -u and -x options may be used with -f");
+ return (1);
+ }
+ if (wp[builtin_opt.optind]) {
+ /*
+ * Take care of exclusions.
+ * At this point, flags in fset are cleared in fclr and vice
+ * versa. This property should be preserved.
+ */
+ if (fset & LCASEV)
+ /* LCASEV has priority over UCASEV_AL */
+ fset &= ~UCASEV_AL;
+ if (fset & LJUST)
+ /* LJUST has priority over RJUST */
+ fset &= ~RJUST;
+ if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) {
+ /* -Z implies -ZR */
+ fset |= RJUST;
+ fclr &= ~RJUST;
+ }
+ /*
+ * Setting these attributes clears the others, unless they
+ * are also set in this command
+ */
+ if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV |
+ INTEGER | INT_U | INT_L)) || new_refflag != SRF_NOP)
+ fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL |
+ LCASEV | INTEGER | INT_U | INT_L);
+ }
+ if (new_refflag != SRF_NOP) {
+ fclr &= ~(ARRAY | ASSOC);
+ fset &= ~(ARRAY | ASSOC);
+ fclr |= EXPORT;
+ fset |= ASSOC;
+ if (new_refflag == SRF_DISABLE)
+ fclr |= ASSOC;
+ }
+
+ /* set variables and attributes */
+ if (wp[builtin_opt.optind] &&
+ /* not "typeset -p varname" */
+ !(!func && pflag && !(fset | fclr))) {
+ int rv = 0;
+ struct tbl *f;
+
+ if (localv && !func)
+ fset |= LOCAL;
+ for (i = builtin_opt.optind; wp[i]; i++) {
+ if (func) {
+ f = findfunc(wp[i], hash(wp[i]),
+ tobool(fset & UCASEV_AL));
+ if (!f) {
+ /* AT&T ksh does ++rv: bogus */
+ rv = 1;
+ continue;
+ }
+ if (fset | fclr) {
+ f->flag |= fset;
+ f->flag &= ~fclr;
+ } else {
+ fpFUNCTf(shl_stdout, 0,
+ tobool(f->flag & FKSH),
+ wp[i], f->val.t);
+ shf_putc('\n', shl_stdout);
+ }
+ } else if (!typeset(wp[i], fset, fclr, field, base)) {
+ bi_errorf(Tf_sD_s, wp[i], Tnot_ident);
+ return (1);
+ }
+ }
+ return (rv);
+ }
+
+ /* list variables and attributes */
+
+ /* no difference at this point.. */
+ flag = fset | fclr;
+ if (func) {
+ for (l = e->loc; l; l = l->next) {
+ for (p = ktsort(&l->funs); (vp = *p++); ) {
+ if (flag && (vp->flag & flag) == 0)
+ continue;
+ if (thing == '-')
+ fpFUNCTf(shl_stdout, 0,
+ tobool(vp->flag & FKSH),
+ vp->name, vp->val.t);
+ else
+ shf_puts(vp->name, shl_stdout);
+ shf_putc('\n', shl_stdout);
+ }
+ }
+ } else if (wp[builtin_opt.optind]) {
+ for (i = builtin_opt.optind; wp[i]; i++) {
+ vp = isglobal(wp[i], false);
+ c_typeset_vardump(vp, flag, thing,
+ last_lookup_was_array ? 4 : 0, pflag, istset);
+ }
+ } else
+ c_typeset_vardump_recursive(e->loc, flag, thing, pflag, istset);
+ return (0);
+}
+
+static void
+c_typeset_vardump_recursive(struct block *l, uint32_t flag, int thing,
+ bool pflag, bool istset)
+{
+ struct tbl **blockvars, *vp;
+
+ if (l->next)
+ c_typeset_vardump_recursive(l->next, flag, thing, pflag, istset);
+ blockvars = ktsort(&l->vars);
+ while ((vp = *blockvars++))
+ c_typeset_vardump(vp, flag, thing, 0, pflag, istset);
+ /*XXX doesn’t this leak? */
+}
+
+static void
+c_typeset_vardump(struct tbl *vp, uint32_t flag, int thing, int any_set,
+ bool pflag, bool istset)
+{
+ struct tbl *tvp;
+ char *s;
+
+ if (!vp)
+ return;
+
+ /*
+ * See if the parameter is set (for arrays, if any
+ * element is set).
+ */
+ for (tvp = vp; tvp; tvp = tvp->u.array)
+ if (tvp->flag & ISSET) {
+ any_set |= 1;
+ break;
+ }
+
+ /*
+ * Check attributes - note that all array elements
+ * have (should have?) the same attributes, so checking
+ * the first is sufficient.
+ *
+ * Report an unset param only if the user has
+ * explicitly given it some attribute (like export);
+ * otherwise, after "echo $FOO", we would report FOO...
+ */
+ if (!any_set && !(vp->flag & USERATTRIB))
+ return;
+ if (flag && (vp->flag & flag) == 0)
+ return;
+ if (!(vp->flag & ARRAY))
+ /* optimise later conditionals */
+ any_set = 0;
+ do {
+ /*
+ * Ignore array elements that aren't set unless there
+ * are no set elements, in which case the first is
+ * reported on
+ */
+ if (any_set && !(vp->flag & ISSET))
+ continue;
+ /* no arguments */
+ if (!thing && !flag) {
+ if (any_set == 1) {
+ shprintf(Tf_s_s_sN, Tset, "-A", vp->name);
+ any_set = 2;
+ }
+ /*
+ * AT&T ksh prints things like export, integer,
+ * leftadj, zerofill, etc., but POSIX says must
+ * be suitable for re-entry...
+ */
+ shprintf(Tf_s_s, Ttypeset, "");
+ if (((vp->flag & (ARRAY | ASSOC)) == ASSOC))
+ shprintf(Tf__c_, 'n');
+ if ((vp->flag & INTEGER))
+ shprintf(Tf__c_, 'i');
+ if ((vp->flag & EXPORT))
+ shprintf(Tf__c_, 'x');
+ if ((vp->flag & RDONLY))
+ shprintf(Tf__c_, 'r');
+ if ((vp->flag & TRACE))
+ shprintf(Tf__c_, 't');
+ if ((vp->flag & LJUST))
+ shprintf("-L%d ", vp->u2.field);
+ if ((vp->flag & RJUST))
+ shprintf("-R%d ", vp->u2.field);
+ if ((vp->flag & ZEROFIL))
+ shprintf(Tf__c_, 'Z');
+ if ((vp->flag & LCASEV))
+ shprintf(Tf__c_, 'l');
+ if ((vp->flag & UCASEV_AL))
+ shprintf(Tf__c_, 'u');
+ if ((vp->flag & INT_U))
+ shprintf(Tf__c_, 'U');
+ } else if (pflag) {
+ shprintf(Tf_s_s, istset ? Ttypeset :
+ (flag & EXPORT) ? Texport : Treadonly, "");
+ }
+ if (any_set)
+ shprintf("%s[%lu]", vp->name, arrayindex(vp));
+ else
+ shf_puts(vp->name, shl_stdout);
+ if ((!thing && !flag && pflag) ||
+ (thing == '-' && (vp->flag & ISSET))) {
+ s = str_val(vp);
+ shf_putc('=', shl_stdout);
+ /* AT&T ksh can't have justified integers... */
+ if ((vp->flag & (INTEGER | LJUST | RJUST)) == INTEGER)
+ shf_puts(s, shl_stdout);
+ else
+ print_value_quoted(shl_stdout, s);
+ }
+ shf_putc('\n', shl_stdout);
+
+ /*
+ * Only report first 'element' of an array with
+ * no set elements.
+ */
+ if (!any_set)
+ return;
+ } while (!(any_set & 4) && (vp = vp->u.array));
+}