Merge remote-tracking branch 'mksh/master'

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

View File

@ -1,8 +1,8 @@
#!/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,
# 2011, 2012, 2013, 2014, 2015, 2016
# 2011, 2012, 2013, 2014, 2015, 2016, 2017
# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
@ -586,11 +586,10 @@ fi
rmf a.exe* a.out* conftest.c conftest.exe* *core core.* ${tfn}* *.bc *.dbg \
*.ll *.o *.gen *.cat1 Rebuild.sh lft no signames.inc test.sh x vv.out
SRCS="lalloc.c eval.c exec.c expr.c funcs.c histrap.c jobs.c"
SRCS="lalloc.c edit.c eval.c exec.c expr.c funcs.c histrap.c jobs.c"
SRCS="$SRCS lex.c main.c misc.c shf.c syn.c tree.c var.c"
if test $legacy = 0; then
SRCS="$SRCS edit.c"
check_categories="$check_categories shell:legacy-no int:32"
else
check_categories="$check_categories shell:legacy-yes"
@ -766,7 +765,6 @@ Harvey)
add_cppflags -DMKSH__NO_SETEUGID
oswarn=' and will currently not work'
add_cppflags -DMKSH_UNEMPLOYED
add_cppflags -DMKSH_NOPROSPECTOFWORK
# these taken from Harvey-OS github and need re-checking
add_cppflags -D_setjmp=setjmp -D_longjmp=longjmp
: "${HAVE_CAN_NO_EH_FRAME=0}"

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 -*-
#-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014, 2015, 2016
# 2011, 2012, 2013, 2014, 2015, 2016, 2017
# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
@ -30,7 +30,7 @@
# (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
expected-stdout:
@(#)MIRBSD KSH R54 2016/11/11
@(#)MIRBSD KSH R54 2017/03/21
description:
Check version of shell.
stdin:
@ -39,7 +39,7 @@ name: KSH_VERSION
category: shell:legacy-no
---
expected-stdout:
@(#)LEGACY KSH R54 2016/11/11
@(#)LEGACY KSH R54 2017/03/21
description:
Check version of legacy shell.
stdin:
@ -92,23 +92,6 @@ category: disabled
stdin:
set
---
name: selftest-legacy
description:
Check some things in the LEGACY KSH
category: shell:legacy-yes
stdin:
set +o emacs
set +o vi
[[ "$(set +o) -o" = *"-o emacs -o"* ]] && echo 1=emacs
[[ "$(set +o) -o" = *"-o vi -o"* ]] && echo 1=vi
set -o emacs
set -o vi
[[ "$(set +o) -o" = *"-o emacs -o"* ]] && echo 2=emacs
[[ "$(set +o) -o" = *"-o vi -o"* ]] && echo 2=vi
expected-stdout:
2=emacs
2=vi
---
name: selftest-direct-builtin-call
description:
Check that direct builtin calls work
@ -119,6 +102,26 @@ stdin:
expected-stdout:
-c echo foo
---
name: selftest-pathsep-unix
description:
Check that $PATHSEP is set correctly.
category: !os:os2
stdin:
PATHSEP=.; export PATHSEP
"$__progname" -c 'print -r -- $PATHSEP'
expected-stdout:
:
---
name: selftest-pathsep-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
description:
Check that recursion is detected/avoided in aliases.
@ -261,14 +264,21 @@ name: alias-11
description:
Check that special argument handling still applies with escaped aliases
stdin:
alias local='\typeset'
function foo {
local x=$1 y=z
alias local1='\typeset'
alias local2='\\builtin typeset'
function fooa {
local1 x=$1 y=z
print -r -- "$x,$y"
}
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:
bar - baz,z
bar - baz,z
---
name: arith-compound
description:
@ -4711,6 +4721,23 @@ expected-stdout:
8 ok
<9> <ab> <a b> .
---
name: IFS-subst-10
description:
Scalar context in ${var=$subst}
stdin:
showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
set -- one "two three" four
unset -v var
save_IFS=$IFS
IFS=
set -- ${var=$*}
IFS=$save_IFS
echo "var=$var"
showargs "$@"
expected-stdout:
var=onetwo threefour
<onetwo threefour> .
---
name: IFS-arith-1
description:
http://austingroupbugs.net/view.php?id=832
@ -5205,6 +5232,24 @@ expected-stdout:
line <6>
expected-exit: 1
---
name: lineno-eval-alias
description:
Check if LINENO is trapped in eval and aliases
stdin:
${ZSH_VERSION+false} || emulate sh; echo $LINENO
echo $LINENO
eval ' echo $LINENO
echo $LINENO
echo $LINENO'
echo $LINENO
expected-stdout:
1
2
3
3
3
6
---
name: unknown-trap
description:
Ensure unknown traps are not a syntax error
@ -6326,7 +6371,7 @@ name: regression-62
description:
Check if test -nt/-ot succeeds if second(first) file is missing.
stdin:
touch a
:>a
test a -nt b && echo nt OK || echo nt BAD
test b -ot a && echo ot OK || echo ot BAD
expected-stdout:
@ -7058,6 +7103,11 @@ description:
Check tilde expansion works
env-setup: !HOME=/sweet!
stdin:
:>'c=a'
typeset c=[ab]
:>'d=a'
x=typeset; $x d=[ab]
echo "<$c>" "<$d>"
wd=$PWD
cd /
plus=$(print -r -- ~+)
@ -7067,10 +7117,106 @@ stdin:
[[ $minus = "$wd" ]]; echo two $? .
[[ $nix = /sweet ]]; echo nix $? .
expected-stdout:
<[ab]> <a>
one 0 .
two 0 .
nix 0 .
---
name: tilde-expand-3
description:
Check mostly Austin 351 stuff
stdin:
showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
set "1 b=2" "3 d=4"
export a=$1 \c=$2
showargs 1 "$a" "$b" "$c" "$d"
unset a b c d
HOME=/tmp
export \a=~ b=~
command export c=~
builtin export d=~
\\builtin export e=~
showargs 2 "$a" "$b" "$c" "$d" "$e" ksh
unset a b c d e
set -o posix
export \a=~ b=~
command export c=~
builtin export d=~
\\builtin export e=~
showargs 3 "$a" "$b" "$c" "$d" "$e" posix
unset a b c d e
set +o posix
export a=$1
showargs 4 "$a" "$b" ksh
unset a b
showargs 5 a=$1 ksh
export \a=$1
showargs 6 "$a" "$b" ksh
unset a b
set -o posix
export a=$1
showargs 7 "$a" "$b" posix
unset a b
showargs 8 a=$1 posix
export \a=$1
showargs 9 "$a" "$b" posix
unset a b
set +o posix
command echo 10 ksh a=~
command command export a=~
showargs 11 "$a"
unset a
set -o posix
command echo 12 posix a=~
command command export a=~
showargs 13 "$a"
unset a
# unspecified whether /tmp or ~
var=export; command $var a=~
showargs 14 "$a"
echo 'echo "<$foo>"' >bar
"$__progname" bar
var=foo
export $var=1
"$__progname" bar
export $var=~
"$__progname" bar
# unspecified
command -- export a=~
showargs 18 "$a"
set -A bla
typeset bla[1]=~:~
global gbl=~ g2=$1
local lcl=~ l2=$1
readonly ro=~ r2=$1
showargs 19 "${bla[1]}" a=~ "$gbl" "$lcl" "$ro" "$g2" "$l2" "$r2"
set +o posix
echo "20 some arbitrary stuff "=~
set -o posix
echo "21 some arbitrary stuff "=~
expected-stdout:
<1> <1 b=2> <> <3> <4> .
<2> </tmp> </tmp> </tmp> </tmp> </tmp> <ksh> .
<3> <~> </tmp> </tmp> <~> </tmp> <posix> .
<4> <1 b=2> <> <ksh> .
<5> <a=1> <b=2> <ksh> .
<6> <1> <2> <ksh> .
<7> <1 b=2> <> <posix> .
<8> <a=1> <b=2> <posix> .
<9> <1> <2> <posix> .
10 ksh a=/tmp
<11> </tmp> .
12 posix a=~
<13> </tmp> .
<14> <~> .
<>
<1>
<~>
<18> <~> .
<19> </tmp:/tmp> <a=~> </tmp> </tmp> </tmp> <1 b=2> <1 b=2> <1 b=2> .
20 some arbitrary stuff =/tmp
21 some arbitrary stuff =~
---
name: exit-err-1
description:
Check some "exit on error" conditions
@ -7903,11 +8049,11 @@ expected-stderr-pattern:
---
name: typeset-1
description:
Check that global does what typeset is supposed to do
Check that typeset -g works correctly
stdin:
set -A arrfoo 65
foo() {
global -Uui16 arrfoo[*]
typeset -g -Uui16 arrfoo[*]
}
echo before ${arrfoo[0]} .
foo
@ -7917,7 +8063,7 @@ stdin:
echo inside before ${arrbar[0]} .
arrbar[0]=97
echo inside changed ${arrbar[0]} .
global -Uui16 arrbar[*]
typeset -g -Uui16 arrbar[*]
echo inside typeset ${arrbar[0]} .
arrbar[0]=48
echo inside changed ${arrbar[0]} .
@ -8173,17 +8319,17 @@ stdin:
alias
typeset -f
expected-stdout:
autoload='\typeset -fu'
functions='\typeset -f'
hash='\builtin alias -t'
history='\builtin fc -l'
integer='\typeset -i'
local='\typeset'
login='\exec login'
nameref='\typeset -n'
autoload='\\builtin typeset -fu'
functions='\\builtin typeset -f'
hash='\\builtin alias -t'
history='\\builtin fc -l'
integer='\\builtin typeset -i'
local='\\builtin typeset'
login='\\builtin exec login'
nameref='\\builtin typeset -n'
nohup='nohup '
r='\builtin fc -e -'
type='\builtin whence -v'
r='\\builtin fc -e -'
type='\\builtin whence -v'
---
name: aliases-2b
description:
@ -8193,17 +8339,17 @@ stdin:
alias
typeset -f
expected-stdout:
autoload='\typeset -fu'
functions='\typeset -f'
hash='\builtin alias -t'
history='\builtin fc -l'
integer='\typeset -i'
local='\typeset'
login='\exec login'
nameref='\typeset -n'
autoload='\\builtin typeset -fu'
functions='\\builtin typeset -f'
hash='\\builtin alias -t'
history='\\builtin fc -l'
integer='\\builtin typeset -i'
local='\\builtin typeset'
login='\\builtin exec login'
nameref='\\builtin typeset -n'
nohup='nohup '
r='\builtin fc -e -'
type='\builtin whence -v'
r='\\builtin fc -e -'
type='\\builtin whence -v'
---
name: aliases-3b
description:
@ -8213,17 +8359,17 @@ stdin:
./sh -c 'alias; typeset -f'
rm -f sh
expected-stdout:
autoload='\typeset -fu'
functions='\typeset -f'
hash='\builtin alias -t'
history='\builtin fc -l'
integer='\typeset -i'
local='\typeset'
login='\exec login'
nameref='\typeset -n'
autoload='\\builtin typeset -fu'
functions='\\builtin typeset -f'
hash='\\builtin alias -t'
history='\\builtin fc -l'
integer='\\builtin typeset -i'
local='\\builtin typeset'
login='\\builtin exec login'
nameref='\\builtin typeset -n'
nohup='nohup '
r='\builtin fc -e -'
type='\builtin whence -v'
r='\\builtin fc -e -'
type='\\builtin whence -v'
---
name: aliases-cmdline
description:
@ -8280,8 +8426,8 @@ stdin:
:|| local() { :; }
alias local
expected-stdout:
local='\typeset'
local='\typeset'
local='\\builtin typeset'
local='\\builtin typeset'
---
name: arrays-1
description:
@ -8691,21 +8837,21 @@ expected-stdout:
name: arrassign-fnc-global
description:
Check locality of array access inside a function
with the mksh-specific global keyword
with the bash4/mksh/yash/zsh typeset -g keyword
stdin:
function fn {
global x
typeset -g x
x+=(f)
echo ".fn:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
}
function rfn {
set -A y
global y
typeset -g y
y+=(f)
echo ".rfn:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
}
function fnr {
global z
typeset -g z
set -A z
z+=(f)
echo ".fnr:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
@ -8843,21 +8989,21 @@ expected-stdout:
name: strassign-fnc-global
description:
Check locality of string access inside a function
with the mksh-specific global keyword
with the bash4/mksh/yash/zsh typeset -g keyword
stdin:
function fn {
global x
typeset -g x
x+=f
echo ".fn:$x:"
}
function rfn {
y=
global y
typeset -g y
y+=f
echo ".rfn:$y:"
}
function fnr {
global z
typeset -g z
z=
z+=f
echo ".fnr:$z:"
@ -9221,7 +9367,7 @@ stdin:
while (( i < ${#line[*]} )); do
hv=${line[i++]}
if (( (pos & 15) == 0 )); then
(( pos )) && print "$dasc|"
(( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
@ -9238,7 +9384,7 @@ stdin:
print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- '
done
(( hv == 2147483647 )) || print "$dasc|"
(( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 3C 64 E4 DB C3 9B E2 82 - AC C3 9B 40 3E 0A 3C 00 |<d.........@>.<.|
@ -9364,7 +9510,7 @@ stdin:
while [[ -n $line ]]; do
hv=1#${line::1}
if (( (pos & 15) == 0 )); then
(( pos )) && print "$dasc|"
(( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
@ -9382,7 +9528,7 @@ stdin:
print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- '
done
(( hv == 2147483647 )) || print "$dasc|"
(( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 5C 20 5C 21 5C 22 5C 23 - 5C 24 5C 25 5C 26 5C 27 |\ \!\"\#\$\%\&\'|
@ -9391,13 +9537,13 @@ expected-stdout:
00000030 20 5C 39 5C 3A 5C 3B 5C - 3C 5C 3D 5C 3E 5C 3F 5C | \9\:\;\<\=\>\?\|
00000040 40 5C 41 5C 42 5C 43 5C - 44 1B 5C 46 5C 47 5C 48 |@\A\B\C\D.\F\G\H|
00000050 5C 49 5C 4A 5C 4B 5C 4C - 5C 4D 5C 4E 5C 4F 5C 50 |\I\J\K\L\M\N\O\P|
00000060 5C 51 5C 52 5C 53 5C 54 - 20 5C 56 5C 57 5C 58 5C |\Q\R\S\T \V\W\X\|
00000070 59 5C 5A 5C 5B 5C 5C 5D - 5C 5E 5C 5F 5C 60 07 08 |Y\Z\[\]\^\_\`..|
00000080 20 20 5C 64 1B 0C 5C 67 - 5C 68 5C 69 5C 6A 5C 6B | \d..\g\h\i\j\k|
00000090 5C 6C 5C 6D 0A 5C 6F 5C - 70 20 5C 71 0D 5C 73 09 |\l\m.\o\p \q.\s.|
000000A0 0B 5C 77 5C 79 5C 7A 5C - 7B 5C 7C 5C 7D 5C 7E 20 |.\w\y\z\{\|\}\~ |
000000B0 E2 82 AC 64 20 EF BF BD - 20 12 33 20 78 20 53 20 |...d ... .3 x S |
000000C0 53 34 0A - |S4.|
00000060 5C 51 5C 52 5C 53 5C 54 - 20 5C 55 5C 56 5C 57 5C |\Q\R\S\T \U\V\W\|
00000070 58 5C 59 5C 5A 5C 5B 5C - 5C 5D 5C 5E 5C 5F 5C 60 |X\Y\Z\[\\]\^\_\`|
00000080 07 08 20 20 5C 64 1B 0C - 5C 67 5C 68 5C 69 5C 6A |.. \d..\g\h\i\j|
00000090 5C 6B 5C 6C 5C 6D 0A 5C - 6F 5C 70 20 5C 71 0D 5C |\k\l\m.\o\p \q.\|
000000A0 73 09 5C 75 0B 5C 77 5C - 78 5C 79 5C 7A 5C 7B 5C |s.\u.\w\x\y\z\{\|
000000B0 7C 5C 7D 5C 7E 20 E2 82 - AC 64 20 EF BF BD 20 12 ||\}\~ ...d ... .|
000000C0 33 20 78 20 53 20 53 34 - 0A |3 x S S4.|
---
name: dollar-doublequoted-strings
description:
@ -9439,7 +9585,7 @@ stdin:
while [[ -n $line ]]; do
hv=1#${line::1}
if (( (pos & 15) == 0 )); then
(( pos )) && print "$dasc|"
(( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
@ -9457,7 +9603,7 @@ stdin:
print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- '
done
(( hv == 2147483647 )) || print "$dasc|"
(( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 20 21 22 23 24 25 26 27 - 28 29 2A 2B 2C 2D 2E 2F | !"#$%&'()*+,-./|
@ -9767,7 +9913,7 @@ stdin:
while [[ -n $line ]]; do
hv=1#${line::1}
if (( (pos & 15) == 0 )); then
(( pos )) && print "$dasc|"
(( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
@ -9785,7 +9931,7 @@ stdin:
print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- '
done
(( hv == 2147483647 )) || print "$dasc|"
(( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 48 65 6C 6C 6F 2C 20 57 - 6F 72 6C 64 21 5C 0A E3 |Hello, World!\..|
@ -9855,7 +10001,7 @@ stdin:
dasc=$dasc$dch
dch=
elif (( (pos & 7) == 0 )); then
(( pos )) && print "$dasc|"
(( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
@ -9870,7 +10016,7 @@ stdin:
print -n ' '
(( (pos++ & 7) == 3 )) && print -n -- '- '
done
(( hv == 2147483647 )) || print "$dasc|"
(( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 0048 0065 006C 006C - 006F 002C 0020 0057 |Hello, W|
@ -9936,7 +10082,7 @@ stdin:
while (( i < ${#line[*]} )); do
hv=${line[i++]}
if (( (pos & 15) == 0 )); then
(( pos )) && print "$dasc|"
(( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
@ -9953,7 +10099,7 @@ stdin:
print -n ' '
(( (pos++ & 15) == 7 )) && print -n -- '- '
done
(( hv == 2147483647 )) || print "$dasc|"
(( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 48 65 6C 6C 6F 2C 20 57 - 6F 72 6C 64 21 5C 0A E3 |Hello, World!\..|
@ -10019,7 +10165,7 @@ stdin:
dasc=$dasc$dch
dch=
elif (( (pos & 7) == 0 )); then
(( pos )) && print "$dasc|"
(( pos )) && print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
@ -10033,7 +10179,7 @@ stdin:
print -n ' '
(( (pos++ & 7) == 3 )) && print -n -- '- '
done
(( hv == 2147483647 )) || print "$dasc|"
(( hv == 2147483647 )) || print -r -- "$dasc|"
}
expected-stdout:
00000000 0048 0065 006C 006C - 006F 002C 0020 0057 |Hello, W|
@ -10123,9 +10269,16 @@ expected-stdout:
16#61 16#0 16#62 16#20AC 16#63 .
---
name: ulimit-1
description:
Check that ulimit as used in dot.mksh works or is stubbed
stdin:
ulimit -c 0
---
name: ulimit-2
description:
Check if we can use a specific syntax idiom for ulimit
category: !os:syllable
XXX Haiku works, but only for -n and -V
category: !os:haiku,!os:syllable
stdin:
if ! x=$(ulimit -d) || [[ $x = unknown ]]; then
#echo expected to fail on this OS
@ -10170,7 +10323,6 @@ name: bashiop-1
description:
Check if GNU bash-like I/O redirection works
Part 1: this is also supported by GNU bash
category: shell:legacy-no
stdin:
exec 3>&1
function threeout {
@ -10191,7 +10343,6 @@ name: bashiop-2a
description:
Check if GNU bash-like I/O redirection works
Part 2: this is *not* supported by GNU bash
category: shell:legacy-no
stdin:
exec 3>&1
function threeout {
@ -10212,7 +10363,6 @@ name: bashiop-2b
description:
Check if GNU bash-like I/O redirection works
Part 2: this is *not* supported by GNU bash
category: shell:legacy-no
stdin:
exec 3>&1
function threeout {
@ -10233,7 +10383,6 @@ name: bashiop-2c
description:
Check if GNU bash-like I/O redirection works
Part 2: this is supported by GNU bash 4 only
category: shell:legacy-no
stdin:
echo mir >foo
set -o noclobber
@ -10257,7 +10406,6 @@ name: bashiop-3a
description:
Check if GNU bash-like I/O redirection fails correctly
Part 1: this is also supported by GNU bash
category: shell:legacy-no
stdin:
echo mir >foo
set -o noclobber
@ -10279,7 +10427,6 @@ name: bashiop-3b
description:
Check if GNU bash-like I/O redirection fails correctly
Part 2: this is *not* supported by GNU bash
category: shell:legacy-no
stdin:
echo mir >foo
set -o noclobber
@ -10303,7 +10450,6 @@ description:
Check if GNU bash-like I/O redirection works
Part 4: this is also supported by GNU bash,
but failed in some mksh versions
category: shell:legacy-no
stdin:
exec 3>&1
function threeout {
@ -10325,11 +10471,10 @@ expected-stdout:
ras
dwa
---
name: bashiop-5-normal
name: bashiop-5
description:
Check if GNU bash-like I/O redirection is only supported
in !POSIX !sh mode as it breaks existing scripts' syntax
category: shell:legacy-no
stdin:
:>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
:>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
@ -10339,20 +10484,6 @@ expected-stdout:
2 = bar .
3 = bar .
---
name: bashiop-5-legacy
description:
Check if GNU bash-like I/O redirection is not parsed
in lksh as it breaks existing scripts' syntax
category: shell:legacy-yes
stdin:
:>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
:>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
:>x; echo 3 "$("$__progname" -o sh -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
expected-stdout:
1 = bar .
2 = bar .
3 = bar .
---
name: oksh-eval
description:
Check expansions.
@ -10589,7 +10720,6 @@ description:
AT&T ksh93 does this still, which means we must keep it as well
XXX fails on some old Perl installations
need-pass: no
category: shell:legacy-no
stdin:
cat >cld <<-EOF
#!$__perlname
@ -10622,22 +10752,6 @@ stdin:
expected-stdout:
Fowl
---
name: fd-cloexec-3
description:
Verify that file descriptors > 2 are not private for LEGACY KSH
category: shell:legacy-yes
stdin:
cat >cld <<-EOF
#!$__perlname
open(my \$fh, ">&", 9) or die "E: open \$!";
syswrite(\$fh, "Fowl\\n", 5) or die "E: write \$!";
EOF
chmod +x cld
exec 9>&1
./cld
expected-stdout:
Fowl
---
name: comsub-1a
description:
COMSUB are now parsed recursively, so this works
@ -11015,7 +11129,7 @@ expected-stdout:
inline_TWHILE() {
i=1
while {
\let] " i < 10 "
\\builtin let " i < 10 "
}
do
echo $i
@ -11026,13 +11140,13 @@ expected-stdout:
i=1; while (( i < 10 )); do echo $i; let ++i; done
); }
function comsub_TWHILE {
x=$(i=1 ; while { \let] " i < 10 " ; } ; do echo $i ; let ++i ; done )
x=$(i=1 ; while { \\builtin let " i < 10 " ; } ; do echo $i ; let ++i ; done )
}
function reread_TWHILE { x=$((
i=1; while (( i < 10 )); do echo $i; let ++i; done
)|tr u x); }
function reread_TWHILE {
x=$(( i=1 ; while { \let] " i < 10 " ; } ; do echo $i ; let ++i ; done ) | tr u x )
x=$(( i=1 ; while { \\builtin let " i < 10 " ; } ; do echo $i ; let ++i ; done ) | tr u x )
}
inline_TUNTIL() {
i=10; until (( !--i )) ; do echo $i; done
@ -11040,7 +11154,7 @@ expected-stdout:
inline_TUNTIL() {
i=10
until {
\let] " !--i "
\\builtin let " !--i "
}
do
echo $i
@ -11050,13 +11164,13 @@ expected-stdout:
i=10; until (( !--i )) ; do echo $i; done
); }
function comsub_TUNTIL {
x=$(i=10 ; until { \let] " !--i " ; } ; do echo $i ; done )
x=$(i=10 ; until { \\builtin let " !--i " ; } ; do echo $i ; done )
}
function reread_TUNTIL { x=$((
i=10; until (( !--i )) ; do echo $i; done
)|tr u x); }
function reread_TUNTIL {
x=$(( i=10 ; until { \let] " !--i " ; } ; do echo $i ; done ) | tr u x )
x=$(( i=10 ; until { \\builtin let " !--i " ; } ; do echo $i ; done ) | tr u x )
}
inline_TCOPROC() {
cat * |& ls
@ -11432,7 +11546,7 @@ expected-stdout:
case x in
(x)
a+=b
\set -A c+ -- d e
\\builtin set -A c+ -- d e
;;
esac
}
@ -11442,7 +11556,7 @@ expected-stdout:
esac
); }
function comsub_wdarrassign {
x=$(case x in (x) a+=b ; \set -A c+ -- d e ;; esac )
x=$(case x in (x) a+=b ; \\builtin set -A c+ -- d e ;; esac )
}
function reread_wdarrassign { x=$((
case x in
@ -11450,7 +11564,7 @@ expected-stdout:
esac
)|tr u x); }
function reread_wdarrassign {
x=$(( case x in (x) a+=b ; \set -A c+ -- d e ;; esac ) | tr u x )
x=$(( case x in (x) a+=b ; \\builtin set -A c+ -- d e ;; esac ) | tr u x )
}
---
name: comsub-torture-io
@ -11671,7 +11785,7 @@ expected-stdout:
inline_TWHILE() {
i=1
while {
\let] " i < 10 "
\\builtin let " i < 10 "
} >&3
do
echo $i
@ -11682,13 +11796,13 @@ expected-stdout:
i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
); }
function comsub_TWHILE {
x=$(i=1 ; while { \let] " i < 10 " ; } >&3 ; do echo $i ; let ++i ; done >&3 )
x=$(i=1 ; while { \\builtin let " i < 10 " ; } >&3 ; do echo $i ; let ++i ; done >&3 )
}
function reread_TWHILE { x=$((
i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
)|tr u x); }
function reread_TWHILE {
x=$(( i=1 ; while { \let] " i < 10 " ; } >&3 ; do echo $i ; let ++i ; done >&3 ) | tr u x )
x=$(( i=1 ; while { \\builtin let " i < 10 " ; } >&3 ; do echo $i ; let ++i ; done >&3 ) | tr u x )
}
inline_TUNTIL() {
i=10; until (( !--i )) >&3 ; do echo $i; done >&3
@ -11696,7 +11810,7 @@ expected-stdout:
inline_TUNTIL() {
i=10
until {
\let] " !--i "
\\builtin let " !--i "
} >&3
do
echo $i
@ -11706,13 +11820,13 @@ expected-stdout:
i=10; until (( !--i )) >&3 ; do echo $i; done >&3
); }
function comsub_TUNTIL {
x=$(i=10 ; until { \let] " !--i " ; } >&3 ; do echo $i ; done >&3 )
x=$(i=10 ; until { \\builtin let " !--i " ; } >&3 ; do echo $i ; done >&3 )
}
function reread_TUNTIL { x=$((
i=10; until (( !--i )) >&3 ; do echo $i; done >&3
)|tr u x); }
function reread_TUNTIL {
x=$(( i=10 ; until { \let] " !--i " ; } >&3 ; do echo $i ; done >&3 ) | tr u x )
x=$(( i=10 ; until { \\builtin let " !--i " ; } >&3 ; do echo $i ; done >&3 ) | tr u x )
}
inline_TCOPROC() {
cat * >&3 |& >&3 ls

View File

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

8
edit.c
View File

@ -5,7 +5,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015, 2016
* 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -28,7 +28,7 @@
#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
@ -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";
* if we have a directory part (the former), try to expand
*/
if (*s == '~' && (cp = mksh_sdirsep(s)) != NULL) {
if (*s == '~' && (cp = /* not sdirsep */ strchr(s, '/')) != NULL) {
/* ok, so split into "~foo"/"bar" or "~"/"baz" */
*cp++ = 0;
/* try to expand the tilde */
@ -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') */
*flagsp |= XCF_IS_NOSPACE;
goto dont_add_glob;

35
eval.c
View File

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

34
exec.c
View File

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015, 2016
* 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#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
#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));
}
/* actual 'builtin' built-in utility call is handled in comexec() */
int
shcomexec(const char **wp)
c_builtin(const char **wp)
{
struct tbl *tp;
return (call_builtin(get_builtin(*wp), wp, Tbuiltin, false));
}
tp = ktsearch(&builtins, *wp, hash(*wp));
return (call_builtin(tp, wp, "shcomexec", false));
struct tbl *
get_builtin(const char *s)
{
return (s && *s ? ktsearch(&builtins, s, hash(s)) : NULL);
}
/*
@ -1117,6 +1121,14 @@ builtin(const char *name, int (*func) (const char **))
/* external utility overrides built-in utility, with flags */
flag |= LOW_BI;
break;
case '-':
/* is declaration utility if argv[1] is one (POSIX: command) */
flag |= DECL_FWDR;
break;
case '^':
/* is declaration utility (POSIX: export, readonly) */
flag |= DECL_UTIL;
break;
default:
goto flags_seen;
}
@ -1150,7 +1162,11 @@ findcom(const char *name, int flags)
char *fpath;
union mksh_cchack npath;
if (mksh_vdirsep(name)) {
if (mksh_vdirsep(name)
#ifdef __OS2__
&& (strcmp(name, T_builtin) != 0)
#endif
) {
insert = 0;
/* prevent FPATH search below */
flags &= ~FC_FUNC;
@ -1361,9 +1377,7 @@ call_builtin(struct tbl *tp, const char **wp, const char *where, bool resetspec)
if (!tp)
internal_errorf(Tf_sD_s, where, wp[0]);
builtin_argv0 = wp[0];
builtin_spec = tobool(!resetspec &&
/*XXX odd use of KEEPASN */
((tp->flag & SPEC_BI) || (Flag(FPOSIX) && (tp->flag & KEEPASN))));
builtin_spec = tobool(!resetspec && (tp->flag & SPEC_BI));
shf_reopen(1, SHF_WR, shl_stdout);
shl_stdout_ok = true;
ksh_getopt_reset(&builtin_opt, GF_ERROR);

94
funcs.c
View File

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

21
lex.c
View File

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

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>
.\"
.\" 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
.\" 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.
.\"
@ -173,37 +173,34 @@ It is built on
refer to its manual page for details on the scripting language.
It is recommended to port scripts to
.Nm mksh
instead of relying on legacy or idiotic POSIX-mandated behaviour,
instead of relying on legacy or objectionable POSIX-mandated behaviour,
since the MirBSD Korn Shell scripting language is much more consistent.
.Pp
Do not use
.Nm
as an interactive or login shell; use
.Nm mksh
instead.
.Pp
Note that it's strongly recommended to invoke
.Nm
with at least the
with
.Fl o Ic posix
option, if not both that
.Em and Fl o Ic sh ,
to fully enjoy better compatibility to the
.Tn POSIX
standard (which is probably why you use
.Nm
over
.Nm mksh
in the first place) or legacy scripts, respectively.
in the first place);
.Fl o Ic sh
(possibly additionally to the above) may be needed for some legacy scripts.
.Sh LEGACY MODE
.Nm
currently has the following differences from
.Nm mksh :
.Bl -bullet
.It
.\"XXX TODO: remove (some systems may wish to have lksh as ksh)
There is no explicit support for interactive use,
nor any command line editing or history code.
Hence,
.Nm
is not suitable as a user's login shell, either; use
.Nm mksh
instead.
.It
The
.Ev KSH_VERSION
string identifies
@ -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
if Undefined Behaviour occurs (see above for an example).
.It
.\"XXX TODO: move this to FPOSIX
The rotation arithmetic operators are not available.
.It
The shift arithmetic operators take all bits of the second operand into
account; if they exceed permitted precision, the result is unspecified.
.It
.\"XXX TODO: move this to FPOSIX
The
.Tn GNU
.Nm bash
extension &\*(Gt to redirect stdout and stderr in one go is not parsed.
.It
.\"XXX TODO: drop along with allowing interactivity
The
.Nm mksh
command line option
.Fl T
is not available.
.It
Unless
.Ic set -o posix
is active,
@ -275,24 +258,13 @@ passes through the errorlevel from the
.Xr getopt 1
command.
.It
.\"XXX TODO: move to FPOSIX/FSH
Unlike
.At
.Nm ksh ,
.Nm mksh
in
.Fl o Ic posix
or
.Fl o Ic sh
mode and
.Nm lksh
do not keep file descriptors \*(Gt 2 private from sub-processes.
.It
Functions defined with the
.Ic function
reserved word share the shell options
.Pq Ic set -o
instead of locally scoping them.
.It
Support for persistent history is never compiled in.
.El
.Sh SEE ALSO
.Xr mksh 1
@ -301,12 +273,6 @@ instead of locally scoping them.
.Pp
.Pa https://www.mirbsd.org/ksh\-chan.htm
.Sh CAVEATS
The distinction between the shell variants
.Pq Nm lksh / Nm mksh
and shell flags
.Pq Fl o Ic posix / Ic sh
will be reworked for an upcoming release.
.Pp
To use
.Nm
as
@ -315,16 +281,22 @@ compilation to enable
.Ic set -o posix
by default if called as
.Nm sh
.Pq adding Dv \-DMKSH_BINSHPOSIX to Dv CPPFLAGS
is highly recommended for better standards compliance.
.Pp
For better compatibility with legacy scripts, such as many
.Tn Debian
maintainer scripts, Upstart and SYSV init scripts, and other
unfixed scripts, using the compile-time options for enabling
unfixed scripts, also adding the
.Dv \-DMKSH_BINSHREDUCED
compile-time option to enable
.Em both
.Ic set -o posix -o sh
when the shell is run as
.Nm sh
is recommended.
.Nm sh ,
as well as integrating the optional disrecommended
.Xr printf 1
builtin, might be necessary.
.Pp
.Nm
tries to make a cross between a legacy bourne/posix compatibl-ish
@ -332,14 +304,6 @@ shell and a legacy pdksh-alike but
.Dq legacy
is not exactly specified.
.Pp
The
.Ic set
built-in command does not currently have all options one would expect
from a full-blown
.Nm mksh
or
.Nm pdksh .
.Pp
Talk to the
.Mx
development team using the mailing list at

41
main.c
View File

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

16
misc.c
View File

@ -3,7 +3,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015, 2016
* 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -30,7 +30,7 @@
#include <grp.h>
#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
#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_FLAG
#endif
#ifdef MKSH_LEGACY_MODE
#undef KSH_CHVT_CODE
#undef KSH_CHVT_FLAG
#endif
/* type bits for unsigned char */
unsigned char chtypes[UCHAR_MAX + 1];
@ -2154,7 +2150,7 @@ getrusage(int what, struct rusage *ru)
int
unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
{
int wc, i, c, fc;
int wc, i, c, fc, n;
fc = (*fg)();
switch (fc) {
@ -2242,7 +2238,8 @@ unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
* four (U: eight) digits; convert to Unicode
*/
wc = 0;
while (i--) {
n = 0;
while (n < i || i == -1) {
wc <<= 4;
if ((c = (*fg)()) >= ord('0') && c <= ord('9'))
wc += ksh_numdig(c);
@ -2255,7 +2252,10 @@ unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
(*fp)(c);
break;
}
++n;
}
if (!n)
goto unknown_escape;
if ((cstyle && wc > 0xFF) || fc != 'x')
/* Unicode marker */
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 $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
.\" 2010, 2011, 2012, 2013, 2014, 2015, 2016
.\" 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
.\" mirabilos <m@mirbsd.org>
.\"
.\" Provided that these terms and disclaimer and all copyright notices
@ -76,7 +76,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
.Dd $Mdocdate: November 11 2016 $
.Dd $Mdocdate: March 19 2017 $
.\"
.\" 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
.Nm
in mind and should be taken as such.
.Ss I'm an Android user, so what's mksh?
.Nm mksh
is a
.Ux
shell / command interpreter, similar to
.Nm COMMAND.COM
or
.Nm CMD.EXE ,
which has been included with
.Tn Android Open Source Project
for a while now.
Basically, it's a program that runs in a terminal (console window),
takes user input and runs commands or scripts, which it can also
be asked to do by other programs, even in the background.
Any privilege pop-ups you might be encountering are thus not
.Nm mksh
issues but questions by some other program utilising it.
.Ss I use Android, OS/2, etc. so what...?
Please see the FAQ at the end of this document.
.Ss Invocation
Most builtins can be called directly, for example if a link points from its
name to the shell; not all make sense, have been tested or work at all though.
@ -1130,17 +1115,17 @@ also by newline) may be one same parse tree.
.Pp
The following command aliases are defined automatically by the shell:
.Bd -literal -offset indent
autoload=\*(aq\etypeset \-fu\*(aq
functions=\*(aq\etypeset \-f\*(aq
hash=\*(aq\ebuiltin alias \-t\*(aq
history=\*(aq\ebuiltin fc \-l\*(aq
integer=\*(aq\etypeset \-i\*(aq
local=\*(aq\etypeset\*(aq
login=\*(aq\eexec login\*(aq
nameref=\*(aq\etypeset \-n\*(aq
autoload=\*(aq\e\ebuiltin typeset \-fu\*(aq
functions=\*(aq\e\ebuiltin typeset \-f\*(aq
hash=\*(aq\e\ebuiltin alias \-t\*(aq
history=\*(aq\e\ebuiltin fc \-l\*(aq
integer=\*(aq\e\ebuiltin typeset \-i\*(aq
local=\*(aq\e\ebuiltin typeset\*(aq
login=\*(aq\e\ebuiltin exec login\*(aq
nameref=\*(aq\e\ebuiltin typeset \-n\*(aq
nohup=\*(aqnohup \*(aq
r=\*(aq\ebuiltin fc \-e \-\*(aq
type=\*(aq\ebuiltin whence \-v\*(aq
r=\*(aq\e\ebuiltin fc \-e \-\*(aq
type=\*(aq\e\ebuiltin whence \-v\*(aq
.Ed
.Pp
Tracked aliases allow the shell to remember where it found a particular
@ -2035,9 +2020,11 @@ searched when looking for commands and files sourced using the
.Dq Li \&.
command (see below).
An empty string resulting from a leading or trailing
colon, or two adjacent colons, is treated as a
(semi)colon, or two adjacent ones, is treated as a
.Dq Li \&.
(the current directory).
.It Ev PATHSEP
A colon (semicolon on OS/2), for the user's convenience.
.It Ev PGRP
The process ID of the shell's process group leader.
.It Ev PIPESTATUS
@ -2127,7 +2114,7 @@ Due to a strong suggestion from David G. Korn,
.Nm
now also supports the following form:
.Bd -literal -offset indent
PS1=$'\e1\er\e1\ee[7m\e1$PWD\e1\ee[0m\e1\*(Gt '
PS1=$\*(aq\e1\er\e1\ee[7m\e1$PWD\e1\ee[0m\e1\*(Gt \*(aq
.Ed
.It Ev PS2
Secondary prompt string, by default
@ -2185,9 +2172,18 @@ files are created in
The effective user id of the shell.
.El
.Ss Tilde expansion
Tilde expansion which is done in parallel with parameter substitution, is done
on words starting with an unquoted
Tilde expansion, which is done in parallel with parameter substitution,
is applied to words starting with an unquoted
.Ql \*(TI .
In parameter assignments (such as those preceding a simple-command or those
occurring in the arguments of a declaration utility), tilde expansion is done
after any assignment (i.e. after the equals sign) or after an unquoted colon
.Pq Ql \&: ;
login names are also delimited by colons.
The Korn shell, except in POSIX mode, always expands tildes after unquoted
equals signs, not just in assignment context (see below), and enables tab
completion for tildes after all unquoted colons during command line editing.
.Pp
The characters following the tilde, up to the first
.Ql / ,
if any, are assumed to be a login name.
@ -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
substitution is performed.
.Pp
In parameter assignments
(such as those preceding a simple-command or those occurring
in the arguments of
.Ic alias ,
.Ic export ,
.Ic global ,
.Ic readonly
and
.Ic typeset ) ,
tilde expansion is done after any assignment
(i.e. after the equals sign)
or after an unquoted colon
.Pq Ql \&: ;
login names are also delimited by colons.
.Pp
The home directory of previously expanded login names are cached and re-used.
The
.Ic alias Fl d
@ -2586,7 +2567,7 @@ Redirections are processed after
pipelines are created and in the order they are given, so the following
will print an error with a line number prepended to it:
.Pp
.D1 $ cat /foo/bar 2\*(Gt&1 \*(Gt/dev/null \*(Ba pr \-n \-t
.Dl $ cat /foo/bar 2\*(Gt&1 \*(Gt/dev/null \*(Ba pr \-n \-t
.Pp
File descriptors created by I/O redirections are private to the shell.
.Ss Arithmetic expressions
@ -3022,18 +3003,18 @@ Additional
.Nm
commands keeping assignments:
.Pp
.Ic builtin , global , source , typeset ,
.Ic wait
.Ic global , source , typeset
.Pp
Builtins that are not special:
.Pp
.Ic [ , alias , bg , bind ,
.Ic cat , cd , command , echo ,
.Ic false , fc , fg , getopts ,
.Ic jobs , kill , let , print ,
.Ic pwd , read , realpath , rename ,
.Ic sleep , suspend , test , true ,
.Ic ulimit , umask , unalias , whence
.Ic builtin , cat , cd , command ,
.Ic echo , false , fc , fg ,
.Ic getopts , jobs , kill , let ,
.Ic print , pwd , read , realpath ,
.Ic rename , sleep , suspend , test ,
.Ic true , ulimit , umask , unalias ,
.Ic wait , whence
.Pp
Once the type of command has been determined, any command-line parameter
assignments are performed and exported for the duration of the command.
@ -3217,6 +3198,18 @@ Execute the built-in command
.Ar command .
.Pp
.It Xo
.Ic \ebuiltin
.Ar command Op Ar arg ...
.Xc
Same as
.Ic builtin .
Additionally acts as declaration utility forwarder, i.e. this is a
declaration utility (see
.Sx Tilde expansion )
.No iff Ar command
is a declaration utility.
.Pp
.It Xo
.Ic cat
.Op Fl u
.Op Ar
@ -3346,6 +3339,7 @@ cannot be a shell function;
and secondly, special built-in commands lose their specialness
(i.e. redirection and utility errors do not cause the shell to
exit, and command assignments are not permanent).
The declaration utility property is not reset.
.Pp
If the
.Fl p
@ -3421,8 +3415,10 @@ If the
.Ic posix
or
.Ic sh
option is set or this is a direct builtin call, only the first argument
is treated as an option, and only if it is exactly
option is set or this is a direct builtin call or
.Ic print
.Fl R ,
only the first argument is treated as an option, and only if it is exactly
.Dq Li \-n .
Backslash interpretation is disabled.
.Pp
@ -3478,6 +3474,7 @@ parameter.
Sets the export attribute of the named parameters.
Exported parameters are passed in the environment to executed commands.
If values are specified, the named parameters are also assigned.
This is a declaration utility.
.Pp
If no parameters are specified, all parameters with the export attribute
set are printed one per line; either their names, or, if a
@ -3632,9 +3629,22 @@ resetting
.Ev OPTIND
may lead to unexpected results.
.Pp
.It global Ar ...
.It Xo
.Ic global
.Op Ic +\-aglpnrtUux
.Oo Fl L Ns Op Ar n
.No \*(Ba Fl R Ns Op Ar n
.No \*(Ba Fl Z Ns Op Ar n Oc
.Op Fl i Ns Op Ar n
.Oo Ar name
.Op Ns = Ns Ar value
.Ar ... Oc
.Xc
See
.Ic typeset .
.Ic typeset Fl g .
.No Deprecated , Em will
be removed from a future version of
.Nm .
.Pp
.It Xo
.Ic hash
@ -3712,12 +3722,8 @@ If an error occurs during
the parsing or evaluation of an expression, the exit status is greater than 1.
Since expressions may need to be quoted,
.No \&(( Ar expr No ))
is syntactic sugar for
.No "{ let '" Ns Ar expr Ns "'; }" .
.Pp
.It Ic let]
Internally used alias for
.Ic let .
is syntactic sugar for:
.Dl "{ \e\ebuiltin let \*(aq" Ns Ar expr Ns "\*(aq; }"
.Pp
.It Xo
.Ic mknod
@ -3757,13 +3763,13 @@ however, distributors may have added this as builtin as a speed hack.
.Pp
.It Xo
.Ic print
.Oo Fl AclNnprsu Ns Oo Ar n Oc \*(Ba
.Fl R Op Fl en Oc
.Oo Fl AcelNnprsu Ns Oo Ar n Oc \*(Ba
.Fl R Op Fl n Oc
.Op Ar argument ...
.Xc
Print the specified argument(s) on the standard output,
separated by spaces, terminated with a newline.
The C escapes mentioned in
The escapes mentioned in
.Sx Backslash expansion
above, as well as
.Dq Li \ec ,
@ -3789,6 +3795,9 @@ utility, tab completion, the
built-in utility and the
.Ic select
statement do.
.It Fl e
Restore backslash expansion after a previous
.Fl r .
.It Fl l
Change the output word separator to newline.
.It Fl N
@ -3803,7 +3812,7 @@ above).
Inhibit backslash expansion.
.It Fl s
Print to the history file instead of standard output.
.It Fl u Op Ar n
.It Fl u Ns Op Ar n
Print to the file descriptor
.Ar n Pq defaults to 1 if omitted
instead of standard output.
@ -3811,31 +3820,13 @@ instead of standard output.
.Pp
The
.Fl R
option is used to emulate, to some degree, the
option mostly emulates the
.Bx
.Xr echo 1
command which does not process
.Ql \e
sequences unless the
.Fl e
option is given.
As above, the
.Fl n
option suppresses the trailing newline.
.Pp
.It Ic printf Ar format Op Ar arguments ...
Formatted output.
Approximately the same as the
.Xr printf 1 ,
utility, except it uses the same
.Sx Backslash expansion
and I/O code and does not handle floating point as the rest of
.Nm mksh .
An external utility is preferred over the builtin.
This is not normally part of
.Nm mksh ;
however, distributors may have added this as builtin as a speed hack.
Do not use in new code.
command which does not expand backslashes and interprets
its first argument as option only if it is exactly
.Dq Li \-n
.Pq to suppress the trailing newline .
.Pp
.It Ic pwd Op Fl LP
Print the present working directory.
@ -3970,40 +3961,6 @@ If no input is read or a timeout occurred,
.Ic read
exits with a non-zero status.
.Pp
Another handy set of tricks:
If
.Ic read
is run in a loop such as
.Ic while read foo; do ...; done
then leading whitespace will be removed (IFS) and backslashes processed.
You might want to use
.Ic while IFS= read \-r foo; do ...; done
for pristine I/O.
Similarly, when using the
.Fl a
option, use of the
.Fl r
option might be prudent; the same applies for:
.Bd -literal -offset indent
find . \-type f \-print0 \*(Ba& \e
while IFS= read \-d \*(aq\*(aq \-pr filename; do
print \-r \-\- "found \*(Lt${filename#./}\*(Gt"
done
.Ed
.Pp
The inner loop will be executed in a subshell and variable changes
cannot be propagated if executed in a pipeline:
.Bd -literal -offset indent
bar \*(Ba baz \*(Ba while read foo; do ...; done
.Ed
.Pp
Use co-processes instead:
.Bd -literal -offset indent
bar \*(Ba baz \*(Ba&
while read \-p foo; do ...; done
exec 3\*(Gt&p; exec 3\*(Gt&\-
.Ed
.Pp
.It Xo
.Ic readonly
.Op Fl p
@ -4012,6 +3969,7 @@ exec 3\*(Gt&p; exec 3\*(Gt&\-
.Ar ... Oc
.Xc
Sets the read-only attribute of the named parameters.
This is a declaration utility.
If values are given,
parameters are set to them before setting the attribute.
Once a parameter is
@ -4266,7 +4224,6 @@ Background jobs are run with lower priority.
.It Fl o Ic braceexpand
Enable brace expansion (a.k.a. alternation).
This is enabled by default.
If disabled, tilde expansion after an equals sign is disabled as a side effect.
.It Fl o Ic emacs
Enable BRL emacs-like command-line editing (interactive shells only); see
.Sx Emacs editing mode .
@ -4800,28 +4757,23 @@ traps in functions are not yet implemented.
A command that exits with a zero value.
.Pp
.It Xo
.Ic global
.Oo Op Ic +\-alpnrtUux
.Op Fl L Ns Op Ar n
.Op Fl R Ns Op Ar n
.Op Fl Z Ns Op Ar n
.Ic typeset
.Op Ic +\-aglpnrtUux
.Oo Fl L Ns Op Ar n
.No \*(Ba Fl R Ns Op Ar n
.No \*(Ba Fl Z Ns Op Ar n Oc
.Op Fl i Ns Op Ar n
.No \*(Ba Fl f Op Fl tux Oc
.Oo Ar name
.Op Ns = Ns Ar value
.Ar ... Oc
.Xc
.It Xo
.Ic typeset
.Oo Op Ic +\-alpnrtUux
.Op Fl LRZ Ns Op Ar n
.Op Fl i Ns Op Ar n
.No \*(Ba Fl f Op Fl tux Oc
.Oo Ar name
.Op Ns = Ns Ar value
.Ar ... Oc
.Fl f Op Fl tux
.Op Ar name ...
.Xc
Display or set parameter attributes.
This is a declaration utility.
With no
.Ar name
arguments, parameter attributes are displayed; if no options are used, the
@ -4837,27 +4789,16 @@ parameter values are not printed.
If
.Ar name
arguments are given, the attributes of the named parameters are set
.Pq Ic \-
.Pq Ic \&\-
or cleared
.Pq Ic + .
.Pq Ic \&+ ;
inside a function, this will cause the parameters to be created
(with no value) in the local scope (but see
.Fl g ) .
Values for parameters may optionally be specified.
For
.Ar name Ns \&[*] ,
the change affects the entire array, and no value may be specified.
.Pp
If
.Ic typeset
is used inside a function, any parameters specified are localised.
This is not done by the otherwise identical
.Ic global .
.Em Note :
This means that
.Nm No 's Ic global
command is
.Em not
equivalent to other programming languages' as it does not allow a
function called from another function to access a parameter at truly
global scope, but only prevents putting an accessed one into local scope.
the change affects all elements of the array, and no value may be specified.
.Pp
When
.Fl f
@ -4877,6 +4818,9 @@ Indexed array attribute.
.It Fl f
Function mode.
Display or set functions and their attributes, instead of parameters.
.It Fl g
Do not cause named parameters to be created in
the local scope when called inside a function.
.It Fl i Ns Op Ar n
Integer attribute.
.Ar n
@ -5028,7 +4972,7 @@ once they are set.
Also note that the types of limits available are system
dependent \*(en some systems have only the
.Fl f
limit.
limit, or not even that, or can set only the soft limits
.Bl -tag -width 5n
.It Fl a
Display all limits; unless
@ -5744,9 +5688,6 @@ Goes to history number
.No KILL Pq \*(haU
.Xc
Deletes the entire input line.
If Ctrl-U should only delete the line up to the cursor, use:
.Pp
.D1 $ bind \-m \*(haU='\*(ha[0\*(haK'
.It kill\-region: \*(haW
Deletes the input between the cursor and the mark.
.It Xo kill\-to\-eol:
@ -6625,24 +6566,6 @@ The complete legalese is at:
.\" to protect it or lose it, which McKusick almost did.
.\"
.Sh CAVEATS
.Nm
has a different scope model from
.At
.Nm ksh ,
which leads to subtle differences in semantics for identical builtins.
This can cause issues with a
.Ic nameref
to suddenly point to a local variable by accident; fixing this is hard.
.Pp
The parts of a pipeline, like below, are executed in subshells.
Thus, variable assignments inside them are not visible in the
surrounding execution environment.
Use co-processes instead.
.Bd -literal -offset indent
foo \*(Ba bar \*(Ba read baz # will not change $baz
foo \*(Ba bar \*(Ba& read \-p baz # will, however, do so
.Ed
.Pp
.Nm mksh
provides a consistent 32-bit integer arithmetic implementation, both
signed and unsigned, with sign of the result of a remainder operation
@ -6687,6 +6610,8 @@ case ${KSH_VERSION:\-} in
esac
.Ed
In near future, (Unicode) locale tracking will be implemented though.
.Pp
See also the FAQ below.
.Sh BUGS
Suspending (using \*(haZ) pipelines like the one below will only suspend
the currently running part of the pipeline; in this example,
@ -6710,7 +6635,7 @@ for the in-memory portion of the history is slow, should use
.Xr memmove 3 .
.Pp
This document attempts to describe
.Nm mksh\ R54
.Nm mksh\ R55
and up,
.\" with vendor patches from insert-your-name-here,
compiled without any options impacting functionality, such as
@ -6727,9 +6652,8 @@ for an operating environment supporting all of its advanced needs.
Please report bugs in
.Nm
to the
.Mx
mailing list at
.Aq Mt miros\-mksh@mirbsd.org
mailing list
or in the
.Li \&#\&!/bin/mksh
.Pq or Li \&#ksh
@ -6738,3 +6662,160 @@ IRC channel at
.Pq Port 6697 SSL, 6667 unencrypted ,
or at:
.Pa https://launchpad.net/mksh
.Sh FREQUENTLY ASKED QUESTIONS
This FAQ attempts to document some of the questions users of
.Nm
or readers of this manual page may encounter.
.Ss I'm an Android user, so what's mksh?
.Nm mksh
is a
.Ux
shell / command interpreter, similar to
.Nm COMMAND.COM
or
.Nm CMD.EXE ,
which has been included with
.Tn Android Open Source Project
for a while now.
Basically, it's a program that runs in a terminal (console window),
takes user input and runs commands or scripts, which it can also
be asked to do by other programs, even in the background.
Any privilege pop-ups you might be encountering are thus not
.Nm mksh
issues but questions by some other program utilising it.
.Ss "I'm an OS/2 user, what do I need to know?"
Unlike the native command prompt, the current working directory is,
for security reasons common on Unix systems which the shell is designed for,
not in the search path at all; if you really need this, run the command
.Li PATH=.$PATHSEP$PATH
or add that to a suitable initialisation file.
.Pp
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,
* 2011, 2012, 2013, 2014, 2015, 2016
* 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -175,9 +175,9 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.791 2016/11/11 23:31:38 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.797 2017/03/22 00:20:53 tg Exp $");
#endif
#define MKSH_VERSION "R54 2016/11/11"
#define MKSH_VERSION "R54 2017/03/21"
/* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES
@ -630,14 +630,6 @@ im_sorry_dave(void)
} while (/* CONSTCOND */ 0)
#endif
#ifdef MKSH_LEGACY_MODE
#ifndef MKSH_NO_CMDLINE_EDITING
#define MKSH_NO_CMDLINE_EDITING /* defined */
#endif
#undef MKSH_S_NOVI
#define MKSH_S_NOVI 1
#endif
#ifdef MKSH_SMALL
#ifndef MKSH_NOPWNAM
#define MKSH_NOPWNAM /* defined */
@ -855,8 +847,8 @@ EXTERN char null[] E_INIT("");
#ifndef HAVE_STRING_POOLING /* helpers for pooled strings */
EXTERN const char T4spaces[] E_INIT(" ");
#define T1space (T4spaces + 3)
EXTERN const char Tcolsp[] E_INIT(": ");
#define T1space (Treal_sp2 + 5)
#define Tcolsp (Tf_sD_ + 2)
EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n");
#define TC_IFSWS (TC_LEX1 + 7)
EXTERN const char TFCEDIT_dollaru[] E_INIT("${FCEDIT:-/bin/ed} $_");
@ -865,15 +857,16 @@ EXTERN const char Tsgdot[] E_INIT("*=.");
EXTERN const char Taugo[] E_INIT("augo");
EXTERN const char Tbracket[] E_INIT("[");
#define Tdot (Tsgdot + 2)
EXTERN const char Talias[] E_INIT("alias");
EXTERN const char Tbadsubst[] E_INIT("bad substitution");
#define Talias (Tunalias + 2)
#define Tbadsubst (Tfg_badsubst + 10)
EXTERN const char Tbg[] E_INIT("bg");
EXTERN const char Tbad_bsize[] E_INIT("bad shf/buf/bsize");
#define Tbsize (Tbad_bsize + 12)
EXTERN const char Tbad_sig_ss[] E_INIT("%s: bad signal '%s'");
#define Tbad_sig_s (Tbad_sig_ss + 4)
EXTERN const char Tgbuiltin[] E_INIT("=builtin");
#define Tbuiltin (Tgbuiltin + 1)
EXTERN const char T__builtin[] E_INIT("-\\builtin");
#define T_builtin (T__builtin + 1)
#define Tbuiltin (T__builtin + 2)
EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes");
EXTERN const char Tcant_cd[] E_INIT("restricted shell - can't cd");
EXTERN const char Tcant_find[] E_INIT("can't find");
@ -882,26 +875,27 @@ EXTERN const char Tcant_open[] E_INIT("can't open");
EXTERN const char Tbcat[] E_INIT("!cat");
#define Tcat (Tbcat + 1)
#define Tcd (Tcant_cd + 25)
EXTERN const char Tcommand[] E_INIT("command");
#define T_command (T_funny_command + 9)
#define Tcommand (T_funny_command + 10)
EXTERN const char Tcreate[] E_INIT("create");
EXTERN const char TELIF_unexpected[] E_INIT("TELIF unexpected");
EXTERN const char TEXECSHELL[] E_INIT("EXECSHELL");
EXTERN const char Tsgexport[] E_INIT("*=export");
#define Texport (Tsgexport + 2)
EXTERN const char Tdsgexport[] E_INIT("^*=export");
#define Texport (Tdsgexport + 3)
#ifdef __OS2__
EXTERN const char Textproc[] E_INIT("extproc");
#endif
EXTERN const char Tfalse[] E_INIT("false");
EXTERN const char Tfg[] E_INIT("fg");
EXTERN const char Tfg_badsubst[] E_INIT("fileglob: bad substitution");
EXTERN const char Tfile[] E_INIT("file");
#define Tfile (Tfile_fd + 20)
EXTERN const char Tfile_fd[] E_INIT("function definition file");
EXTERN const char TFPATH[] E_INIT("FPATH");
EXTERN const char T_function[] E_INIT(" function");
#define Tfunction (T_function + 1)
EXTERN const char T_funny_command[] E_INIT("funny $() command");
EXTERN const char T_funny_command[] E_INIT("funny $()-command");
EXTERN const char Tgetopts[] E_INIT("getopts");
EXTERN const char Thistory[] E_INIT("history");
#define Thistory (Tnot_in_history + 7)
EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented");
EXTERN const char Tjobs[] E_INIT("jobs");
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 Topen (Tcant_open + 6)
#define TPATH (TFPATH + 1)
EXTERN const char Tpv[] E_INIT("pv");
#define Tpv (TpVv + 1)
EXTERN const char TpVv[] E_INIT("Vpv");
#define TPWD (Tno_OLDPWD + 6)
EXTERN const char Tread[] E_INIT("read");
EXTERN const char Tsgreadonly[] E_INIT("*=readonly");
#define Treadonly (Tsgreadonly + 2)
#define Tread (Tshf_read + 4)
EXTERN const char Tdsgreadonly[] E_INIT("^*=readonly");
#define Treadonly (Tdsgreadonly + 3)
EXTERN const char Tredirection_dup[] E_INIT("can't finish (dup) redirection");
#define Tredirection (Tredirection_dup + 19)
EXTERN const char Treal_sp1[] E_INIT("real ");
#define Treal_sp1 (Treal_sp2 + 1)
EXTERN const char Treal_sp2[] E_INIT(" real ");
EXTERN const char Treq_arg[] E_INIT("requires an argument");
EXTERN const char Tselect[] E_INIT("select");
EXTERN const char Tsgset[] E_INIT("*=set");
#define Tset (Tsgset + 2)
#define Tset (Tf_parm + 18)
#define Tsh (Tmksh + 2)
#define TSHELL (TEXECSHELL + 4)
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 Ttty_fd_dupof[] E_INIT("dup of tty fd");
#define Ttty_fd (Ttty_fd_dupof + 7)
EXTERN const char Tgtypeset[] E_INIT("=typeset");
#define Ttypeset (Tgtypeset + 1)
EXTERN const char Tdgtypeset[] E_INIT("^=typeset");
#define Ttypeset (Tdgtypeset + 2)
#define Tugo (Taugo + 1)
EXTERN const char Tunalias[] E_INIT("unalias");
#define Tunexpected (TELIF_unexpected + 6)
EXTERN const char 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 ");
#define Twrite (Tshf_write + 4)
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__sN[] E_INIT(" %s\n");
#define Tf__sN (Tf_s_s_sN + 5)
EXTERN const char Tf_sSs[] E_INIT("%s/%s");
EXTERN const char Tf_T[] E_INIT("%T");
#define Tf_T (Tf_s_T + 3)
EXTERN const char Tf_dN[] E_INIT("%d\n");
EXTERN const char Tf_s_[] E_INIT("%s ");
EXTERN const char Tf_s_T[] E_INIT("%s %T");
EXTERN const char Tf_s_s_sN[] E_INIT("%s %s %s\n");
EXTERN const char Tf_s_s[] E_INIT("%s %s");
EXTERN const char Tf_s_sD_s[] E_INIT("%s %s: %s");
#define Tf_s_s (Tf_sD_s_s + 4)
#define Tf_s_sD_s (Tf_cant + 6)
EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s");
EXTERN const char Tf_sD_[] E_INIT("%s: ");
EXTERN const char Tf_szs[] E_INIT("%s: %zd %s");
@ -976,18 +970,18 @@ EXTERN const char Tf_nonnum[] E_INIT("non-numeric %s %s '%s'");
#endif
EXTERN const char Tf_S_[] E_INIT("%S ");
#define Tf_S (Tf__S + 1)
EXTERN const char Tf_lu[] E_INIT("%lu");
#define Tf_lu (Tf_toolarge + 17)
EXTERN const char Tf_toolarge[] E_INIT("%s %s too large: %lu");
EXTERN const char Tf_ldfailed[] E_INIT("%s %s(%d, %ld) failed: %s");
#define Tf_ss (Tf__ss + 1)
#define Tf_ss (Tf_sss + 2)
EXTERN const char Tf_sss[] E_INIT("%s%s%s");
EXTERN const char Tf_sD_s_sD_s[] E_INIT("%s: %s %s: %s");
EXTERN const char Tf_toomany[] E_INIT("too many %ss\n");
EXTERN const char Tf_sd[] E_INIT("%s %d");
#define Tf_s (Tf__ss + 3)
#define Tf_s (Tf_temp + 28)
EXTERN const char Tft_end[] E_INIT("%;");
EXTERN const char Tft_R[] E_INIT("%R");
#define Tf_d (Tf__d + 1)
#define Tf_d (Tf_sd + 3)
EXTERN const char Tf_sD_s_qs[] E_INIT("%s: %s '%s'");
EXTERN const char Tf_ro[] E_INIT("read-only: %s");
EXTERN const char Tf_flags[] E_INIT("%s: flags 0x%X");
@ -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__c_[] E_INIT("-%c ");
EXTERN const char Tf_sD_s_s[] E_INIT("%s: %s %s");
#define Tf_sN (Tf__sN + 1)
#define Tf_sD_s (Tf_s_sD_s + 3)
#define Tf_sN (Tf_s_s_sN + 6)
#define Tf_sD_s (Tf_temp + 24)
EXTERN const char T_devtty[] E_INIT("/dev/tty");
#else /* helpers for string pooling */
#define T4spaces " "
@ -1018,7 +1012,8 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define Tbsize "bsize"
#define Tbad_sig_ss "%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 Toomem "can't allocate %zu data bytes"
#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 Tcat "cat"
#define Tcd "cd"
#define T_command "-command"
#define Tcommand "command"
#define Tcreate "create"
#define TELIF_unexpected "TELIF unexpected"
#define TEXECSHELL "EXECSHELL"
#define Tsgexport "*=export"
#define Tdsgexport "^*=export"
#define Texport "export"
#ifdef __OS2__
#define Textproc "extproc"
@ -1045,7 +1041,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define TFPATH "FPATH"
#define T_function " function"
#define Tfunction "function"
#define T_funny_command "funny $() command"
#define T_funny_command "funny $()-command"
#define Tgetopts "getopts"
#define Thistory "history"
#define Tintovfl "integer overflow %zu %c %zu prevented"
@ -1067,7 +1063,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define TpVv "Vpv"
#define TPWD "PWD"
#define Tread "read"
#define Tsgreadonly "*=readonly"
#define Tdsgreadonly "^*=readonly"
#define Treadonly "readonly"
#define Tredirection_dup "can't finish (dup) redirection"
#define Tredirection "redirection"
@ -1089,7 +1085,7 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define Ttrue "true"
#define Ttty_fd_dupof "dup of tty fd"
#define Ttty_fd "tty fd"
#define Tgtypeset "=typeset"
#define Tdgtypeset "^=typeset"
#define Ttypeset "typeset"
#define Tugo "ugo"
#define Tunalias "unalias"
@ -1330,7 +1326,7 @@ EXTERN sigset_t sm_default, sm_sigchld;
/* name of called builtin function (used by error functions) */
EXTERN const char *builtin_argv0;
/* is called builtin SPEC_BI? (also KEEPASN, odd use though) */
/* is called builtin a POSIX special builtin? (error functions only) */
EXTERN bool builtin_spec;
/* current working directory */
@ -1500,6 +1496,8 @@ EXTERN bool last_lookup_was_array;
#define SPEC_BI BIT(12) /* a POSIX special builtin */
#define LOWER_BI BIT(13) /* (with LOW_BI) override even w/o flags */
#define LOW_BI BIT(14) /* external utility overrides built-in one */
#define DECL_UTIL BIT(15) /* is declaration utility */
#define DECL_FWDR BIT(16) /* is declaration utility forwarder */
/*
* Attributes that can be set by the user (used to decide if an unset
@ -2019,7 +2017,8 @@ int glob_str(char *, XPtrV *, bool);
char *do_tilde(char *);
/* exec.c */
int execute(struct op * volatile, volatile int, volatile int * volatile);
int shcomexec(const char **);
int c_builtin(const char **);
struct tbl *get_builtin(const char *);
struct tbl *findfunc(const char *, uint32_t, bool);
int define(const char *, struct op *);
const char *builtin(const char *, int (*)(const char **));
@ -2086,8 +2085,6 @@ int c_times(const char **);
int timex(struct op *, int, volatile int *);
void timex_hook(struct op *, char ** volatile *);
int c_exec(const char **);
/* dummy function (just need pointer value), special case in comexec() */
#define c_builtin shcomexec
int c_test(const char **);
#if HAVE_MKNOD
int c_mknod(const char **);
@ -2303,7 +2300,6 @@ char *shf_smprintf(const char *, ...)
ssize_t shf_vfprintf(struct shf *, const char *, va_list)
MKSH_A_FORMAT(__printf__, 2, 0);
/* syn.c */
int assign_command(const char *, bool) MKSH_A_PURE;
void initkeywords(void);
struct op *compile(Source *, bool);
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>
*
* Provided that these terms and disclaimer and all copyright notices
@ -19,7 +19,7 @@
*/
@SHFLAGS_DEFNS
__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.4 2015/12/12 21:08:44 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.5 2017/02/18 02:33:15 tg Exp $");
@SHFLAGS_ENUMS
#define FN(sname,cname,flags,ochar) cname,
#define F0(sname,cname,flags,ochar) cname = 0,
@ -52,7 +52,7 @@ FN("bgnice", FBGNICE, OF_ANY
FN("braceexpand", FBRACEEXPAND, OF_ANY
/* ./. Emacs command line editing mode */
>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
>|!MKSH_NO_CMDLINE_EDITING
FN("emacs", FEMACS, OF_ANY
/* -e quit on error */
@ -60,7 +60,7 @@ FN("emacs", FEMACS, OF_ANY
FN("errexit", FERREXIT, OF_ANY
/* ./. Emacs command line editing mode, gmacs variant */
>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
>|!MKSH_NO_CMDLINE_EDITING
FN("gmacs", FGMACS, OF_ANY
/* ./. reading EOF does not exit */
@ -160,19 +160,19 @@ FN("utf8-mode", FUNICODE, OF_ANY
FN("verbose", FVERBOSE, OF_ANY
/* ./. Vi command line editing mode */
>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
>|!MKSH_NO_CMDLINE_EDITING
FN("vi", FVI, OF_ANY
/* ./. enable ESC as file name completion character (non-standard) */
>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
>|!MKSH_NO_CMDLINE_EDITING
FN("vi-esccomplete", FVIESCCOMPLETE, OF_ANY
/* ./. enable Tab as file name completion character (non-standard) */
>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
>|!MKSH_NO_CMDLINE_EDITING
FN("vi-tabcomplete", FVITABCOMPLETE, OF_ANY
/* ./. always read in raw mode (no effect) */
>|!defined(MKSH_NO_CMDLINE_EDITING) || defined(MKSH_LEGACY_MODE)
>|!MKSH_NO_CMDLINE_EDITING
FN("viraw", FVIRAW, OF_ANY
/* -x execution trace (display commands as they are run) */

58
syn.c
View File

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
* 2011, 2012, 2013, 2014, 2015, 2016
* 2011, 2012, 2013, 2014, 2015, 2016, 2017
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#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 {
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));
}
static const char builtin_cmd[] = {
QCHAR, '\\', CHAR, 'b', CHAR, 'u', CHAR, 'i',
CHAR, 'l', CHAR, 't', CHAR, 'i', CHAR, 'n', EOS
};
static const char let_cmd[] = {
QCHAR, 'l', CHAR, 'e', CHAR, 't', CHAR, ']', EOS
CHAR, 'l', CHAR, 'e', CHAR, 't', EOS
};
static const char setA_cmd0[] = {
QCHAR, 's', CHAR, 'e', CHAR, 't', EOS
CHAR, 's', CHAR, 'e', CHAR, 't', EOS
};
static const char setA_cmd1[] = {
CHAR, '-', CHAR, 'A', EOS
@ -289,11 +293,11 @@ get_command(int cf)
t->lineno = source->line;
goto get_command_start;
while (/* CONSTCOND */ 1) {
bool check_assign_cmd;
bool check_decl_utility;
if (XPsize(args) == 0) {
get_command_start:
check_assign_cmd = true;
check_decl_utility = true;
cf = sALIAS | CMDASN;
} else if (t->u.evalflags)
cf = CMDWORD | CMDASN;
@ -311,16 +315,15 @@ get_command(int cf)
case LWORD:
ACCEPT;
/*
* the iopn == 0 and XPsize(vars) == 0 are
* dubious but AT&T ksh acts this way
*/
if (iopn == 0 && XPsize(vars) == 0 &&
check_assign_cmd) {
if (assign_command(ident, false))
if (check_decl_utility) {
struct tbl *tt = get_builtin(ident);
uint32_t flag;
flag = tt ? tt->flag : 0;
if (flag & DECL_UTIL)
t->u.evalflags = DOVACHECK;
else if (strcmp(ident, Tcommand) != 0)
check_assign_cmd = false;
if (!(flag & DECL_FWDR))
check_decl_utility = false;
}
if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
is_wdvarassign(yylval.cp))
@ -343,6 +346,7 @@ get_command(int cf)
tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
/* construct new args strings */
XPput(args, wdcopy(builtin_cmd, ATEMP));
XPput(args, wdcopy(setA_cmd0, ATEMP));
XPput(args, wdcopy(setA_cmd1, ATEMP));
XPput(args, tcp);
@ -412,6 +416,7 @@ get_command(int cf)
}
t = newtp(TCOM);
t->lineno = lno;
XPput(args, wdcopy(builtin_cmd, ATEMP));
XPput(args, wdcopy(let_cmd, ATEMP));
XPput(args, yylval.cp);
break;
@ -937,29 +942,6 @@ compile(Source *s, bool skiputf8bom)
return (outtree);
}
/*-
* This kludge exists to take care of sh/AT&T ksh oddity in which
* the arguments of alias/export/readonly/typeset have no field
* splitting, file globbing, or (normal) tilde expansion done.
* AT&T ksh seems to do something similar to this since
* $ touch a=a; typeset a=[ab]; echo "$a"
* a=[ab]
* $ x=typeset; $x a=[ab]; echo "$a"
* a=a
* $
*/
int
assign_command(const char *s, bool docommand)
{
if (!*s)
return (0);
return ((strcmp(s, Talias) == 0) ||
(strcmp(s, Texport) == 0) ||
(strcmp(s, Treadonly) == 0) ||
(docommand && (strcmp(s, Tcommand) == 0)) ||
(strcmp(s, Ttypeset) == 0));
}
/* Check if we are in the middle of reading an alias */
static int
inalias(struct source *s)