Merge remote-tracking branch 'mksh/master'

This commit is contained in:
KO Myung-Hun
2017-03-22 17:50:23 +09:00
15 changed files with 982 additions and 837 deletions

View File

@ -1,8 +1,8 @@
#!/bin/sh #!/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.709 2017/03/17 23:47:05 tg Exp $'
#- #-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 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> # mirabilos <m@mirbsd.org>
# #
# Provided that these terms and disclaimer and all copyright notices # Provided that these terms and disclaimer and all copyright notices
@ -586,11 +586,10 @@ fi
rmf a.exe* a.out* conftest.c conftest.exe* *core core.* ${tfn}* *.bc *.dbg \ 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 *.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" SRCS="$SRCS lex.c main.c misc.c shf.c syn.c tree.c var.c"
if test $legacy = 0; then if test $legacy = 0; then
SRCS="$SRCS edit.c"
check_categories="$check_categories shell:legacy-no int:32" check_categories="$check_categories shell:legacy-no int:32"
else else
check_categories="$check_categories shell:legacy-yes" check_categories="$check_categories shell:legacy-yes"
@ -766,7 +765,6 @@ Harvey)
add_cppflags -DMKSH__NO_SETEUGID add_cppflags -DMKSH__NO_SETEUGID
oswarn=' and will currently not work' oswarn=' and will currently not work'
add_cppflags -DMKSH_UNEMPLOYED add_cppflags -DMKSH_UNEMPLOYED
add_cppflags -DMKSH_NOPROSPECTOFWORK
# these taken from Harvey-OS github and need re-checking # these taken from Harvey-OS github and need re-checking
add_cppflags -D_setjmp=setjmp -D_longjmp=longjmp add_cppflags -D_setjmp=setjmp -D_longjmp=longjmp
: "${HAVE_CAN_NO_EH_FRAME=0}" : "${HAVE_CAN_NO_EH_FRAME=0}"

406
check.t
View File

@ -1,8 +1,8 @@
# $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.765 2017/03/22 00:20:39 tg Exp $
# -*- mode: sh -*- # -*- mode: sh -*-
#- #-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 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> # mirabilos <m@mirbsd.org>
# #
# Provided that these terms and disclaimer and all copyright notices # Provided that these terms and disclaimer and all copyright notices
@ -30,7 +30,7 @@
# (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date # (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R54 2016/11/11 @(#)MIRBSD KSH R54 2017/03/21
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -39,7 +39,7 @@ name: KSH_VERSION
category: shell:legacy-no category: shell:legacy-no
--- ---
expected-stdout: expected-stdout:
@(#)LEGACY KSH R54 2016/11/11 @(#)LEGACY KSH R54 2017/03/21
description: description:
Check version of legacy shell. Check version of legacy shell.
stdin: stdin:
@ -92,23 +92,6 @@ category: disabled
stdin: stdin:
set 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 name: selftest-direct-builtin-call
description: description:
Check that direct builtin calls work Check that direct builtin calls work
@ -119,6 +102,26 @@ stdin:
expected-stdout: expected-stdout:
-c echo foo -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-os2
description:
Check that $PATHSEP is set correctly.
category: os:os2
stdin:
PATHSEP=.; export PATHSEP
"$__progname" -c 'print -r -- $PATHSEP'
expected-stdout:
;
---
name: alias-1 name: alias-1
description: description:
Check that recursion is detected/avoided in aliases. Check that recursion is detected/avoided in aliases.
@ -261,14 +264,21 @@ name: alias-11
description: description:
Check that special argument handling still applies with escaped aliases Check that special argument handling still applies with escaped aliases
stdin: stdin:
alias local='\typeset' alias local1='\typeset'
function foo { alias local2='\\builtin typeset'
local x=$1 y=z function fooa {
local1 x=$1 y=z
print -r -- "$x,$y" print -r -- "$x,$y"
} }
foo 'bar - baz' function foob {
local2 x=$1 y=z
print -r -- "$x,$y"
}
x=1 y=2; fooa 'bar - baz'
x=1 y=2; foob 'bar - baz'
expected-stdout: expected-stdout:
bar - baz,z bar - baz,z
bar - baz,z
--- ---
name: arith-compound name: arith-compound
description: description:
@ -4711,6 +4721,23 @@ expected-stdout:
8 ok 8 ok
<9> <ab> <a b> . <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 name: IFS-arith-1
description: description:
http://austingroupbugs.net/view.php?id=832 http://austingroupbugs.net/view.php?id=832
@ -5205,6 +5232,24 @@ expected-stdout:
line <6> line <6>
expected-exit: 1 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 name: unknown-trap
description: description:
Ensure unknown traps are not a syntax error Ensure unknown traps are not a syntax error
@ -6326,7 +6371,7 @@ name: regression-62
description: description:
Check if test -nt/-ot succeeds if second(first) file is missing. Check if test -nt/-ot succeeds if second(first) file is missing.
stdin: stdin:
touch a :>a
test a -nt b && echo nt OK || echo nt BAD test a -nt b && echo nt OK || echo nt BAD
test b -ot a && echo ot OK || echo ot BAD test b -ot a && echo ot OK || echo ot BAD
expected-stdout: expected-stdout:
@ -7058,6 +7103,11 @@ description:
Check tilde expansion works Check tilde expansion works
env-setup: !HOME=/sweet! env-setup: !HOME=/sweet!
stdin: stdin:
:>'c=a'
typeset c=[ab]
:>'d=a'
x=typeset; $x d=[ab]
echo "<$c>" "<$d>"
wd=$PWD wd=$PWD
cd / cd /
plus=$(print -r -- ~+) plus=$(print -r -- ~+)
@ -7067,10 +7117,106 @@ stdin:
[[ $minus = "$wd" ]]; echo two $? . [[ $minus = "$wd" ]]; echo two $? .
[[ $nix = /sweet ]]; echo nix $? . [[ $nix = /sweet ]]; echo nix $? .
expected-stdout: expected-stdout:
<[ab]> <a>
one 0 . one 0 .
two 0 . two 0 .
nix 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 name: exit-err-1
description: description:
Check some "exit on error" conditions Check some "exit on error" conditions
@ -7903,11 +8049,11 @@ expected-stderr-pattern:
--- ---
name: typeset-1 name: typeset-1
description: description:
Check that global does what typeset is supposed to do Check that typeset -g works correctly
stdin: stdin:
set -A arrfoo 65 set -A arrfoo 65
foo() { foo() {
global -Uui16 arrfoo[*] typeset -g -Uui16 arrfoo[*]
} }
echo before ${arrfoo[0]} . echo before ${arrfoo[0]} .
foo foo
@ -7917,7 +8063,7 @@ stdin:
echo inside before ${arrbar[0]} . echo inside before ${arrbar[0]} .
arrbar[0]=97 arrbar[0]=97
echo inside changed ${arrbar[0]} . echo inside changed ${arrbar[0]} .
global -Uui16 arrbar[*] typeset -g -Uui16 arrbar[*]
echo inside typeset ${arrbar[0]} . echo inside typeset ${arrbar[0]} .
arrbar[0]=48 arrbar[0]=48
echo inside changed ${arrbar[0]} . echo inside changed ${arrbar[0]} .
@ -8173,17 +8319,17 @@ stdin:
alias alias
typeset -f typeset -f
expected-stdout: expected-stdout:
autoload='\typeset -fu' autoload='\\builtin typeset -fu'
functions='\typeset -f' functions='\\builtin typeset -f'
hash='\builtin alias -t' hash='\\builtin alias -t'
history='\builtin fc -l' history='\\builtin fc -l'
integer='\typeset -i' integer='\\builtin typeset -i'
local='\typeset' local='\\builtin typeset'
login='\exec login' login='\\builtin exec login'
nameref='\typeset -n' nameref='\\builtin typeset -n'
nohup='nohup ' nohup='nohup '
r='\builtin fc -e -' r='\\builtin fc -e -'
type='\builtin whence -v' type='\\builtin whence -v'
--- ---
name: aliases-2b name: aliases-2b
description: description:
@ -8193,17 +8339,17 @@ stdin:
alias alias
typeset -f typeset -f
expected-stdout: expected-stdout:
autoload='\typeset -fu' autoload='\\builtin typeset -fu'
functions='\typeset -f' functions='\\builtin typeset -f'
hash='\builtin alias -t' hash='\\builtin alias -t'
history='\builtin fc -l' history='\\builtin fc -l'
integer='\typeset -i' integer='\\builtin typeset -i'
local='\typeset' local='\\builtin typeset'
login='\exec login' login='\\builtin exec login'
nameref='\typeset -n' nameref='\\builtin typeset -n'
nohup='nohup ' nohup='nohup '
r='\builtin fc -e -' r='\\builtin fc -e -'
type='\builtin whence -v' type='\\builtin whence -v'
--- ---
name: aliases-3b name: aliases-3b
description: description:
@ -8213,17 +8359,17 @@ stdin:
./sh -c 'alias; typeset -f' ./sh -c 'alias; typeset -f'
rm -f sh rm -f sh
expected-stdout: expected-stdout:
autoload='\typeset -fu' autoload='\\builtin typeset -fu'
functions='\typeset -f' functions='\\builtin typeset -f'
hash='\builtin alias -t' hash='\\builtin alias -t'
history='\builtin fc -l' history='\\builtin fc -l'
integer='\typeset -i' integer='\\builtin typeset -i'
local='\typeset' local='\\builtin typeset'
login='\exec login' login='\\builtin exec login'
nameref='\typeset -n' nameref='\\builtin typeset -n'
nohup='nohup ' nohup='nohup '
r='\builtin fc -e -' r='\\builtin fc -e -'
type='\builtin whence -v' type='\\builtin whence -v'
--- ---
name: aliases-cmdline name: aliases-cmdline
description: description:
@ -8280,8 +8426,8 @@ stdin:
:|| local() { :; } :|| local() { :; }
alias local alias local
expected-stdout: expected-stdout:
local='\typeset' local='\\builtin typeset'
local='\typeset' local='\\builtin typeset'
--- ---
name: arrays-1 name: arrays-1
description: description:
@ -8691,21 +8837,21 @@ expected-stdout:
name: arrassign-fnc-global name: arrassign-fnc-global
description: description:
Check locality of array access inside a function Check locality of array access inside a function
with the mksh-specific global keyword with the bash4/mksh/yash/zsh typeset -g keyword
stdin: stdin:
function fn { function fn {
global x typeset -g x
x+=(f) x+=(f)
echo ".fn:${x[0]}.${x[1]}.${x[2]}.${x[3]}:" echo ".fn:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
} }
function rfn { function rfn {
set -A y set -A y
global y typeset -g y
y+=(f) y+=(f)
echo ".rfn:${y[0]}.${y[1]}.${y[2]}.${y[3]}:" echo ".rfn:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
} }
function fnr { function fnr {
global z typeset -g z
set -A z set -A z
z+=(f) z+=(f)
echo ".fnr:${z[0]}.${z[1]}.${z[2]}.${z[3]}:" echo ".fnr:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
@ -8843,21 +8989,21 @@ expected-stdout:
name: strassign-fnc-global name: strassign-fnc-global
description: description:
Check locality of string access inside a function Check locality of string access inside a function
with the mksh-specific global keyword with the bash4/mksh/yash/zsh typeset -g keyword
stdin: stdin:
function fn { function fn {
global x typeset -g x
x+=f x+=f
echo ".fn:$x:" echo ".fn:$x:"
} }
function rfn { function rfn {
y= y=
global y typeset -g y
y+=f y+=f
echo ".rfn:$y:" echo ".rfn:$y:"
} }
function fnr { function fnr {
global z typeset -g z
z= z=
z+=f z+=f
echo ".fnr:$z:" echo ".fnr:$z:"
@ -9221,7 +9367,7 @@ stdin:
while (( i < ${#line[*]} )); do while (( i < ${#line[*]} )); do
hv=${line[i++]} hv=${line[i++]}
if (( (pos & 15) == 0 )); then if (( (pos & 15) == 0 )); then
(( pos )) && print "$dasc|" (( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} " print -n "${pos#16#} "
dasc=' |' dasc=' |'
fi fi
@ -9238,7 +9384,7 @@ stdin:
print -n ' ' print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- ' (( (pos++ & 15) == 7 )) && print -n -- '- '
done done
(( hv == 2147483647 )) || print "$dasc|" (( hv == 2147483647 )) || print -r -- "$dasc|"
} }
expected-stdout: expected-stdout:
00000000 3C 64 E4 DB C3 9B E2 82 - AC C3 9B 40 3E 0A 3C 00 |<d.........@>.<.| 00000000 3C 64 E4 DB C3 9B E2 82 - AC C3 9B 40 3E 0A 3C 00 |<d.........@>.<.|
@ -9364,7 +9510,7 @@ stdin:
typeset -Uui16 -Z11 pos=0 typeset -Uui16 -Z11 pos=0
typeset -Uui16 -Z5 hv=2147483647 typeset -Uui16 -Z5 hv=2147483647
typeset -i1 wc=0x0A typeset -i1 wc=0x0A
dasc= dasc=
nl=${wc#1#} nl=${wc#1#}
while IFS= read -r line; do while IFS= read -r line; do
line=$line$nl line=$line$nl
@ -9382,7 +9528,7 @@ stdin:
dasc=$dasc${line::1} dasc=$dasc${line::1}
fi fi
(( (pos++ & 15) == 7 )) && print -n -- '- ' (( (pos++ & 15) == 7 )) && print -n -- '- '
line=${line:1} line=${line:1}
done done
done done
while (( pos & 15 )); do while (( pos & 15 )); do
@ -9391,13 +9537,13 @@ expected-stdout:
done done
(( hv == 2147483647 )) || print -r -- "$dasc|" (( hv == 2147483647 )) || print -r -- "$dasc|"
} }
expected-stdout: expected-stdout:
00000000 5C 20 5C 21 5C 22 5C 23 - 5C 24 5C 25 5C 26 5C 27 |\ \!\"\#\$\%\&\'| 00000000 5C 20 5C 21 5C 22 5C 23 - 5C 24 5C 25 5C 26 5C 27 |\ \!\"\#\$\%\&\'|
00000010 5C 28 5C 29 5C 2A 5C 2B - 5C 2C 5C 2D 5C 2E 5C 2F |\(\)\*\+\,\-\.\/| 00000010 5C 28 5C 29 5C 2A 5C 2B - 5C 2C 5C 2D 5C 2E 5C 2F |\(\)\*\+\,\-\.\/|
00000020 5C 31 5C 32 5C 33 5C 34 - 5C 35 5C 36 5C 37 5C 38 |\1\2\3\4\5\6\7\8| 00000020 5C 31 5C 32 5C 33 5C 34 - 5C 35 5C 36 5C 37 5C 38 |\1\2\3\4\5\6\7\8|
00000030 20 5C 39 5C 3A 5C 3B 5C - 3C 5C 3D 5C 3E 5C 3F 5C | \9\:\;\<\=\>\?\| 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| 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| 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 55 5C 56 5C 57 5C |\Q\R\S\T \U\V\W\| 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\[\\]\^\_\`| 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| 00000080 07 08 20 20 5C 64 1B 0C - 5C 67 5C 68 5C 69 5C 6A |.. \d..\g\h\i\j|
@ -9439,7 +9585,7 @@ stdin:
typeset -Uui16 -Z11 pos=0 typeset -Uui16 -Z11 pos=0
typeset -Uui16 -Z5 hv=2147483647 typeset -Uui16 -Z5 hv=2147483647
typeset -i1 wc=0x0A typeset -i1 wc=0x0A
dasc= dasc=
nl=${wc#1#} nl=${wc#1#}
while IFS= read -r line; do while IFS= read -r line; do
line=$line$nl line=$line$nl
@ -9457,7 +9603,7 @@ stdin:
dasc=$dasc${line::1} dasc=$dasc${line::1}
fi fi
(( (pos++ & 15) == 7 )) && print -n -- '- ' (( (pos++ & 15) == 7 )) && print -n -- '- '
line=${line:1} line=${line:1}
done done
done done
while (( pos & 15 )); do while (( pos & 15 )); do
@ -9767,7 +9913,7 @@ stdin:
typeset -Uui16 -Z11 pos=0 typeset -Uui16 -Z11 pos=0
typeset -Uui16 -Z5 hv=2147483647 typeset -Uui16 -Z5 hv=2147483647
typeset -i1 wc=0x0A typeset -i1 wc=0x0A
dasc= dasc=
nl=${wc#1#} nl=${wc#1#}
while IFS= read -r line; do while IFS= read -r line; do
line=$line$nl line=$line$nl
@ -9785,7 +9931,7 @@ stdin:
dasc=$dasc${line::1} dasc=$dasc${line::1}
fi fi
(( (pos++ & 15) == 7 )) && print -n -- '- ' (( (pos++ & 15) == 7 )) && print -n -- '- '
line=${line:1} line=${line:1}
done done
done done
while (( pos & 15 )); do while (( pos & 15 )); do
@ -9855,7 +10001,7 @@ stdin:
dch=. dch=.
elif (( (wc & 0xFF80) == 0xEF80 )); then elif (( (wc & 0xFF80) == 0xEF80 )); then
dch=<EFBFBD> dch=<EFBFBD>
else else
dch=${wc#1#} dch=${wc#1#}
fi fi
if (( (pos & 7) == 7 )); then if (( (pos & 7) == 7 )); then
@ -9870,7 +10016,7 @@ stdin:
print -n "${hv#16#} " print -n "${hv#16#} "
(( (pos++ & 7) == 3 )) && \ (( (pos++ & 7) == 3 )) && \
print -n -- '- ' print -n -- '- '
dasc=$dasc$dch dasc=$dasc$dch
done done
done done
while (( pos & 7 )); do while (( pos & 7 )); do
@ -9936,7 +10082,7 @@ stdin:
# integer-base-one-3Ar # integer-base-one-3Ar
typeset -Uui16 -Z11 pos=0 typeset -Uui16 -Z11 pos=0
typeset -Uui16 -Z5 hv=2147483647 typeset -Uui16 -Z5 hv=2147483647
dasc= dasc=
if read -arN -1 line; then if read -arN -1 line; then
typeset -i1 line typeset -i1 line
i=0 i=0
@ -9953,7 +10099,7 @@ stdin:
else else
dasc=$dasc${line[i-1]#1#} dasc=$dasc${line[i-1]#1#}
fi fi
(( (pos++ & 15) == 7 )) && print -n -- '- ' (( (pos++ & 15) == 7 )) && print -n -- '- '
done done
fi fi
while (( pos & 15 )); do while (( pos & 15 )); do
@ -10019,7 +10165,7 @@ stdin:
dch=. dch=.
elif (( (hv & 0xFF80) == 0xEF80 )); then elif (( (hv & 0xFF80) == 0xEF80 )); then
dch=<EFBFBD> dch=<EFBFBD>
else else
dch=${line[i-1]#1#} dch=${line[i-1]#1#}
fi fi
if (( (pos & 7) == 7 )); then if (( (pos & 7) == 7 )); then
@ -10033,7 +10179,7 @@ stdin:
print -n "${hv#16#} " print -n "${hv#16#} "
(( (pos++ & 7) == 3 )) && \ (( (pos++ & 7) == 3 )) && \
print -n -- '- ' print -n -- '- '
dasc=$dasc$dch dasc=$dasc$dch
done done
fi fi
while (( pos & 7 )); do while (( pos & 7 )); do
@ -10123,9 +10269,16 @@ expected-stdout:
set -U set -U
print 'a\0b€c' >x print 'a\0b€c' >x
read -a y <x read -a y <x
set +U
typeset -Uui16 y
print ${y[*]} .
expected-stdout:
16#61 16#0 16#62 16#20AC 16#63 .
---
name: ulimit-1 name: ulimit-1
description: description:
print ${y[*]} . Check that ulimit as used in dot.mksh works or is stubbed
stdin:
ulimit -c 0 ulimit -c 0
--- ---
name: ulimit-2 name: ulimit-2
@ -10170,7 +10323,6 @@ name: bashiop-1
=3= =3=
e1. e1.
=4= =4=
o1.
o1. o1.
=5= =5=
--- ---
@ -10191,7 +10343,6 @@ name: bashiop-2a
expected-stdout: expected-stdout:
tri tri
=== ===
ras
ras ras
dwa dwa
--- ---
@ -10212,7 +10363,6 @@ name: bashiop-2b
expected-stdout: expected-stdout:
ras ras
=== ===
dwa
dwa dwa
tri tri
--- ---
@ -10233,7 +10383,6 @@ name: bashiop-2c
expected-stdout: expected-stdout:
=== ===
ras ras
dwa
dwa dwa
tri tri
--- ---
@ -10257,7 +10406,6 @@ name: bashiop-3a
tri tri
=== ===
mir mir
ras
ras ras
dwa dwa
--- ---
@ -10279,7 +10427,6 @@ name: bashiop-3b
cat foo cat foo
expected-stdout: expected-stdout:
=== ===
mir
mir mir
expected-stderr-pattern: /.*: can't (create|overwrite) .*/ expected-stderr-pattern: /.*: can't (create|overwrite) .*/
--- ---
@ -10303,7 +10450,6 @@ description:
tri tri
=== ===
ras ras
dwa
dwa dwa
--- ---
name: bashiop-4 name: bashiop-4
@ -10325,11 +10471,10 @@ expected-stdout:
echo -n >bar echo -n >bar
blubb blubb
echo === echo ===
cat foo cat foo
expected-stdout: expected-stdout:
tri tri
=== ===
ras
ras ras
dwa dwa
--- ---
@ -10339,20 +10484,6 @@ expected-stdout:
in !POSIX !sh mode as it breaks existing scripts' syntax in !POSIX !sh mode as it breaks existing scripts' syntax
stdin: stdin:
:>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" . :>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
:>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
:>x; echo 3 "$("$__progname" -o sh -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
expected-stdout:
1 = foo echo bar .
2 = bar .
3 = bar .
---
name: bashiop-5-legacy
description:
Check if GNU bash-like I/O redirection is not parsed
in lksh as it breaks existing scripts' syntax
category: shell:legacy-yes
stdin:
:>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
:>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" . :>x; echo 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)" . :>x; echo 3 "$("$__progname" -o sh -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
expected-stdout: expected-stdout:
@ -10589,7 +10720,6 @@ description:
if [ x$FOO != xfoo ]; then if [ x$FOO != xfoo ]; then
exit 1 exit 1
fi fi
---
--- ---
name: fd-cloexec-1 name: fd-cloexec-1
description: description:
@ -10622,22 +10752,6 @@ stdin:
open(my \$fh, ">&", 9) or die "E: open \$!"; open(my \$fh, ">&", 9) or die "E: open \$!";
syswrite(\$fh, "Fowl\\n", 5) or die "E: write \$!"; syswrite(\$fh, "Fowl\\n", 5) or die "E: write \$!";
EOF EOF
chmod +x cld
test -n "$POSH_VERSION" || set -o posix
exec 9>&1
./cld
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 \$!";
chmod +x cld chmod +x cld
test -n "$POSH_VERSION" || set -o posix test -n "$POSH_VERSION" || set -o posix
exec 9>&1 exec 9>&1
@ -11015,7 +11129,7 @@ expected-stdout:
)|tr u x); } )|tr u x); }
function reread_TIF_TBANG_TDBRACKET_TELIF { 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() { inline_TWHILE() {
i=1; while (( i < 10 )); do echo $i; let ++i; done i=1; while (( i < 10 )); do echo $i; let ++i; done
} }
@ -11026,13 +11140,13 @@ expected-stdout:
} }
do do
echo $i echo $i
let ++i let ++i
done done
} }
function comsub_TWHILE { x=$( function comsub_TWHILE { x=$(
i=1; while (( i < 10 )); do echo $i; let ++i; done i=1; while (( i < 10 )); do echo $i; let ++i; done
); } ); }
function comsub_TWHILE { function comsub_TWHILE {
x=$(i=1 ; while { \\builtin 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=$(( function reread_TWHILE { x=$((
@ -11040,7 +11154,7 @@ expected-stdout:
)|tr u x); } )|tr u x); }
function reread_TWHILE { function reread_TWHILE {
x=$(( i=1 ; while { \\builtin 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() { inline_TUNTIL() {
i=10; until (( !--i )) ; do echo $i; done i=10; until (( !--i )) ; do echo $i; done
} }
@ -11050,13 +11164,13 @@ expected-stdout:
\\builtin let " !--i " \\builtin let " !--i "
} }
do do
echo $i echo $i
done done
} }
function comsub_TUNTIL { x=$( function comsub_TUNTIL { x=$(
i=10; until (( !--i )) ; do echo $i; done i=10; until (( !--i )) ; do echo $i; done
); } ); }
function comsub_TUNTIL { function comsub_TUNTIL {
x=$(i=10 ; until { \\builtin let " !--i " ; } ; do echo $i ; done ) x=$(i=10 ; until { \\builtin let " !--i " ; } ; do echo $i ; done )
} }
function reread_TUNTIL { x=$(( function reread_TUNTIL { x=$((
@ -11432,7 +11546,7 @@ expected-stdout:
} }
inline_wdarrassign() { inline_wdarrassign() {
case x in case x in
x) a+=b; c+=(d e) x) a+=b; c+=(d e)
esac esac
} }
inline_wdarrassign() { inline_wdarrassign() {
@ -11442,7 +11556,7 @@ expected-stdout:
\\builtin set -A c+ -- d e \\builtin set -A c+ -- d e
;; ;;
esac esac
} }
function comsub_wdarrassign { x=$( function comsub_wdarrassign { x=$(
case x in case x in
x) a+=b; c+=(d e) x) a+=b; c+=(d e)
@ -11450,7 +11564,7 @@ expected-stdout:
); } ); }
function comsub_wdarrassign { function comsub_wdarrassign {
x=$(case x in (x) a+=b ; \\builtin set -A c+ -- d e ;; esac ) x=$(case x in (x) a+=b ; \\builtin set -A c+ -- d e ;; esac )
} }
function reread_wdarrassign { x=$(( function reread_wdarrassign { x=$((
case x in case x in
x) a+=b; c+=(d e) x) a+=b; c+=(d e)
@ -11671,7 +11785,7 @@ expected-stdout:
)|tr u x); } )|tr u x); }
function reread_TIF_TBANG_TDBRACKET_TELIF { 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() { inline_TWHILE() {
i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3 i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
} }
@ -11682,13 +11796,13 @@ expected-stdout:
} >&3 } >&3
do do
echo $i echo $i
let ++i let ++i
done >&3 done >&3
} }
function comsub_TWHILE { x=$( function comsub_TWHILE { x=$(
i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3 i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
); } ); }
function comsub_TWHILE { function comsub_TWHILE {
x=$(i=1 ; while { \\builtin 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=$(( function reread_TWHILE { x=$((
@ -11696,7 +11810,7 @@ expected-stdout:
)|tr u x); } )|tr u x); }
function reread_TWHILE { function reread_TWHILE {
x=$(( i=1 ; while { \\builtin 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() { inline_TUNTIL() {
i=10; until (( !--i )) >&3 ; do echo $i; done >&3 i=10; until (( !--i )) >&3 ; do echo $i; done >&3
} }
@ -11706,13 +11820,13 @@ expected-stdout:
\\builtin let " !--i " \\builtin let " !--i "
} >&3 } >&3
do do
echo $i echo $i
done >&3 done >&3
} }
function comsub_TUNTIL { x=$( function comsub_TUNTIL { x=$(
i=10; until (( !--i )) >&3 ; do echo $i; done >&3 i=10; until (( !--i )) >&3 ; do echo $i; done >&3
); } ); }
function comsub_TUNTIL { function comsub_TUNTIL {
x=$(i=10 ; until { \\builtin 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=$(( function reread_TUNTIL { x=$((

View File

@ -1,8 +1,8 @@
# $Id$ # $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, # 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> # mirabilos <m@mirbsd.org>
# #
# Provided that these terms and disclaimer and all copyright notices # Provided that these terms and disclaimer and all copyright notices
@ -22,65 +22,100 @@
#- #-
# ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells # ${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 case ${KSH_VERSION:-} in
*MIRBSD\ KSH*) ;; *LEGACY\ KSH*|*MIRBSD\ KSH*) ;;
*) return 0 ;; *) \return 0 ;;
esac esac
PS1='#'; (( USER_ID )) && PS1='$'; \: "${TERM:=vt100}${HOSTNAME:=$(\ulimit -c \ # give MidnightBSD's laffer1 a bit of csh feeling
0; hostname 2>/dev/null)}${EDITOR:=/bin/ed}${USER:=$(\ulimit -c 0; id -un \ function setenv {
2>/dev/null || \echo \?)}${MKSH:=$(\builtin whence -p mksh)}" if (( $# )); then
HOSTNAME=${HOSTNAME%%*([ ]).*}; HOSTNAME=${HOSTNAME##*([ ])} \\builtin eval '\\builtin export "$1"="${2:-}"'
[[ $HOSTNAME = ?(ip6-)localhost?(6) ]] && HOSTNAME= else
\: "${HOSTNAME:=nil}${MKSH:=/bin/mksh}"; \export EDITOR HOSTNAME MKSH TERM USER \\builtin typeset -x
PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${| fi
\typeset e=$? }
# 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|" (( e )) && REPLY+="$e|"
REPLY+=${USER}@${HOSTNAME%%.*}: REPLY+=${USER}@${HOSTNAME%%.*}:
\typeset d=${PWD:-?}/ p=~; [[ $p = ?(*/) ]] || d=${d/#$p\//\~/} \\builtin typeset d=${PWD:-?}/ p=~; [[ $p = ?(*/) ]] || d=${d/#$p\//\~/}
d=${d%/}; \typeset m=${%d} n p=...; (( m > 0 )) || m=${#d} d=${d%/}; \\builtin typeset m=${%d} n p=...; (( m > 0 )) || m=${#d}
(( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p= (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
REPLY+=$p$d REPLY+=$p$d
\return $e \\builtin return $e
} '"$PS1 " } '"$PS1 "
\alias ls=ls \\builtin alias doch='sudo mksh -c "$(\\builtin fc -ln -1)"'
\unalias ls \\builtin command -v rot13 >/dev/null || \\builtin alias rot13='tr \
\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 \
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM' 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 { function hd {
hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \ hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \
-e '" |" "%_p"' -e '"|\n"' "$@" -e '" |" "%_p"' -e '"|\n"' "$@"
} }
else else
function hd { function hd {
\typeset -Uui16 -Z11 pos=0 \\builtin typeset -Uui16 -Z11 pos=0
\typeset -Uui16 -Z5 hv=2147483647 \\builtin typeset -Uui16 -Z5 hv=2147483647
\typeset dasc line i \\builtin typeset dasc line i
\set +U \\builtin set +U
\cat "$@" | if \read -arN -1 line; then \\builtin cat "$@" | if \\builtin read -arN -1 line; then
\typeset -i1 'line[*]' \\builtin typeset -i1 'line[*]'
i=0 i=0
while (( i < ${#line[*]} )); do while (( i < ${#line[*]} )); do
hv=${line[i++]} hv=${line[i++]}
if (( (pos & 15) == 0 )); then if (( (pos & 15) == 0 )); then
(( pos )) && \ (( pos )) && \
\builtin print -r -- "$dasc|" \\builtin print -r -- "$dasc|"
\builtin print -n "${pos#16#} " \\builtin print -nr "${pos#16#} "
dasc=' |' dasc=' |'
fi fi
\builtin print -n "${hv#16#} " \\builtin print -nr "${hv#16#} "
#XXX EBCDIC, but we need [[:print:]] to fix this #XXX EBCDIC, but we need [[:print:]] to fix this
if (( (hv < 32) || (hv > 126) )); then if (( (hv < 32) || (hv > 126) )); then
dasc+=. dasc+=.
@ -88,69 +123,69 @@ else
dasc+=${line[i-1]#1#} dasc+=${line[i-1]#1#}
fi fi
(( (pos++ & 15) == 7 )) && \ (( (pos++ & 15) == 7 )) && \
\builtin print -n -- '- ' \\builtin print -nr -- '- '
done done
while (( pos & 15 )); do while (( pos & 15 )); do
\builtin print -n ' ' \\builtin print -nr ' '
(( (pos++ & 15) == 7 )) && \ (( (pos++ & 15) == 7 )) && \
\builtin print -n -- '- ' \\builtin print -nr -- '- '
done done
(( hv == 2147483647 )) || \builtin print -r -- "$dasc|" (( hv == 2147483647 )) || \\builtin print -r -- "$dasc|"
fi fi
} }
fi fi
# Berkeley C shell compatible dirs, popd, and pushd functions # Berkeley C shell compatible dirs, popd, and pushd functions
# Z shell compatible chpwd() hook, used to update DIRSTACK[0] # Z shell compatible chpwd() hook, used to update DIRSTACK[0]
DIRSTACKBASE=$(\builtin realpath ~/. 2>/dev/null || \ DIRSTACKBASE=$(\\builtin realpath ~/. 2>/dev/null || \
\builtin print -nr -- "${HOME:-/}") \\builtin print -nr -- "${HOME:-/}")
set -A DIRSTACK \\builtin set -A DIRSTACK
function chpwd { function chpwd {
DIRSTACK[0]=$(\builtin realpath . 2>/dev/null || \ DIRSTACK[0]=$(\\builtin realpath . 2>/dev/null || \
\builtin print -r -- "$PWD") \\builtin print -nr -- "$PWD")
[[ $DIRSTACKBASE = ?(*/) ]] || \ [[ $DIRSTACKBASE = ?(*/) ]] || \
DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/\~} DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/\~}
\: \:
} }
\chpwd . \chpwd .
cd() { cd() {
\builtin cd "$@" || \return $? \\builtin cd "$@" || \\builtin return $?
\chpwd "$@" \chpwd "$@"
} }
function cd_csh { function cd_csh {
\typeset d t=${1/#\~/$DIRSTACKBASE} \\builtin typeset d t=${1/#\~/$DIRSTACKBASE}
if ! d=$(\builtin cd "$t" 2>&1); then if ! d=$(\\builtin cd "$t" 2>&1); then
\builtin print -u2 "${1}: ${d##*cd: $t: }." \\builtin print -ru2 "${1}: ${d##*cd: $t: }."
\return 1 \\builtin return 1
fi fi
\cd "$t" \cd "$t"
} }
function dirs { function dirs {
\typeset d dwidth \\builtin typeset d dwidth
\typeset -i fl=0 fv=0 fn=0 cpos=0 \\builtin typeset -i fl=0 fv=0 fn=0 cpos=0
while \getopts ":lvn" d; do while \\builtin getopts ":lvn" d; do
case $d { case $d {
(l) fl=1 ;; (l) fl=1 ;;
(v) fv=1 ;; (v) fv=1 ;;
(n) fn=1 ;; (n) fn=1 ;;
(*) \builtin print -u2 'Usage: dirs [-lvn].' (*) \\builtin print -ru2 'Usage: dirs [-lvn].'
\return 1 ;; \\builtin return 1 ;;
} }
done done
\shift $((OPTIND - 1)) \\builtin shift $((OPTIND - 1))
if (( $# > 0 )); then if (( $# > 0 )); then
\builtin print -u2 'Usage: dirs [-lvn].' \\builtin print -ru2 'Usage: dirs [-lvn].'
\return 1 \\builtin return 1
fi fi
if (( fv )); then if (( fv )); then
fv=0 fv=0
while (( fv < ${#DIRSTACK[*]} )); do while (( fv < ${#DIRSTACK[*]} )); do
d=${DIRSTACK[fv]} d=${DIRSTACK[fv]}
(( fl )) && d=${d/#\~/$DIRSTACKBASE} (( fl )) && d=${d/#\~/$DIRSTACKBASE}
\builtin print -r -- "$fv $d" \\builtin print -r -- "$fv $d"
\builtin let fv++ (( ++fv ))
done done
else else
fv=0 fv=0
@ -160,136 +195,117 @@ function dirs {
(( dwidth = (${%d} > 0 ? ${%d} : ${#d}) )) (( dwidth = (${%d} > 0 ? ${%d} : ${#d}) ))
if (( fn && (cpos += dwidth + 1) >= 79 && \ if (( fn && (cpos += dwidth + 1) >= 79 && \
dwidth < 80 )); then dwidth < 80 )); then
\builtin print \\builtin print
(( cpos = dwidth + 1 )) (( cpos = dwidth + 1 ))
fi fi
\builtin print -nr -- "$d " \\builtin print -nr -- "$d "
\builtin let fv++ (( ++fv ))
done done
\builtin print \\builtin print
fi fi
\return 0 \\builtin return 0
} }
function popd { function popd {
\typeset d fa \\builtin typeset d fa
\typeset -i n=1 \\builtin typeset -i n=1
while \getopts ":0123456789lvn" d; do while \\builtin getopts ":0123456789lvn" d; do
case $d { case $d {
(l|v|n) fa+=" -$d" ;; (l|v|n) fa+=" -$d" ;;
(+*) n=2 (+*) n=2
\break ;; \\builtin break ;;
(*) \builtin print -u2 'Usage: popd [-lvn] [+<n>].' (*) \\builtin print -ru2 'Usage: popd [-lvn] [+<n>].'
\return 1 ;; \\builtin return 1 ;;
} }
done done
\shift $((OPTIND - n)) \\builtin shift $((OPTIND - n))
n=0 n=0
if (( $# > 1 )); then if (( $# > 1 )); then
\builtin print -u2 popd: Too many arguments. \\builtin print -ru2 popd: Too many arguments.
\return 1 \\builtin return 1
elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then
if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then
\builtin print -u2 popd: Directory stack not that deep. \\builtin print -ru2 popd: Directory stack not that deep.
\return 1 \\builtin return 1
fi fi
elif [[ -n $1 ]]; then elif [[ -n $1 ]]; then
\builtin print -u2 popd: Bad directory. \\builtin print -ru2 popd: Bad directory.
\return 1 \\builtin return 1
fi fi
if (( ${#DIRSTACK[*]} < 2 )); then if (( ${#DIRSTACK[*]} < 2 )); then
\builtin print -u2 popd: Directory stack empty. \\builtin print -ru2 popd: Directory stack empty.
\return 1 \\builtin return 1
fi fi
\unset DIRSTACK[n] \\builtin unset DIRSTACK[n]
\set -A DIRSTACK -- "${DIRSTACK[@]}" \\builtin set -A DIRSTACK -- "${DIRSTACK[@]}"
\cd_csh "${DIRSTACK[0]}" || \return 1 \cd_csh "${DIRSTACK[0]}" || \\builtin return 1
\dirs $fa \dirs $fa
} }
function pushd { function pushd {
\typeset d fa \\builtin typeset d fa
\typeset -i n=1 \\builtin typeset -i n=1
while \getopts ":0123456789lvn" d; do while \\builtin getopts ":0123456789lvn" d; do
case $d { case $d {
(l|v|n) fa+=" -$d" ;; (l|v|n) fa+=" -$d" ;;
(+*) n=2 (+*) n=2
\break ;; \\builtin break ;;
(*) \builtin print -u2 'Usage: pushd [-lvn] [<dir>|+<n>].' (*) \\builtin print -ru2 'Usage: pushd [-lvn] [<dir>|+<n>].'
\return 1 ;; \\builtin return 1 ;;
} }
done done
\shift $((OPTIND - n)) \\builtin shift $((OPTIND - n))
if (( $# == 0 )); then if (( $# == 0 )); then
if (( ${#DIRSTACK[*]} < 2 )); then if (( ${#DIRSTACK[*]} < 2 )); then
\builtin print -u2 pushd: No other directory. \\builtin print -ru2 pushd: No other directory.
\return 1 \\builtin return 1
fi fi
d=${DIRSTACK[1]} d=${DIRSTACK[1]}
DIRSTACK[1]=${DIRSTACK[0]} DIRSTACK[1]=${DIRSTACK[0]}
\cd_csh "$d" || \return 1 \cd_csh "$d" || \\builtin return 1
elif (( $# > 1 )); then elif (( $# > 1 )); then
\builtin print -u2 pushd: Too many arguments. \\builtin print -ru2 pushd: Too many arguments.
\return 1 \\builtin return 1
elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then
if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then
\builtin print -u2 pushd: Directory stack not that deep. \\builtin print -ru2 pushd: Directory stack not that deep.
\return 1 \\builtin return 1
fi fi
while (( n-- )); do while (( n-- )); do
d=${DIRSTACK[0]} d=${DIRSTACK[0]}
\unset DIRSTACK[0] \\builtin unset DIRSTACK[0]
\set -A DIRSTACK -- "${DIRSTACK[@]}" "$d" \\builtin set -A DIRSTACK -- "${DIRSTACK[@]}" "$d"
done done
\cd_csh "${DIRSTACK[0]}" || \return 1 \cd_csh "${DIRSTACK[0]}" || \\builtin return 1
else else
\set -A DIRSTACK -- placeholder "${DIRSTACK[@]}" \\builtin set -A DIRSTACK -- placeholder "${DIRSTACK[@]}"
\cd_csh "$1" || \return 1 \cd_csh "$1" || \\builtin return 1
fi fi
\dirs $fa \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 # base64 encoder and decoder, RFC compliant, NUL safe, not EBCDIC safe
function Lb64decode { function Lb64decode {
\set +U \\builtin set +U
\typeset c s="$*" t \\builtin typeset c s="$*" t
[[ -n $s ]] || { s=$(\cat; \builtin print x); s=${s%x}; } [[ -n $s ]] || { s=$(\\builtin cat; \\builtin print x); s=${s%x}; }
\typeset -i i=0 j=0 n=${#s} p=0 v x \\builtin typeset -i i=0 j=0 n=${#s} p=0 v x
\typeset -i16 o \\builtin typeset -i16 o
while (( i < n )); do while (( i < n )); do
c=${s:(i++):1} c=${s:(i++):1}
case $c { case $c {
(=) \break ;; (=) \\builtin break ;;
([A-Z]) (( v = 1#$c - 65 )) ;; ([A-Z]) (( v = 1#$c - 65 )) ;;
([a-z]) (( v = 1#$c - 71 )) ;; ([a-z]) (( v = 1#$c - 71 )) ;;
([0-9]) (( v = 1#$c + 4 )) ;; ([0-9]) (( v = 1#$c + 4 )) ;;
(+) v=62 ;; (+) v=62 ;;
(/) v=63 ;; (/) v=63 ;;
(*) \continue ;; (*) \\builtin continue ;;
} }
(( x = (x << 6) | v )) (( x = (x << 6) | v ))
case $((p++)) { case $((p++)) {
(0) \continue ;; (0) \\builtin continue ;;
(1) (( o = (x >> 4) & 255 )) ;; (1) (( o = (x >> 4) & 255 )) ;;
(2) (( o = (x >> 2) & 255 )) ;; (2) (( o = (x >> 2) & 255 )) ;;
(3) (( o = x & 255 )) (3) (( o = x & 255 ))
@ -297,63 +313,60 @@ function Lb64decode {
;; ;;
} }
t+=\\x${o#16#} t+=\\x${o#16#}
(( ++j & 4095 )) && \continue (( ++j & 4095 )) && \\builtin continue
\builtin print -n $t \\builtin print -n $t
t= t=
done 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 { function Lb64encode {
\set +U \\builtin set +U
\typeset c s t \\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 if (( $# )); then
\read -raN-1 s <<<"$*" \\builtin read -raN-1 s <<<"$*"
\unset s[${#s[*]}-1] \\builtin unset s[${#s[*]}-1]
else else
\read -raN-1 s \\builtin read -raN-1 s
fi fi
\typeset -i i=0 n=${#s[*]} j v \\builtin typeset -i i=0 n=${#s[*]} v
while (( i < n )); do while (( i < n )); do
(( v = s[i++] << 16 )) (( v = s[i++] << 16 ))
(( j = i < n ? s[i++] : 0 )) (( v |= s[i++] << 8 ))
(( v |= j << 8 )) (( v |= s[i++] ))
(( j = i < n ? s[i++] : 0 )) t+=${table[v >> 18]}${table[v >> 12 & 63]}
(( v |= j )) c=${table[v >> 6 & 63]}
t+=${Lb64encode_tbl[v >> 18]}${Lb64encode_tbl[v >> 12 & 63]}
c=${Lb64encode_tbl[v >> 6 & 63]}
if (( i <= n )); then if (( i <= n )); then
t+=$c${Lb64encode_tbl[v & 63]} t+=$c${table[v & 63]}
elif (( i == n + 1 )); then elif (( i == n + 1 )); then
t+=$c= t+=$c=
else else
t+=== t+===
fi fi
if (( ${#t} == 76 || i >= n )); then if (( ${#t} == 76 || i >= n )); then
\builtin print $t \\builtin print -r $t
t= t=
fi fi
done done
} }
# Better Avalanche for the Jenkins Hash # Better Avalanche for the Jenkins Hash
\typeset -Z11 -Uui16 Lbafh_v \\builtin typeset -Z11 -Uui16 Lbafh_v
function Lbafh_init { function Lbafh_init {
Lbafh_v=0 Lbafh_v=0
} }
function Lbafh_add { function Lbafh_add {
\set +U \\builtin set +U
\typeset s \\builtin typeset s
if (( $# )); then if (( $# )); then
\read -raN-1 s <<<"$*" \\builtin read -raN-1 s <<<"$*"
\unset s[${#s[*]}-1] \\builtin unset s[${#s[*]}-1]
else else
\read -raN-1 s \\builtin read -raN-1 s
fi fi
\typeset -i i=0 n=${#s[*]} \\builtin typeset -i i=0 n=${#s[*]}
while (( i < n )); do while (( i < n )); do
((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 )) ((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 ))
@ -361,7 +374,7 @@ function Lbafh_add {
done done
} }
function Lbafh_finish { function Lbafh_finish {
\typeset -Ui t \\builtin typeset -Ui t
((# t = (((Lbafh_v >> 7) & 0x01010101) * 0x1B) ^ \ ((# t = (((Lbafh_v >> 7) & 0x01010101) * 0x1B) ^ \
((Lbafh_v << 1) & 0xFEFEFEFE) )) ((Lbafh_v << 1) & 0xFEFEFEFE) ))
@ -373,42 +386,33 @@ function Lbafh_finish {
# strip comments (and leading/trailing whitespace if IFS is set) from # 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 # any file(s) given as argument, or stdin if none, and spew to stdout
function Lstripcom { function Lstripcom {
\set -o noglob \\builtin set -o noglob
\cat "$@" | while \read _line; do \\builtin cat "$@" | while \\builtin read _line; do
_line=${_line%%#*} _line=${_line%%#*}
[[ -n $_line ]] && \builtin print -r -- $_line [[ -n $_line ]] && \\builtin print -r -- $_line
done 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 # toggle built-in aliases and utilities, and aliases and functions from mkshrc
function enable { function enable {
\typeset doprnt=0 mode=1 x y z rv=0 \\builtin typeset doprnt=0 mode=1 x y z rv=0
\typeset b_alias i_alias i_func nalias=0 nfunc=0 i_all \\builtin typeset b_alias i_alias i_func nalias=0 nfunc=0 i_all
\set -A b_alias \\builtin set -A b_alias
\set -A i_alias \\builtin set -A i_alias
\set -A i_func \\builtin set -A i_func
# accumulate mksh built-in aliases, in ASCIIbetical order # accumulate mksh built-in aliases, in ASCIIbetical order
i_alias[nalias]=autoload; b_alias[nalias++]='\typeset -fu' i_alias[nalias]=autoload; b_alias[nalias++]='\\builtin typeset -fu'
i_alias[nalias]=functions; b_alias[nalias++]='\typeset -f' i_alias[nalias]=functions; b_alias[nalias++]='\\builtin typeset -f'
i_alias[nalias]=hash; b_alias[nalias++]='\builtin alias -t' i_alias[nalias]=hash; b_alias[nalias++]='\\builtin alias -t'
i_alias[nalias]=history; b_alias[nalias++]='\builtin fc -l' i_alias[nalias]=history; b_alias[nalias++]='\\builtin fc -l'
i_alias[nalias]=integer; b_alias[nalias++]='\typeset -i' i_alias[nalias]=integer; b_alias[nalias++]='\\builtin typeset -i'
i_alias[nalias]=local; b_alias[nalias++]='\typeset' i_alias[nalias]=local; b_alias[nalias++]='\\builtin typeset'
i_alias[nalias]=login; b_alias[nalias++]='\exec login' i_alias[nalias]=login; b_alias[nalias++]='\\builtin exec login'
i_alias[nalias]=nameref; b_alias[nalias++]='\typeset -n' i_alias[nalias]=nameref; b_alias[nalias++]='\\builtin typeset -n'
i_alias[nalias]=nohup; b_alias[nalias++]='nohup ' i_alias[nalias]=nohup; b_alias[nalias++]='nohup '
i_alias[nalias]=r; b_alias[nalias++]='\builtin fc -e -' i_alias[nalias]=r; b_alias[nalias++]='\\builtin fc -e -'
i_alias[nalias]=type; b_alias[nalias++]='\builtin whence -v' i_alias[nalias]=type; b_alias[nalias++]='\\builtin whence -v'
# accumulate mksh built-in utilities, in definition order, even ifndef # accumulate mksh built-in utilities, in definition order, even ifndef
i_func[nfunc++]=. i_func[nfunc++]=.
@ -416,6 +420,7 @@ function enable {
i_func[nfunc++]='[' i_func[nfunc++]='['
i_func[nfunc++]=alias i_func[nfunc++]=alias
i_func[nfunc++]=break i_func[nfunc++]=break
# \\builtin cannot, by design, be overridden
i_func[nfunc++]=builtin i_func[nfunc++]=builtin
i_func[nfunc++]=cat i_func[nfunc++]=cat
i_func[nfunc++]=cd i_func[nfunc++]=cd
@ -434,7 +439,6 @@ function enable {
i_func[nfunc++]=jobs i_func[nfunc++]=jobs
i_func[nfunc++]=kill i_func[nfunc++]=kill
i_func[nfunc++]=let i_func[nfunc++]=let
i_func[nfunc++]='let]'
i_func[nfunc++]=print i_func[nfunc++]=print
i_func[nfunc++]=pwd i_func[nfunc++]=pwd
i_func[nfunc++]=read i_func[nfunc++]=read
@ -471,11 +475,13 @@ function enable {
i_alias[nalias]=la; b_alias[nalias++]='l -a' i_alias[nalias]=la; b_alias[nalias++]='l -a'
i_alias[nalias]=ll; b_alias[nalias++]='l -l' i_alias[nalias]=ll; b_alias[nalias++]='l -l'
i_alias[nalias]=lo; b_alias[nalias++]='l -alo' 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]=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 # accumulate functions from dot.mkshrc, in definition order
i_func[nfunc++]=setenv
i_func[nfunc++]=smores
i_func[nfunc++]=hd i_func[nfunc++]=hd
i_func[nfunc++]=chpwd i_func[nfunc++]=chpwd
i_func[nfunc++]=cd i_func[nfunc++]=cd
@ -483,21 +489,19 @@ function enable {
i_func[nfunc++]=dirs i_func[nfunc++]=dirs
i_func[nfunc++]=popd i_func[nfunc++]=popd
i_func[nfunc++]=pushd i_func[nfunc++]=pushd
i_func[nfunc++]=smores
i_func[nfunc++]=Lb64decode i_func[nfunc++]=Lb64decode
i_func[nfunc++]=Lb64encode i_func[nfunc++]=Lb64encode
i_func[nfunc++]=Lbafh_init i_func[nfunc++]=Lbafh_init
i_func[nfunc++]=Lbafh_add i_func[nfunc++]=Lbafh_add
i_func[nfunc++]=Lbafh_finish i_func[nfunc++]=Lbafh_finish
i_func[nfunc++]=Lstripcom i_func[nfunc++]=Lstripcom
i_func[nfunc++]=setenv
i_func[nfunc++]=enable i_func[nfunc++]=enable
# collect all identifiers, sorted ASCIIbetically # 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 # handle options, we don't do dynamic loading
while \getopts "adf:nps" x; do while \\builtin getopts "adf:nps" x; do
case $x { case $x {
(a) (a)
mode=-1 mode=-1
@ -506,8 +510,8 @@ function enable {
# deliberately causing an error, like bash-static # deliberately causing an error, like bash-static
;| ;|
(f) (f)
\builtin print -u2 enable: dynamic loading not available \\builtin print -ru2 enable: dynamic loading not available
\return 2 \\builtin return 2
;; ;;
(n) (n)
mode=0 mode=0
@ -516,88 +520,89 @@ function enable {
doprnt=1 doprnt=1
;; ;;
(s) (s)
\set -sA i_all -- . : break continue eval exec exit \ \\builtin set -sA i_all -- . : break continue eval \
export readonly return set shift times trap unset 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 ...]" "enable [-adnps] [-f filename] [name ...]"
return 2 return 2
;; ;;
} }
done done
\shift $((OPTIND - 1)) \\builtin shift $((OPTIND - 1))
# display builtins enabled/disabled/all/special? # display builtins enabled/disabled/all/special?
if (( doprnt || ($# == 0) )); then if (( doprnt || ($# == 0) )); then
for x in "${i_all[@]}"; do for x in "${i_all[@]}"; do
y=$(\alias "$x") || y= y=$(\\builtin 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 = "$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 { case $mode:$z {
(-1:0|0:0) (-1:0|0:0)
\print -r -- "enable -n $x" \\builtin print -r -- "enable -n $x"
;; ;;
(-1:1|1:1) (-1:1|1:1)
\print -r -- "enable $x" \\builtin print -r -- "enable $x"
;; ;;
} }
done done
\return 0 \\builtin return 0
fi fi
for x in "$@"; do for x in "$@"; do
z=0 z=0
for y in "${i_alias[@]}" "${i_func[@]}"; do for y in "${i_alias[@]}" "${i_func[@]}"; do
[[ $x = "$y" ]] || \continue [[ $x = "$y" ]] || \\builtin continue
z=1 z=1
\break \\builtin break
done done
if (( !z )); then if (( !z )); then
\builtin print -ru2 enable: "$x": not a shell builtin \\builtin print -ru2 enable: "$x": not a shell builtin
rv=1 rv=1
\continue \\builtin continue
fi fi
if (( !mode )); then if (( !mode )); then
# disable this # 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 else
# find out if this is an alias or not, first # find out if this is an alias or not, first
z=0 z=0
y=-1 y=-1
while (( ++y < nalias )); do while (( ++y < nalias )); do
[[ $x = "${i_alias[y]}" ]] || \continue [[ $x = "${i_alias[y]}" ]] || \\builtin continue
z=1 z=1
\break \\builtin break
done done
if (( z )); then if (( z )); then
# re-enable the original alias body # re-enable the original alias body
\alias "$x=${b_alias[y]}" \\builtin alias "$x=${b_alias[y]}"
else else
# re-enable the original utility/function # re-enable the original utility/function
\unalias "$x" \\builtin unalias "$x"
fi fi
fi fi
done done
\return $rv \\builtin return $rv
} }
\: place customisations below this line \: place customisations below this line
for p in ~/.etc/bin ~/bin; do for p in ~/.etc/bin ~/bin; do
[[ -d $p/. ]] || \continue [[ -d $p/. ]] || \\builtin continue
#XXX OS/2 [[ $PATHSEP$PATH$PATHSEP = *"$PATHSEP$p$PATHSEP"* ]] || \
[[ :$PATH: = *:$p:* ]] || PATH=$p:$PATH PATH=$p$PATHSEP$PATH
done done
\export SHELL=$MKSH MANWIDTH=80 LESSHISTFILE=- \\builtin export SHELL=$MKSH MANWIDTH=80 LESSHISTFILE=-
\alias cls='\builtin print -n \\ec' \\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 # LC_NAME LC_NUMERIC LC_TELEPHONE LC_TIME
#p=en_GB.UTF-8 #p=en_GB.UTF-8
#\export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p #\\builtin export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
#\set -U #\\builtin set -U
\unset p \\builtin unset p
\: place customisations above this line \: place customisations above this line

8
edit.c
View File

@ -5,7 +5,7 @@
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, * 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> * mirabilos <m@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -28,7 +28,7 @@
#ifndef MKSH_NO_CMDLINE_EDITING #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.313 2017/03/11 22:49:54 tg Exp $");
/* /*
* in later versions we might use libtermcap for this, but since external * in later versions we might use libtermcap for this, but since external
@ -343,7 +343,7 @@ x_glob_hlp_tilde_and_rem_qchar(char *s, bool magic_flag)
* and if so, discern "~foo/bar" and "~/baz" from "~blah"; * and if so, discern "~foo/bar" and "~/baz" from "~blah";
* if we have a directory part (the former), try to expand * 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" */ /* ok, so split into "~foo"/"bar" or "~"/"baz" */
*cp++ = 0; *cp++ = 0;
/* try to expand the tilde */ /* try to expand the tilde */
@ -662,7 +662,7 @@ x_cf_glob(int *flagsp, const char *buf, int buflen, int pos, int *startp,
} }
} }
if (*toglob == '~' && !mksh_vdirsep(toglob)) { if (*toglob == '~' && /* not vdirsep */ !vstrchr(toglob, '/')) {
/* neither for '~foo' (but '~foo/bar') */ /* neither for '~foo' (but '~foo/bar') */
*flagsp |= XCF_IS_NOSPACE; *flagsp |= XCF_IS_NOSPACE;
goto dont_add_glob; goto dont_add_glob;

35
eval.c
View File

@ -2,7 +2,7 @@
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, * 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> * mirabilos <m@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h" #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.198 2017/03/11 22:49:55 tg Exp $");
/* /*
* string expansion * string expansion
@ -625,13 +625,12 @@ expand(
break; break;
case '=': case '=':
/* /*
* Enabling tilde expansion * Tilde expansion for string
* after :s here is * variables in POSIX mode is
* non-standard ksh, but is * governed by Austinbug 351.
* consistent with rules for * In non-POSIX mode historic
* other assignments. Not * ksh behaviour (enable it!)
* sure what POSIX thinks of * us followed.
* this.
* Not doing tilde expansion * Not doing tilde expansion
* for integer variables is a * for integer variables is a
* non-POSIX thing - makes * non-POSIX thing - makes
@ -640,7 +639,7 @@ expand(
*/ */
if (!(x.var->flag & INTEGER)) if (!(x.var->flag & INTEGER))
f |= DOASNTILDE | DOTILDE; f |= DOASNTILDE | DOTILDE;
f |= DOTEMP; f |= DOTEMP | DOSCALAR;
/* /*
* These will be done after the * These will be done after the
* value has been assigned. * value has been assigned.
@ -1224,12 +1223,16 @@ varsub(Expand *xp, const char *sp, const char *word,
} }
} else if (c == '@') { } else if (c == '@') {
/* @x where x is command char */ /* @x where x is command char */
slen += 2; switch (c = word[slen + 2] == CHAR ? word[slen + 3] : 0) {
stype |= 0x100; case '#':
if (word[slen] == CHAR) { case '/':
stype |= word[slen + 1]; case 'Q':
slen += 2; break;
default:
return (-1);
} }
stype |= 0x100 | c;
slen += 4;
} else if (stype) } else if (stype)
/* : is not ok */ /* : is not ok */
return (-1); return (-1);
@ -1730,7 +1733,7 @@ maybe_expand_tilde(const char *p, XString *dsp, char **dpp, bool isassign)
Xinit(ts, tp, 16, ATEMP); Xinit(ts, tp, 16, ATEMP);
/* : only for DOASNTILDE form */ /* : only for DOASNTILDE form */
while (p[0] == CHAR && !mksh_cdirsep(p[1]) && while (p[0] == CHAR && /* not cdirsep */ p[1] != '/' &&
(!isassign || p[1] != ':')) { (!isassign || p[1] != ':')) {
Xcheck(ts, tp); Xcheck(ts, tp);
*tp++ = p[1]; *tp++ = p[1];

34
exec.c
View File

@ -2,7 +2,7 @@
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, * 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> * mirabilos <m@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.187 2016/11/12 03:54:48 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/exec.c,v 1.191 2017/03/22 00:20:51 tg Exp $");
#ifndef MKSH_DEFAULT_EXECSHELL #ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh" #define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
@ -1005,13 +1005,17 @@ scriptexec(struct op *tp, const char **ap)
errorf(Tf_sD_sD_s, tp->str, sh, cstrerror(errno)); errorf(Tf_sD_sD_s, tp->str, sh, cstrerror(errno));
} }
/* actual 'builtin' built-in utility call is handled in comexec() */
int 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)); struct tbl *
return (call_builtin(tp, wp, "shcomexec", false)); get_builtin(const char *s)
{
return (s && *s ? ktsearch(&builtins, s, hash(s)) : NULL);
} }
/* /*
@ -1117,6 +1121,14 @@ builtin(const char *name, int (*func) (const char **))
/* external utility overrides built-in utility, with flags */ /* external utility overrides built-in utility, with flags */
flag |= LOW_BI; flag |= LOW_BI;
break; 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: default:
goto flags_seen; goto flags_seen;
} }
@ -1150,7 +1162,11 @@ findcom(const char *name, int flags)
char *fpath; char *fpath;
union mksh_cchack npath; union mksh_cchack npath;
if (mksh_vdirsep(name)) { if (mksh_vdirsep(name)
#ifdef __OS2__
&& (strcmp(name, T_builtin) != 0)
#endif
) {
insert = 0; insert = 0;
/* prevent FPATH search below */ /* prevent FPATH search below */
flags &= ~FC_FUNC; flags &= ~FC_FUNC;
@ -1361,9 +1377,7 @@ call_builtin(struct tbl *tp, const char **wp, const char *where, bool resetspec)
if (!tp) if (!tp)
internal_errorf(Tf_sD_s, where, wp[0]); internal_errorf(Tf_sD_s, where, wp[0]);
builtin_argv0 = wp[0]; builtin_argv0 = wp[0];
builtin_spec = tobool(!resetspec && builtin_spec = tobool(!resetspec && (tp->flag & SPEC_BI));
/*XXX odd use of KEEPASN */
((tp->flag & SPEC_BI) || (Flag(FPOSIX) && (tp->flag & KEEPASN))));
shf_reopen(1, SHF_WR, shl_stdout); shf_reopen(1, SHF_WR, shl_stdout);
shl_stdout_ok = true; shl_stdout_ok = true;
ksh_getopt_reset(&builtin_opt, GF_ERROR); ksh_getopt_reset(&builtin_opt, GF_ERROR);

94
funcs.c
View File

@ -5,7 +5,7 @@
/*- /*-
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, * 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> * mirabilos <m@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -38,7 +38,7 @@
#endif #endif
#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.331 2017/03/22 00:20:41 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
/* /*
@ -92,6 +92,7 @@ c_false(const char **wp MKSH_A_UNUSED)
/* /*
* A leading = means assignments before command are kept. * A leading = means assignments before command are kept.
* A leading * means a POSIX special builtin. * A leading * means a POSIX special builtin.
* A leading ^ means declaration utility, - forwarder.
*/ */
const struct builtin mkshbuiltins[] = { const struct builtin mkshbuiltins[] = {
{Tsgdot, c_dot}, {Tsgdot, c_dot},
@ -100,30 +101,31 @@ const struct builtin mkshbuiltins[] = {
/* no =: AT&T manual wrong */ /* no =: AT&T manual wrong */
{Talias, c_alias}, {Talias, c_alias},
{"*=break", c_brkcont}, {"*=break", c_brkcont},
{Tgbuiltin, c_builtin}, {T__builtin, c_builtin},
{Tbuiltin, c_builtin},
{Tbcat, c_cat}, {Tbcat, c_cat},
{Tcd, c_cd}, {Tcd, c_cd},
/* dash compatibility hack */ /* dash compatibility hack */
{"chdir", c_cd}, {"chdir", c_cd},
{Tcommand, c_command}, {T_command, c_command},
{"*=continue", c_brkcont}, {"*=continue", c_brkcont},
{"echo", c_print}, {"echo", c_print},
{"*=eval", c_eval}, {"*=eval", c_eval},
{"*=exec", c_exec}, {"*=exec", c_exec},
{"*=exit", c_exitreturn}, {"*=exit", c_exitreturn},
{Tsgexport, c_typeset}, {Tdsgexport, c_typeset},
{Tfalse, c_false}, {Tfalse, c_false},
{"fc", c_fc}, {"fc", c_fc},
{Tgetopts, c_getopts}, {Tgetopts, c_getopts},
{"=global", c_typeset}, /* deprecated, replaced by typeset -g */
{"^=global", c_typeset},
{Tjobs, c_jobs}, {Tjobs, c_jobs},
{"kill", c_kill}, {"kill", c_kill},
{"let", c_let}, {"let", c_let},
{"let]", c_let},
{"print", c_print}, {"print", c_print},
{"pwd", c_pwd}, {"pwd", c_pwd},
{Tread, c_read}, {Tread, c_read},
{Tsgreadonly, c_typeset}, {Tdsgreadonly, c_typeset},
{"!realpath", c_realpath}, {"!realpath", c_realpath},
{"~rename", c_rename}, {"~rename", c_rename},
{"*=return", c_exitreturn}, {"*=return", c_exitreturn},
@ -137,12 +139,12 @@ const struct builtin mkshbuiltins[] = {
{"*=times", c_times}, {"*=times", c_times},
{"*=trap", c_trap}, {"*=trap", c_trap},
{Ttrue, c_true}, {Ttrue, c_true},
{Tgtypeset, c_typeset}, {Tdgtypeset, c_typeset},
{"ulimit", c_ulimit}, {"ulimit", c_ulimit},
{"umask", c_umask}, {"umask", c_umask},
{Tunalias, c_unalias}, {Tunalias, c_unalias},
{"*=unset", c_unset}, {"*=unset", c_unset},
{"=wait", c_wait}, {"wait", c_wait},
{"whence", c_whence}, {"whence", c_whence},
#ifndef MKSH_UNEMPLOYED #ifndef MKSH_UNEMPLOYED
{Tbg, c_fgbg}, {Tbg, c_fgbg},
@ -307,8 +309,6 @@ c_print(const char **wp)
bool hist; bool hist;
/* print words as wide characters? */ /* print words as wide characters? */
bool chars; bool chars;
/* print a "--" argument? */
bool pminusminus;
/* writing to a coprocess (SIGPIPE blocked)? */ /* writing to a coprocess (SIGPIPE blocked)? */
bool coproc; bool coproc;
bool copipe; bool copipe;
@ -319,47 +319,39 @@ c_print(const char **wp)
po.ws = ' '; po.ws = ' ';
po.ls = '\n'; po.ls = '\n';
po.nl = true; po.nl = true;
po.exp = true;
if (wp[0][0] == 'e') { if (wp[0][0] == 'e') {
/* "echo" builtin */ /* "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) || if (Flag(FPOSIX) ||
#ifndef MKSH_MIDNIGHTBSD01ASH_COMPAT #ifndef MKSH_MIDNIGHTBSD01ASH_COMPAT
Flag(FSH) || Flag(FSH) ||
#endif #endif
Flag(FAS_BUILTIN)) { 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")) { if (*wp && !strcmp(*wp, "-n")) {
/* recognise "-n" only as the first arg */
po.nl = false; po.nl = false;
++wp; ++wp;
} }
/* print everything as-is */
po.exp = false; po.exp = false;
} else { } else {
bool new_exp = po.exp, new_nl = po.nl; bool new_exp, new_nl = true;
/** /*-
* a compromise between sysV and BSD echo commands: * compromise between various historic echos: only
* escape sequences are enabled by default, and -n, * recognise -Een if they appear in arguments with
* -e and -E are recognised if they appear in argu- * no illegal options; e.g. echo -nq outputs '-nq'
* 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.
*/ */
#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: print_tradparse_arg:
if ((s = *wp) && *s++ == '-' && *s) { if ((s = *wp) && *s++ == '-' && *s) {
@ -375,6 +367,7 @@ c_print(const char **wp)
new_nl = false; new_nl = false;
goto print_tradparse_ch; goto print_tradparse_ch;
case '\0': case '\0':
print_tradparse_beg:
po.exp = new_exp; po.exp = new_exp;
po.nl = new_nl; po.nl = new_nl;
++wp; ++wp;
@ -384,10 +377,10 @@ c_print(const char **wp)
} }
} else { } else {
/* "print" builtin */ /* "print" builtin */
const char *opts = "AclNnpRrsu,"; const char *opts = "AcelNnpRrsu,";
const char *emsg; const char *emsg;
po.pminusminus = false; po.exp = true;
while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1) while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1)
switch (c) { switch (c) {
@ -417,11 +410,9 @@ c_print(const char **wp)
} }
break; break;
case 'R': case 'R':
/* fake BSD echo command */ /* fake BSD echo but don't reset other flags */
po.pminusminus = true; wp += builtin_opt.optind;
po.exp = false; goto bsd_echo;
opts = "en";
break;
case 'r': case 'r':
po.exp = false; po.exp = false;
break; break;
@ -445,8 +436,7 @@ c_print(const char **wp)
if (wp[builtin_opt.optind] && if (wp[builtin_opt.optind] &&
ksh_isdash(wp[builtin_opt.optind])) ksh_isdash(wp[builtin_opt.optind]))
builtin_opt.optind++; builtin_opt.optind++;
} else if (po.pminusminus) }
builtin_opt.optind--;
wp += builtin_opt.optind; wp += builtin_opt.optind;
} }
@ -751,7 +741,7 @@ do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
return (rv); return (rv);
} }
/* typeset, global, export, and readonly */ /* typeset, global(deprecated), export, and readonly */
static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool); static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool);
static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool, static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool,
bool); bool);
@ -793,7 +783,7 @@ c_typeset(const char **wp)
} }
/* see comment below regarding possible opions */ /* see comment below regarding possible opions */
opts = istset ? "L#R#UZ#afi#lnprtux" : "p"; opts = istset ? "L#R#UZ#afgi#lnprtux" : "p";
builtin_opt.flags |= GF_PLUSOPT; builtin_opt.flags |= GF_PLUSOPT;
/* /*
@ -838,6 +828,9 @@ c_typeset(const char **wp)
case 'f': case 'f':
func = true; func = true;
break; break;
case 'g':
localv = (builtin_opt.info & GI_PLUS) ? true : false;
break;
case 'i': case 'i':
flag = INTEGER; flag = INTEGER;
basestr = builtin_opt.optarg; basestr = builtin_opt.optarg;
@ -2392,6 +2385,7 @@ c_eval(const char **wp)
return (1); return (1);
s = pushs(SWORDS, ATEMP); s = pushs(SWORDS, ATEMP);
s->u.strv = wp + builtin_opt.optind; s->u.strv = wp + builtin_opt.optind;
s->line = current_lineno;
/*- /*-
* The following code handles the case where the command is * The following code handles the case where the command is
@ -2833,7 +2827,6 @@ c_exec(const char **wp MKSH_A_UNUSED)
for (i = 0; i < NUFILE; i++) { for (i = 0; i < NUFILE; i++) {
if (e->savefd[i] > 0) if (e->savefd[i] > 0)
close(e->savefd[i]); close(e->savefd[i]);
#ifndef MKSH_LEGACY_MODE
/* /*
* keep all file descriptors > 2 private for ksh, * keep all file descriptors > 2 private for ksh,
* but not for POSIX or legacy/kludge sh * but not for POSIX or legacy/kludge sh
@ -2841,7 +2834,6 @@ c_exec(const char **wp MKSH_A_UNUSED)
if (!Flag(FPOSIX) && !Flag(FSH) && i > 2 && if (!Flag(FPOSIX) && !Flag(FSH) && i > 2 &&
e->savefd[i]) e->savefd[i])
fcntl(i, F_SETFD, FD_CLOEXEC); fcntl(i, F_SETFD, FD_CLOEXEC);
#endif
} }
e->savefd = NULL; e->savefd = NULL;
} }
@ -3682,7 +3674,7 @@ c_ulimit(const char **wp)
if (!all) if (!all)
print_ulimit(rlimits[i], how); print_ulimit(rlimits[i], how);
else for (i = 0; i < NELEM(rlimits); ++i) { 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); print_ulimit(rlimits[i], how);
} }
return (0); return (0);

21
lex.c
View File

@ -2,7 +2,7 @@
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, * 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> * mirabilos <m@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h" #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.231 2017/03/22 00:20:43 tg Exp $");
/* /*
* states while lexing word * states while lexing word
@ -893,9 +893,7 @@ yylex(int cf)
dp = Xstring(ws, wp); dp = Xstring(ws, wp);
if (state == SBASE && ( if (state == SBASE && (
#ifndef MKSH_LEGACY_MODE
(c == '&' && !Flag(FSH) && !Flag(FPOSIX)) || (c == '&' && !Flag(FSH) && !Flag(FPOSIX)) ||
#endif
c == '<' || c == '>') && ((c2 = Xlength(ws, wp)) == 0 || c == '<' || c == '>') && ((c2 = Xlength(ws, wp)) == 0 ||
(c2 == 2 && dp[0] == CHAR && ksh_isdigit(dp[1])))) { (c2 == 2 && dp[0] == CHAR && ksh_isdigit(dp[1])))) {
struct ioword *iop = alloc(sizeof(struct ioword), ATEMP); struct ioword *iop = alloc(sizeof(struct ioword), ATEMP);
@ -1016,15 +1014,12 @@ yylex(int cf)
while ((dp - ident) < IDENT && (c = *sp++) == CHAR) while ((dp - ident) < IDENT && (c = *sp++) == CHAR)
*dp++ = *sp++; *dp++ = *sp++;
if (c != EOS) if (c != EOS)
/* word is not unquoted */ /* word is not unquoted, or space ran out */
dp = ident; dp = ident;
/* make sure the ident array stays NUL padded */ /* make sure the ident array stays NUL padded */
memset(dp, 0, (ident + IDENT) - dp + 1); memset(dp, 0, (ident + IDENT) - dp + 1);
if (!(cf & (KEYWORD | ALIAS))) if (*ident != '\0' && (cf & (KEYWORD | ALIAS))) {
return (LWORD);
if (*ident != '\0') {
struct tbl *p; struct tbl *p;
uint32_t h = hash(ident); uint32_t h = hash(ident);
@ -1068,6 +1063,7 @@ yylex(int cf)
s->start = s->str = p->val.s; s->start = s->str = p->val.s;
s->u.tblp = p; s->u.tblp = p;
s->flags |= SF_HASALIAS; s->flags |= SF_HASALIAS;
s->line = source->line;
s->next = source; s->next = source;
if (source->type == SEOF) { if (source->type == SEOF) {
/* prevent infinite recursion at EOS */ /* prevent infinite recursion at EOS */
@ -1079,9 +1075,12 @@ yylex(int cf)
goto Again; goto Again;
} }
} }
} else if (cf & ALIAS) { } else if (*ident == '\0') {
/* retain typeset et al. even when quoted */ /* 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)); strlcpy(ident, dp, sizeof(ident));
afree(dp, ATEMP); afree(dp, ATEMP);
} }

86
lksh.1
View File

@ -1,6 +1,6 @@
.\" $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.22 2017/02/27 16:04:37 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> .\" mirabilos <m@mirbsd.org>
.\" .\"
.\" Provided that these terms and disclaimer and all copyright notices .\" Provided that these terms and disclaimer and all copyright notices
@ -74,7 +74,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to .\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always. .\" use our own definition. And .Dd must come *first*, always.
.\" .\"
.Dd $Mdocdate: November 11 2016 $ .Dd $Mdocdate: February 27 2017 $
.\" .\"
.\" Check which macro package we use, and do other -mdoc setup. .\" Check which macro package we use, and do other -mdoc setup.
.\" .\"
@ -173,37 +173,34 @@ It is built on
refer to its manual page for details on the scripting language. refer to its manual page for details on the scripting language.
It is recommended to port scripts to It is recommended to port scripts to
.Nm mksh .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. since the MirBSD Korn Shell scripting language is much more consistent.
.Pp .Pp
Do not use
.Nm
as an interactive or login shell; use
.Nm mksh
instead.
.Pp
Note that it's strongly recommended to invoke Note that it's strongly recommended to invoke
.Nm .Nm
with at least the with
.Fl o Ic posix .Fl o Ic posix
option, if not both that
.Em and Fl o Ic sh ,
to fully enjoy better compatibility to the to fully enjoy better compatibility to the
.Tn POSIX .Tn POSIX
standard (which is probably why you use standard (which is probably why you use
.Nm .Nm
over over
.Nm mksh .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 .Sh LEGACY MODE
.Nm .Nm
currently has the following differences from currently has the following differences from
.Nm mksh : .Nm mksh :
.Bl -bullet .Bl -bullet
.It .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 The
.Ev KSH_VERSION .Ev KSH_VERSION
string identifies string identifies
@ -241,25 +238,11 @@ Division of the largest negative number by \-1 is Undefined Behaviour.
The compiler is permitted to delete all data and crash the system The compiler is permitted to delete all data and crash the system
if Undefined Behaviour occurs (see above for an example). if Undefined Behaviour occurs (see above for an example).
.It .It
.\"XXX TODO: move this to FPOSIX
The rotation arithmetic operators are not available. The rotation arithmetic operators are not available.
.It .It
The shift arithmetic operators take all bits of the second operand into The shift arithmetic operators take all bits of the second operand into
account; if they exceed permitted precision, the result is unspecified. account; if they exceed permitted precision, the result is unspecified.
.It .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 Unless
.Ic set -o posix .Ic set -o posix
is active, is active,
@ -275,24 +258,13 @@ passes through the errorlevel from the
.Xr getopt 1 .Xr getopt 1
command. command.
.It .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 Functions defined with the
.Ic function .Ic function
reserved word share the shell options reserved word share the shell options
.Pq Ic set -o .Pq Ic set -o
instead of locally scoping them. instead of locally scoping them.
.It
Support for persistent history is never compiled in.
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr mksh 1 .Xr mksh 1
@ -301,12 +273,6 @@ instead of locally scoping them.
.Pp .Pp
.Pa https://www.mirbsd.org/ksh\-chan.htm .Pa https://www.mirbsd.org/ksh\-chan.htm
.Sh CAVEATS .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 To use
.Nm .Nm
as as
@ -315,16 +281,22 @@ compilation to enable
.Ic set -o posix .Ic set -o posix
by default if called as by default if called as
.Nm sh .Nm sh
.Pq adding Dv \-DMKSH_BINSHPOSIX to Dv CPPFLAGS
is highly recommended for better standards compliance. is highly recommended for better standards compliance.
.Pp
For better compatibility with legacy scripts, such as many For better compatibility with legacy scripts, such as many
.Tn Debian .Tn Debian
maintainer scripts, Upstart and SYSV init scripts, and other 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 .Em both
.Ic set -o posix -o sh .Ic set -o posix -o sh
when the shell is run as when the shell is run as
.Nm sh .Nm sh ,
is recommended. as well as integrating the optional disrecommended
.Xr printf 1
builtin, might be necessary.
.Pp .Pp
.Nm .Nm
tries to make a cross between a legacy bourne/posix compatibl-ish tries to make a cross between a legacy bourne/posix compatibl-ish
@ -332,14 +304,6 @@ shell and a legacy pdksh-alike but
.Dq legacy .Dq legacy
is not exactly specified. is not exactly specified.
.Pp .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 Talk to the
.Mx .Mx
development team using the mailing list at development team using the mailing list at

41
main.c
View File

@ -5,7 +5,7 @@
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, * 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> * mirabilos <m@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -34,7 +34,7 @@
#include <locale.h> #include <locale.h>
#endif #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.328 2017/03/19 22:31:27 tg Exp $");
extern char **environ; extern char **environ;
@ -56,8 +56,6 @@ static mksh_uari_t rndsetup(void);
static void x_sigwinch(int); static void x_sigwinch(int);
#endif #endif
static const char initifs[] = "IFS= \t\n";
static const char initsubs[] = static const char initsubs[] =
"${PS2=> }" "${PS2=> }"
"${PS3=#? }" "${PS3=#? }"
@ -71,18 +69,18 @@ static const char *initcoms[] = {
Ttypeset, "-x", "HOME", TPATH, TSHELL, NULL, Ttypeset, "-x", "HOME", TPATH, TSHELL, NULL,
Ttypeset, "-i10", "COLUMNS", "LINES", "SECONDS", "TMOUT", NULL, Ttypeset, "-i10", "COLUMNS", "LINES", "SECONDS", "TMOUT", NULL,
Talias, Talias,
"integer=\\typeset -i", "integer=\\\\builtin typeset -i",
"local=\\typeset", "local=\\\\builtin typeset",
/* not "alias -t --": hash -r needs to work */ /* not "alias -t --": hash -r needs to work */
"hash=\\builtin alias -t", "hash=\\\\builtin alias -t",
"type=\\builtin whence -v", "type=\\\\builtin whence -v",
"autoload=\\typeset -fu", "autoload=\\\\builtin typeset -fu",
"functions=\\typeset -f", "functions=\\\\builtin typeset -f",
"history=\\builtin fc -l", "history=\\\\builtin fc -l",
"nameref=\\typeset -n", "nameref=\\\\builtin typeset -n",
"nohup=nohup ", "nohup=nohup ",
"r=\\builtin fc -e -", "r=\\\\builtin fc -e -",
"login=\\exec login", "login=\\\\builtin exec login",
NULL, NULL,
/* this is what AT&T ksh seems to track, with the addition of emacs */ /* this is what AT&T ksh seems to track, with the addition of emacs */
Talias, "-tU", Talias, "-tU",
@ -365,9 +363,10 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
} }
/* for security */ /* for security */
typeset(initifs, 0, 0, 0, 0); typeset("IFS= \t\n", 0, 0, 0, 0);
/* assign default shell variable values */ /* assign default shell variable values */
typeset("PATHSEP=" MKSH_PATHSEPS, 0, 0, 0, 0);
substitute(initsubs, 0); substitute(initsubs, 0);
/* Figure out the current working directory and set $PWD */ /* Figure out the current working directory and set $PWD */
@ -384,7 +383,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
setstr(vp, current_wd, KSH_RETURN_ERROR); setstr(vp, current_wd, KSH_RETURN_ERROR);
for (wp = initcoms; *wp != NULL; wp++) { for (wp = initcoms; *wp != NULL; wp++) {
shcomexec(wp); c_builtin(wp);
while (*wp != NULL) while (*wp != NULL)
wp++; wp++;
} }
@ -631,7 +630,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
} }
if (restricted_shell) { if (restricted_shell) {
shcomexec(restr_com); c_builtin(restr_com);
/* After typeset command... */ /* After typeset command... */
Flag(FRESTRICTED) = 1; Flag(FRESTRICTED) = 1;
} }
@ -661,7 +660,7 @@ main(int argc, const char *argv[])
if ((rv = main_init(argc, argv, &s, &l)) == 0) { if ((rv = main_init(argc, argv, &s, &l)) == 0) {
if (Flag(FAS_BUILTIN)) { if (Flag(FAS_BUILTIN)) {
rv = shcomexec(l->argv); rv = c_builtin(l->argv);
} else { } else {
shell(s, true); shell(s, true);
/* NOTREACHED */ /* NOTREACHED */
@ -1275,12 +1274,10 @@ bi_errorf(const char *fmt, ...)
VWARNINGF_BUILTIN, fmt, va); VWARNINGF_BUILTIN, fmt, va);
va_end(va); va_end(va);
/* /* POSIX special builtins cause non-interactive shells to exit */
* POSIX special builtins and ksh special builtins cause
* non-interactive shells to exit. XXX may not want LERROR here
*/
if (builtin_spec) { if (builtin_spec) {
builtin_argv0 = NULL; builtin_argv0 = NULL;
/* may not want to use LERROR here */
unwind(LERROR); unwind(LERROR);
} }
} }

16
misc.c
View File

@ -3,7 +3,7 @@
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, * 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> * mirabilos <m@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -30,7 +30,7 @@
#include <grp.h> #include <grp.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.250 2016/11/12 03:54:48 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.252 2017/03/11 23:56:17 tg Exp $");
#define KSH_CHVT_FLAG #define KSH_CHVT_FLAG
#ifdef MKSH_SMALL #ifdef MKSH_SMALL
@ -40,10 +40,6 @@ __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.250 2016/11/12 03:54:48 tg Exp $");
#define KSH_CHVT_CODE #define KSH_CHVT_CODE
#define KSH_CHVT_FLAG #define KSH_CHVT_FLAG
#endif #endif
#ifdef MKSH_LEGACY_MODE
#undef KSH_CHVT_CODE
#undef KSH_CHVT_FLAG
#endif
/* type bits for unsigned char */ /* type bits for unsigned char */
unsigned char chtypes[UCHAR_MAX + 1]; unsigned char chtypes[UCHAR_MAX + 1];
@ -2154,7 +2150,7 @@ getrusage(int what, struct rusage *ru)
int int
unbksl(bool cstyle, int (*fg)(void), void (*fp)(int)) unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
{ {
int wc, i, c, fc; int wc, i, c, fc, n;
fc = (*fg)(); fc = (*fg)();
switch (fc) { switch (fc) {
@ -2242,7 +2238,8 @@ unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
* four (U: eight) digits; convert to Unicode * four (U: eight) digits; convert to Unicode
*/ */
wc = 0; wc = 0;
while (i--) { n = 0;
while (n < i || i == -1) {
wc <<= 4; wc <<= 4;
if ((c = (*fg)()) >= ord('0') && c <= ord('9')) if ((c = (*fg)()) >= ord('0') && c <= ord('9'))
wc += ksh_numdig(c); wc += ksh_numdig(c);
@ -2255,7 +2252,10 @@ unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
(*fp)(c); (*fp)(c);
break; break;
} }
++n;
} }
if (!n)
goto unknown_escape;
if ((cstyle && wc > 0xFF) || fc != 'x') if ((cstyle && wc > 0xFF) || fc != 'x')
/* Unicode marker */ /* Unicode marker */
wc += 0x100; wc += 0x100;

451
mksh.1
View File

@ -1,8 +1,8 @@
.\" $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.435 2017/03/19 22:31:27 tg Exp $
.\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $ .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $
.\"- .\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, .\" 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> .\" mirabilos <m@mirbsd.org>
.\" .\"
.\" Provided that these terms and disclaimer and all copyright notices .\" Provided that these terms and disclaimer and all copyright notices
@ -76,7 +76,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to .\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always. .\" use our own definition. And .Dd must come *first*, always.
.\" .\"
.Dd $Mdocdate: November 11 2016 $ .Dd $Mdocdate: March 19 2017 $
.\" .\"
.\" Check which macro package we use, and do other -mdoc setup. .\" Check which macro package we use, and do other -mdoc setup.
.\" .\"
@ -186,23 +186,8 @@ sometimes does take portable shell scripting or various standards
into account all information is first and foremost presented with into account all information is first and foremost presented with
.Nm .Nm
in mind and should be taken as such. in mind and should be taken as such.
.Ss I'm an Android user, so what's mksh? .Ss I use Android, OS/2, etc. so what...?
.Nm mksh Please see the FAQ at the end of this document.
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 Invocation .Ss Invocation
Most builtins can be called directly, for example if a link points from its 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. name to the shell; not all make sense, have been tested or work at all though.
@ -1130,17 +1115,17 @@ also by newline) may be one same parse tree.
.Pp .Pp
The following command aliases are defined automatically by the shell: The following command aliases are defined automatically by the shell:
.Bd -literal -offset indent .Bd -literal -offset indent
autoload=\*(aq\etypeset \-fu\*(aq autoload=\*(aq\e\ebuiltin typeset \-fu\*(aq
functions=\*(aq\etypeset \-f\*(aq functions=\*(aq\e\ebuiltin typeset \-f\*(aq
hash=\*(aq\ebuiltin alias \-t\*(aq hash=\*(aq\e\ebuiltin alias \-t\*(aq
history=\*(aq\ebuiltin fc \-l\*(aq history=\*(aq\e\ebuiltin fc \-l\*(aq
integer=\*(aq\etypeset \-i\*(aq integer=\*(aq\e\ebuiltin typeset \-i\*(aq
local=\*(aq\etypeset\*(aq local=\*(aq\e\ebuiltin typeset\*(aq
login=\*(aq\eexec login\*(aq login=\*(aq\e\ebuiltin exec login\*(aq
nameref=\*(aq\etypeset \-n\*(aq nameref=\*(aq\e\ebuiltin typeset \-n\*(aq
nohup=\*(aqnohup \*(aq nohup=\*(aqnohup \*(aq
r=\*(aq\ebuiltin fc \-e \-\*(aq r=\*(aq\e\ebuiltin fc \-e \-\*(aq
type=\*(aq\ebuiltin whence \-v\*(aq type=\*(aq\e\ebuiltin whence \-v\*(aq
.Ed .Ed
.Pp .Pp
Tracked aliases allow the shell to remember where it found a particular Tracked aliases allow the shell to remember where it found a particular
@ -2035,9 +2020,11 @@ searched when looking for commands and files sourced using the
.Dq Li \&. .Dq Li \&.
command (see below). command (see below).
An empty string resulting from a leading or trailing 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 \&. .Dq Li \&.
(the current directory). (the current directory).
.It Ev PATHSEP
A colon (semicolon on OS/2), for the user's convenience.
.It Ev PGRP .It Ev PGRP
The process ID of the shell's process group leader. The process ID of the shell's process group leader.
.It Ev PIPESTATUS .It Ev PIPESTATUS
@ -2127,7 +2114,7 @@ Due to a strong suggestion from David G. Korn,
.Nm .Nm
now also supports the following form: now also supports the following form:
.Bd -literal -offset indent .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 .Ed
.It Ev PS2 .It Ev PS2
Secondary prompt string, by default Secondary prompt string, by default
@ -2185,9 +2172,18 @@ files are created in
The effective user id of the shell. The effective user id of the shell.
.El .El
.Ss Tilde expansion .Ss Tilde expansion
Tilde expansion which is done in parallel with parameter substitution, is done Tilde expansion, which is done in parallel with parameter substitution,
on words starting with an unquoted is applied to words starting with an unquoted
.Ql \*(TI . .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 The characters following the tilde, up to the first
.Ql / , .Ql / ,
if any, are assumed to be a login name. if any, are assumed to be a login name.
@ -2208,21 +2204,6 @@ If the login name is not found in the password file or
if any quoting or parameter substitution occurs in the login name, no if any quoting or parameter substitution occurs in the login name, no
substitution is performed. substitution is performed.
.Pp .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 home directory of previously expanded login names are cached and re-used.
The The
.Ic alias Fl d .Ic alias Fl d
@ -2586,7 +2567,7 @@ Redirections are processed after
pipelines are created and in the order they are given, so the following pipelines are created and in the order they are given, so the following
will print an error with a line number prepended to it: will print an error with a line number prepended to it:
.Pp .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 .Pp
File descriptors created by I/O redirections are private to the shell. File descriptors created by I/O redirections are private to the shell.
.Ss Arithmetic expressions .Ss Arithmetic expressions
@ -3022,18 +3003,18 @@ Additional
.Nm .Nm
commands keeping assignments: commands keeping assignments:
.Pp .Pp
.Ic builtin , global , source , typeset , .Ic global , source , typeset
.Ic wait
.Pp .Pp
Builtins that are not special: Builtins that are not special:
.Pp .Pp
.Ic [ , alias , bg , bind , .Ic [ , alias , bg , bind ,
.Ic cat , cd , command , echo , .Ic builtin , cat , cd , command ,
.Ic false , fc , fg , getopts , .Ic echo , false , fc , fg ,
.Ic jobs , kill , let , print , .Ic getopts , jobs , kill , let ,
.Ic pwd , read , realpath , rename , .Ic print , pwd , read , realpath ,
.Ic sleep , suspend , test , true , .Ic rename , sleep , suspend , test ,
.Ic ulimit , umask , unalias , whence .Ic true , ulimit , umask , unalias ,
.Ic wait , whence
.Pp .Pp
Once the type of command has been determined, any command-line parameter Once the type of command has been determined, any command-line parameter
assignments are performed and exported for the duration of the command. assignments are performed and exported for the duration of the command.
@ -3217,6 +3198,18 @@ Execute the built-in command
.Ar command . .Ar command .
.Pp .Pp
.It Xo .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 .Ic cat
.Op Fl u .Op Fl u
.Op Ar .Op Ar
@ -3346,6 +3339,7 @@ cannot be a shell function;
and secondly, special built-in commands lose their specialness and secondly, special built-in commands lose their specialness
(i.e. redirection and utility errors do not cause the shell to (i.e. redirection and utility errors do not cause the shell to
exit, and command assignments are not permanent). exit, and command assignments are not permanent).
The declaration utility property is not reset.
.Pp .Pp
If the If the
.Fl p .Fl p
@ -3421,8 +3415,10 @@ If the
.Ic posix .Ic posix
or or
.Ic sh .Ic sh
option is set or this is a direct builtin call, only the first argument option is set or this is a direct builtin call or
is treated as an option, and only if it is exactly .Ic print
.Fl R ,
only the first argument is treated as an option, and only if it is exactly
.Dq Li \-n . .Dq Li \-n .
Backslash interpretation is disabled. Backslash interpretation is disabled.
.Pp .Pp
@ -3478,6 +3474,7 @@ parameter.
Sets the export attribute of the named parameters. Sets the export attribute of the named parameters.
Exported parameters are passed in the environment to executed commands. Exported parameters are passed in the environment to executed commands.
If values are specified, the named parameters are also assigned. If values are specified, the named parameters are also assigned.
This is a declaration utility.
.Pp .Pp
If no parameters are specified, all parameters with the export attribute If no parameters are specified, all parameters with the export attribute
set are printed one per line; either their names, or, if a set are printed one per line; either their names, or, if a
@ -3632,9 +3629,22 @@ resetting
.Ev OPTIND .Ev OPTIND
may lead to unexpected results. may lead to unexpected results.
.Pp .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 See
.Ic typeset . .Ic typeset Fl g .
.No Deprecated , Em will
be removed from a future version of
.Nm .
.Pp .Pp
.It Xo .It Xo
.Ic hash .Ic hash
@ -3712,12 +3722,8 @@ If an error occurs during
the parsing or evaluation of an expression, the exit status is greater than 1. the parsing or evaluation of an expression, the exit status is greater than 1.
Since expressions may need to be quoted, Since expressions may need to be quoted,
.No \&(( Ar expr No )) .No \&(( Ar expr No ))
is syntactic sugar for is syntactic sugar for:
.No "{ let '" Ns Ar expr Ns "'; }" . .Dl "{ \e\ebuiltin let \*(aq" Ns Ar expr Ns "\*(aq; }"
.Pp
.It Ic let]
Internally used alias for
.Ic let .
.Pp .Pp
.It Xo .It Xo
.Ic mknod .Ic mknod
@ -3757,13 +3763,13 @@ however, distributors may have added this as builtin as a speed hack.
.Pp .Pp
.It Xo .It Xo
.Ic print .Ic print
.Oo Fl AclNnprsu Ns Oo Ar n Oc \*(Ba .Oo Fl AcelNnprsu Ns Oo Ar n Oc \*(Ba
.Fl R Op Fl en Oc .Fl R Op Fl n Oc
.Op Ar argument ... .Op Ar argument ...
.Xc .Xc
Print the specified argument(s) on the standard output, Print the specified argument(s) on the standard output,
separated by spaces, terminated with a newline. separated by spaces, terminated with a newline.
The C escapes mentioned in The escapes mentioned in
.Sx Backslash expansion .Sx Backslash expansion
above, as well as above, as well as
.Dq Li \ec , .Dq Li \ec ,
@ -3789,6 +3795,9 @@ utility, tab completion, the
built-in utility and the built-in utility and the
.Ic select .Ic select
statement do. statement do.
.It Fl e
Restore backslash expansion after a previous
.Fl r .
.It Fl l .It Fl l
Change the output word separator to newline. Change the output word separator to newline.
.It Fl N .It Fl N
@ -3803,7 +3812,7 @@ above).
Inhibit backslash expansion. Inhibit backslash expansion.
.It Fl s .It Fl s
Print to the history file instead of standard output. 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 Print to the file descriptor
.Ar n Pq defaults to 1 if omitted .Ar n Pq defaults to 1 if omitted
instead of standard output. instead of standard output.
@ -3811,31 +3820,13 @@ instead of standard output.
.Pp .Pp
The The
.Fl R .Fl R
option is used to emulate, to some degree, the option mostly emulates the
.Bx .Bx
.Xr echo 1 .Xr echo 1
command which does not process command which does not expand backslashes and interprets
.Ql \e its first argument as option only if it is exactly
sequences unless the .Dq Li \-n
.Fl e .Pq to suppress the trailing newline .
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.
.Pp .Pp
.It Ic pwd Op Fl LP .It Ic pwd Op Fl LP
Print the present working directory. Print the present working directory.
@ -3970,40 +3961,6 @@ If no input is read or a timeout occurred,
.Ic read .Ic read
exits with a non-zero status. exits with a non-zero status.
.Pp .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 .It Xo
.Ic readonly .Ic readonly
.Op Fl p .Op Fl p
@ -4012,6 +3969,7 @@ exec 3\*(Gt&p; exec 3\*(Gt&\-
.Ar ... Oc .Ar ... Oc
.Xc .Xc
Sets the read-only attribute of the named parameters. Sets the read-only attribute of the named parameters.
This is a declaration utility.
If values are given, If values are given,
parameters are set to them before setting the attribute. parameters are set to them before setting the attribute.
Once a parameter is Once a parameter is
@ -4266,7 +4224,6 @@ Background jobs are run with lower priority.
.It Fl o Ic braceexpand .It Fl o Ic braceexpand
Enable brace expansion (a.k.a. alternation). Enable brace expansion (a.k.a. alternation).
This is enabled by default. This is enabled by default.
If disabled, tilde expansion after an equals sign is disabled as a side effect.
.It Fl o Ic emacs .It Fl o Ic emacs
Enable BRL emacs-like command-line editing (interactive shells only); see Enable BRL emacs-like command-line editing (interactive shells only); see
.Sx Emacs editing mode . .Sx Emacs editing mode .
@ -4800,28 +4757,23 @@ traps in functions are not yet implemented.
A command that exits with a zero value. A command that exits with a zero value.
.Pp .Pp
.It Xo .It Xo
.Ic global .Ic typeset
.Oo Op Ic +\-alpnrtUux .Op Ic +\-aglpnrtUux
.Op Fl L Ns Op Ar n .Oo Fl L Ns Op Ar n
.Op Fl R Ns Op Ar n .No \*(Ba Fl R Ns Op Ar n
.Op Fl Z Ns Op Ar n .No \*(Ba Fl Z Ns Op Ar n Oc
.Op Fl i Ns Op Ar n .Op Fl i Ns Op Ar n
.No \*(Ba Fl f Op Fl tux Oc
.Oo Ar name .Oo Ar name
.Op Ns = Ns Ar value .Op Ns = Ns Ar value
.Ar ... Oc .Ar ... Oc
.Xc .Xc
.It Xo .It Xo
.Ic typeset .Ic typeset
.Oo Op Ic +\-alpnrtUux .Fl f Op Fl tux
.Op Fl LRZ Ns Op Ar n .Op Ar name ...
.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 .Xc
Display or set parameter attributes. Display or set parameter attributes.
This is a declaration utility.
With no With no
.Ar name .Ar name
arguments, parameter attributes are displayed; if no options are used, the arguments, parameter attributes are displayed; if no options are used, the
@ -4837,27 +4789,16 @@ parameter values are not printed.
If If
.Ar name .Ar name
arguments are given, the attributes of the named parameters are set arguments are given, the attributes of the named parameters are set
.Pq Ic \- .Pq Ic \&\-
or cleared 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. Values for parameters may optionally be specified.
For For
.Ar name Ns \&[*] , .Ar name Ns \&[*] ,
the change affects the entire array, and no value may be specified. the change affects all elements of the 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.
.Pp .Pp
When When
.Fl f .Fl f
@ -4877,6 +4818,9 @@ Indexed array attribute.
.It Fl f .It Fl f
Function mode. Function mode.
Display or set functions and their attributes, instead of parameters. 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 .It Fl i Ns Op Ar n
Integer attribute. Integer attribute.
.Ar n .Ar n
@ -5028,7 +4972,7 @@ once they are set.
Also note that the types of limits available are system Also note that the types of limits available are system
dependent \*(en some systems have only the dependent \*(en some systems have only the
.Fl f .Fl f
limit. limit, or not even that, or can set only the soft limits
.Bl -tag -width 5n .Bl -tag -width 5n
.It Fl a .It Fl a
Display all limits; unless Display all limits; unless
@ -5744,9 +5688,6 @@ Goes to history number
.No KILL Pq \*(haU .No KILL Pq \*(haU
.Xc .Xc
Deletes the entire input line. 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 .It kill\-region: \*(haW
Deletes the input between the cursor and the mark. Deletes the input between the cursor and the mark.
.It Xo kill\-to\-eol: .It Xo kill\-to\-eol:
@ -6625,24 +6566,6 @@ The complete legalese is at:
.\" to protect it or lose it, which McKusick almost did. .\" to protect it or lose it, which McKusick almost did.
.\" .\"
.Sh CAVEATS .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 .Nm mksh
provides a consistent 32-bit integer arithmetic implementation, both provides a consistent 32-bit integer arithmetic implementation, both
signed and unsigned, with sign of the result of a remainder operation signed and unsigned, with sign of the result of a remainder operation
@ -6687,6 +6610,8 @@ case ${KSH_VERSION:\-} in
esac esac
.Ed .Ed
In near future, (Unicode) locale tracking will be implemented though. In near future, (Unicode) locale tracking will be implemented though.
.Pp
See also the FAQ below.
.Sh BUGS .Sh BUGS
Suspending (using \*(haZ) pipelines like the one below will only suspend Suspending (using \*(haZ) pipelines like the one below will only suspend
the currently running part of the pipeline; in this example, the currently running part of the pipeline; in this example,
@ -6710,7 +6635,7 @@ for the in-memory portion of the history is slow, should use
.Xr memmove 3 . .Xr memmove 3 .
.Pp .Pp
This document attempts to describe This document attempts to describe
.Nm mksh\ R54 .Nm mksh\ R55
and up, and up,
.\" with vendor patches from insert-your-name-here, .\" with vendor patches from insert-your-name-here,
compiled without any options impacting functionality, such as compiled without any options impacting functionality, such as
@ -6727,9 +6652,8 @@ for an operating environment supporting all of its advanced needs.
Please report bugs in Please report bugs in
.Nm .Nm
to the to the
.Mx
mailing list at
.Aq Mt miros\-mksh@mirbsd.org .Aq Mt miros\-mksh@mirbsd.org
mailing list
or in the or in the
.Li \&#\&!/bin/mksh .Li \&#\&!/bin/mksh
.Pq or Li \&#ksh .Pq or Li \&#ksh
@ -6738,3 +6662,160 @@ IRC channel at
.Pq Port 6697 SSL, 6667 unencrypted , .Pq Port 6697 SSL, 6667 unencrypted ,
or at: or at:
.Pa https://launchpad.net/mksh .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
You will have gotten this shell through komh's port on Shellworld
most likely. It differs from standard mksh in that ASCII (CR+LF)
newlines are accepted in many places.
.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
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.

102
sh.h
View File

@ -10,7 +10,7 @@
/*- /*-
* Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, * 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> * mirabilos <m@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -175,9 +175,9 @@
#endif #endif
#ifdef EXTERN #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.797 2017/03/22 00:20:53 tg Exp $");
#endif #endif
#define MKSH_VERSION "R54 2016/11/11" #define MKSH_VERSION "R54 2017/03/21"
/* arithmetic types: C implementation */ /* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES #if !HAVE_CAN_INTTYPES
@ -630,14 +630,6 @@ im_sorry_dave(void)
} while (/* CONSTCOND */ 0) } while (/* CONSTCOND */ 0)
#endif #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 #ifdef MKSH_SMALL
#ifndef MKSH_NOPWNAM #ifndef MKSH_NOPWNAM
#define MKSH_NOPWNAM /* defined */ #define MKSH_NOPWNAM /* defined */
@ -855,8 +847,8 @@ EXTERN char null[] E_INIT("");
#ifndef HAVE_STRING_POOLING /* helpers for pooled strings */ #ifndef HAVE_STRING_POOLING /* helpers for pooled strings */
EXTERN const char T4spaces[] E_INIT(" "); EXTERN const char T4spaces[] E_INIT(" ");
#define T1space (T4spaces + 3) #define T1space (Treal_sp2 + 5)
EXTERN const char Tcolsp[] E_INIT(": "); #define Tcolsp (Tf_sD_ + 2)
EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n"); EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n");
#define TC_IFSWS (TC_LEX1 + 7) #define TC_IFSWS (TC_LEX1 + 7)
EXTERN const char TFCEDIT_dollaru[] E_INIT("${FCEDIT:-/bin/ed} $_"); EXTERN const char TFCEDIT_dollaru[] E_INIT("${FCEDIT:-/bin/ed} $_");
@ -865,15 +857,16 @@ EXTERN const char Tsgdot[] E_INIT("*=.");
EXTERN const char Taugo[] E_INIT("augo"); EXTERN const char Taugo[] E_INIT("augo");
EXTERN const char Tbracket[] E_INIT("["); EXTERN const char Tbracket[] E_INIT("[");
#define Tdot (Tsgdot + 2) #define Tdot (Tsgdot + 2)
EXTERN const char Talias[] E_INIT("alias"); #define Talias (Tunalias + 2)
EXTERN const char Tbadsubst[] E_INIT("bad substitution"); #define Tbadsubst (Tfg_badsubst + 10)
EXTERN const char Tbg[] E_INIT("bg"); EXTERN const char Tbg[] E_INIT("bg");
EXTERN const char Tbad_bsize[] E_INIT("bad shf/buf/bsize"); EXTERN const char Tbad_bsize[] E_INIT("bad shf/buf/bsize");
#define Tbsize (Tbad_bsize + 12) #define Tbsize (Tbad_bsize + 12)
EXTERN const char Tbad_sig_ss[] E_INIT("%s: bad signal '%s'"); EXTERN const char Tbad_sig_ss[] E_INIT("%s: bad signal '%s'");
#define Tbad_sig_s (Tbad_sig_ss + 4) #define Tbad_sig_s (Tbad_sig_ss + 4)
EXTERN const char Tgbuiltin[] E_INIT("=builtin"); EXTERN const char T__builtin[] E_INIT("-\\builtin");
#define Tbuiltin (Tgbuiltin + 1) #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 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_cd[] E_INIT("restricted shell - can't cd");
EXTERN const char Tcant_find[] E_INIT("can't find"); EXTERN const char Tcant_find[] E_INIT("can't find");
@ -882,26 +875,27 @@ EXTERN const char Tcant_open[] E_INIT("can't open");
EXTERN const char Tbcat[] E_INIT("!cat"); EXTERN const char Tbcat[] E_INIT("!cat");
#define Tcat (Tbcat + 1) #define Tcat (Tbcat + 1)
#define Tcd (Tcant_cd + 25) #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 Tcreate[] E_INIT("create"); EXTERN const char Tcreate[] E_INIT("create");
EXTERN const char TELIF_unexpected[] E_INIT("TELIF unexpected"); EXTERN const char TELIF_unexpected[] E_INIT("TELIF unexpected");
EXTERN const char TEXECSHELL[] E_INIT("EXECSHELL"); EXTERN const char TEXECSHELL[] E_INIT("EXECSHELL");
EXTERN const char Tsgexport[] E_INIT("*=export"); EXTERN const char Tdsgexport[] E_INIT("^*=export");
#define Texport (Tsgexport + 2) #define Texport (Tdsgexport + 3)
#ifdef __OS2__ #ifdef __OS2__
EXTERN const char Textproc[] E_INIT("extproc"); EXTERN const char Textproc[] E_INIT("extproc");
#endif #endif
EXTERN const char Tfalse[] E_INIT("false"); EXTERN const char Tfalse[] E_INIT("false");
EXTERN const char Tfg[] E_INIT("fg"); EXTERN const char Tfg[] E_INIT("fg");
EXTERN const char Tfg_badsubst[] E_INIT("fileglob: bad substitution"); 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 Tfile_fd[] E_INIT("function definition file");
EXTERN const char TFPATH[] E_INIT("FPATH"); EXTERN const char TFPATH[] E_INIT("FPATH");
EXTERN const char T_function[] E_INIT(" function"); EXTERN const char T_function[] E_INIT(" function");
#define Tfunction (T_function + 1) #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 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 Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented");
EXTERN const char Tjobs[] E_INIT("jobs"); EXTERN const char Tjobs[] E_INIT("jobs");
EXTERN const char Tjob_not_started[] E_INIT("job not started"); EXTERN const char Tjob_not_started[] E_INIT("job not started");
@ -917,20 +911,20 @@ EXTERN const char Tnot_found_s[] E_INIT("%s not found");
#define TOLDPWD (Tno_OLDPWD + 3) #define TOLDPWD (Tno_OLDPWD + 3)
#define Topen (Tcant_open + 6) #define Topen (Tcant_open + 6)
#define TPATH (TFPATH + 1) #define TPATH (TFPATH + 1)
EXTERN const char Tpv[] E_INIT("pv"); #define Tpv (TpVv + 1)
EXTERN const char TpVv[] E_INIT("Vpv"); EXTERN const char TpVv[] E_INIT("Vpv");
#define TPWD (Tno_OLDPWD + 6) #define TPWD (Tno_OLDPWD + 6)
EXTERN const char Tread[] E_INIT("read"); #define Tread (Tshf_read + 4)
EXTERN const char Tsgreadonly[] E_INIT("*=readonly"); EXTERN const char Tdsgreadonly[] E_INIT("^*=readonly");
#define Treadonly (Tsgreadonly + 2) #define Treadonly (Tdsgreadonly + 3)
EXTERN const char Tredirection_dup[] E_INIT("can't finish (dup) redirection"); EXTERN const char Tredirection_dup[] E_INIT("can't finish (dup) redirection");
#define Tredirection (Tredirection_dup + 19) #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 Treal_sp2[] E_INIT(" real ");
EXTERN const char Treq_arg[] E_INIT("requires an argument"); EXTERN const char Treq_arg[] E_INIT("requires an argument");
EXTERN const char Tselect[] E_INIT("select"); EXTERN const char Tselect[] E_INIT("select");
EXTERN const char Tsgset[] E_INIT("*=set"); EXTERN const char Tsgset[] E_INIT("*=set");
#define Tset (Tsgset + 2) #define Tset (Tf_parm + 18)
#define Tsh (Tmksh + 2) #define Tsh (Tmksh + 2)
#define TSHELL (TEXECSHELL + 4) #define TSHELL (TEXECSHELL + 4)
EXTERN const char Tshf_read[] E_INIT("shf_read"); EXTERN const char Tshf_read[] E_INIT("shf_read");
@ -943,27 +937,27 @@ EXTERN const char Ttoo_many_args[] E_INIT("too many arguments");
EXTERN const char Ttrue[] E_INIT("true"); EXTERN const char Ttrue[] E_INIT("true");
EXTERN const char Ttty_fd_dupof[] E_INIT("dup of tty fd"); EXTERN const char Ttty_fd_dupof[] E_INIT("dup of tty fd");
#define Ttty_fd (Ttty_fd_dupof + 7) #define Ttty_fd (Ttty_fd_dupof + 7)
EXTERN const char Tgtypeset[] E_INIT("=typeset"); EXTERN const char Tdgtypeset[] E_INIT("^=typeset");
#define Ttypeset (Tgtypeset + 1) #define Ttypeset (Tdgtypeset + 2)
#define Tugo (Taugo + 1) #define Tugo (Taugo + 1)
EXTERN const char Tunalias[] E_INIT("unalias"); EXTERN const char Tunalias[] E_INIT("unalias");
#define Tunexpected (TELIF_unexpected + 6) #define Tunexpected (TELIF_unexpected + 6)
EXTERN const char Tunknown_option[] E_INIT("unknown option"); EXTERN const char Tunknown_option[] E_INIT("unknown option");
EXTERN const char Tuser_sp1[] E_INIT("user "); #define Tuser_sp1 (Tuser_sp2 + 1)
EXTERN const char Tuser_sp2[] E_INIT(" user "); EXTERN const char Tuser_sp2[] E_INIT(" user ");
#define Twrite (Tshf_write + 4) #define Twrite (Tshf_write + 4)
EXTERN const char Tf__S[] E_INIT(" %S"); EXTERN const char Tf__S[] E_INIT(" %S");
EXTERN const char Tf__d[] E_INIT(" %d"); #define Tf__d (Tf_sd + 2)
EXTERN const char Tf__ss[] E_INIT(" %s%s"); 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_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_dN[] E_INIT("%d\n");
EXTERN const char Tf_s_[] E_INIT("%s "); EXTERN const char Tf_s_[] E_INIT("%s ");
EXTERN const char Tf_s_T[] E_INIT("%s %T"); 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_sN[] E_INIT("%s %s %s\n");
EXTERN const char Tf_s_s[] E_INIT("%s %s"); #define Tf_s_s (Tf_sD_s_s + 4)
EXTERN const char Tf_s_sD_s[] E_INIT("%s %s: %s"); #define Tf_s_sD_s (Tf_cant + 6)
EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s"); EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s");
EXTERN const char Tf_sD_[] E_INIT("%s: "); EXTERN const char Tf_sD_[] E_INIT("%s: ");
EXTERN const char Tf_szs[] E_INIT("%s: %zd %s"); EXTERN const char Tf_szs[] E_INIT("%s: %zd %s");
@ -976,18 +970,18 @@ EXTERN const char Tf_nonnum[] E_INIT("non-numeric %s %s '%s'");
#endif #endif
EXTERN const char Tf_S_[] E_INIT("%S "); EXTERN const char Tf_S_[] E_INIT("%S ");
#define Tf_S (Tf__S + 1) #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_toolarge[] E_INIT("%s %s too large: %lu");
EXTERN const char Tf_ldfailed[] E_INIT("%s %s(%d, %ld) failed: %s"); 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_sss[] E_INIT("%s%s%s");
EXTERN const char Tf_sD_s_sD_s[] E_INIT("%s: %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\n");
EXTERN const char Tf_sd[] E_INIT("%s %d"); 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_end[] E_INIT("%;");
EXTERN const char Tft_R[] E_INIT("%R"); EXTERN const char Tft_R[] E_INIT("%R");
#define Tf_d (Tf__d + 1) #define Tf_d (Tf_sd + 3)
EXTERN const char Tf_sD_s_qs[] E_INIT("%s: %s '%s'"); 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_ro[] E_INIT("read-only: %s");
EXTERN const char Tf_flags[] E_INIT("%s: flags 0x%X"); EXTERN const char Tf_flags[] E_INIT("%s: flags 0x%X");
@ -996,8 +990,8 @@ EXTERN const char Tf_ssfaileds[] E_INIT("%s: %s failed: %s");
EXTERN const char Tf_sD_sD_s[] E_INIT("%s: %s: %s"); EXTERN const char Tf_sD_sD_s[] E_INIT("%s: %s: %s");
EXTERN const char Tf__c_[] E_INIT("-%c "); EXTERN const char Tf__c_[] E_INIT("-%c ");
EXTERN const char Tf_sD_s_s[] E_INIT("%s: %s %s"); EXTERN const char Tf_sD_s_s[] E_INIT("%s: %s %s");
#define Tf_sN (Tf__sN + 1) #define Tf_sN (Tf_s_s_sN + 6)
#define Tf_sD_s (Tf_s_sD_s + 3) #define Tf_sD_s (Tf_temp + 24)
EXTERN const char T_devtty[] E_INIT("/dev/tty"); EXTERN const char T_devtty[] E_INIT("/dev/tty");
#else /* helpers for string pooling */ #else /* helpers for string pooling */
#define T4spaces " " #define T4spaces " "
@ -1018,7 +1012,8 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define Tbsize "bsize" #define Tbsize "bsize"
#define Tbad_sig_ss "%s: bad signal '%s'" #define Tbad_sig_ss "%s: bad signal '%s'"
#define Tbad_sig_s "bad signal '%s'" #define Tbad_sig_s "bad signal '%s'"
#define Tgbuiltin "=builtin" #define T__builtin "-\\builtin"
#define T_builtin "\\builtin"
#define Tbuiltin "builtin" #define Tbuiltin "builtin"
#define Toomem "can't allocate %zu data bytes" #define Toomem "can't allocate %zu data bytes"
#define Tcant_cd "restricted shell - can't cd" #define Tcant_cd "restricted shell - can't cd"
@ -1028,11 +1023,12 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define Tbcat "!cat" #define Tbcat "!cat"
#define Tcat "cat" #define Tcat "cat"
#define Tcd "cd" #define Tcd "cd"
#define T_command "-command"
#define Tcommand "command" #define Tcommand "command"
#define Tcreate "create" #define Tcreate "create"
#define TELIF_unexpected "TELIF unexpected" #define TELIF_unexpected "TELIF unexpected"
#define TEXECSHELL "EXECSHELL" #define TEXECSHELL "EXECSHELL"
#define Tsgexport "*=export" #define Tdsgexport "^*=export"
#define Texport "export" #define Texport "export"
#ifdef __OS2__ #ifdef __OS2__
#define Textproc "extproc" #define Textproc "extproc"
@ -1045,7 +1041,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define TFPATH "FPATH" #define TFPATH "FPATH"
#define T_function " function" #define T_function " function"
#define Tfunction "function" #define Tfunction "function"
#define T_funny_command "funny $() command" #define T_funny_command "funny $()-command"
#define Tgetopts "getopts" #define Tgetopts "getopts"
#define Thistory "history" #define Thistory "history"
#define Tintovfl "integer overflow %zu %c %zu prevented" #define Tintovfl "integer overflow %zu %c %zu prevented"
@ -1067,7 +1063,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define TpVv "Vpv" #define TpVv "Vpv"
#define TPWD "PWD" #define TPWD "PWD"
#define Tread "read" #define Tread "read"
#define Tsgreadonly "*=readonly" #define Tdsgreadonly "^*=readonly"
#define Treadonly "readonly" #define Treadonly "readonly"
#define Tredirection_dup "can't finish (dup) redirection" #define Tredirection_dup "can't finish (dup) redirection"
#define Tredirection "redirection" #define Tredirection "redirection"
@ -1089,7 +1085,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define Ttrue "true" #define Ttrue "true"
#define Ttty_fd_dupof "dup of tty fd" #define Ttty_fd_dupof "dup of tty fd"
#define Ttty_fd "tty fd" #define Ttty_fd "tty fd"
#define Tgtypeset "=typeset" #define Tdgtypeset "^=typeset"
#define Ttypeset "typeset" #define Ttypeset "typeset"
#define Tugo "ugo" #define Tugo "ugo"
#define Tunalias "unalias" #define Tunalias "unalias"
@ -1330,7 +1326,7 @@ EXTERN sigset_t sm_default, sm_sigchld;
/* name of called builtin function (used by error functions) */ /* name of called builtin function (used by error functions) */
EXTERN const char *builtin_argv0; 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; EXTERN bool builtin_spec;
/* current working directory */ /* current working directory */
@ -1500,6 +1496,8 @@ EXTERN bool last_lookup_was_array;
#define SPEC_BI BIT(12) /* a POSIX special builtin */ #define SPEC_BI BIT(12) /* a POSIX special builtin */
#define LOWER_BI BIT(13) /* (with LOW_BI) override even w/o flags */ #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 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 * Attributes that can be set by the user (used to decide if an unset
@ -2019,7 +2017,8 @@ int glob_str(char *, XPtrV *, bool);
char *do_tilde(char *); char *do_tilde(char *);
/* exec.c */ /* exec.c */
int execute(struct op * volatile, volatile int, volatile int * volatile); 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); struct tbl *findfunc(const char *, uint32_t, bool);
int define(const char *, struct op *); int define(const char *, struct op *);
const char *builtin(const char *, int (*)(const char **)); const char *builtin(const char *, int (*)(const char **));
@ -2086,8 +2085,6 @@ int c_times(const char **);
int timex(struct op *, int, volatile int *); int timex(struct op *, int, volatile int *);
void timex_hook(struct op *, char ** volatile *); void timex_hook(struct op *, char ** volatile *);
int c_exec(const char **); int c_exec(const char **);
/* dummy function (just need pointer value), special case in comexec() */
#define c_builtin shcomexec
int c_test(const char **); int c_test(const char **);
#if HAVE_MKNOD #if HAVE_MKNOD
int c_mknod(const char **); int c_mknod(const char **);
@ -2303,7 +2300,6 @@ char *shf_smprintf(const char *, ...)
ssize_t shf_vfprintf(struct shf *, const char *, va_list) ssize_t shf_vfprintf(struct shf *, const char *, va_list)
MKSH_A_FORMAT(__printf__, 2, 0); MKSH_A_FORMAT(__printf__, 2, 0);
/* syn.c */ /* syn.c */
int assign_command(const char *, bool) MKSH_A_PURE;
void initkeywords(void); void initkeywords(void);
struct op *compile(Source *, bool); struct op *compile(Source *, bool);
bool parse_usec(const char *, struct timeval *); bool parse_usec(const char *, struct timeval *);

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2013, 2014, 2015 * Copyright (c) 2013, 2014, 2015, 2017
* mirabilos <m@mirbsd.org> * mirabilos <m@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -19,7 +19,7 @@
*/ */
@SHFLAGS_DEFNS @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 @SHFLAGS_ENUMS
#define FN(sname,cname,flags,ochar) cname, #define FN(sname,cname,flags,ochar) cname,
#define F0(sname,cname,flags,ochar) cname = 0, #define F0(sname,cname,flags,ochar) cname = 0,
@ -52,7 +52,7 @@ FN("bgnice", FBGNICE, OF_ANY
FN("braceexpand", FBRACEEXPAND, OF_ANY FN("braceexpand", FBRACEEXPAND, OF_ANY
/* ./. Emacs command line editing mode */ /* ./. Emacs command line editing mode */
>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) >|!MKSH_NO_CMDLINE_EDITING
FN("emacs", FEMACS, OF_ANY FN("emacs", FEMACS, OF_ANY
/* -e quit on error */ /* -e quit on error */
@ -60,7 +60,7 @@ FN("emacs", FEMACS, OF_ANY
FN("errexit", FERREXIT, OF_ANY FN("errexit", FERREXIT, OF_ANY
/* ./. Emacs command line editing mode, gmacs variant */ /* ./. 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 FN("gmacs", FGMACS, OF_ANY
/* ./. reading EOF does not exit */ /* ./. reading EOF does not exit */
@ -160,19 +160,19 @@ FN("utf8-mode", FUNICODE, OF_ANY
FN("verbose", FVERBOSE, OF_ANY FN("verbose", FVERBOSE, OF_ANY
/* ./. Vi command line editing mode */ /* ./. Vi command line editing mode */
>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE) >|!MKSH_NO_CMDLINE_EDITING
FN("vi", FVI, OF_ANY FN("vi", FVI, OF_ANY
/* ./. enable ESC as file name completion character (non-standard) */ /* ./. 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 FN("vi-esccomplete", FVIESCCOMPLETE, OF_ANY
/* ./. enable Tab as file name completion character (non-standard) */ /* ./. 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 FN("vi-tabcomplete", FVITABCOMPLETE, OF_ANY
/* ./. always read in raw mode (no effect) */ /* ./. 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 FN("viraw", FVIRAW, OF_ANY
/* -x execution trace (display commands as they are run) */ /* -x execution trace (display commands as they are run) */

58
syn.c
View File

@ -2,7 +2,7 @@
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, * 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> * mirabilos <m@mirbsd.org>
* *
* Provided that these terms and disclaimer and all copyright notices * Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h" #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.118 2017/03/19 20:59:29 tg Exp $");
struct nesting_state { struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */ int start_token; /* token than began nesting (eg, FOR) */
@ -244,11 +244,15 @@ nested(int type, int smark, int emark)
return (block(type, t, NULL)); 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[] = { 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[] = { static const char setA_cmd0[] = {
QCHAR, 's', CHAR, 'e', CHAR, 't', EOS CHAR, 's', CHAR, 'e', CHAR, 't', EOS
}; };
static const char setA_cmd1[] = { static const char setA_cmd1[] = {
CHAR, '-', CHAR, 'A', EOS CHAR, '-', CHAR, 'A', EOS
@ -289,11 +293,11 @@ get_command(int cf)
t->lineno = source->line; t->lineno = source->line;
goto get_command_start; goto get_command_start;
while (/* CONSTCOND */ 1) { while (/* CONSTCOND */ 1) {
bool check_assign_cmd; bool check_decl_utility;
if (XPsize(args) == 0) { if (XPsize(args) == 0) {
get_command_start: get_command_start:
check_assign_cmd = true; check_decl_utility = true;
cf = sALIAS | CMDASN; cf = sALIAS | CMDASN;
} else if (t->u.evalflags) } else if (t->u.evalflags)
cf = CMDWORD | CMDASN; cf = CMDWORD | CMDASN;
@ -311,16 +315,15 @@ get_command(int cf)
case LWORD: case LWORD:
ACCEPT; ACCEPT;
/* if (check_decl_utility) {
* the iopn == 0 and XPsize(vars) == 0 are struct tbl *tt = get_builtin(ident);
* dubious but AT&T ksh acts this way uint32_t flag;
*/
if (iopn == 0 && XPsize(vars) == 0 && flag = tt ? tt->flag : 0;
check_assign_cmd) { if (flag & DECL_UTIL)
if (assign_command(ident, false))
t->u.evalflags = DOVACHECK; t->u.evalflags = DOVACHECK;
else if (strcmp(ident, Tcommand) != 0) if (!(flag & DECL_FWDR))
check_assign_cmd = false; check_decl_utility = false;
} }
if ((XPsize(args) == 0 || Flag(FKEYWORD)) && if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
is_wdvarassign(yylval.cp)) is_wdvarassign(yylval.cp))
@ -343,6 +346,7 @@ get_command(int cf)
tcp[wdscan(tcp, EOS) - tcp - 3] = EOS; tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
/* construct new args strings */ /* construct new args strings */
XPput(args, wdcopy(builtin_cmd, ATEMP));
XPput(args, wdcopy(setA_cmd0, ATEMP)); XPput(args, wdcopy(setA_cmd0, ATEMP));
XPput(args, wdcopy(setA_cmd1, ATEMP)); XPput(args, wdcopy(setA_cmd1, ATEMP));
XPput(args, tcp); XPput(args, tcp);
@ -412,6 +416,7 @@ get_command(int cf)
} }
t = newtp(TCOM); t = newtp(TCOM);
t->lineno = lno; t->lineno = lno;
XPput(args, wdcopy(builtin_cmd, ATEMP));
XPput(args, wdcopy(let_cmd, ATEMP)); XPput(args, wdcopy(let_cmd, ATEMP));
XPput(args, yylval.cp); XPput(args, yylval.cp);
break; break;
@ -937,29 +942,6 @@ compile(Source *s, bool skiputf8bom)
return (outtree); 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 */ /* Check if we are in the middle of reading an alias */
static int static int
inalias(struct source *s) inalias(struct source *s)