diff options
Diffstat (limited to 'src/cmd/ksh93/tests')
50 files changed, 17201 insertions, 0 deletions
diff --git a/src/cmd/ksh93/tests/alias.sh b/src/cmd/ksh93/tests/alias.sh new file mode 100755 index 0000000..5a75fa3 --- /dev/null +++ b/src/cmd/ksh93/tests/alias.sh @@ -0,0 +1,102 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +alias foo='print hello' +if [[ $(foo) != hello ]] +then err_exit 'foo, where foo is alias for "print hello" failed' +fi +if [[ $(foo world) != 'hello world' ]] +then err_exit 'foo world, where foo is alias for "print hello" failed' +fi +alias foo='print hello ' +alias bar=world +if [[ $(foo bar) != 'hello world' ]] +then err_exit 'foo bar, where foo is alias for "print hello " failed' +fi +if [[ $(foo \bar) != 'hello bar' ]] +then err_exit 'foo \bar, where foo is alias for "print hello " failed' +fi +alias bar='foo world' +if [[ $(bar) != 'hello world' ]] +then err_exit 'bar, where bar is alias for "foo world" failed' +fi +if [[ $(alias bar) != "bar='foo world'" ]] +then err_exit 'alias bar, where bar is alias for "foo world" failed' +fi +unalias foo || err_exit "unalias foo failed" +alias foo 2> /dev/null && err_exit "alias for non-existent alias foo returns true" +unset bar +alias bar="print foo$bar" +bar=bar +if [[ $(bar) != foo ]] +then err_exit 'alias bar, where bar is alias for "print foo$bar" failed' +fi +unset bar +alias bar='print hello' +if [[ $bar != '' ]] +then err_exit 'alias bar cause variable bar to be set' +fi +alias !!=print +if [[ $(!! hello 2>/dev/null) != hello ]] +then err_exit 'alias for !!=print not working' +fi +alias foo=echo +if [[ $(print "$(foo bar)" ) != bar ]] +then err_exit 'alias in command substitution not working' +fi +( unalias foo) +if [[ $(foo bar 2> /dev/null) != bar ]] +then err_exit 'alias not working after unalias in subshell' +fi +builtin -d rm 2> /dev/null +if whence rm > /dev/null +then [[ ! $(alias -t | grep rm= ) ]] && err_exit 'tracked alias not set' + PATH=$PATH + [[ $(alias -t | grep rm= ) ]] && err_exit 'tracked alias not cleared' +fi +if hash -r 2>/dev/null && [[ ! $(hash) ]] +then PATH=$tmp:/bin:/usr/bin + for i in foo -foo -- + do print ':' > $tmp/$i + chmod +x $tmp/$i + hash -r -- $i 2>/dev/null || err_exit "hash -r -- $i failed" + [[ $(hash) == $i=$tmp/$i ]] || err_exit "hash -r -- $i failed, expected $i=$tmp/$i, got $(hash)" + done +else err_exit 'hash -r failed' +fi +( alias :pr=print) 2> /dev/null || err_exit 'alias beginning with : fails' +( alias p:r=print) 2> /dev/null || err_exit 'alias with : in name fails' + +unalias no_such_alias && err_exit 'unalias should return non-zero for unknown alias' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/append.sh b/src/cmd/ksh93/tests/append.sh new file mode 100755 index 0000000..80a7f25 --- /dev/null +++ b/src/cmd/ksh93/tests/append.sh @@ -0,0 +1,86 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 +{ +x=abc +x+=def ;} 2> /dev/null +if [[ $x != abcdef ]] +then err_exit 'abc+def != abcdef' +fi +integer i=3 +{ i+=4;} 2> /dev/null +if (( i != 7 )) +then err_exit '3+4!=7' +fi +iarray=( one two three ) +{ iarray+= (four five six) ;} 2> /dev/null +if [[ ${iarray[@]} != 'one two three four five six' ]] +then err_exit 'index array append fails' +fi +unset iarray +iarray=one +{ iarray+= (four five six) ;} 2> /dev/null +if [[ ${iarray[@]} != 'one four five six' ]] +then err_exit 'index array append to scalar fails' +fi +typeset -A aarray +aarray=( [1]=1 [3]=4 [xyz]=xyz ) +aarray+=( [2]=2 [3]=3 [foo]=bar ) +if [[ ${aarray[3]} != 3 ]] +then err_exit 'associative array append fails' +fi +if [[ ${#aarray[@]} != 5 ]] +then err_exit 'number of elements of associative array append fails' +fi +point=(x=1 y=2) +point+=( y=3 z=4) +if [[ ${point.y} != 3 ]] +then err_exit 'compound append fails' +fi +if [[ ${point.x} != 1 ]] +then err_exit 'compound append to compound variable unsets existing variables' +fi +unset foo +foo=one +foo+=(two) +if [[ ${foo[@]} != 'one two' ]] +then err_exit 'array append to non array variable fails' +fi +unset foo +foo[0]=(x=3) +foo+=(x=4) +[[ ${foo[1].x} == 4 ]] || err_exit 'compound append to index array not working' +[[ ${foo[0].x} == 3 ]] || err_exit 'compound append to index array unsets existing variables' + +unset foo +foo=a +foo+='' +[[ $foo == 'a' ]] || err_exit 'appending an empty string not working' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/arith.sh b/src/cmd/ksh93/tests/arith.sh new file mode 100755 index 0000000..4d48ac2 --- /dev/null +++ b/src/cmd/ksh93/tests/arith.sh @@ -0,0 +1,737 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +trap '' FPE # NOTE: osf.alpha requires this (no ieee math) + +integer x=1 y=2 z=3 +if (( 2+2 != 4 )) +then err_exit 2+2!=4 +fi +if ((x+y!=z)) +then err_exit x+y!=z +fi +if (($x+$y!=$z)) +then err_exit $x+$y!=$z +fi +if (((x|y)!=z)) +then err_exit "(x|y)!=z" +fi +if ((y >= z)) +then err_exit "y>=z" +fi +if ((y+3 != z+2)) +then err_exit "y+3!=z+2" +fi +if ((y<<2 != 1<<3)) +then err_exit "y<<2!=1<<3" +fi +if ((133%10 != 3)) +then err_exit "133%10!=3" + if (( 2.5 != 2.5 )) + then err_exit 2.5!=2.5 + fi +fi +d=0 +((d || 1)) || err_exit 'd=0; ((d||1))' +if (( d++!=0)) +then err_exit "d++!=0" +fi +if (( --d!=0)) +then err_exit "--d!=0" +fi +if (( (d++,6)!=6 && d!=1)) +then err_exit '(d++,6)!=6 && d!=1' +fi +d=0 +if (( (1?2+1:3*4+d++)!=3 || d!=0)) +then err_exit '(1?2+1:3*4+d++) !=3' +fi +for ((i=0; i < 20; i++)) +do : +done +if (( i != 20)) +then err_exit 'for (( expr)) failed' +fi +for ((i=0; i < 20; i++)); do : ; done +if (( i != 20)) +then err_exit 'for (( expr));... failed' +fi +for ((i=0; i < 20; i++)) do : ; done +if (( i != 20)) +then err_exit 'for (( expr))... failed' +fi +if (( (i?0:1) )) +then err_exit '(( (i?0:1) )) failed' +fi +if (( (1 || 1 && 0) != 1 )) +then err_exit '( (1 || 1 && 0) != 1) failed' +fi +if (( (_=1)+(_x=0)-_ )) +then err_exit '(_=1)+(_x=0)-_ failed' +fi +if (( (3^6) != 5)) +then err_exit '((3^6) != 5) failed' +fi +integer x=1 +if (( (x=-x) != -1 )) +then err_exit '(x=-x) != -1 failed' +fi +i=2 +if (( 1$(($i))3 != 123 )) +then err_exit ' 1$(($i))3 failed' +fi +((pi=4*atan(1.))) +point=( + float x + float y +) +(( point.x = cos(pi/6), point.y = sin(pi/6) )) +if (( point.x*point.x + point.y*point.y > 1.01 )) +then err_exit 'cos*cos +sin*sin > 1.01' +fi +if (( point.x*point.x + point.y*point.y < .99 )) +then err_exit 'cos*cos +sin*sin < .99' +fi +if [[ $((y=x=1.5)) != 1 ]] +then err_exit 'typecast not working in arithmetic evaluation' +fi +typeset -E x=1.5 +( ((x++)) ) 2>/dev/null +if [[ $? == 0 ]] +then err_exit 'postincrement of floating point allowed' +fi +( ((++x)) ) 2>/dev/null +if [[ $? == 0 ]] +then err_exit 'preincrement of floating point allowed' +fi +x=1.5 +( ((x%1.1)) ) 2>/dev/null +if [[ $? == 0 ]] +then err_exit 'floating point allowed with % operator' +fi +x=.125 +if [[ $(( 4 * x/2 )) != 0.25 ]] +then err_exit '(( 4 * x/2 )) is not 0.25, with x=.125' +fi +if [[ $(( pow(2,3) )) != 8 ]] +then err_exit '$(( pow(2,3) )) != 8' +fi +( [[ $(( pow(2,(3)) )) == 8 ]] ) 2> /dev/null +if (( $? )) +then err_exit '$(( pow(2,(3)) )) != 8' +fi +unset x +integer x=1; integer x=1 +if [[ $x != 1 ]] +then err_exit 'two consecutive integer x=1 not working' +fi +unset z +{ z=$(typeset -RZ2 z2; (( z2 = 8 )); print $z2) ;} 2>/dev/null +if [[ $z != "08" ]] +then err_exit "typeset -RZ2 leading 0 decimal not working [z=$z]" +fi +{ z=$(typeset -RZ3 z3; (( z3 = 8 )); print $z3) ;} 2>/dev/null +if [[ $z != "008" ]] +then err_exit "typeset -RZ3 leading 0 decimal not working [z=$z]" +fi +unset z +typeset -Z3 z=010 +(( z=z+1)) +if [[ $z != 011 ]] +then err_exit "leading 0's in -Z not treated as decimal" +fi +unset x +integer x=0 +if [[ $((x+=1)) != 1 ]] || ((x!=1)) +then err_exit "+= not working" + x=1 +fi +x=1 +if [[ $((x*=5)) != 5 ]] || ((x!=5)) +then err_exit "*= not working" + x=5 +fi +if [[ $((x%=4)) != 1 ]] || ((x!=1)) +then err_exit "%= not working" + x=1 +fi +if [[ $((x|=6)) != 7 ]] || ((x!=7)) +then err_exit "|= not working" + x=7 +fi +if [[ $((x&=5)) != 5 ]] || ((x!=5)) +then err_exit "&= not working" + x=5 +fi +function newscope +{ + float x=1.5 + (( x += 1 )) + print -r -- $x +} +if [[ $(newscope) != 2.5 ]] +then err_exit "arithmetic using wrong scope" +fi +unset x +integer y[3]=9 y[4]=2 i=3 +(( x = y[3] + y[4] )) +if [[ $x != 11 ]] +then err_exit "constant index array arithmetic failure" +fi +(( x = $empty y[3] + y[4] )) +if [[ $x != 11 ]] +then err_exit "empty constant index array arithmetic failure" +fi +(( x = y[i] + y[i+1] )) +if [[ $x != 11 ]] +then err_exit "variable subscript index array arithmetic failure" +fi +integer a[5]=3 a[2]=4 +(( x = y[a[5]] + y[a[2]] )) +if [[ $x != 11 ]] +then err_exit "nested subscript index array arithmetic failure" +fi +unset y +typeset -Ai y +y[three]=9 y[four]=2 +three=four +four=three +(( x = y[three] + y[four] )) +if [[ $x != 11 ]] +then err_exit "constant associative array arithmetic failure" +fi +(( x = y[$three] + y[$four] )) +if [[ $x != 11 ]] +then err_exit "variable subscript associative array arithmetic failure" +fi +$SHELL -nc '((a = 1))' 2> /dev/null || err_exit "sh -n fails with arithmetic" +$SHELL -nc '((a.b++))' 2> /dev/null || err_exit "sh -n fails with arithmetic2" +unset z +float z=7.5 +if { (( z%2 != 1));} 2> /dev/null +then err_exit '% not working on floating point' +fi +chr=(a ' ' '=' '\r' '\n' '\\' '\"' '$' "\\'" '[' ']' '(' ')' '<' '\xab' '\040' '`' '{' '}' '*' '\E') +if (('a' == 97)) +then val=(97 32 61 13 10 92 34 36 39 91 93 40 41 60 171 32 96 123 125 42 27) +else val=(129 64 126 13 21 224 127 91 125 173 189 77 93 76 171 32 121 192 208 92 39 21) +fi +q=0 +for ((i=0; i < ${#chr[@]}; i++)) +do if (( '${chr[i]}' != ${val[i]} )) + then err_exit "(( '${chr[i]}' != ${val[i]} ))" + fi + if [[ $(( '${chr[i]}' )) != ${val[i]} ]] + then err_exit "(( '${chr[i]}' )) != ${val[i]}" + fi + if [[ $(( L'${chr[i]}' )) != ${val[i]} ]] + then err_exit "(( '${chr[i]}' )) != ${val[i]}" + fi + if eval '((' "'${chr[i]}'" != ${val[i]} '))' + then err_exit "eval (( '${chr[i]}' != ${val[i]} ))" + fi + if eval '((' "'${chr[i]}'" != ${val[i]} ' + $q ))' + then err_exit "eval (( '${chr[i]}' != ${val[i]} ))" + fi +done +unset x +typeset -ui x=4294967293 +[[ $x != 4294967293 ]] && err_exit "unsigned integers not working" +x=32767 +x=x+1 +[[ $x != 32768 ]] && err_exit "unsigned integer addition not working" +unset x +float x=99999999999999999999999999 +if (( x < 1e20 )) +then err_exit 'large integer constants not working' +fi +unset x y +function foobar +{ + nameref x=$1 + (( x +=1 )) + print $x +} +x=0 y=4 +if [[ $(foobar y) != 5 ]] +then err_exit 'name references in arithmetic statements in functions broken' +fi +if (( 2**3 != pow(2,3) )) +then err_exit '2**3 not working' +fi +if (( 2**3*2 != pow(2,3)*2 )) +then err_exit '2**3*2 not working' +fi +if (( 4**3**2 != pow(4,pow(3,2)) )) +then err_exit '4**3**2 not working' +fi +if (( (4**3)**2 != pow(pow(4,3),2) )) +then err_exit '(4**3)**2 not working' +fi +typeset -Z3 x=11 +typeset -i x +if (( x != 11 )) +then err_exit '-Z3 not treated as decimal' +fi +unset x +typeset -ui x=-1 +(( x >= 0 )) || err_exit 'unsigned integer not working' +(( $x >= 0 )) || err_exit 'unsigned integer not working as $x' +unset x +typeset -ui42 x=50 +if [[ $x != 42#18 ]] +then err_exit 'display of unsigned integers in non-decimal bases wrong' +fi +$SHELL -c 'i=0;(( ofiles[i] != -1 && (ofiles[i] < mins || mins == -1) ));exit 0' 2> /dev/null || err_exit 'lexical error with arithemtic expression' +$SHELL -c '(( +1 == 1))' 2> /dev/null || err_exit 'unary + not working' +typeset -E20 val=123.01234567890 +[[ $val == 123.0123456789 ]] || err_exit "rounding error val=$val" +if [[ $(print x$((10))=foo) != x10=foo ]] +then err_exit 'parsing error with x$((10))=foo' +fi +$SHELL -c 'typeset x$((10))=foo' 2> /dev/null || err_exit 'typeset x$((10)) parse error' +unset x +x=$(( exp(log(2.0)) )) +(( x > 1.999 && x < 2.001 )) || err_exit 'composite functions not working' +unset x y n +typeset -Z8 x=0 y=0 +integer n +for (( n=0; n < 20; n++ )) +do let "x = $x+1" + (( y = $y+1 )) +done +(( x == n )) || err_exit 'let with zero filled fields not working' +(( y == n )) || err_exit '((...)) with zero filled fields not working' +typeset -RZ3 x=10 +[[ $(($x)) == 10 && $((1$x)) == 1010 ]] || err_exit 'zero filled fields not preserving leading zeros' +unset y +[[ $(let y=$x;print $y) == 10 && $(let y=1$x;print $y) == 1010 ]] || err_exit 'zero filled fields not preserving leading zeros with let' +unset i ip ipx +typeset -i hex=( 172 30 18 1) +typeset -ui ip=0 ipx=0 +integer i +for ((i=0; i < 4; i++)) +do (( ip = (ip<<8) | hex[i])) +done +for ((i=0; i < 4; i++)) +do (( ipx = ip % 256 )) + (( ip /= 256 )) + (( ipx != hex[3-i] )) && err_exit "hex digit $((3-i)) not correct" +done +unset x +x=010 +(( x == 10 )) || err_exit 'leading zeros in x treated as octal arithmetic with $((x))' +(( $x == 8 )) || err_exit 'leading zeros not treated as octal arithmetic with $x' +unset x +typeset -Z x=010 +(( x == 10 )) || err_exit 'leading zeros not ignored for arithmetic' +(( $x == 10 )) || err_exit 'leading zeros not ignored for arithmetic with $x' +typeset -i i=x +(( i == 10 )) || err_exit 'leading zeros not ignored for arithmetic assignment' +(( ${x:0:1} == 0 )) || err_exit 'leading zero should not be stripped for x:a:b' +c010=3 +(( c$x == 3 )) || err_exit 'leading zero with variable should not be stripped' +[[ $( ($SHELL -c '((++1))' 2>&1) 2>/dev/null ) == *++1:* ]] || err_exit "((++1)) not generating error message" +i=2 +(( "22" == 22 )) || err_exit "double quoted constants fail" +(( "2$i" == 22 )) || err_exit "double quoted variables fail" +(( "18+$i+2" == 22 )) || err_exit "double quoted expressions fail" +# 04-04-28 bug fix +unset i; typeset -i i=01-2 +(( i == -1 )) || err_exit "01-2 is not -1" + +cat > $tmp/script <<-\! +tests=$* +typeset -A blop +function blop.get +{ + .sh.value=777 +} +function mkobj +{ + nameref obj=$1 + obj=() + [[ $tests == *1* ]] && { + (( obj.foo = 1 )) + (( obj.bar = 2 )) + (( obj.baz = obj.foo + obj.bar )) # ok + echo $obj + } + [[ $tests == *2* ]] && { + (( obj.faz = faz = obj.foo + obj.bar )) # ok + echo $obj + } + [[ $tests == *3* ]] && { + # case 3, 'active' variable involved, w/ intermediate variable + (( obj.foz = foz = ${blop[1]} )) # coredump + echo $obj + } + [[ $tests == *4* ]] && { + # case 4, 'active' variable, in two steps + (( foz = ${blop[1]} )) # ok + (( obj.foz = foz )) # ok + echo $obj + } + [[ $tests == *5* ]] && { + # case 5, 'active' variable involved, w/o intermediate variable + (( obj.fuz = ${blop[1]} )) # coredump + echo $obj + } + [[ $tests == *6* ]] && { + echo $(( obj.baz = obj.foo + obj.bar )) # coredump + } + [[ $tests == *7* ]] && { + echo $(( obj.foo + obj.bar )) # coredump + } +} +mkobj bla +! +chmod +x $tmp/script +[[ $($tmp/script 1) != '( bar=2 baz=3 foo=1 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 2) != '( faz=0 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 3) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 4) != '( foz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 5) != '( fuz=777 )' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 6) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +[[ $($tmp/script 7) != '0' ]] 2>/dev/null && err_exit 'compound var arithmetic failed' +unset foo +typeset -F1 foo=123456789.19 +[[ $foo == 123456789.2 ]] || err_exit 'typeset -F1 not working correctly' + +# divide by zero + +for expr in '1/(1/2)' '8%(1/2)' '8%(1.0/2)' +do [[ $( ( $SHELL -c "( (($expr)) ) || print ok" ) 2>/dev/null ) == ok ]] || err_exit "divide by zero not trapped: $expr" +done + +for expr in '1/(1.0/2)' '1/(1/2.0)' +do [[ $( ( $SHELL -c "( print -r -- \$(($expr)) )" ) 2>/dev/null ) == 2 ]] || err_exit "invalid value for: $expr" +done +[[ $((5||0)) == 1 ]] || err_exit '$((5||0))'" == $((5||0)) should be 1" +$SHELL -c 'integer x=3 y=2; (( (y += x += 2) == 7 && x==5))' 2> /dev/null || err_exit '((y += x += 2)) not working' +$SHELL -c 'b=0; [[ $((b?a=1:b=9)) == 9 ]]' 2> /dev/null || err_exit 'b?a=1:b=9 not working' +unset x +(( x = 4*atan(1.0) )) +[[ $x == "$((x))" ]] || err_exit '$x !- $((x)) when x is pi' +$SHELL -c "[[ ${x//./} == {14,100}(\d) ]]" 2> /dev/null || err_exit 'pi has less than 14 significant places' +if (( Inf+1 == Inf )) +then set \ + Inf inf \ + -Inf -inf \ + Nan nan \ + -Nan -nan \ + 1.0/0.0 inf + while (( $# >= 2 )) + do x=$(printf "%g\n" $(($1))) + [[ $x == $2 ]] || err_exit "printf '%g\\n' \$(($1)) failed -- expected $2, got $x" + x=$(printf "%g\n" $1) + [[ $x == $2 ]] || err_exit "printf '%g\\n' $1 failed -- expected $2, got $x" + x=$(printf -- $(($1))) + [[ $x == $2 ]] || err_exit "print -- \$(($1)) failed -- expected $2, got $x" + shift 2 + done + (( 1.0/0.0 == Inf )) || err_exit '1.0/0.0 != Inf' + [[ $(print -- $((0.0/0.0))) == ?(-)nan ]] || err_exit '0.0/0.0 != NaN' + (( Inf*Inf == Inf )) || err_exit 'Inf*Inf != Inf' + (( NaN != NaN )) || err_exit 'NaN == NaN' + (( -5*Inf == -Inf )) || err_exit '-5*Inf != -Inf' + [[ $(print -- $((sqrt(-1.0)))) == ?(-)nan ]]|| err_exit 'sqrt(-1.0) != NaN' + (( pow(1.0,Inf) == 1.0 )) || err_exit 'pow(1.0,Inf) != 1.0' + (( pow(Inf,0.0) == 1.0 )) || err_exit 'pow(Inf,0.0) != 1.0' + [[ $(print -- $((NaN/Inf))) == ?(-)nan ]] || err_exit 'NaN/Inf != NaN' + (( 4.0/Inf == 0.0 )) || err_exit '4.0/Inf != 0.0' +else err_exit 'Inf and NaN not working' +fi +unset x y n r +n=14.555 +float x=$n y +y=$(printf "%a" x) +r=$y +[[ $r == $n ]] || err_exit "output of printf %a not self preserving -- expected $x, got $y" +unset x y r +x=-0 +y=$(printf "%g %g %g %g %g %g\n" -0. -0 $((-0)) x $x $((x))) +r="-0 -0 -0 -0 -0 -0" +[[ $y == "$r" ]] || err_exit "-0 vs -0.0 inconsistency -- expected '$r', got '$y'" +$SHELL -c '(( x=));:' 2> /dev/null && err_exit '((x=)) should be an error' +$SHELL -c '(( x+=));:' 2> /dev/null && err_exit '((x+=)) should be an error' +$SHELL -c '(( x=+));:' 2> /dev/null && err_exit '((x=+)) should be an error' +$SHELL -c 'x=();x.arr[0]=(z=3); ((x.arr[0].z=2))' 2> /dev/null || err_exit '(((x.arr[0].z=2)) should not be an error' + +float t +typeset a b r +v="-0.0 0.0 +0.0 -1.0 1.0 +1.0" +for a in $v +do for b in $v + do (( r = copysign(a,b) )) + (( t = copysign(a,b) )) + [[ $r == $t ]] || err_exit $(printf "float t=copysign(%3.1f,%3.1f) => %3.1f -- expected %3.1f\n" a b t r) + done +done + +typeset -l y y_ascii +(( y=sin(90) )) +y_ascii=$y +(( y == y_ascii )) || err_exit "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf "%a\n" y_ascii)" + +( $SHELL <<- \EOF + p=5 + t[p]=6 + while (( t[p] != 0 )) ; do + (( + p+=1 , + t[p]+=2 , + p+=3 , + t[p]+=5 , + p+=1 , + t[p]+=2 , + p+=1 , + t[p]+=1 , + p-=6 , + t[p]-=1 + )) + : + done +EOF) 2> /dev/null || err_exit 'error with comma expression' + +N=(89551 89557) +i=0 j=1 +[[ $(printf "%d" N[j]-N[i]) == 6 ]] || err_exit 'printf %d N[i]-N[j] failed' +[[ $((N[j]-N[i])) == 6 ]] || err_exit '$((N[j]-N[i])) incorrect' + +unset a x +x=0 +((a[++x]++)) +(( x==1)) || err_exit '((a[++x]++)) should only increment x once' +(( a[1]==1)) || err_exit 'a[1] not incremented' +unset a +x=0 +((a[x++]++)) +(( x==1)) || err_exit '((a[x++]++)) should only increment x once' +(( a[0]==1)) || err_exit 'a[0] not incremented' +unset a +x=0 +((a[x+=2]+=1)) +(( x==2)) || err_exit '((a[x+=2]++)) should result in x==2' +(( a[2]==1)) || err_exit 'a[0] not 1' + +unset a i +typeset -a a +i=1 +(( a[i]=1 )) +(( a[0] == 0 )) || err_exit 'a[0] not 0' +(( a[1] == 1 )) || err_exit 'a[1] not 1' + +unset a +typeset -i a +for ((i=0;i<1000;i++)) +do ((a[RANDOM%2]++)) +done +(( (a[0]+a[1])==1000)) || err_exit '(a[0]+a[1])!=1000' + +(( 4.**3/10 == 6.4 )) || err_exit '4.**3/10!=6.4' +(( (.5+3)/7 == .5 )) || err_exit '(.5+3)/7!==.5' + +function .sh.math.mysin x +{ + ((.sh.value = x - x**3/6. + x**5/120.-x**7/5040. + x**9/362880.)) +} + +(( abs(sin(.5)-mysin(.5)) < 1e-6 )) || err_exit 'mysin() not close to sin()' + +$SHELL 2> /dev/null <<- \EOF || err_exit "arithmetic functions defined and referenced in compound command not working" +{ + function .sh.math.mysin x + { + ((.sh.value = x-x**3/6. + x**5/120.-x**7/5040. + x**9/362880.)) + } + (( abs(sin(.5)-mysin(.5)) < 1e-6 )) + exit 0 +} +EOF + + + +function .sh.math.max x y z +{ + .sh.value=x + (( y > x )) && .sh.value=y + (( z > .sh.value )) && .sh.value=z +} +(( max(max(3,8,5),7,5)==8)) || err_exit 'max(max(3,8,5),7,5)!=8' +(( max(max(3,8,5),7,9)==9)) || err_exit 'max(max(3,8,9),7,5)!=9' +(( max(6,max(3,9,5),7)==9 )) || err_exit 'max(6,max(3,8,5),7)!=9' +(( max(6,7, max(3,8,5))==8 )) || err_exit 'max(6,7,max(3,8,5))!=8' + +enum color_t=(red green blue yellow) +color_t shirt pants=blue +(( pants == blue )) || err_exit 'pants should be blue' +(( shirt == red )) || err_exit 'pants should be red' +(( shirt != green )) || err_exit 'shirt should not be green' +(( pants != shirt )) || err_exit 'pants should be the same as shirt' +(( pants = yellow )) +(( pants == yellow )) || err_exit 'pants should be yellow' + +unset z +integer -a z=( [1]=90 ) +function x +{ + nameref nz=$1 + float x y + float x=$((log10(nz))) y=$((log10($nz))) + (( abs(x-y) < 1e-10 )) || err_exit '$nz and nz differs in arithmetic expression when nz is reference to array instance' +} +x z[1] + +unset x +float x +x=$( ($SHELL -c 'print -- $(( asinh(acosh(atanh(sin(cos(tan(atan(acos(asin(tanh(cosh(sinh(asinh(acosh(atanh(sin(cos(tan(atan(acos(asin(tanh(cosh(sinh(.5)))))))))))))))))))))))) )) ';:) 2> /dev/null) +(( abs(x-.5) < 1.e-10 )) || err_exit 'bug in composite function evaluation' + +unset x +typeset -X x=16 +{ (( $x == 16 )) ;} 2> /dev/null || err_exit 'expansions of hexfloat not working in arithmetic expansions' + +unset foo +function foobar +{ + (( foo = 8)) +} +typeset -i foo +foobar +(( foo == 8 )) || err_exit 'arithmetic assignment binding to the wrong scope' + +(( tgamma(4)/12 )) || err_exit 'floating point attribute for functions not preserved' + +unset F +function f +{ + ((F=1)) +} +f +[[ $F == 1 ]] || err_exit 'scoping bug with arithmetic expression' + +F=1 +function f +{ + typeset F + ((F=2)) +} +[[ $F == 1 ]] || err_exit 'scoping bug2 with arithmetic expression' + +unset play foo x z +typeset -A play +x=foo +play[$x]=(x=2) +for ((i=0; i < 2; i++)) +do (( play[$x].y , z++ )) +done +(( z==2 )) || err_exit 'unset compound array variable error with for loop optimization' + +[[ $($SHELL 2> /dev/null -c 'print -- $(( ldexp(1, 4) ))' ) == 16 ]] || err_exit 'function ldexp not implement or not working correctly' + + +$SHELL 2> /dev/null -c 'str="0x1.df768ed398ee1e01329a130627ae0000p-1";typeset -l -E x;((x=str))' || err_exit '((x=var)) fails for hexfloat with var begining with 0x1.nnn' + +x=(3 6 12) +(( x[2] /= x[0])) +(( x[2] == 4 )) || err_exit '(( x[2] /= x[0])) fails for index array' + +x=([0]=3 [1]=6 [2]=12) +(( x[2] /= x[0])) +(( x[2] == 4 )) || err_exit '(( x[2] /= x[0])) fails for associative array' + +got=$($SHELL 2> /dev/null -c 'compound -a x;compound -a x[0].y; integer -a x[0].y[0].z; (( x[0].y[0].z[2]=3 )); typeset -p x') +exp='typeset -C -a x=((typeset -C -a y=( [0]=(typeset -a -l -i z=([2]=3);));))' +[[ $got == "$exp" ]] || err_exit '(( x[0].y[0].z[2]=3 )) not working' + +unset x +let x=010 +[[ $x == 10 ]] || err_exit 'let treating 010 as octal' +set -o letoctal +let x=010 +[[ $x == 8 ]] || err_exit 'let not treating 010 as octal with letoctal on' + +float z=0 +integer aa=2 a=1 +typeset -A A +A[a]=(typeset -A AA) +A[a].AA[aa]=1 +(( z= A[a].AA[aa]++ )) +(( z == 1 )) || err_exit "z should be 1 but is $z for associative array of +associative array arithmetic" +[[ ${A[a].AA[aa]} == 2 ]] || err_exit '${A[a].AA[aa]} should be 2 after ++ operation for associative array of associative array arithmetic' +unset A[a] + +A[a]=(typeset -a AA) +A[a].AA[aa]=1 +(( z += A[a].AA[aa++]++ )) +(( z == 2 )) || err_exit "z should be 2 but is $z for associative array of +index array arithmetic" +(( aa == 3 )) || err_exit "subscript aa should be 3 but is $aa after ++" +[[ ${A[a].AA[aa-1]} == 2 ]] || err_exit '${A[a].AA[aa]} should be 2 after ++ operation for ssociative array of index array arithmetic' +unset A + +typeset -a A +A[a]=(typeset -A AA) +A[a].AA[aa]=1 +(( z += A[a].AA[aa]++ )) +(( z == 3 )) || err_exit "z should be 3 but is $z for index array of +associative array arithmetic" +[[ ${A[a].AA[aa]} == 2 ]] || err_exit '${A[a].AA[aa]} should be 2 after ++ operation for index array of associative array arithmetic' +unset A[a] + +A[a]=(typeset -a AA) +A[a].AA[aa]=1 +(( z += A[a++].AA[aa++]++ )) +(( z == 4 )) || err_exit "z should be 4 but is $z for index array of +index array arithmetic" +[[ ${A[a-1].AA[aa-1]} == 2 ]] || err_exit '${A[a].AA[aa]} should be 2 after ++ operation for index array of index array arithmetic' +(( aa == 4 )) || err_exit "subscript aa should be 4 but is $aa after ++" +(( a == 2 )) || err_exit "subscript a should be 2 but is $a after ++" +unset A + +unset r x +integer x +r=020 +(($r == 16)) || err_exit 'leading 0 not treated as octal inside ((...))' +x=$(($r)) +(( x == 16 )) || err_exit 'leading 0 not treated as octal inside $((...))' +x=$r +((x == 20 )) || err_exit 'leading 0 should not be treated as octal outside ((...))' +print -- -020 | read x +((x == -20)) || err_exit 'numbers with leading -0 should not be treated as octal outside ((...))' +print -- -8#20 | read x +((x == -16)) || err_exit 'numbers with leading -8# should be treated as octal' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/arrays.sh b/src/cmd/ksh93/tests/arrays.sh new file mode 100755 index 0000000..8aec386 --- /dev/null +++ b/src/cmd/ksh93/tests/arrays.sh @@ -0,0 +1,588 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +function fun +{ + integer i + unset xxx + for i in 0 1 + do xxx[$i]=$i + done +} + +set -A x zero one two three four 'five six' +if [[ $x != zero ]] +then err_exit '$x is not element 0' +fi +if [[ ${x[0]} != zero ]] +then err_exit '${x[0] is not element 0' +fi +if (( ${#x[0]} != 4 )) +then err_exit "length of ${x[0]} is not 4" +fi +if (( ${#x[@]} != 6 )) +then err_exit 'number of elements of x is not 6' +fi +if [[ ${x[2]} != two ]] +then err_exit ' element two is not 2' +fi +if [[ ${x[@]:2:1} != two ]] +then err_exit ' ${x[@]:2:1} is not two' +fi +set -A y -- ${x[*]} +if [[ $y != zero ]] +then err_exit '$x is not element 0' +fi +if [[ ${y[0]} != zero ]] +then err_exit '${y[0] is not element 0' +fi +if (( ${#y[@]} != 7 )) +then err_exit 'number of elements of y is not 7' +fi +if [[ ${y[2]} != two ]] +then err_exit ' element two is not 2' +fi +set +A y nine ten +if [[ ${y[2]} != two ]] +then err_exit ' element two is not 2' +fi +if [[ ${y[0]} != nine ]] +then err_exit '${y[0] is not nine' +fi +unset y[4] +if (( ${#y[@]} != 6 )) +then err_exit 'number of elements of y is not 6' +fi +if (( ${#y[4]} != 0 )) +then err_exit 'string length of unset element is not 0' +fi +unset foo +if (( ${#foo[@]} != 0 )) +then err_exit 'number of elements of unset variable foo is not 0' +fi +foo='' +if (( ${#foo[0]} != 0 )) +then err_exit 'string length of null element is not 0' +fi +if (( ${#foo[@]} != 1 )) +then err_exit 'number of elements of null variable foo is not 1' +fi +unset foo +foo[0]=foo +foo[3]=bar +unset foo[0] +unset foo[3] +if (( ${#foo[@]} != 0 )) +then err_exit 'number of elements of left in variable foo is not 0' +fi +unset foo +foo[3]=bar +foo[0]=foo +unset foo[3] +unset foo[0] +if (( ${#foo[@]} != 0 )) +then err_exit 'number of elements of left in variable foo again is not 0' +fi +fun +if (( ${#xxx[@]} != 2 )) +then err_exit 'number of elements of left in variable xxx is not 2' +fi +fun +if (( ${#xxx[@]} != 2 )) +then err_exit 'number of elements of left in variable xxx again is not 2' +fi +set -A foo -- "${x[@]}" +if (( ${#foo[@]} != 6 )) +then err_exit 'number of elements of foo is not 6' +fi +if (( ${#PWD[@]} != 1 )) +then err_exit 'number of elements of PWD is not 1' +fi +unset x +x[2]=foo x[4]=bar +if (( ${#x[@]} != 2 )) +then err_exit 'number of elements of x is not 2' +fi +s[1]=1 c[1]=foo +if [[ ${c[s[1]]} != foo ]] +then err_exit 'c[1]=foo s[1]=1; ${c[s[1]]} != foo' +fi +unset s +typeset -Ai s +y=* z=[ +s[$y]=1 +s[$z]=2 +if (( ${#s[@]} != 2 )) +then err_exit 'number of elements of is not 2' +fi +(( s[$z] = s[$z] + ${s[$y]} )) +if [[ ${s[$z]} != 3 ]] +then err_exit '[[ ${s[$z]} != 3 ]]' +fi +if (( s[$z] != 3 )) +then err_exit '(( s[$z] != 3 ))' +fi +(( s[$y] = s[$y] + ${s[$z]} )) +if [[ ${s[$y]} != 4 ]] +then err_exit '[[ ${s[$y]} != 4 ]]' +fi +if (( s[$y] != 4 )) +then err_exit '(( s[$y] != 4 ))' +fi +set -A y 2 4 6 +typeset -i y +z=${y[@]} +typeset -R12 y +typeset -i y +if [[ ${y[@]} != "$z" ]] +then err_exit 'error in array conversion from int to R12' +fi +if (( ${#y[@]} != 3 )) +then err_exit 'error in count of array conversion from int to R12' +fi +unset abcdefg +: ${abcdefg[1]} +set | grep '^abcdefg$' >/dev/null && err_exit 'empty array variable in set list' +unset x y +x=1 +typeset -i y[$x]=4 +if [[ ${y[1]} != 4 ]] +then err_exit 'arithmetic expressions in typeset not working' +fi +unset foo +typeset foo=bar +typeset -A foo +if [[ ${foo[0]} != bar ]] +then err_exit 'initial value not preserved when typecast to associative' +fi +unset foo +foo=(one two) +typeset -A foo +foo[two]=3 +if [[ ${#foo[*]} != 3 ]] +then err_exit 'conversion of indexed to associative array failed' +fi +set a b c d e f g h i j k l m +if [[ ${#} != 13 ]] +then err_exit '${#} not 13' +fi +unset xxx +xxx=foo +if [[ ${!xxx[@]} != 0 ]] +then err_exit '${!xxx[@]} for scalar not 0' +fi +if [[ ${11} != k ]] +then err_exit '${11} not working' +fi +if [[ ${@:4:1} != d ]] +then err_exit '${@:4:1} not working' +fi +foovar1=abc +foovar2=def +if [[ ${!foovar@} != +(foovar[[:alnum:]]?([ ])) ]] +then err_exit '${!foovar@} does not expand correctly' +fi +if [[ ${!foovar1} != foovar1 ]] +then err_exit '${!foovar1} != foovar1' +fi +unset xxx +: ${xxx[3]} +if [[ ${!xxx[@]} ]] +then err_exit '${!xxx[@]} should be null' +fi +integer i=0 +{ + set -x + xxx[++i]=1 + set +x +} 2> /dev/null +if (( i != 1)) +then err_exit 'execution trace side effects with array subscripts' +fi +unset list +: $(set -A list foo bar) +if (( ${#list[@]} != 0)) +then err_exit '$(set -A list ...) leaves side effects' +fi +unset list +list= (foo bar bam) +( set -A list one two three four) +if [[ ${list[1]} != bar ]] +then err_exit 'array not restored after subshell' +fi +XPATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:.:/sbin:/usr/sbin +xpath=( $( IFS=: ; echo $XPATH ) ) +if [[ $(print -r "${xpath[@]##*/}") != 'bin bin ucb bin . sbin sbin' ]] +then err_exit '${xpath[@]##*/} not applied to each element' +fi +foo=( zero one '' three four '' six) +integer n=-1 +if [[ ${foo[@]:n} != six ]] +then err_exit 'array offset of -1 not working' +fi +if [[ ${foo[@]: -3:1} != four ]] +then err_exit 'array offset of -3:1 not working' +fi +$SHELL -c 'x=(if then else fi)' 2> /dev/null || err_exit 'reserved words in x=() assignment not working' +unset foo +foo=one +foo=( $foo two) +if [[ ${#foo[@]} != 2 ]] +then err_exit 'array getting unset before right hand side evaluation' +fi +foo=(143 3643 38732) +export foo +typeset -i foo +if [[ $($SHELL -c 'print $foo') != 143 ]] +then err_exit 'exporting indexed array not exporting 0-th element' +fi +( $SHELL -c ' + unset foo + typeset -A foo=([0]=143 [1]=3643 [2]=38732) + export foo + typeset -i foo + [[ $($SHELL -c "print $foo") == 143 ]]' +) 2> /dev/null || + err_exit 'exporting associative array not exporting 0-th element' +unset foo +typeset -A foo +foo[$((10))]=ok 2> /dev/null || err_exit 'arithmetic expression as subscript not working' +unset foo +typeset -A foo +integer foo=0 +[[ $foo == 0 ]] || err_exit 'zero element of associative array not being set' +unset foo +typeset -A foo=( [two]=1) +for i in one three four five +do : ${foo[$i]} +done +if [[ ${!foo[@]} != two ]] +then err_exit 'error in subscript names' +fi +unset x +x=( 1 2 3) +(x[1]=8) +[[ ${x[1]} == 2 ]] || err_exit 'index array produce side effects in subshells' +x=( 1 2 3) +( + x+=(8) + [[ ${#x[@]} == 4 ]] || err_exit 'index array append in subshell error' +) +[[ ${#x[@]} == 3 ]] || err_exit 'index array append in subshell effects parent' +x=( [one]=1 [two]=2 [three]=3) +(x[two]=8) +[[ ${x[two]} == 2 ]] || err_exit 'associative array produce side effects in subshells' +unset x +x=( [one]=1 [two]=2 [three]=3) +( + x+=( [four]=4 ) + [[ ${#x[@]} == 4 ]] || err_exit 'associative array append in subshell error' +) +[[ ${#x[@]} == 3 ]] || err_exit 'associative array append in subshell effects parent' +unset x +integer i +for ((i=0; i < 40; i++)) +do x[i]=$i +done +[[ ${#x[@]} == 40 ]] || err_exit 'index arrays loosing values' +[[ $( ($SHELL -c 'typeset -A var; (IFS=: ; set -A var a:b:c ;print ${var[@]});:' )2>/dev/null) == 'a b c' ]] || err_exit 'change associative to index failed' +unset foo +[[ $(foo=good +for ((i=0; i < 2; i++)) +do [[ ${foo[i]} ]] && print ok +done) == ok ]] || err_exit 'invalid optimization for subscripted variables' +( +x=([foo]=bar) +set +A x bam +) 2> /dev/null && err_exit 'set +A with associative array should be an error' +unset bam foo +foo=0 +typeset -A bam +unset bam[foo] +bam[foo]=value +[[ $bam == value ]] && err_exit 'unset associative array element error' +: only first element of an array can be exported +unset bam +print 'print ${var[0]} ${var[1]}' > $tmp/script +chmod +x $tmp/script +[[ $($SHELL -c "var=(foo bar);export var;$tmp/script") == foo ]] || err_exit 'export array not exporting just first element' + +unset foo +set --allexport +foo=one +foo[1]=two +foo[0]=three +[[ $foo == three ]] || err_exit '--allexport not working with arrays' +set --noallexport +unset foo + +cat > $tmp/script <<- \! + typeset -A foo + print foo${foo[abc]} +! +[[ $($SHELL -c "typeset -A foo;$tmp/script") == foo ]] 2> /dev/null || err_exit 'empty associative arrays not being cleared correctly before scripts' +[[ $($SHELL -c "typeset -A foo;foo[abc]=abc;$tmp/script") == foo ]] 2> /dev/null || err_exit 'associative arrays not being cleared correctly before scripts' +unset foo +foo=(one two) +[[ ${foo[@]:1} == two ]] || err_exit '${foo[@]:1} == two' +[[ ! ${foo[@]:2} ]] || err_exit '${foo[@]:2} not null' +unset foo +foo=one +[[ ! ${foo[@]:1} ]] || err_exit '${foo[@]:1} not null' +function EMPTY +{ + typeset i + typeset -n ARRAY=$1 + for i in ${!ARRAY[@]} + do unset ARRAY[$i] + done +} +unset foo +typeset -A foo +foo[bar]=bam +foo[x]=y +EMPTY foo +[[ $(typeset | grep foo$) == *associative* ]] || err_exit 'array lost associative attribute' +[[ ! ${foo[@]} ]] || err_exit 'array not empty' +[[ ! ${!foo[@]} ]] || err_exit 'array names not empty' +unset foo +foo=bar +set -- "${foo[@]:1}" +(( $# == 0 )) || err_exit '${foo[@]:1} should not have any values' +unset bar +exp=4 +: ${_foo[bar=4]} +(( bar == 4 )) || err_exit "subscript of unset variable not evaluated -- expected '4', got '$got'" +unset bar +: ${_foo[bar=$exp]} +(( bar == $exp )) || err_exit "subscript of unset variable not evaluated -- expected '$exp', got '$got'" +unset foo bar +foo[5]=4 +bar[4]=3 +bar[0]=foo +foo[0]=bam +foo[4]=5 +[[ ${!foo[2+2]} == 'foo[4]' ]] || err_exit '${!var[sub]} should be var[sub]' +[[ ${bar[${foo[5]}]} == 3 ]] || err_exit 'array subscript cannot be an array instance' +[[ $bar[4] == 3 ]] || err_exit '$bar[x] != ${bar[x]} inside [[ ]]' +(( $bar[4] == 3 )) || err_exit '$bar[x] != ${bar[x]} inside (( ))' +[[ $bar[$foo[5]] == 3 ]] || err_exit '$bar[foo[x]] != ${bar[foo[x]]} inside [[ ]]' +(( $bar[$foo[5]] == 3 )) || err_exit '$bar[foo[x]] != ${bar[foo[x]]} inside (( ))' +x=$bar[4] +[[ $x == 4 ]] && err_exit '$bar[4] should not be an array in an assignment' +x=${bar[$foo[5]]} +(( $x == 3 )) || err_exit '${bar[$foo[sub]]} not working' +[[ $($SHELL <<- \++EOF+++ + typeset -i test_variable=0 + typeset -A test_array + test_array[1]=100 + read test_array[2] <<-! + 2 + ! + read test_array[3] <<-! + 3 + ! + test_array[3]=4 + print "val=${test_array[3]}" +++EOF+++ +) == val=4 ]] 2> /dev/null || err_exit 'after reading array[j] and assign array[j] fails' +[[ $($SHELL <<- \+++EOF+++ + pastebin=( typeset -a form) + pastebin.form+=( name="name" data="clueless" ) + print -r -- ${pastebin.form[0].name} ++++EOF+++ +) == name ]] 2> /dev/null || err_exit 'indexed array in compound variable not working' +unset foo bar +: ${foo[bar=2]} +[[ $bar == 2 ]] || err_exit 'subscript not evaluated for unset variable' +unset foo bar +bar=1 +typeset -a foo=([1]=ok [2]=no) +[[ $foo[bar] == ok ]] || err_exit 'typeset -a not working for simple assignment' +unset foo +typeset -a foo=([1]=(x=ok) [2]=(x=no)) +[[ $(typeset | grep 'foo$') == *index* ]] || err_exit 'typeset -a not creating an indexed array' +foo+=([5]=good) +[[ $(typeset | grep 'foo$') == *index* ]] || err_exit 'append to indexed array not preserving array type' +unset foo +typeset -A foo=([1]=ok [2]=no) +[[ $foo[bar] == ok ]] && err_exit 'typeset -A not working for simple assignment' +unset foo +typeset -A foo=([1]=(x=ok) [2]=(x=no)) +[[ ${foo[bar].x} == ok ]] && err_exit 'typeset -A not working for compound assignment' +[[ $($SHELL -c 'typeset -a foo;typeset | grep "foo$"' 2> /dev/null) == *index* ]] || err_exit 'typeset fails for indexed array with no elements' +xxxxx=(one) +[[ $(typeset | grep xxxxx$) == *'indexed array'* ]] || err_exit 'array of one element not an indexed array' +unset foo +foo[1]=(x=3 y=4) +{ [[ ${!foo[1].*} == 'foo[1].x foo[1].y' ]] ;} 2> /dev/null || err_exit '${!foo[sub].*} not expanding correctly' +unset x +x=( typeset -a foo=( [0]="a" [1]="b" [2]="c" )) +[[ ${@x.foo} == 'typeset -a'* ]] || err_exit 'x.foo is not an indexed array' +x=( typeset -A foo=( [0]="a" [1]="b" [2]="c" )) +[[ ${@x.foo} == 'typeset -A'* ]] || err_exit 'x.foo is not an associative array' +$SHELL -c $'x=(foo\n\tbar\nbam\n)' 2> /dev/null || err_exit 'compound array assignment with new-lines not working' +$SHELL -c $'x=(foo\n\tbar:\nbam\n)' 2> /dev/null || err_exit 'compound array assignment with labels not working' +$SHELL -c $'x=(foo\n\tdone\nbam\n)' 2> /dev/null || err_exit 'compound array assignment with reserved words not working' +[[ $($SHELL -c 'typeset -A A; print $(( A[foo].bar ))' 2> /dev/null) == 0 ]] || err_exit 'unset variable not evaluating to 0' +unset a +typeset -A a +a[a].z=1 +a[z].z=2 +unset a[a] +[[ ${!a[@]} == z ]] || err_exit '"unset a[a]" unsets entire array' +unset a +a=([x]=1 [y]=2 [z]=(foo=3 bar=4)) +eval "b=$(printf "%B\n" a)" +eval "c=$(printf "%#B\n" a)" +[[ ${a[*]} == "${b[*]}" ]] || err_exit 'printf %B not preserving values for arrays' +[[ ${a[*]} == "${c[*]}" ]] || err_exit 'printf %#B not preserving values for arrays' +unset a +a=(zero one two three four) +a[6]=six +[[ ${a[-1]} == six ]] || err_exit 'a[-1] should be six' +[[ ${a[-3]} == four ]] || err_exit 'a[-3] should be four' +[[ ${a[-3..-1]} == 'four six' ]] || err_exit "a[-3,-1] should be 'four six'" + +FILTER=(typeset scope) +FILTER[0].scope=include +FILTER[1].scope=exclude +[[ ${#FILTER[@]} == 2 ]] || err_exit "FILTER array should have two elements not ${#FILTER[@]}" + +unset x +function x.get +{ + print sub=${.sh.subscript} +} +x[2]= +z=$(: ${x[1]} ) +[[ $z == sub=1 ]] || err_exit 'get function not invoked for index array' + +unset x +typeset -A x +function x.get +{ + print sub=${.sh.subscript} +} +x[2]= +z=$(: ${x[1]} ) +[[ $z == sub=1 ]] || err_exit 'get function not invoked for associative array' + +unset y +i=1 +a=(11 22) +typeset -m y=a[i] +[[ $y == 22 ]] || err_exit 'typeset -m for index array not working' +[[ ${a[i]} || ${a[0]} != 11 ]] && err_exit 'typeset -m for index array not deleting element' + +unset y +a=([0]=11 [1]=22) +typeset -m y=a[$i] +[[ $y == 22 ]] || err_exit 'typeset -m for associative array not working' +[[ ${a[$i]} || ${a[0]} != 11 ]] && err_exit 'typeset -m for associative array not deleting element' +unset x a j + +typeset -a a=( [0]="aa" [1]="bb" [2]="cc" ) +typeset -m 'j=a[0]' +typeset -m 'a[0]=a[1]' +typeset -m 'a[1]=j' +[[ ${a[@]} == 'bb aa cc' ]] || err_exit 'moving index array elements not working' +unset a j + +typeset -A a=( [0]="aa" [1]="bb" [2]="cc" ) +typeset -m 'j=a[0]' +typeset -m 'a[0]=a[1]' +typeset -m 'a[1]=j' +[[ ${a[@]} == 'bb aa cc' ]] || err_exit 'moving associative array elements not working' +unset a j + +z=(a b c) +unset x +typeset -m x[1]=z +[[ ${x[1][@]} == 'a b c' ]] || err_exit 'moving indexed array to index array element not working' + +unset x z +z=([0]=a [1]=b [2]=c) +typeset -m x[1]=z +[[ ${x[1][@]} == 'a b c' ]] || err_exit 'moving associative array to index array element not working' + +{ +typeset -a arr=( + float +) +} 2> /dev/null +[[ ${arr[0]} == float ]] || err_exit 'typeset -a should not expand alias for float' +unset arr + +{ +typeset -r -a arr=( + float +) +} 2> /dev/null +[[ ${arr[0]} == float ]] || err_exit 'typeset -r -a should not expand alias for float' +{ +typeset -a arr2=( + typeset +r +) +} 2> /dev/null +[[ ${arr2[0]} == typeset ]] || err_exit 'typeset -a should not process declarations' +unset arr2 + +$SHELL 2> /dev/null -c $'typeset -a arr=(\nfor)' || err_exit 'typeset -a should allow reserved words as first argument' + +$SHELL 2> /dev/null -c $'typeset -r -a arr=(\nfor)' || err_exit 'typeset -r -a should allow reserved words as first argument' + +typeset arr2[6] +[[ ${#arr2[@]} == 0 ]] || err_exit 'declartion "typeset array[6]" should not show any elements' + +arr2[1]=def +[[ ${arr2[1]} == def ]] || err_exit 'declaration "typeset array[6]" causes arrays causes wrong side effects' + +unset foo +typeset foo[7] +[[ ${#foo[@]} == 0 ]] || err_exit 'typeset foo[7] should not have one element' + +a=123 $SHELL 2> /dev/null -c 'integer a[5]=3 a[2]=4; unset a;x=0; ((a[++x]++));:' || err_exit 'unsetting array variable leaves side effect' + +unset foo +foo=(aa bb cc) +foo=( ${foo[@]:1} ) +[[ ${foo[@]} == 'bb cc' ]] || err_exit "indexed array assignment using parts of array for values gives wrong result of ${foo[@]}" + +unset foo +foo=([xx]=aa [yy]=bb [zz]=cc) +foo=( ${foo[yy]} ${foo[zz]} ) +[[ ${foo[@]} == 'bb cc' ]] || err_exit "associative array assignment using parts of array for values gives wrong result of ${foo[@]}" + + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/arrays2.sh b/src/cmd/ksh93/tests/arrays2.sh new file mode 100755 index 0000000..70de3b0 --- /dev/null +++ b/src/cmd/ksh93/tests/arrays2.sh @@ -0,0 +1,212 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 +for ((i=0; i < 4; i++ )) +do for ((j=0; j < 5; j++ )) + do a[i][j]=$i$j + done +done +for ((i=0; i < 4; i++ )) +do for ((j=0; j < 5; j++ )) + do [[ ${a[i][j]} == "$i$j" ]] || err_exit "\${a[$i][$j]} != $i$j" + done +done +for ((i=0; i < 4; i++ )) +do j=0;for k in ${a[i][@]} + do [[ $k == "$i$j" ]] || err_exit "\${a[i][@]} != $i$j" + (( j++ )) + done +done +unset a +a=( + ( 00 01 02 03 04 ) + ( 10 11 12 13 14 15) + ( 20 21 22 23 24 ) + ( 30 31 32 33 34 ) +) + +function check +{ + nameref a=$1 + nameref b=a[2] + typeset c=$1 + integer i j + for ((i=0; i < 4; i++ )) + do for ((j=0; j < 5; j++ )) + do [[ ${a[$i][$j]} == "$i$j" ]] || err_exit "\${$c[$i][$j]} != $i$j" + done + done + (( ${#a[@]} == 4 )) || err_exit "\${#$c[@]} not 4" + (( ${#a[0][@]} == 5 )) || err_exit "\${#$c[0][@]} not 5" + (( ${#a[1][@]} == 6 )) || err_exit "\${#$c[1][@]} not 6" + set -s -- ${!a[@]} + [[ ${@} == '0 1 2 3' ]] || err_exit "\${!$c[@]} not 0 1 2 3" + set -s -- ${!a[0][@]} + [[ ${@} == '0 1 2 3 4' ]] || err_exit "\${!$c[0][@]} not 0 1 2 3 4" + set -s -- ${!a[1][@]} + [[ ${@} == '0 1 2 3 4 5' ]] || err_exit "\${!$c[1][@]} not 0 1 2 3 4 5" + [[ $a == 00 ]] || err_exit "\$$c is not 00" + [[ ${a[0]} == 00 ]] || err_exit "\${$a[0]} is not 00" + [[ ${a[0][0]} == 00 ]] || err_exit "${a[0][0]} is not 00" + [[ ${a[0][0][0]} == 00 ]] || err_exit "\${$c[0][0][0]} is not 00" + [[ ${a[0][0][1]} == '' ]] || err_exit "\${$c[0][0][1]} is not empty" + [[ ${b[3]} == 23 ]] || err_exit "${!b}[3] not = 23" +} + +check a + +unset a +typeset -A a +for ((i=0; i < 4; i++ )) +do for ((j=0; j < 5; j++ )) + do a[$i][j]=$i$j + done +done +for ((i=0; i < 4; i++ )) +do for ((j=0; j < 5; j++ )) + do [[ ${a[$i][j]} == "$i$j" ]] || err_exit "\${a[$i][$j]} == $i$j" + done +done +a[1][5]=15 +b=( + [0]=( 00 01 02 03 04 ) + [1]=( 10 11 12 13 14 15) + [2]=( 20 21 22 23 24 ) + [3]=( 30 31 32 33 34 ) +) +check b +[[ ${a[1][@]} == "${b[1][@]}" ]] || err_exit "a[1] not equal to b[1]" +c=( + [0]=( [0]=00 [1]=01 [2]=02 [3]=03 [4]=04 ) + [1]=( [0]=10 [1]=11 [2]=12 [3]=13 [4]=14 [5]=15) + [2]=( [0]=20 [1]=21 [2]=22 [3]=23 [4]=24 ) + [3]=( [0]=30 [1]=31 [2]=32 [3]=33 [4]=34 ) +) +check c +typeset -A d +d[0]=( [0]=00 [1]=01 [2]=02 [3]=03 [4]=04 ) +d[1]=( [0]=10 [1]=11 [2]=12 [3]=13 [4]=14 [5]=15) +d[2]=( [0]=20 [1]=21 [2]=22 [3]=23 [4]=24 ) +d[3]=( [0]=30 [1]=31 [2]=32 [3]=33 [4]=34 ) +check d +unset a b c d +[[ ${a-set} ]] || err_exit "a is set after unset" +[[ ${b-set} ]] || err_exit "b is set after unset" +[[ ${c-set} ]] || err_exit "c is set after unset" +[[ ${d-set} ]] || err_exit "c is set after unset" + +$SHELL 2> /dev/null <<\+++ || err_exit 'input of 3 dimensional array not working' +typeset x=( + ( (g G) (h H) (i I) ) + ( (d D) (e E) (f F) ) + ( (a A) (b B) (c C) ) +) +[[ ${x[0][0][0]} == g ]] || err_exit '${x[0][0][0]} == G' +[[ ${x[1][1][0]} == e ]] || err_exit '${x[1][1][0]} == e' +[[ ${x[1][1][1]} == E ]] || err_exit '${x[2][2][1]} == C' +[[ ${x[0][2][1]} == I ]] || err_exit '${x[0][2][1]} == I' ++++ + +typeset -a -si x=( [0]=(1 2 3) [1]=(4 5 6) [2]=(7 8 9) ) +[[ ${x[1][1]} == 5 ]] || err_exit 'changing two dimensional indexed array to short integer failed' +unset x +typeset -A -si x=( [0]=(1 2 3) [1]=(4 5 6) [2]=(7 8 9) ) +[[ ${x[1][2]} == 6 ]] || err_exit 'changing two dimensional associative array to short integer failed' + +unset ar x y +integer -a ar +integer i x y +for (( i=0 ; i < 100 ; i++ )) +do (( ar[y][x++]=i )) + (( x > 9 )) && (( y++ , x=0 )) +done +[[ ${#ar[0][*]} == 10 ]] || err_exit "\${#ar[0][*]} is '${#ar[0][*]}', should be 10" +[[ ${#ar[*]} == 10 ]] || err_exit "\${#ar[*]} is '${#ar[*]}', should be 10" +[[ ${ar[5][5]} == 55 ]] || err_exit "ar[5][5] is '${ar[5][5]}', should be 55" + +unset ar +integer -a ar +x=0 y=0 +for (( i=0 ; i < 81 ; i++ )) +do nameref ar_y=ar[$y] + (( ar_y[x++]=i )) + (( x > 8 )) && (( y++ , x=0 )) + typeset +n ar_y +done +[[ ${#ar[0][*]} == 9 ]] || err_exit "\${#ar[0][*]} is '${#ar[0][*]}', should be 9" +[[ ${#ar[*]} == 9 ]] || err_exit "\${#ar[*]} is '${#ar[*]}', should be 9" +[[ ${ar[4][4]} == 40 ]] || err_exit "ar[4][4] is '${ar[4][4]}', should be 40" + +$SHELL 2> /dev/null -c 'compound c;float -a c.ar;(( c.ar[2][3][3] = 5))' || 'multi-dimensional arrays in arithemtic expressions not working' + +expected='typeset -a -l -E c.ar=([2]=([3]=([3]=5) ) )' +unset c +float c.ar +c.ar[2][3][3]=5 +[[ $(typeset -p c.ar) == "$expected" ]] || err_exit "c.ar[2][3][3]=5;typeset -c c.ar expands to $(typeset -p c.ar)" + +unset values +float -a values=( [1][3]=90 [1][4]=89 ) +function fx +{ + nameref arg=$1 + [[ ${arg[0..5]} == '90 89' ]] || err_exit '${arg[0..5]} not correct where arg is a nameref to values[1]' +} +fx values[1] + +function test_short_integer +{ + compound out=( typeset stdout stderr ; integer res ) + compound -r -a tests=( + ( cmd='integer -s -r -a x=( 1 2 3 ) ; print "${x[2]}"' stdoutpattern='3' ) + ( cmd='integer -s -r -A x=( [0]=1 [1]=2 [2]=3 ) ; print "${x[2]}"' stdoutpattern='3' ) + # 2D integer arrays: the following two tests crash for both "integer -s" and "integer" + ( cmd='integer -r -a x=( [0]=( [0]=1 [1]=2 [2]=3 ) [1]=( [0]=4 [1]=5 [2]=6 ) [2]=( [0]=7 [1]=8 [2]=9 ) ) ; print "${x[1][1]}"' stdoutpattern='5' ) + ( cmd='integer -s -r -a x=( [0]=( [0]=1 [1]=2 [2]=3 ) [1]=( [0]=4 [1]=5 [2]=6 ) [2]=( [0]=7 [1]=8 [2]=9 ) ) ; print "${x[1][1]}"' stdoutpattern='5' ) + ) + typeset testname + integer i + + for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do + nameref tst=tests[i] + testname="${0}/${i}" + + out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -o errexit -c "${tst.cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" + + [[ "${out.stdout}" == ${tst.stdoutpattern} ]] || err_exit "${testname}: Expected stdout to match $(printf '%q\n' "${tst.stdoutpattern}"), got $(printf '%q\n' "${out.stdout}")" + [[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got $(printf '%q\n' "${out.stderr}")" + (( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}" + done + + return 0 +} +# run tests +test_short_integer + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/attributes.sh b/src/cmd/ksh93/tests/attributes.sh new file mode 100755 index 0000000..9deca59 --- /dev/null +++ b/src/cmd/ksh93/tests/attributes.sh @@ -0,0 +1,418 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +r=readonly u=Uppercase l=Lowercase i=22 i8=10 L=abc L5=def uL5=abcdef xi=20 +x=export t=tagged H=hostname LZ5=026 RZ5=026 Z5=123 lR5=ABcdef R5=def n=l +for option in u l i i8 L L5 LZ5 RZ5 Z5 r x H t R5 uL5 lR5 xi n +do typeset -$option $option +done +(r=newval) 2> /dev/null && err_exit readonly attribute fails +i=i+5 +if ((i != 27)) +then err_exit integer attributes fails +fi +if [[ $i8 != 8#12 ]] +then err_exit integer base 8 fails +fi +if [[ $u != UPPERCASE ]] +then err_exit uppercase fails +fi +if [[ $l != lowercase ]] +then err_exit lowercase fails +fi +if [[ $n != lowercase ]] +then err_exit reference variables fail +fi +if [[ t=tagged != $(typeset -t) ]] +then err_exit tagged fails +fi +if [[ t != $(typeset +t) ]] +then err_exit tagged fails +fi +if [[ $Z5 != 00123 ]] +then err_exit zerofill fails +fi +if [[ $RZ5 != 00026 ]] +then err_exit right zerofill fails +fi +L=12345 +if [[ $L != 123 ]] +then err_exit leftjust fails +fi +if [[ $L5 != "def " ]] +then err_exit leftjust fails +fi +if [[ $uL5 != ABCDE ]] +then err_exit leftjust uppercase fails +fi +if [[ $lR5 != bcdef ]] +then err_exit rightjust fails +fi +if [[ $R5 != " def" ]] +then err_exit rightjust fails +fi +if [[ $($SHELL -c 'echo $x') != export ]] +then err_exit export fails +fi +if [[ $($SHELL -c 'xi=xi+4;echo $xi') != 24 ]] +then err_exit export attributes fails +fi +x=$(foo=abc $SHELL <<! + foo=bar + $SHELL -c 'print \$foo' +! +) +if [[ $x != bar ]] +then err_exit 'environment variables require re-export' +fi +(typeset + ) > /dev/null 2>&1 || err_exit 'typeset + not working' +(typeset -L-5 buf="A" 2>/dev/null) +if [[ $? == 0 ]] +then err_exit 'typeset allows negative field for left/right adjust' +fi +a=b +readonly $a=foo +if [[ $b != foo ]] +then err_exit 'readonly $a=b not working' +fi +if [[ $(export | grep '^PATH=') != PATH=* ]] +then err_exit 'export not working' +fi +picture=( + bitmap=/fruit + size=(typeset -E x=2.5) +) +string="$(print $picture)" +if [[ "${string}" != *'size=( typeset -E'* ]] +then err_exit 'print of compound exponential variable not working' +fi +sz=(typeset -E y=2.2) +string="$(print $sz)" +if [[ "${sz}" == *'typeset -E -F'* ]] +then err_exit 'print of exponential shows both -E and -F attributes' +fi +print 'typeset -i m=48/4+1;print -- $m' > $tmp/script +chmod +x $tmp/script +typeset -Z2 m +if [[ $($tmp/script) != 13 ]] +then err_exit 'attributes not cleared for script execution' +fi +print 'print VAR=$VAR' > $tmp/script +typeset -L70 VAR=var +$tmp/script > $tmp/script.1 +[[ $(< $tmp/script.1) == VAR= ]] || err_exit 'typeset -L should not be inherited' +typeset -Z LAST=00 +unset -f foo +function foo +{ + if [[ $1 ]] + then LAST=$1 + else ((LAST++)) + fi +} +foo 1 +if (( ${#LAST} != 2 )) +then err_exit 'LAST!=2' +fi +foo +if (( ${#LAST} != 2 )) +then err_exit 'LAST!=2' +fi +[[ $(set | grep LAST) == LAST=02 ]] || err_exit "LAST not correct in set list" +set -a +unset foo +foo=bar +if [[ $(export | grep ^foo=) != 'foo=bar' ]] +then err_exit 'all export not working' +fi +unset foo +read foo <<! +bar +! +if [[ $(export | grep ^foo=) != 'foo=bar' ]] +then err_exit 'all export not working with read' +fi +if [[ $(typeset | grep PS2) == PS2 ]] +then err_exit 'typeset without arguments outputs names without attributes' +fi +unset a z q x +w1=hello +w2=world +t1="$w1 $w2" +if (( 'a' == 97 )) +then b1=aGVsbG8gd29ybGQ= + b2=aGVsbG8gd29ybGRoZWxsbyB3b3JsZA== +else b1=iIWTk5ZAppaZk4Q= + b2=iIWTk5ZAppaZk4SIhZOTlkCmlpmThA== +fi +z=$b1 +typeset -b x=$b1 +[[ $x == "$z" ]] || print -u2 'binary variable not expanding correctly' +[[ $(printf "%B" x) == $t1 ]] || err_exit 'typeset -b not working' +typeset -b -Z5 a=$b1 +[[ $(printf "%B" a) == $w1 ]] || err_exit 'typeset -b -Z5 not working' +typeset -b q=$x$x +[[ $q == $b2 ]] || err_exit 'typeset -b not working with concatination' +[[ $(printf "%B" q) == $t1$t1 ]] || err_exit 'typeset -b concatination not working' +x+=$b1 +[[ $x == $b2 ]] || err_exit 'typeset -b not working with append' +[[ $(printf "%B" x) == $t1$t1 ]] || err_exit 'typeset -b append not working' +typeset -b -Z20 z=$b1 +(( $(printf "%B" z | wc -c) == 20 )) || err_exit 'typeset -b -Z20 not storing 20 bytes' +{ + typeset -b v1 v2 + read -N11 v1 + read -N22 v2 +} << ! +hello worldhello worldhello world +! +[[ $v1 == "$b1" ]] || err_exit "v1=$v1 should be $b1" +[[ $v2 == "$x" ]] || err_exit "v1=$v2 should be $x" +if env '!=1' >/dev/null 2>&1 +then [[ $(env '!=1' $SHELL -c 'echo ok' 2>/dev/null) == ok ]] || err_exit 'malformed environment terminates shell' +fi +unset var +typeset -b var +printf '12%Z34' | read -r -N 5 var +[[ $var == MTIAMzQ= ]] || err_exit 'binary files with zeros not working' +unset var +if command typeset -usi var=0xfffff 2> /dev/null +then (( $var == 0xffff )) || err_exit 'unsigned short integers not working' +else err_exit 'typeset -usi cannot be used for unsigned short' +fi +[[ $($SHELL -c 'unset foo;typeset -Z2 foo; print ${foo:-3}' 2> /dev/null) == 3 ]] || err_exit '${foo:-3} not 3 when typeset -Z2 field undefined' +[[ $($SHELL -c 'unset foo;typeset -Z2 foo; print ${foo:=3}' 2> /dev/null) == 03 ]] || err_exit '${foo:=-3} not 3 when typeset -Z2 foo undefined' +unset foo bar +unset -f fun +function fun +{ + export foo=hello + typeset -x bar=world + [[ $foo == hello ]] || err_exit 'export scoping problem in function' +} +fun +[[ $(export | grep foo) == 'foo=hello' ]] || err_exit 'export not working in functions' +[[ $(export | grep bar) ]] && err_exit 'typeset -x not local' +[[ $($SHELL -c 'typeset -r IFS=;print -r $(pwd)' 2> /dev/null) == "$(pwd)" ]] || err_exit 'readonly IFS causes command substitution to fail' +fred[66]=88 +[[ $(typeset -pa) == *fred* ]] || err_exit 'typeset -pa not working' +unset x y z +typeset -LZ3 x=abcd y z=00abcd +y=03 +[[ $y == "3 " ]] || err_exit '-LZ3 not working for value 03' +[[ $x == "abc" ]] || err_exit '-LZ3 not working for value abcd' +[[ $x == "abc" ]] || err_exit '-LZ3 not working for value 00abcd' +unset x z +set +a +[[ $(typeset -p z) ]] && err_exit "typeset -p for z undefined failed" +unset z +x='typeset -i z=45' +eval "$x" +[[ $(typeset -p z) == "$x" ]] || err_exit "typeset -p for '$x' failed" +[[ $(typeset +p z) == "${x%=*}" ]] || err_exit "typeset +p for '$x' failed" +unset z +x='typeset -a z=(a b c)' +eval "$x" +[[ $(typeset -p z) == "$x" ]] || err_exit "typeset -p for '$x' failed" +[[ $(typeset +p z) == "${x%=*}" ]] || err_exit "typeset +p for '$x' failed" +unset z +x='typeset -C z=( + foo=bar + xxx=bam +)' +eval "$x" +x=${x//$'\t'} +x=${x//$'(\n'/'('} +x=${x//$'\n'/';'} +x=${x%';)'}')' +[[ $(typeset -p z) == "$x" ]] || err_exit "typeset -p for '$x' failed" +[[ $(typeset +p z) == "${x%%=*}" ]] || err_exit "typeset +p for '$x' failed" +unset z +x='typeset -A z=([bar]=bam [xyz]=bar)' +eval "$x" +[[ $(typeset -p z) == "$x" ]] || err_exit "typeset -p for '$x' failed" +[[ $(typeset +p z) == "${x%%=*}" ]] || err_exit "typeset +p for '$x' failed" +unset z +foo=abc +x='typeset -n z=foo' +eval "$x" +[[ $(typeset -p z) == "$x" ]] || err_exit "typeset -p for '$x' failed" +[[ $(typeset +p z) == "${x%%=*}" ]] || err_exit "typeset +p for '$x' failed" +typeset +n z +unset foo z +typeset -T Pt_t=( + float x=1 y=2 +) +Pt_t z +x=${z//$'\t'} +x=${x//$'(\n'/'('} +x=${x//$'\n'/';'} +x=${x%';)'}')' +[[ $(typeset -p z) == "Pt_t z=$x" ]] || err_exit "typeset -p for type failed" +[[ $(typeset +p z) == "Pt_t z" ]] || err_exit "typeset +p for type failed" +unset z +function foo +{ + typeset -p bar +} +bar=xxx +[[ $(foo) == bar=xxx ]] || err_exit 'typeset -p not working inside a function' +unset foo +typeset -L5 foo +[[ $(typeset -p foo) == 'typeset -L 5 foo' ]] || err_exit 'typeset -p not working for variables with attributes but without a value' +{ $SHELL <<- EOF + typeset -L3 foo=aaa + typeset -L6 foo=bbbbbb + [[ \$foo == bbbbbb ]] +EOF +} || err_exit 'typeset -L should not preserve old attributes' +{ $SHELL <<- EOF + typeset -R3 foo=aaa + typeset -R6 foo=bbbbbb + [[ \$foo == bbbbbb ]] +EOF +} 2> /dev/null || err_exit 'typeset -R should not preserve old attributes' + +expected='YWJjZGVmZ2hpag==' +unset foo +typeset -b -Z10 foo +read foo <<< 'abcdefghijklmnop' +[[ $foo == "$expected" ]] || err_exit 'read foo, where foo is "typeset -b -Z10" not working' +unset foo +typeset -b -Z10 foo +read -N10 foo <<< 'abcdefghijklmnop' +[[ $foo == "$expected" ]] || err_exit 'read -N10 foo, where foo is "typeset -b -Z10" not working' +unset foo +typeset -b -A foo +read -N10 foo[4] <<< 'abcdefghijklmnop' +[[ ${foo[4]} == "$expected" ]] || err_exit 'read -N10 foo, where foo is "typeset -b -A" foo not working' +unset foo +typeset -b -a foo +read -N10 foo[4] <<< 'abcdefghijklmnop' +[[ ${foo[4]} == "$expected" ]] || err_exit 'read -N10 foo, where foo is "typeset -b -a" foo not working' +[[ $(printf %B foo[4]) == abcdefghij ]] || err_exit 'printf %B for binary associative array element not working' +[[ $(printf %B foo[4]) == abcdefghij ]] || err_exit 'printf %B for binary indexed array element not working' +unset foo + +$SHELL 2> /dev/null -c 'export foo=(bar=3)' && err_exit 'compound variables cannot be exported' + +$SHELL -c 'builtin date' >/dev/null 2>&1 && +{ + +# check env var changes against a builtin that uses the env var + +SEC=1234252800 +ETZ=EST5EDT +EDT=03 +PTZ=PST8PDT +PDT=00 + +CMD="date -f%H \\#$SEC" + +export TZ=$ETZ + +set -- \ + "$EDT $PDT $EDT" "" "TZ=$PTZ" "" \ + "$EDT $PDT $EDT" "" "TZ=$PTZ" "TZ=$ETZ" \ + "$EDT $PDT $EDT" "TZ=$ETZ" "TZ=$PTZ" "TZ=$ETZ" \ + "$PDT $EDT $PDT" "TZ=$PTZ" "" "TZ=$PTZ" \ + "$PDT $EDT $PDT" "TZ=$PTZ" "TZ=$ETZ" "TZ=$PTZ" \ + "$EDT $PDT $EDT" "foo=bar" "TZ=$PTZ" "TZ=$ETZ" \ + +while (( $# >= 4 )) +do exp=$1 + got=$(print $($SHELL -c "builtin date; $2 $CMD; $3 $CMD; $4 $CMD")) + [[ $got == $exp ]] || err_exit "[ '$2' '$3' '$4' ] env sequence failed -- expected '$exp', got '$got'" + shift 4 +done + +} + +unset v +typeset -H v=/dev/null +[[ $v == *nul* ]] || err_exit 'typeset -H for /dev/null not working' + +unset x +(typeset +C x) 2> /dev/null && err_exit 'typeset +C should be an error' +(typeset +A x) 2> /dev/null && err_exit 'typeset +A should be an error' +(typeset +a x) 2> /dev/null && err_exit 'typeset +a should be an error' + +unset x +{ +x=$($SHELL -c 'integer -s x=5;print -r -- $x') +} 2> /dev/null +[[ $x == 5 ]] || err_exit 'integer -s not working' + +[[ $(typeset -l) == *namespace*.sh* ]] && err_exit 'typeset -l should not contain namespace .sh' + +unset got +typeset -u got +exp=100 +((got=$exp)) +[[ $got == $exp ]] || err_exit "typeset -l fails on numeric value -- expected '$exp', got '$got'" + +unset s +typeset -a -u s=( hello world chicken ) +[[ ${s[2]} == CHICKEN ]] || err_exit 'typeset -u not working with indexed arrays' +unset s +typeset -A -u s=( [1]=hello [0]=world [2]=chicken ) +[[ ${s[2]} == CHICKEN ]] || err_exit 'typeset -u not working with associative arrays' +expected=$'(\n\t[0]=WORLD\n\t[1]=HELLO\n\t[2]=CHICKEN\n)' +[[ $(print -v s) == "$expected" ]] || err_exit 'typeset -u for associative array does not display correctly' + +unset s +if command typeset -M totitle s 2> /dev/null +then [[ $(typeset +p s) == 'typeset -M totitle s' ]] || err_exit 'typeset -M totitle does not display correctly with typeset -p' +fi + +{ $SHELL <<- \EOF + compound -a a1 + for ((i=1 ; i < 100 ; i++ )) + do [[ "$( typeset + a1[$i] )" == '' ]] && a1[$i].text='hello' + done + [[ ${a1[70].text} == hello ]] +EOF +} 2> /dev/null +(( $? )) && err_exit 'typeset + a[i] not working' + +typeset groupDB="" userDB="" +typeset -l -L1 DBPick="" +[[ -n "$groupDB" ]] && err_exit 'typeset -l -L1 causes unwanted side effect' + +HISTFILE=foo +typeset -u PS1='hello --- ' +HISTFILE=foo +[[ $HISTFILE == foo ]] || err_exit 'typeset -u PS1 affects HISTFILE' + + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/basic.sh b/src/cmd/ksh93/tests/basic.sh new file mode 100755 index 0000000..2941543 --- /dev/null +++ b/src/cmd/ksh93/tests/basic.sh @@ -0,0 +1,513 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +# test basic file operations like redirection, pipes, file expansion +set -- \ + go+r 0000 \ + go-r 0044 \ + ug=r 0330 \ + go+w 0000 \ + go-w 0022 \ + ug=w 0550 \ + go+x 0000 \ + go-x 0011 \ + ug=x 0660 \ + go-rx 0055 \ + uo-wx 0303 \ + ug-rw 0660 \ + o= 0007 +while (( $# >= 2 )) +do umask 0 + umask $1 + g=$(umask) + [[ $g == $2 ]] || err_exit "umask 0; umask $1 failed -- expected $2, got $g" + shift 2 +done +umask u=rwx,go=rx || err_exit "umask u=rws,go=rx failed" +if [[ $(umask -S) != u=rwx,g=rx,o=rx ]] +then err_exit 'umask -S incorrect' +fi +pwd=$PWD +[[ $SHELL != /* ]] && SHELL=$pwd/$SHELL +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } +um=$(umask -S) +( umask 0777; > foobar ) +rm -f foobar +> foobar +[[ -r foobar ]] || err_exit 'umask not being restored after subshell' +umask "$um" +rm -f foobar +# optimizer bug test +> foobar +for i in 1 2 +do print foobar* + rm -f foobar +done > out +if [[ "$(<out)" != "foobar"$'\n'"foobar*" ]] +then print -u2 "optimizer bug with file expansion" +fi +rm -f out foobar +mkdir dir +if [[ $(print */) != dir/ ]] +then err_exit 'file expansion with trailing / not working' +fi +if [[ $(print *) != dir ]] +then err_exit 'file expansion with single file not working' +fi +print hi > .foo +if [[ $(print *) != dir ]] +then err_exit 'file expansion leading . not working' +fi +date > dat1 || err_exit "date > dat1 failed" +test -r dat1 || err_exit "dat1 is not readable" +x=dat1 +cat <$x > dat2 || err_exit "cat < $x > dat2 failed" +cat dat1 dat2 | cat | cat | cat > dat3 || err_exit "cat pipe failed" +cat > dat4 <<! +$(date) +! +cat dat1 dat2 | cat | cat | cat > dat5 & +wait $! +set -- dat* +if (( $# != 5 )) +then err_exit "dat* matches only $# files" +fi +if (command > foo\\abc) 2> /dev/null +then set -- foo* + if [[ $1 != 'foo\abc' ]] + then err_exit 'foo* does not match foo\abc' + fi +fi +if ( : > TT* && : > TTfoo ) 2>/dev/null +then set -- TT* + if (( $# < 2 )) + then err_exit 'TT* not expanding when file TT* exists' + fi +fi +cd ~- || err_exit "cd back failed" +cat > $tmp/script <<- ! + #! $SHELL + print -r -- \$0 +! +chmod 755 $tmp/script +if [[ $($tmp/script) != "$tmp/script" ]] +then err_exit '$0 not correct for #! script' +fi +bar=foo +eval foo=\$bar +if [[ $foo != foo ]] +then err_exit 'eval foo=\$bar not working' +fi +bar='foo=foo\ bar' +eval $bar +if [[ $foo != 'foo bar' ]] +then err_exit 'eval foo=\$bar, with bar="foo\ bar" not working' +fi +cd /tmp +cd ../../tmp || err_exit "cd ../../tmp failed" +if [[ $PWD != /tmp ]] +then err_exit 'cd ../../tmp is not /tmp' +fi +( sleep 2; cat <<! +foobar +! +) | cat > $tmp/foobar & +wait $! +foobar=$( < $tmp/foobar) +if [[ $foobar != foobar ]] +then err_exit "$foobar is not foobar" +fi +{ + print foo + /bin/echo bar + print bam +} > $tmp/foobar +if [[ $( < $tmp/foobar) != $'foo\nbar\nbam' ]] +then err_exit "output file pointer not shared correctly" +fi +cat > $tmp/foobar <<\! + print foo + /bin/echo bar + print bam +! +chmod +x $tmp/foobar +if [[ $($tmp/foobar) != $'foo\nbar\nbam' ]] +then err_exit "script not working" +fi +if [[ $($tmp/foobar | /bin/cat) != $'foo\nbar\nbam' ]] +then err_exit "script | cat not working" +fi +if [[ $( $tmp/foobar) != $'foo\nbar\nbam' ]] +then err_exit "output file pointer not shared correctly" +fi +rm -f $tmp/foobar +x=$( (print foo) ; (print bar) ) +if [[ $x != $'foo\nbar' ]] +then err_exit " ( (print foo);(print bar ) failed" +fi +x=$( (/bin/echo foo) ; (print bar) ) +if [[ $x != $'foo\nbar' ]] +then err_exit " ( (/bin/echo);(print bar ) failed" +fi +x=$( (/bin/echo foo) ; (/bin/echo bar) ) +if [[ $x != $'foo\nbar' ]] +then err_exit " ( (/bin/echo);(/bin/echo bar ) failed" +fi +cat > $tmp/script <<\! +if [[ -p /dev/fd/0 ]] +then builtin cat + cat - > /dev/null + [[ -p /dev/fd/0 ]] && print ok +else print no +fi +! +chmod +x $tmp/script +case $( (print) | $tmp/script;:) in +ok) ;; +no) err_exit "[[ -p /dev/fd/0 ]] fails for standard input pipe" ;; +*) err_exit "builtin replaces standard input pipe" ;; +esac +print 'print $0' > $tmp/script +print ". $tmp/script" > $tmp/scriptx +chmod +x $tmp/scriptx +if [[ $($tmp/scriptx) != $tmp/scriptx ]] +then err_exit '$0 not correct for . script' +fi +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } +print ./b > ./a; print ./c > b; print ./d > c; print ./e > d; print "echo \"hello there\"" > e +chmod 755 a b c d e +x=$(./a) +if [[ $x != "hello there" ]] +then err_exit "nested scripts failed" +fi +x=$( (./a) | cat) +if [[ $x != "hello there" ]] +then err_exit "scripts in subshells fail" +fi +cd ~- || err_exit "cd back failed" +x=$( (/bin/echo foo) 2> /dev/null ) +if [[ $x != foo ]] +then err_exit "subshell in command substitution fails" +fi +exec 9>& 1 +exec 1>&- +x=$(print hello) +if [[ $x != hello ]] +then err_exit "command subsitution with stdout closed failed" +fi +exec >& 9 +cd $pwd +x=$(cat <<\! | $SHELL +/bin/echo | /bin/cat +/bin/echo hello +! +) +if [[ $x != $'\n'hello ]] +then err_exit "$SHELL not working when standard input is a pipe" +fi +x=$( (/bin/echo hello) 2> /dev/null ) +if [[ $x != hello ]] +then err_exit "subshell in command substitution with 1 closed fails" +fi +cat > $tmp/script <<- \! +read line 2> /dev/null +print done +! +if [[ $($SHELL $tmp/script <&-) != done ]] +then err_exit "executing script with 0 closed fails" +fi +trap '' INT +cat > $tmp/script <<- \! +trap 'print bad' INT +kill -s INT $$ +print good +! +chmod +x $tmp/script +if [[ $($SHELL $tmp/script) != good ]] +then err_exit "traps ignored by parent not ignored" +fi +trap - INT +cat > $tmp/script <<- \! +read line +/bin/cat +! +if [[ $($SHELL $tmp/script <<! +one +two +! +) != two ]] +then err_exit "standard input not positioned correctly" +fi +word=$(print $'foo\nbar' | { read line; /bin/cat;}) +if [[ $word != bar ]] +then err_exit "pipe to { read line; /bin/cat;} not working" +fi +word=$(print $'foo\nbar' | ( read line; /bin/cat) ) +if [[ $word != bar ]] +then err_exit "pipe to ( read line; /bin/cat) not working" +fi +if [[ $(print x{a,b}y) != 'xay xby' ]] +then err_exit 'brace expansion not working' +fi +if [[ $(for i in foo bar + do ( tgz=$(print $i) + print $tgz) + done) != $'foo\nbar' ]] +then err_exit 'for loop subshell optimizer bug' +fi +unset a1 +optbug() +{ + set -A a1 foo bar bam + integer i + for ((i=0; i < 3; i++)) + do + (( ${#a1[@]} < 2 )) && return 0 + set -- "${a1[@]}" + shift + set -A a1 -- "$@" + done + return 1 +} +optbug || err_exit 'array size optimzation bug' +wait # not running --pipefail which would interfere with subsequent tests +: $(jobs -p) # required to clear jobs for next jobs -p (interactive side effect) +sleep 20 & +pids=$! +if [[ $(jobs -p) != $! ]] +then err_exit 'jobs -p not reporting a background job' +fi +sleep 20 & +pids="$pids $!" +foo() +{ + set -- $(jobs -p) + (( $# == 2 )) || err_exit "$# jobs not reported -- 2 expected" +} +foo +kill $pids + +[[ $( (trap 'print alarm' ALRM; sleep 4) & sleep 2; kill -ALRM $!; sleep 2; wait) == alarm ]] || err_exit 'ALRM signal not working' +[[ $($SHELL -c 'trap "" HUP; $SHELL -c "(sleep 2;kill -HUP $$)& sleep 4;print done"') != done ]] && err_exit 'ignored traps not being ignored' +[[ $($SHELL -c 'o=foobar; for x in foo bar; do (o=save);print $o;done' 2> /dev/null ) == $'foobar\nfoobar' ]] || err_exit 'for loop optimization subshell bug' +command exec 3<> /dev/null +if cat /dev/fd/3 >/dev/null 2>&1 || whence mkfifo > /dev/null +then [[ $($SHELL -c 'cat <(print foo)' 2> /dev/null) == foo ]] || err_exit 'process substitution not working' + [[ $($SHELL -c $'tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! + line0 + line1 + line2 + !!! + wait + cat '$tmp/scriptx 2> /dev/null) == line1 ]] || err_exit '>() process substitution fails' + > $tmp/scriptx + [[ $($SHELL -c $' + for i in 1 + do tee >(grep \'1$\' > '$tmp/scriptx$') > /dev/null <<- \!!! + line0 + line1 + line2 + !!! + done + wait + cat '$tmp/scriptx 2>> /dev/null) == line1 ]] || err_exit '>() process substitution fails in for loop' + [[ $({ $SHELL -c 'cat <(for i in x y z; do print $i; done)';} 2> /dev/null) == $'x\ny\nz' ]] || + err_exit 'process substitution of compound commands not working' +fi +[[ $($SHELL -r 'command -p :' 2>&1) == *restricted* ]] || err_exit 'command -p not restricted' +print cat > $tmp/scriptx +chmod +x $tmp/scriptx +[[ $($SHELL -c "print foo | $tmp/scriptx ;:" 2> /dev/null ) == foo ]] || err_exit 'piping into script fails' +[[ $($SHELL -c 'X=1;print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 1 ]] || err_exit 'x=1;${x:=$(..."...")} failure' +[[ $($SHELL -c 'print -r -- ${X:=$(expr "a(0)" : '"'a*(\([^)]\))')}'" 2> /dev/null) == 0 ]] || err_exit '${x:=$(..."...")} failure' +if cat /dev/fd/3 >/dev/null 2>&1 || whence mkfifo > /dev/null +then [[ $(cat <(print hello) ) == hello ]] || err_exit "process substitution not working outside for or while loop" + $SHELL -c '[[ $(for i in 1;do cat <(print hello);done ) == hello ]]' 2> /dev/null|| err_exit "process substitution not working in for or while loop" +fi +exec 3> /dev/null +print 'print foo "$@"' > $tmp/scriptx +[[ $( print "($tmp/scriptx bar)" | $SHELL 2>/dev/null) == 'foo bar' ]] || err_exit 'script pipe to shell fails' +print "#! $SHELL" > $tmp/scriptx +print 'print -- $0' >> $tmp/scriptx +chmod +x $tmp/scriptx +[[ $($tmp/scriptx) == $tmp/scriptx ]] || err_exit "\$0 is $0 instead of $tmp/scriptx" +cat > $tmp/scriptx <<- \EOF + myfilter() { x=$(print ok | cat); print -r -- $SECONDS;} + set -o pipefail + sleep 3 | myfilter +EOF +(( $($SHELL $tmp/scriptx) > 2.0 )) && err_exit 'command substitution causes pipefail option to hang' +exec 3<&- +( typeset -r foo=bar) 2> /dev/null || err_exit 'readonly variables set in a subshell cannot unset' +$SHELL -c 'x=${ print hello;}; [[ $x == hello ]]' 2> /dev/null || err_exit '${ command;} not supported' +$SHELL 2> /dev/null <<- \EOF || err_exit 'multiline ${...} command substitution not supported' + x=${ + print hello + } + [[ $x == hello ]] +EOF +$SHELL 2> /dev/null <<- \EOF || err_exit '${...} command substitution with side effects not supported ' + y=bye + x=${ + y=hello + print hello + } + [[ $y == $x ]] +EOF +$SHELL 2> /dev/null <<- \EOF || err_exit 'nested ${...} command substitution not supported' + x=${ + print ${ print hello;} $(print world) + } + [[ $x == 'hello world' ]] +EOF +$SHELL 2> /dev/null <<- \EOF || err_exit 'terminating } is not a reserved word with ${ command }' + x=${ { print -n } ; print -n hello ; } ; print ' world' } + [[ $x == '}hello world' ]] +EOF +$SHELL 2> /dev/null <<- \EOF || err_exit '${ command;}xxx not working' + f() + { + print foo + } + [[ ${ f;}bar == foobar ]] +EOF + +unset foo +[[ ! ${foo[@]} ]] || err_exit '${foo[@]} is not empty when foo is unset' +[[ ! ${foo[3]} ]] || err_exit '${foo[3]} is not empty when foo is unset' +[[ $(print "[${ print foo }]") == '[foo]' ]] || err_exit '${...} not working when } is followed by ]' +[[ $(print "${ print "[${ print foo }]" }") == '[foo]' ]] || err_exit 'nested ${...} not working when } is followed by ]' +unset foo +foo=$(false) > /dev/null && err_exit 'failed command substitution with redirection not returning false' +expected=foreback +got=$(print -n fore; (sleep 2;print back)&) +[[ $got == $expected ]] || err_exit "command substitution background process output error -- got '$got', expected '$expected'" + +binfalse=$(whence -p false) +for false in false $binfalse +do x=$($false) && err_exit "x=\$($false) should fail" + $($false) && err_exit "\$($false) should fail" + $($false) > /dev/null && err_exit "\$($false) > /dev/null should fail" +done +if env x-a=y >/dev/null 2>&1 +then [[ $(env 'x-a=y' $SHELL -c 'env | grep x-a') == *x-a=y* ]] || err_exit 'invalid environment variables not preserved' +fi +float s=SECONDS +sleep=$(whence -p sleep) +for i in 1 2 +do print $i +done | while read sec; do ( $sleep $sec; $sleep $sec) done +(( (SECONDS-s) < 4)) && err_exit '"command | while read...done" finishing too fast' +s=SECONDS +set -o pipefail +for ((i=0; i < 30; i++)) +do print hello + sleep .1 +done | $sleep 1 +(( (SECONDS-s) < 2 )) || err_exit 'early termination not causing broken pipe' +[[ $({ trap 'print trap' 0; print -n | $(whence -p cat); } & wait $!) == trap ]] || err_exit 'trap on exit not getting triggered' +var=$({ trap 'print trap' ERR; print -n | $binfalse; } & wait $!) +[[ $var == trap ]] || err_exit 'trap on ERR not getting triggered' + +exp= +got=$( + function fun + { + $binfalse && echo FAILED + } + : works if this line deleted : | + fun + : works if this line deleted : +) +[[ $got == $exp ]] || err_exit "pipe to function with conditional fails -- expected '$exp', got '$got'" +got=$( + : works if this line deleted : | + { $binfalse && echo FAILED; } + : works if this line deleted : +) +[[ $got == $exp ]] || err_exit "pipe to { ... } with conditional fails -- expected '$exp', got '$got'" + +got=$( + : works if this line deleted : | + ( $binfalse && echo FAILED ) + : works if this line deleted : +) +[[ $got == $exp ]] || err_exit "pipe to ( ... ) with conditional fails -- expected '$exp', got '$got'" + +( $SHELL -c 'trap : DEBUG; x=( $foo); exit 0') 2> /dev/null || err_exit 'trap DEBUG fails' + +bintrue=$(whence -p true) +set -o pipefail +float start=$SECONDS end +for ((i=0; i < 2; i++)) +do print foo + sleep 1.5 +done | { read; $bintrue; end=$SECONDS ;} +(( (SECONDS-start) < 1 )) && err_exit "pipefail not waiting for pipe to finish" +set +o pipefail +(( (SECONDS-end) > 2 )) && err_exit "pipefail causing $bintrue to wait for other end of pipe" + + +{ env A__z=C+SHLVL $SHELL -c : ;} 2> /dev/null || err_exit "SHLVL with wrong attribute fails" + +if [[ $bintrue ]] +then float t0=SECONDS + { time sleep 1.5 | $bintrue ;} 2> /dev/null + (( (SECONDS-t0) < 1 )) && err_exit 'time not waiting for pipeline to complete' +fi + +cat > $tmp/foo.sh <<- \EOF + eval "cat > /dev/null < /dev/null" + sleep 1 +EOF +float sec=SECONDS +. $tmp/foo.sh | cat > /dev/null +(( (SECONDS-sec) < .7 )) && err_exit '. script does not restore output redirection with eval' + +file=$tmp/foobar +builtin cat +for ((n=0; n < 1000; n++)) +do + > $file + { sleep .001;echo $? >$file;} | cat > /dev/null + if [[ ! -s $file ]] + then err_exit 'output from pipe is lost with pipe to builtin' + break; + fi +done + +$SHELL -c 'kill -0 123456789123456789123456789' 2> /dev/null && err_exit 'kill not catching process id overflows' + +[[ $($SHELL -c '{ cd..; print ok;}' 2> /dev/null) == ok ]] || err_exit 'command name ending in .. causes shell to abort' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/bracket.sh b/src/cmd/ksh93/tests/bracket.sh new file mode 100755 index 0000000..cfe4055 --- /dev/null +++ b/src/cmd/ksh93/tests/bracket.sh @@ -0,0 +1,340 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +null='' +if [[ ! -z $null ]] +then err_exit "-z: null string should be of zero length" +fi +file=$tmp/original +newer_file=$tmp/newer +if [[ -z $file ]] +then err_exit "-z: $file string should not be of zero length" +fi +if [[ -a $file ]] +then err_exit "-a: $file shouldn't exist" +fi +if [[ -e $file ]] +then err_exit "-e: $file shouldn't exist" +fi +> $file +if [[ ! -a $file ]] +then err_exit "-a: $file should exist" +fi +if [[ ! -e $file ]] +then err_exit "-e: $file should exist" +fi +chmod 777 $file +if [[ ! -r $file ]] +then err_exit "-r: $file should be readable" +fi +if [[ ! -w $file ]] +then err_exit "-w: $file should be writable" +fi +if [[ ! -w $file ]] +then err_exit "-x: $file should be executable" +fi +if [[ ! -w $file || ! -r $file ]] +then err_exit "-rw: $file should be readable/writable" +fi +if [[ -s $file ]] +then err_exit "-s: $file should be of zero size" +fi +if [[ ! -f $file ]] +then err_exit "-f: $file should be an ordinary file" +fi +if [[ -d $file ]] +then err_exit "-f: $file should not be a directory file" +fi +if [[ ! -d . ]] +then err_exit "-d: . should not be a directory file" +fi +if [[ -f /dev/null ]] +then err_exit "-f: /dev/null should not be an ordinary file" +fi +chmod 000 $file +if [[ -r $file ]] +then err_exit "-r: $file should not be readable" +fi +if [[ ! -O $file ]] +then err_exit "-r: $file should be owned by me" +fi +if [[ -w $file ]] +then err_exit "-w: $file should not be writable" +fi +if [[ -w $file ]] +then err_exit "-x: $file should not be executable" +fi +if [[ -w $file || -r $file ]] +then err_exit "-rw: $file should not be readable/writable" +fi +if [[ -z x && -z x || ! -z x ]] +then : +else err_exit " wrong precedence" +fi +if [[ -z x && (-z x || ! -z x) ]] +then err_exit " () grouping not working" +fi +if [[ foo < bar ]] +then err_exit "foo comes before bar" +fi +[[ . -ef $(pwd) ]] || err_exit ". is not $PWD" +set -o allexport +[[ -o allexport ]] || err_exit '-o: did not set allexport option' +if [[ -n $null ]] +then err_exit "'$null' has non-zero length" +fi +if [[ ! -r /dev/fd/0 ]] +then err_exit "/dev/fd/0 not open for reading" +fi +if [[ ! -w /dev/fd/2 ]] +then err_exit "/dev/fd/2 not open for writing" +fi +sleep 1 +> $newer_file +if [[ ! $file -ot $newer_file ]] +then err_exit "$file should be older than $newer_file" +fi +if [[ $file -nt $newer_file ]] +then err_exit "$newer_file should be newer than $file" +fi +if [[ $file != $tmp/* ]] +then err_exit "$file should match $tmp/*" +fi +if [[ $file == $tmp'/*' ]] +then err_exit "$file should not equal $tmp'/*'" +fi +[[ ! ( ! -z $null && ! -z x) ]] || err_exit "negation and grouping" +[[ -z '' || -z '' || -z '' ]] || err_exit "three ors not working" +[[ -z '' && -z '' && -z '' ]] || err_exit "three ors not working" +(exit 8) +if [[ $? -ne 8 || $? -ne 8 ]] +then err_exit 'value $? within [[...]]' +fi +x='(x' +if [[ '(x' != '('* ]] +then err_exit " '(x' does not match '('* within [[...]]" +fi +if [[ '(x' != "("* ]] +then err_exit ' "(x" does not match "("* within [[...]]' +fi +if [[ '(x' != \(* ]] +then err_exit ' "(x" does not match \(* within [[...]]' +fi +if [[ 'x(' != *'(' ]] +then err_exit " 'x(' does not match '('* within [[...]]" +fi +if [[ 'x&' != *'&' ]] +then err_exit " 'x&' does not match '&'* within [[...]]" +fi +if [[ 'xy' == *'*' ]] +then err_exit " 'xy' matches *'*' within [[...]]" +fi +if [[ 3 > 4 ]] +then err_exit '3 < 4' +fi +if [[ 4 < 3 ]] +then err_exit '3 > 4' +fi +if [[ 3x > 4x ]] +then err_exit '3x < 4x' +fi +x='@(bin|dev|?)' +cd / +if [[ $(print $x) != "$x" ]] +then err_exit 'extended pattern matching on command arguments' +fi +if [[ dev != $x ]] +then err_exit 'extended pattern matching not working on variables' +fi +if [[ -u $SHELL ]] +then err_exit "setuid on $SHELL" +fi +if [[ -g $SHELL ]] +then err_exit "setgid on $SHELL" +fi +test -d . -a '(' ! -f . ')' || err_exit 'test not working' +if [[ '!' != ! ]] +then err_exit 'quoting unary operator not working' +fi +test \( -n x \) -o \( -n y \) 2> /dev/null || err_exit 'test ( -n x ) -o ( -n y) not working' +test \( -n x \) -o -n y 2> /dev/null || err_exit 'test ( -n x ) -o -n y not working' +chmod 600 $file +exec 4> $file +print -u4 foobar +if [[ ! -s $file ]] +then err_exit "-s: $file should be non-zero" +fi +exec 4>&- +if [[ 011 -ne 11 ]] +then err_exit "leading zeros in arithmetic compares not ignored" +fi +{ + set -x + [[ foo > bar ]] +} 2> /dev/null || { set +x; err_exit "foo<bar with -x enabled" ;} +set +x +( + eval "[[ (a) ]]" +) 2> /dev/null || err_exit "[[ (a) ]] not working" +> $file +chmod 4755 "$file" +if test -u $file && test ! -u $file +then err_exit "test ! -u suidfile not working" +fi +for i in '(' ')' '[' ']' +do [[ $i == $i ]] || err_exit "[[ $i != $i ]]" +done +( + [[ aaaa == {4}(a) ]] || err_exit 'aaaa != {4}(a)' + [[ aaaa == {2,5}(a) ]] || err_exit 'aaaa != {2,4}(a)' + [[ abcdcdabcd == {3,6}(ab|cd) ]] || err_exit 'abcdcdabcd == {3,4}(ab|cd)' + [[ abcdcdabcde == {5}(ab|cd)e ]] || err_exit 'abcdcdabcd == {5}(ab|cd)e' +) || err_exit 'errors with {..}(...) patterns' +[[ D290.2003.02.16.temp == D290.+(2003.02.16).temp* ]] || err_exit 'pattern match bug with +(...)' +rm -rf $file +{ +[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after creat' +sleep 2 +print 'hello world' +[[ -N $file ]] || err_exit 'test -N $tmp/*: st_mtime<=st_atime after write' +sleep 2 +read +[[ -N $file ]] && err_exit 'test -N $tmp/*: st_mtime>st_atime after read' +} > $file < $file +if rm -rf "$file" && ln -s / "$file" +then [[ -L "$file" ]] || err_exit '-L not working' + [[ -L "$file"/ ]] && err_exit '-L with file/ not working' +fi +$SHELL -c 't=1234567890; [[ $t == @({10}(\d)) ]]' 2> /dev/null || err_exit ' @({10}(\d)) pattern not working' +$SHELL -c '[[ att_ == ~(E)(att|cus)_.* ]]' 2> /dev/null || err_exit ' ~(E)(att|cus)_* pattern not working' +$SHELL -c '[[ att_ =~ (att|cus)_.* ]]' 2> /dev/null || err_exit ' =~ ere not working' +$SHELL -c '[[ abc =~ a(b)c ]]' 2> /dev/null || err_exit '[[ abc =~ a(b)c ]] fails' +$SHELL -xc '[[ abc =~ \babc\b ]]' 2> /dev/null || err_exit '[[ abc =~ \babc\b ]] fails' +[[ abc == ~(E)\babc\b ]] || err_exit '\b not preserved for ere when not in ()' +[[ abc == ~(iEi)\babc\b ]] || err_exit '\b not preserved for ~(iEi) when not in ()' + +e=$($SHELL -c '[ -z "" -a -z "" ]' 2>&1) +[[ $e ]] && err_exit "[ ... ] compatibility check failed -- $e" +i=hell +[[ hell0 == $i[0] ]] || err_exit 'pattern $i[0] interpreded as array ref' +test '(' = ')' && err_exit '"test ( = )" should not be true' +[[ $($SHELL -c 'case F in ~(Eilr)[a-z0-9#]) print ok;;esac' 2> /dev/null) == ok ]] || err_exit '~(Eilr) not working in case command' +[[ $($SHELL -c "case Q in ~(Fi)q | \$'\E') print ok;;esac" 2> /dev/null) == ok ]] || err_exit '~(Fi)q | \E not working in case command' + +for l in C en_US.ISO8859-15 +do [[ $($SHELL -c "LC_COLLATE=$l" 2>&1) ]] && continue + export LC_COLLATE=$l + set -- \ + 'A' 0 1 1 0 1 1 1 0 0 1 0 0 \ + 'Z' 0 1 1 0 1 1 1 0 0 1 0 0 \ + '/' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '.' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '_' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '-' 1 1 1 1 1 1 0 0 0 0 0 0 \ + '%' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '@' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '!' 0 0 0 0 0 0 1 1 1 1 1 1 \ + '^' 0 0 0 0 0 0 1 1 1 1 1 1 \ + # retain this line # + while (( $# >= 13 )) + do c=$1 + shift + for p in \ + '[![.-.]]' \ + '[![.-.][:upper:]]' \ + '[![.-.]A-Z]' \ + '[!-]' \ + '[!-[:upper:]]' \ + '[!-A-Z]' \ + '[[.-.]]' \ + '[[.-.][:upper:]]' \ + '[[.-.]A-Z]' \ + '[-]' \ + '[-[:upper:]]' \ + '[-A-Z]' \ + # retain this line # + do e=$1 + shift + [[ $c == $p ]] + g=$? + [[ $g == $e ]] || err_exit "[[ '$c' == $p ]] for LC_COLLATE=$l failed -- expected $e, got $g" + done + done +done +integer n +if ( : < /dev/tty ) 2>/dev/null && exec {n}< /dev/tty +then [[ -t $n ]] || err_exit "[[ -t n ]] fails when n > 9" +fi +foo=([1]=a [2]=b [3]=c) +[[ -v foo[1] ]] || err_exit 'foo[1] should be set' +[[ ${foo[1]+x} ]] || err_exit '${foo[1]+x} should be x' +[[ ${foo[@]+x} ]] || err_exit '${foo[@]+x} should be x' +unset foo[1] +[[ -v foo[1] ]] && err_exit 'foo[1] should not be set' +[[ ${foo[1]+x} ]] && err_exit '${foo[1]+x} should be empty' +bar=(a b c) +[[ -v bar[1] ]] || err_exit 'bar[1] should be set' +[[ ${bar[1]+x} ]] || err_exit '${foo[1]+x} should be x' +unset bar[1] +[[ ${bar[1]+x} ]] && err_exit '${foo[1]+x} should be empty' +[[ -v bar ]] || err_exit 'bar should be set' +[[ -v bar[1] ]] && err_exit 'bar[1] should not be set' +integer z=( 1 2 4) +[[ -v z[1] ]] || err_exit 'z[1] should be set' +unset z[1] +[[ -v z[1] ]] && err_exit 'z[1] should not be set' +typeset -si y=( 1 2 4) +[[ -v y[6] ]] && err_exit 'y[6] should not be set' +[[ -v y[1] ]] || err_exit 'y[1] should be set' +unset y[1] +[[ -v y[1] ]] && err_exit 'y[1] should not be set' +x=abc +[[ -v x[0] ]] || err_exit 'x[0] should be set' +[[ ${x[0]+x} ]] || err_exit print '${x[0]+x} should be x' +[[ -v x[3] ]] && err_exit 'x[3] should not be set' +[[ ${x[3]+x} ]] && err_exit '${x[0]+x} should be Empty' +unset x +[[ ${x[@]+x} ]] && err_exit '${x[@]+x} should be Empty' +unset x y z foo bar + +{ x=$($SHELL -c '[[ (( $# -eq 0 )) ]] && print ok') 2> /dev/null;} +[[ $x == ok ]] || err_exit '((...)) inside [[...]] not treated as nested ()' + +[[ -e /dev/fd/ ]] || err_exit '/dev/fd/ does not exits' +[[ -e /dev/tcp/ ]] || err_exit '/dev/tcp/ does not exist' +[[ -e /dev/udp/ ]] || err_exit '/dev/udp/ does not exist' +[[ -e /dev/xxx/ ]] && err_exit '/dev/xxx/ exists' + +$SHELL 2> /dev/null -c '[[(-n foo)]]' || err_exit '[[(-n foo)]] should not require space in front of (' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/builtins.sh b/src/cmd/ksh93/tests/builtins.sh new file mode 100755 index 0000000..6346aff --- /dev/null +++ b/src/cmd/ksh93/tests/builtins.sh @@ -0,0 +1,562 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +# test shell builtin commands +builtin getconf +: ${foo=bar} || err_exit ": failed" +[[ $foo == bar ]] || err_exit ": side effects failed" +set -- - foobar +[[ $# == 2 && $1 == - && $2 == foobar ]] || err_exit "set -- - foobar failed" +set -- -x foobar +[[ $# == 2 && $1 == -x && $2 == foobar ]] || err_exit "set -- -x foobar failed" +getopts :x: foo || err_exit "getopts :x: returns false" +[[ $foo == x && $OPTARG == foobar ]] || err_exit "getopts :x: failed" +OPTIND=1 +getopts :r:s var -r +if [[ $var != : || $OPTARG != r ]] +then err_exit "'getopts :r:s var -r' not working" +fi +OPTIND=1 +getopts :d#u OPT -d 16177 +if [[ $OPT != d || $OPTARG != 16177 ]] +then err_exit "'getopts :d#u OPT=d OPTARG=16177' failed -- OPT=$OPT OPTARG=$OPTARG" +fi +OPTIND=1 +while getopts 'ab' option -a -b +do [[ $OPTIND == $((OPTIND)) ]] || err_exit "OPTIND optimization bug" +done + +USAGE=$'[-][S:server?Operate on the specified \asubservice\a:]:[subservice:=pmserver] + { + [p:pmserver] + [r:repserver] + [11:notifyd] + }' +set pmser p rep r notifyd -11 +while (( $# > 1 )) +do OPTIND=1 + getopts "$USAGE" OPT -S $1 + [[ $OPT == S && $OPTARG == $2 ]] || err_exit "OPT=$OPT OPTARG=$OPTARG -- expected OPT=S OPTARG=$2" + shift 2 +done + +false ${foo=bar} && err_exit "false failed" +read <<! +hello world +! +[[ $REPLY == 'hello world' ]] || err_exit "read builtin failed" +print x:y | IFS=: read a b +if [[ $a != x ]] +then err_exit "IFS=: read ... not working" +fi +read <<! +hello \ +world +! +[[ $REPLY == 'hello world' ]] || err_exit "read continuation failed" +read -d x <<! +hello worldxfoobar +! +[[ $REPLY == 'hello world' ]] || err_exit "read builtin failed" +read <<\! +hello \ + world \ + +! +[[ $REPLY == 'hello world' ]] || err_exit "read continuation2 failed" +print "one\ntwo" | { read line + print $line | /bin/cat > /dev/null + read line +} +read <<\! +\ +a\ +\ +\ +b +! +if [[ $REPLY != ab ]] +then err_exit "read multiple continuation failed" +fi +if [[ $line != two ]] +then err_exit "read from pipeline failed" +fi +line=two +read line < /dev/null +if [[ $line != "" ]] +then err_exit "read from /dev/null failed" +fi +if [[ $(print -R -) != - ]] +then err_exit "print -R not working correctly" +fi +if [[ $(print -- -) != - ]] +then err_exit "print -- not working correctly" +fi +print -f "hello%nbar\n" size > /dev/null +if (( size != 5 )) +then err_exit "%n format of printf not working" +fi +print -n -u2 2>&1- +[[ -w /dev/fd/1 ]] || err_exit "2<&1- with built-ins has side effects" +x=$0 +if [[ $(eval 'print $0') != $x ]] +then err_exit '$0 not correct for eval' +fi +$SHELL -c 'read x <<< hello' 2> /dev/null || err_exit 'syntax <<< not recognized' +($SHELL -c 'read x[1] <<< hello') 2> /dev/null || err_exit 'read x[1] not working' +unset x +readonly x +set -- $(readonly) +if [[ " $@ " != *" x "* ]] +then err_exit 'unset readonly variables are not displayed' +fi +if [[ $( for i in foo bar + do print $i + continue 10 + done + ) != $'foo\nbar' ]] +then err_exit 'continue breaks out of loop' +fi +(continue bad 2>/dev/null && err_exit 'continue bad should return an error') +(break bad 2>/dev/null && err_exit 'break bad should return an error') +(continue 0 2>/dev/null && err_exit 'continue 0 should return an error') +(break 0 2>/dev/null && err_exit 'break 0 should return an error') +breakfun() { break;} +continuefun() { continue;} +for fun in break continue +do if [[ $( for i in foo + do ${fun}fun + print $i + done + ) != foo ]] + then err_exit "$fun call in ${fun}fun breaks out of for loop" + fi +done +if [[ $(print -f "%b" "\a\n\v\b\r\f\E\03\\oo") != $'\a\n\v\b\r\f\E\03\\oo' ]] +then err_exit 'print -f "%b" not working' +fi +if [[ $(print -f "%P" "[^x].*b\$") != '*[!x]*b' ]] +then err_exit 'print -f "%P" not working' +fi +if [[ $(abc: for i in foo bar;do print $i;break abc;done) != foo ]] +then err_exit 'break labels not working' +fi +if [[ $(command -v if) != if ]] +then err_exit 'command -v not working' +fi +read -r var <<\! + +! +if [[ $var != "" ]] +then err_exit "read -r of blank line not working" +fi +mkdir -p $tmp/a/b/c 2>/dev/null || err_exit "mkdir -p failed" +$SHELL -c "cd $tmp/a/b; cd c" 2>/dev/null || err_exit "initial script relative cd fails" + +trap 'print TERM' TERM +exp=$'trap -- \'print TERM\' TERM\ntrap -- \'cd /; rm -rf '$tmp$'\' EXIT' +got=$(trap) +[[ $got == $exp ]] || err_exit "\$(trap) failed -- expected \"$exp\", got \"$got\"" +exp='print TERM' +got=$(trap -p TERM) +[[ $got == $exp ]] || err_exit "\$(trap -p TERM) failed -- expected \"$exp\", got \"$got\"" + +[[ $($SHELL -c 'trap "print ok" SIGTERM; kill -s SIGTERM $$' 2> /dev/null) == ok ]] || err_exit 'SIGTERM not recognized' +[[ $($SHELL -c 'trap "print ok" sigterm; kill -s sigterm $$' 2> /dev/null) == ok ]] || err_exit 'SIGTERM not recognized' +[[ $($SHELL -c '( trap "" TERM);kill $$;print bad' == bad) ]] 2> /dev/null && err_exit 'trap ignored in subshell causes it to be ignored by parent' +${SHELL} -c 'kill -1 -$$' 2> /dev/null +[[ $(kill -l $?) == HUP ]] || err_exit 'kill -1 -pid not working' +${SHELL} -c 'kill -1 -$$' 2> /dev/null +[[ $(kill -l $?) == HUP ]] || err_exit 'kill -n1 -pid not working' +${SHELL} -c 'kill -s HUP -$$' 2> /dev/null +[[ $(kill -l $?) == HUP ]] || err_exit 'kill -HUP -pid not working' +n=123 +typeset -A base +base[o]=8# +base[x]=16# +base[X]=16# +for i in d i o u x X +do if (( $(( ${base[$i]}$(printf "%$i" $n) )) != n )) + then err_exit "printf %$i not working" + fi +done +if [[ $( trap 'print done' EXIT) != done ]] +then err_exit 'trap on EXIT not working' +fi +if [[ $( trap 'print done' EXIT; trap - EXIT) == done ]] +then err_exit 'trap on EXIT not being cleared' +fi +if [[ $(LC_MESSAGES=C type test) != 'test is a shell builtin' ]] +then err_exit 'whence -v test not a builtin' +fi +builtin -d test +if [[ $(type test) == *builtin* ]] +then err_exit 'whence -v test after builtin -d incorrect' +fi +typeset -Z3 percent=$(printf '%o\n' "'%'") +forrmat=\\${percent}s +if [[ $(printf "$forrmat") != %s ]] +then err_exit "printf $forrmat not working" +fi +if (( $(printf 'x\0y' | wc -c) != 3 )) +then err_exit 'printf \0 not working' +fi +if [[ $(printf "%bx%s\n" 'f\to\cbar') != $'f\to' ]] +then err_exit 'printf %bx%s\n not working' +fi +alpha=abcdefghijklmnop +if [[ $(printf "%10.*s\n" 5 $alpha) != ' abcde' ]] +then err_exit 'printf %10.%s\n not working' +fi +float x2=.0000625 +if [[ $(printf "%10.5E\n" x2) != 6.25000E-05 ]] +then err_exit 'printf "%10.5E" not normalizing correctly' +fi +x2=.000000001 +if [[ $(printf "%g\n" x2 2>/dev/null) != 1e-09 ]] +then err_exit 'printf "%g" not working correctly' +fi +#FIXME#($SHELL read -s foobar <<\! +#FIXME#testing +#FIXME#! +#FIXME#) 2> /dev/null || err_exit ksh read -s var fails +if [[ $(printf +3 2>/dev/null) != +3 ]] +then err_exit 'printf is not processing formats beginning with + correctly' +fi +if printf "%d %d\n" 123bad 78 >/dev/null 2>/dev/null +then err_exit "printf not exiting non-zero with conversion errors" +fi +if [[ $(trap --version 2> /dev/null;print done) != done ]] +then err_exit 'trap builtin terminating after --version' +fi +if [[ $(set --version 2> /dev/null;print done) != done ]] +then err_exit 'set builtin terminating after --veresion' +fi +unset -f foobar +function foobar +{ + print 'hello world' +} +OPTIND=1 +if [[ $(getopts $'[+?X\ffoobar\fX]' v --man 2>&1) != *'Xhello world'X* ]] +then err_exit '\f...\f not working in getopts usage strings' +fi +if [[ $(printf '%H\n' $'<>"& \'\tabc') != '<>"& '	abc' ]] +then err_exit 'printf %H not working' +fi +if [[ $( printf 'foo://ab_c%#H\n' $'<>"& \'\tabc') != 'foo://ab_c%3C%3E%22%26%20%27%09abc' ]] +then err_exit 'printf %#H not working' +fi +if [[ $(printf '%R %R %R %R\n' 'a.b' '*.c' '^' '!(*.*)') != '^a\.b$ \.c$ ^\^$ ^(.*\..*)!$' ]] +then err_exit 'printf %R not working' +fi +if [[ $(printf '%..:c\n' abc) != a:b:c ]] +then err_exit "printf '%..:c' not working" +fi +if [[ $(printf '%..*c\n' : abc) != a:b:c ]] +then err_exit "printf '%..*c' not working" +fi +if [[ $(printf '%..:s\n' abc def ) != abc:def ]] +then err_exit "printf '%..:s' not working" +fi +if [[ $(printf '%..*s\n' : abc def) != abc:def ]] +then err_exit "printf '%..*s' not working" +fi +[[ $(printf '%q\n') == '' ]] || err_exit 'printf "%q" with missing arguments' +# we won't get hit by the one second boundary twice, right? +[[ $(printf '%T\n' now) == "$(date)" ]] || +[[ $(printf '%T\n' now) == "$(date)" ]] || +err_exit 'printf "%T" now' +behead() +{ + read line + left=$(cat) +} +print $'line1\nline2' | behead +if [[ $left != line2 ]] +then err_exit "read reading ahead on a pipe" +fi +read -n1 y <<! +abc +! +exp=a +if [[ $y != $exp ]] +then err_exit "read -n1 failed -- expected '$exp', got '$y'" +fi +print -n $'{ read -r line;print $line;}\nhello' > $tmp/script +chmod 755 $tmp/script +if [[ $($SHELL < $tmp/script) != hello ]] +then err_exit 'read of incomplete line not working correctly' +fi +set -f +set -- * +if [[ $1 != '*' ]] +then err_exit 'set -f not working' +fi +unset pid1 pid2 +false & +pid1=$! +pid2=$( + wait $pid1 + (( $? == 127 )) || err_exit "job known to subshell" + print $! +) +wait $pid1 +(( $? == 1 )) || err_exit "wait not saving exit value" +wait $pid2 +(( $? == 127 )) || err_exit "subshell job known to parent" +env= +v=$(getconf LIBPATH) +for v in ${v//,/ } +do v=${v#*:} + v=${v%%:*} + eval [[ \$$v ]] && env="$env $v=\"\$$v\"" +done +if [[ $(foo=bar; eval foo=\$foo $env exec -c \$SHELL -c \'print \$foo\') != bar ]] +then err_exit '"name=value exec -c ..." not working' +fi +$SHELL -c 'OPTIND=-1000000; getopts a opt -a' 2> /dev/null +[[ $? == 1 ]] || err_exit 'getopts with negative OPTIND not working' +getopts 'n#num' opt -n 3 +[[ $OPTARG == 3 ]] || err_exit 'getopts with numerical arguments failed' +if [[ $($SHELL -c $'printf \'%2$s %1$s\n\' world hello') != 'hello world' ]] +then err_exit 'printf %2$s %1$s not working' +fi +val=$(( 'C' )) +set -- \ + "'C" $val 0 \ + "'C'" $val 0 \ + '"C' $val 0 \ + '"C"' $val 0 \ + "'CX" $val 1 \ + "'CX'" $val 1 \ + "'C'X" $val 1 \ + '"CX' $val 1 \ + '"CX"' $val 1 \ + '"C"X' $val 1 +while (( $# >= 3 )) +do arg=$1 val=$2 code=$3 + shift 3 + for fmt in '%d' '%g' + do out=$(printf "$fmt" "$arg" 2>/dev/null) + err=$(printf "$fmt" "$arg" 2>&1 >/dev/null) + printf "$fmt" "$arg" >/dev/null 2>&1 + ret=$? + [[ $out == $val ]] || err_exit "printf $fmt $arg failed -- expected '$val', got '$out'" + if (( $code )) + then [[ $err ]] || err_exit "printf $fmt $arg failed, error message expected" + else [[ $err ]] && err_exit "$err: printf $fmt $arg failed, error message not expected -- got '$err'" + fi + (( $ret == $code )) || err_exit "printf $fmt $arg failed -- expected exit code $code, got $ret" + done +done +((n=0)) +((n++)); ARGC[$n]=1 ARGV[$n]="" +((n++)); ARGC[$n]=2 ARGV[$n]="-a" +((n++)); ARGC[$n]=4 ARGV[$n]="-a -v 2" +((n++)); ARGC[$n]=4 ARGV[$n]="-a -v 2 x" +((n++)); ARGC[$n]=4 ARGV[$n]="-a -v 2 x y" +for ((i=1; i<=n; i++)) +do set -- ${ARGV[$i]} + OPTIND=0 + while getopts -a tst "av:" OPT + do : + done + if [[ $OPTIND != ${ARGC[$i]} ]] + then err_exit "\$OPTIND after getopts loop incorrect -- expected ${ARGC[$i]}, got $OPTIND" + fi +done +options=ab:c +optarg=foo +set -- -a -b $optarg -c bar +while getopts $options opt +do case $opt in + a|c) [[ $OPTARG ]] && err_exit "getopts $options \$OPTARG for flag $opt failed, expected \"\", got \"$OPTARG\"" ;; + b) [[ $OPTARG == $optarg ]] || err_exit "getopts $options \$OPTARG failed -- \"$optarg\" expected, got \"$OPTARG\"" ;; + *) err_exit "getopts $options failed -- got flag $opt" ;; + esac +done + +[[ $($SHELL 2> /dev/null -c 'readonly foo; getopts a: foo -a blah; echo foo') == foo ]] || err_exit 'getopts with readonly variable causes script to abort' + +unset a +{ read -N3 a; read -N1 b;} <<! +abcdefg +! +exp=abc +[[ $a == $exp ]] || err_exit "read -N3 here-document failed -- expected '$exp', got '$a'" +exp=d +[[ $b == $exp ]] || err_exit "read -N1 here-document failed -- expected '$exp', got '$b'" +read -n3 a <<! +abcdefg +! +exp=abc +[[ $a == $exp ]] || err_exit "read -n3 here-document failed -- expected '$exp', got '$a'" +#(print -n a;sleep 1; print -n bcde) | { read -N3 a; read -N1 b;} +#[[ $a == $exp ]] || err_exit "read -N3 from pipe failed -- expected '$exp', got '$a'" +#exp=d +#[[ $b == $exp ]] || err_exit "read -N1 from pipe failed -- expected '$exp', got '$b'" +#(print -n a;sleep 1; print -n bcde) | read -n3 a +#exp=a +#[[ $a == $exp ]] || err_exit "read -n3 from pipe failed -- expected '$exp', got '$a'" +#rm -f $tmp/fifo +#if mkfifo $tmp/fifo 2> /dev/null +#then (print -n a; sleep 1;print -n bcde) > $tmp/fifo & +# { +# read -u5 -n3 -t2 a || err_exit 'read -n3 from fifo timedout' +# read -u5 -n1 -t2 b || err_exit 'read -n1 from fifo timedout' +# } 5< $tmp/fifo +# exp=a +# [[ $a == $exp ]] || err_exit "read -n3 from fifo failed -- expected '$exp', got '$a'" +# rm -f $tmp/fifo +# mkfifo $tmp/fifo 2> /dev/null +# (print -n a; sleep 1;print -n bcde) > $tmp/fifo & +# { +# read -u5 -N3 -t2 a || err_exit 'read -N3 from fifo timed out' +# read -u5 -N1 -t2 b || err_exit 'read -N1 from fifo timedout' +# } 5< $tmp/fifo +# exp=abc +# [[ $a == $exp ]] || err_exit "read -N3 from fifo failed -- expected '$exp', got '$a'" +# exp=d +# [[ $b == $exp ]] || err_exit "read -N1 from fifo failed -- expected '$exp', got '$b'" +#fi +#rm -f $tmp/fifo + +function longline +{ + integer i + for((i=0; i < $1; i++)) + do print argument$i + done +} +# test command -x option +integer sum=0 n=10000 +if ! ${SHELL:-ksh} -c 'print $#' count $(longline $n) > /dev/null 2>&1 +then for i in $(command command -x ${SHELL:-ksh} -c 'print $#;[[ $1 != argument0 ]]' count $(longline $n) 2> /dev/null) + do ((sum += $i)) + done + (( sum == n )) || err_exit "command -x processed only $sum arguments" + command -p command -x ${SHELL:-ksh} -c 'print $#;[[ $1 == argument0 ]]' count $(longline $n) > /dev/null 2>&1 + [[ $? != 1 ]] && err_exit 'incorrect exit status for command -x' +fi +# test command -x option with extra arguments +integer sum=0 n=10000 +if ! ${SHELL:-ksh} -c 'print $#' count $(longline $n) > /dev/null 2>&1 +then for i in $(command command -x ${SHELL:-ksh} -c 'print $#;[[ $1 != argument0 ]]' count $(longline $n) one two three) #2> /dev/null) + do ((sum += $i)) + done + (( sum > n )) || err_exit "command -x processed only $sum arguments" + (( (sum-n)%3==0 )) || err_exit "command -x processed only $sum arguments" + (( sum == n+3)) && err_exit "command -x processed only $sum arguments" + command -p command -x ${SHELL:-ksh} -c 'print $#;[[ $1 == argument0 ]]' count $(longline $n) > /dev/null 2>&1 + [[ $? != 1 ]] && err_exit 'incorrect exit status for command -x' +fi +# test for debug trap +[[ $(typeset -i i=0 + trap 'print $i' DEBUG + while (( i <2)) + do (( i++)) + done) == $'0\n0\n1\n1\n2' ]] || err_exit "DEBUG trap not working" +getconf UNIVERSE - ucb +[[ $($SHELL -c 'echo -3') == -3 ]] || err_exit "echo -3 not working in ucb universe" +typeset -F3 start_x=SECONDS total_t delay=0.02 +typeset reps=50 leeway=5 +#sleep $(( 2 * leeway * reps * delay )) | +#for (( i=0 ; i < reps ; i++ )) +#do read -N1 -t $delay +#done +#(( total_t = SECONDS - start_x )) +#if (( total_t > leeway * reps * delay )) +#then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too long" +#elif (( total_t < reps * delay )) +#then err_exit "read -t in pipe taking $total_t secs - $(( reps * delay )) minimum - too fast" +#fi +#$SHELL -c 'sleep $(printf "%a" .95)' 2> /dev/null || err_exit "sleep doesn't except %a format constants" +#$SHELL -c 'test \( ! -e \)' 2> /dev/null ; [[ $? == 1 ]] || err_exit 'test \( ! -e \) not working' +[[ $(ulimit) == "$(ulimit -fS)" ]] || err_exit 'ulimit is not the same as ulimit -fS' +tmpfile=$tmp/file.2 +print $'\nprint -r -- "${.sh.file} ${LINENO} ${.sh.lineno}"' > $tmpfile +[[ $( . "$tmpfile") == "$tmpfile 2 1" ]] || err_exit 'dot command not working' +print -r -- "'xxx" > $tmpfile +[[ $($SHELL -c ". $tmpfile"$'\n print ok' 2> /dev/null) == ok ]] || err_exit 'syntax error in dot command affects next command' + +#float sec=$SECONDS del=4 +#exec 3>&2 2>/dev/null +#$SHELL -c "( sleep 1; kill -ALRM \$\$ ) & sleep $del" 2> /dev/null +#exitval=$? +#(( sec = SECONDS - sec )) +#exec 2>&3- +#(( exitval )) && err_exit "sleep doesn't exit 0 with ALRM interupt" +#(( sec > (del - 1) )) || err_exit "ALRM signal causes sleep to terminate prematurely -- expected 3 sec, got $sec" +typeset -r z=3 +y=5 +for i in 123 z %x a.b.c +do ( unset $i) 2>/dev/null && err_exit "unset $i should fail" +done +a=() +for i in y y y[8] t[abc] y.d a.b a +do unset $i || print -u2 "err_exit unset $i should not fail" +done +[[ $($SHELL -c 'y=3; unset 123 y;print $?$y') == 1 ]] 2> /dev/null || err_exit 'y is not getting unset with unset 123 y' +[[ $($SHELL -c 'trap foo TERM; (trap;(trap) )') == 'trap -- foo TERM' ]] || err_exit 'traps not getting reset when subshell is last process' + +n=$(printf "%b" 'a\0b\0c' | wc -c) +(( n == 5 )) || err_exit '\0 not working with %b format with printf' + +t=$(ulimit -t) +[[ $($SHELL -c 'ulimit -v 15000 2>/dev/null; ulimit -t') == "$t" ]] || err_exit 'ulimit -v changes ulimit -t' + +$SHELL 2> /dev/null -c 'cd ""' && err_exit 'cd "" not producing an error' +[[ $($SHELL 2> /dev/null -c 'cd "";print hi') != hi ]] && err_exit 'cd "" should not terminate script' + +bincat=$(whence -p cat) +builtin cat +out=$tmp/seq.out +seq 11 >$out +cmp -s <(print -- "$($bincat<( $bincat $out ) )") <(print -- "$(cat <( cat $out ) )") || err_exit "builtin cat differs from $bincat" + +[[ $($SHELL -c '{ printf %R "["; print ok;}' 2> /dev/null) == ok ]] || err_exit $'\'printf %R "["\' causes shell to abort' + +v=$( $SHELL -c $' + trap \'print "usr1"\' USR1 + trap exit USR2 + sleep 1 && { + kill -USR1 $$ && sleep 1 + kill -0 $$ 2>/dev/null && kill -USR2 $$ + } & + sleep 2 | read + echo done +' ) 2> /dev/null +[[ $v == $'usr1\ndone' ]] || err_exit 'read not terminating when receiving USR1 signal' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/case.sh b/src/cmd/ksh93/tests/case.sh new file mode 100755 index 0000000..7fe01ea --- /dev/null +++ b/src/cmd/ksh93/tests/case.sh @@ -0,0 +1,85 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +bar=foo2 +bam=foo[3] +for i in foo1 foo2 foo3 foo4 foo5 foo6 +do foo=0 + case $i in + foo1) foo=1;; + $bar) foo=2;; + $bam) foo=3;; + foo[4]) foo=4;; + ${bar%?}5) + foo=5;; + "${bar%?}6") + foo=6;; + esac + if [[ $i != foo$foo ]] + then err_exit "$i not matching correct pattern" + fi +done +f="[ksh92]" +case $f in +\[*\]) ;; +*) err_exit "$f does not match \[*\]";; +esac + +if [[ $($SHELL -c ' + x=$(case abc { + abc) { print yes;};; + *) print no;; + } + ) + print -r -- "$x"' 2> /dev/null) != yes ]] +then err_exit 'case abc {...} not working' +fi +[[ $($SHELL -c 'case a in +a) print -n a > /dev/null ;& +b) print b;; +esac') != b ]] && err_exit 'bug in ;& at end of script' +[[ $(VMDEBUG=1 $SHELL -c ' + tmp=foo + for i in a b + do case $i in + a) : tmp=$tmp tmp.h=$tmp.h;; + b) ( tmp=bar ) + for j in a + do print -r -- $tmp.h + done + ;; + esac + done +') == foo.h ]] || err_exit "optimizer bug" + +x=$($SHELL -ec 'case a in a) echo 1; false; echo 2 ;& b) echo 3;; esac') +[[ $x == 1 ]] || err_exit 'set -e ignored on case fail through' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/comvar.sh b/src/cmd/ksh93/tests/comvar.sh new file mode 100755 index 0000000..e08f972 --- /dev/null +++ b/src/cmd/ksh93/tests/comvar.sh @@ -0,0 +1,689 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +#test for compound variables +Command=${0##*/} +integer Errors=0 +Point=( + float x=1. y=0. +) +eval p="$Point" +if (( (p.x*p.x + p.y*p.y) > 1.01 )) +then err_exit 'compound variable not working' +fi +nameref foo=p +if [[ ${foo.x} != ${Point.x} ]] +then err_exit 'reference to compound object not working' +fi +unset foo +rec=( + name='Joe Blow' + born=( + month=jan + integer day=16 + year=1980 + ) +) +eval newrec="$rec" +if [[ ${newrec.name} != "${rec.name}" ]] +then err_exit 'copying a compound object not working' +fi +if (( newrec.born.day != 16 )) +then err_exit 'copying integer field of compound object not working' +fi +p_t=( + integer z=0 + typeset -A tokens +) +unset x +typeset -A x +x=( [foo]=bar ) +if [[ ${x[@]} != bar ]] +then err_exit 'compound assignemnt of associative arrays not working' +fi +unset -n foo x +unset foo x +foo=( x=3) +nameref x=foo +if [[ ${!x.@} != foo.x ]] +then err_exit 'name references not expanded on prefix matching' +fi +unset x +unset -n x +( + x=() + x.foo.bar=7 + [[ ${x.foo.bar} == 7 ]] || err_exit '[[ ${x.foo.bar} != 7 ]]' + (( x.foo.bar == 7 ))|| err_exit '(( x.foo.bar != 7 ))' + [[ ${x.foo} == *bar=7* ]] || err_exit '[[ ${x.foo} != *bar=7* ]]' +) +foo=(integer x=3) +if [[ ${foo} != *x=3* ]] +then err_exit "compound variable with integer subvariable not working" +fi +$SHELL -c $'x=(foo=bar)\n[[ x == x ]]' 2> /dev/null || + err_exit '[[ ... ]] not working after compound assignment' +unset foo +[[ ${!foo.@} ]] && err_exit 'unset compound variable leaves subvariables' +suitable=( + label="Table Viewer" + langs="ksh" + uselang=ksh + launch=no + groups="default" + default=( + label="Table Viewer Preferences" + entrylist=" \ + vieworigin viewsize viewcolor viewfontname viewfontsize \ + showheader header showfooter footer showtitle title showlegends \ + class_td_lg1_style class_tr_tr1_style \ + class_th_th1_style class_td_td1_style \ + fields fieldorder \ + " + entries=( + vieworigin=( + type=coord var=vieworigin val="0 0" label="Window Position" + ) + viewsize=( + type=coord var=viewsize val="400 400" label="Window Size" + ) + viewcolor=( + type=2colors var=viewcolor val="gray black" + label="Window Colors" + ) + viewfontname=( + type=fontname var=viewfontname val="Times-Roman" + label="Window Font Name" + ) + viewfontsize=( + type=fontsize var=viewfontsize val=14 label="Window Font Size" + ) + + showheader=( + type=yesno var=showheader val=no label="Show Header" + ) + header=( + type=text var=header val="" label="Header" + ) + + showfooter=( + type=yesno var=showfooter val=no label="Show Footer" + ) + footer=( + type=text var=footer val="" label="Footer" + ) + + showtitle=( + type=yesno var=showtitle val=yes label="Show Title" + ) + title=( + type=text var=title val="SWIFTUI - Table View" label="Title" + ) + + showlegends=( + type=yesno var=showlegends val=yes label="Show Legends" + ) + + class_td_lg1_style=( + type=style var=class_td_lg1_style + val="color: black; font-family: Times-Roman; font-size: 14pt" + label="Legend 1 Style" + ) + + class_tr_tr1_style=( + type=style var=class_tr_tr1_style val="background: black" + label="Table Row 1 Style" + ) + + class_th_th1_style=( + type=style var=class_th_th1_style + val="color: black; font-family: Times-Roman; font-size: 14pt; text-align: left" + label="Table Header 1 Style" + ) + + class_td_td1_style=( + type=style var=class_td_td1_style + val="color: black; font-family: Times-Roman; font-size: 14pt; text-align: left" + label="Table Cell 1 Style" + ) + + fields=( + type=text var=fields val= label="List of Fields" + ) + fieldorder=( + type=text var=fieldorder val= label="Order of Fields" + ) + ) + ) +) +[[ "${suitable}" == *entrylist=* ]] || err_exit 'compound variable expansion omitting fields' +foo=( bar=foo barbar=bar) +[[ $foo == *bar=foo* ]] || err_exit 'no prefix elements in compound variable output' +function localvar +{ + typeset point=(typeset -i x=3 y=4) + (( (point.x*point.x + point.y*point.y) == 25 )) || err_exit "local compound variable not working" +} +point=(integer x=6 y=8) +localvar + (( (point.x*point.x + point.y*point.y) == 100 )) || err_exit "global compound variable not preserved" +[[ $($SHELL -c 'foo=();foo.[x]=(y z); print ${foo.x[@]}') == 'y z' ]] 2> /dev/null || err_exit 'foo=( [x]=(y z) not working' +function staticvar +{ + if [[ $1 ]] + then print -r -- "$point" + return + fi + typeset -S point=(typeset -i x=3 y=4) + (( (point.x*point.x + point.y*point.y) == 25 )) || err_exit "local compound variable not working" + point.y=5 + point.z=foobar +} +staticvar + (( (point.x*point.x + point.y*point.y) == 100 )) || err_exit "global compound variable not preserved" +[[ $(staticvar x) == $'(\n\ttypeset -i x=3\n\ttypeset -i y=5\n\tz=foobar\n)' ]] || err_exit 'static variables in function not working' +integer x=3 +( typeset -S x=+++)2> /dev/null || err_exit "typeset -S doesn't unset first" + +unset z +( [[ ${z.foo.bar:-abc} == abc ]] 2> /dev/null) || err_exit ':- not working with compound variables' +stack=() +typeset -a stack.items=([0]=foo [1]=bar) +[[ ${stack.items[0]} == foo ]] || err_exit 'typeset -a variable not expanding correctly' +$SHELL -c 'typeset -a info=( [1]=( passwd=( since=2005-07-20) ))' || err_exit 'problem with embedded index array in compound variable' +x=(foo=([1]=(y=([2]=(z=4))))) +[[ $x == *'.y'=* ]] && err_exit 'expansion with bogus leading . in name' +unset z +z=1 +function foo +{ + z=3 + [[ ${a.z} == 3 ]] && err_exit "\${a.z} should not be 3" + print hi +} +a=( b=$(foo) ) +[[ ${a.z} == 3 ]] && err_exit 'a.z should not be set to 3' +function a.b.get +{ + .sh.value=foo +} +{ b=( b1=${a.b} ) ;} 2> /dev/null +[[ ${b.b1} == foo ]] || err_exit '${b.b1} should be foo' +function dcl1 +{ + eval 'a=1 + function a.set + { print ${.sh.name}=${.sh.value}; }' +} +function dcl2 +{ + eval 'b=(typeset x=0; typeset y=0 ) + function b.x.set + { print ${.sh.name}=${.sh.value}; }' +} +dcl1 +[[ ${ a=123;} == 'a=123' ]] || err_exit 'should be a=123' +dcl2 +[[ ${ b.x=456;} == 'b.x=456' ]] || err_exit 'should be b.x=456' +eval 'b=(typeset x=0; typeset y=0 ) +function b.x.set +{ print ${.sh.name}=${.sh.value}; }' > /dev/null +[[ ${ b.x=789;} == 'b.x=789' ]] || err_exit 'should be b.x=789' +unset a b +function func +{ + typeset X + X=( bar=2 ) +} + +X=( foo=1 ) +func +[[ $X == $'(\n\tfoo=1\n)' ]] || err_exit 'scoping problem with compound variables' +unset foo +typeset -A foo=([a]=aa;[b]=bb;[c]=cc) +[[ ${foo[c]} == cc ]] || err_exit 'associative array assignment with; not working' +[[ $({ $SHELL -c 'x=(); typeset -a x.foo; x.foo=bar; print -r -- "$x"' ;} 2> /dev/null) == $'(\n\ttypeset -a foo=bar\n)' ]] || err_exit 'indexed array in compound variable with only element 0 defined fails' +unset foo +foo=(typeset -a bar) +[[ $foo == *'typeset -a bar'* ]] || err_exit 'array attribute -a not preserved in compound variable' +unset s +typeset -A s=( [foo]=(y=2 z=3) [bar]=(y=4 z=5)) +[[ ${s[@]} == *z=*z=* ]] || err_exit 'missing elements in compound associative array' +unset nodes +typeset -A nodes +nodes[0]+=( integer x=5) +[[ ${nodes[0].x} == 5 ]] || err_exit '${nodes[0].x} should be 5' +unset foo +typeset -C foo +foo.bar=abc +[[ $foo == $'(\n\tbar=abc\n)' ]] || err_exit 'typeset -C not working for foo' +typeset -C foo=(bar=def) +[[ $foo == $'(\n\tbar=def\n)' ]] || err_exit 'typeset -C not working when initialized' +foo=( + hello=ok + yes=( bam=2 yes=4) + typeset -A array=([one]=one [two]=2) + last=me +) +eval foo2="$foo" +foo2.hello=notok foo2.yes.yex=no foo2.extra=yes. +typeset -C bar bam +{ + read -Cu3 bar + read -Cu3 bam + read -ru3 +} 3<<- ++++ + "$foo" + "$foo2" + last line +++++ +[[ $? == 0 ]] || err_exit ' read -C failed' +[[ $bar == "$foo" ]] || err_exit '$foo != $bar' +[[ $bam == "$foo2" ]] || err_exit '$foo2 != $bmr' +[[ $REPLY == 'last line' ]] || err_exit "\$REPLY=$REPLY should be 'last line" +typeset x=( typeset -a foo=( [1][3]=hello [9][2]="world" ) ) +eval y="(typeset -a foo=$(printf "%B\n" x.foo) )" +[[ $x == "$y" ]] || err_exit '$x.foo != $y.foo with %B' +eval y="(typeset -a foo=$(printf "%#B\n" x.foo) )" +[[ $x == "$y" ]] || err_exit '$x.foo != $y.foo with %#B' +eval y="$(printf "%B\n" x)" +[[ $x == "$y" ]] || err_exit '$x != $y with %B' +eval y="$(printf "%#B\n" x)" +[[ $x == "$y" ]] || err_exit '$x != $y with %#B' +y=$(set | grep ^x=) 2> /dev/null +eval "${y/#x/y}" +[[ $x == "$y" ]] || err_exit '$x != $y with set | grep' +unset x y z +x=( float x=0 y=1; z=([foo]=abc [bar]=def)) +typeset -C y=x +[[ $x == "$y" ]] || err_exit '$x != $y with typeset -C' +unset y +y=() +y=x +[[ $x == "$y" ]] || err_exit '$x != $y when x=y and x and y are -C ' +function foobar +{ + typeset -C z + z=x + [[ $x == "$z" ]] || err_exit '$x != $z when x=z and x and z are -C ' + y=z +} +[[ $x == "$y" ]] || err_exit '$x != $y when x=y -C copied in a function ' +z=(foo=abc) +y+=z +[[ $y == *foo=abc* ]] || err_exit 'z not appended to y' +unset y.foo +[[ $x == "$y" ]] || err_exit '$x != $y when y.foo deleted' +unset x y +x=( foo=(z=abc d=ghi) bar=abc; typeset -A r=([x]=3 [y]=4)) +unset x +x=() +[[ $x == $'(\n)' ]] || err_exit 'unset compound variable is not empty' + +unset z +z=() +z.foo=( [one]=hello [two]=(x=3 y=4) [three]=hi) +z.bar[0]=hello +z.bar[2]=world +z.bar[1]=(x=4 y=5) +exp='( + typeset -a bar=( + [0]=hello + [2]=world + [1]=( + x=4 + y=5 + ) + ) + typeset -A foo=( + [one]=hello + [three]=hi + [two]=( + x=3 + y=4 + ) + ) +)' +got=$z +[[ $got == "$exp" ]] || { + exp=$(printf %q "$exp") + got=$(printf %q "$got") + err_exit "compound indexed array pretty print failed -- expected $exp, got $got" +} + +typeset -A record +record[a]=( + typeset -a x=( + [1]=( + X=1 + ) + ) +) +exp=$'(\n\ttypeset -a x=(\n\t\t[1]=(\n\t\t\tX=1\n\t\t)\n\t)\n)' +got=${record[a]} +[[ $got == "$exp" ]] || { + exp=$(printf %q "$exp") + got=$(printf %q "$got") + err_exit "compound indexed array pretty print failed -- expected $exp, got $got" +} + +unset r +r=( + typeset -a x=( + [1]=( + X=1 + ) + ) +) +exp=$'(\n\ttypeset -a x=(\n\t\t[1]=(\n\t\t\tX=1\n\t\t)\n\t)\n)' +got=$r +[[ $got == "$exp" ]] || { + exp=$(printf %q "$exp") + got=$(printf %q "$got") + err_exit "compound indexed array pretty print failed -- expected $exp, got $got" +} + +# array of compund variables +typeset -C data=( + typeset -a samples +) +data.samples+=( + type1="greeting1" + timestamp1="now1" + command1="grrrr1" +) +data.samples+=( + type2="greeting2" + timestamp2="now2" + command2="grrrr2" +) + +[[ $data == %(()) ]] || err_exit "unbalanced parenthesis with compound variable containing array of compound variables" +typeset -C -A hello=( [foo]=bar) +[[ $(typeset -p hello) == 'typeset -C -A hello=([foo]=bar)' ]] || err_exit 'typeset -A -C with intial assignment not working' +# this caused a core dump before ksh93t+ +[[ $($SHELL -c 'foo=(x=3 y=4);function bar { typeset z=4;: $z;};bar;print ${!foo.@}') == 'foo.x foo.y' ]] 2> /dev/null || err_exit '${!foo.@} after function not working' + +function foo +{ + typeset tmp + read -C tmp + read -C tmp +} +foo 2> /dev/null <<- \EOF || err_exit 'deleting compound variable in function failed' + ( + typeset -A myarray3=( + [a]=( foo=bar) + [b]=( foo=bar) + [c d]=( foo=bar) + [e]=( foo=bar) + [f]=( foo=bar) + [g]=( foo=bar) + [h]=( foo=bar) + [i]=( foo=bar) + [j]=( foo=bar) + ) + ) + hello +EOF + +typeset -C -a mica01 +mica01[4]=( a_string="foo bar" ) +typeset -C more_content=( + some_stuff="hello" +) +mica01[4]+=more_content +expected=$'typeset -C -a mica01=([4]=(a_string=\'foo bar\';some_stuff=hello))' +[[ $(typeset -p mica01) == "$expected" ]] || err_exit 'appened to indexed array compound variable not working' + +unset x +compound x=( integer x ; ) +[[ ! -v x.x ]] && err_exit 'x.x should be set' +expected=$'(\n\ttypeset -l -i x=0\n)' +[[ $(print -v x) == "$expected" ]] || err_exit "'print -v x' should be $expected" + +typeset -C -A hello19=( + [19]=( + one="xone 19" + two="xtwo 19" + ) + [23]=( + one="xone 23" + two="xtwo 23" + ) +) +expected="typeset -C -A hello19=([19]=(one='xone 19';two='xtwo 19') [23]=(one='xone 23';two='xtwo 23'))" +[[ $(typeset -p hello19) == "$expected" ]] || print -u2 'typeset -p hello19 incorrect' +expected=$'(\n\tone=\'xone 19\'\n\ttwo=\'xtwo 19\'\n) (\n\tone=\'xone 23\'\n\ttwo=\'xtwo 23\'\n)' +[[ ${hello19[@]} == "$expected" ]] || print -u2 '${hello19[@]} incorrect' + +typeset -C -A foo1=( abc="alphabet" ) foo2=( abc="alphabet" ) +function add_one +{ + nameref left_op=$1 + typeset -C info + info.hello="world" + nameref x=info + left_op+=x +} +nameref node1="foo1[1234]" +add_one "node1" +add_one "foo2[1234]" +[[ "${foo1[1234]}" == "${foo2[1234]}" ]] || err_exit "test failed\n$(diff -u <( print -r -- "${foo1[1234]}") <(print -r -- "${foo2[1234]}"))." + +typeset -C tree +function f1 +{ + nameref tr=$1 + typeset -A tr.subtree + typeset -C node + node.one="hello" + node.two="world" + + # move local note into the array + typeset -m tr.subtree["a_node"]=node +} +f1 tree +expected=$'(\n\ttypeset -A subtree=(\n\t\t[a_node]=(\n\t\t\tone=hello\n\t\t\ttwo=world\n\t\t)\n\t)\n)' +[[ $tree == "$expected" ]] || err_exit 'move of compound local variable to global variable not working' + +typeset -C -A array +float array[12].amount=2.9 +expected='typeset -C -A array=([12]=(typeset -l -E amount=2.9))' +[[ $(typeset -p array) == "$expected" ]] || err_exit 'typeset with compound variable with compound variable array not working' + +typeset -T foo_t=( + function diff + { + print 1.0 + return 0 + } +) +foo_t sw +compound output=( + integer one=1 + float mydiff=sw.diff + float end=.314 +) +[[ $output == *end=* ]] || err_exit "The field 'name' end is missing" + +compound cpv1=( integer f=2 ) +compound x=( + integer a=1 + compound b=cpv1 +) +[[ $x == *f=2* ]] || err_exit "The field b containg 'f=2' is missing" + +unset x +compound x=( + compound -a nodes=( + [4]=( ) + ) +) +expected='typeset -C x=(typeset -C -a nodes=([4]=());)' +[[ $(typeset -p x) == "$expected" ]] || err_exit 'typeset -p with nested compound index array not working' + +unset v +compound v=( + integer -A ar=( + [aa]=4 [bb]=9 + ) +) +expected='typeset -C v=(typeset -A -l -i ar=([aa]=4 [bb]=9);)' +[[ $(typeset -p v) == "$expected" ]] || err_exit 'attributes for associative arrays embedded in compound variables not working' + +unset x +compound -a x +x[1]=( a=1 b=2 ) +[[ $(print -v x[1]) == "${x[1]}" ]] || err_exit 'print -v x[1] not working for index array of compound variables' + +unset x +z='typeset -a x=(hello (x=12;y=5) world)' +{ eval "$z" ;} 2> /dev/null +[[ $(typeset -p x) == "$z" ]] || err_exit "compound assignment '$z' not working" + +expected='typeset -C -A l=([4]=(typeset -a ar=(1 2 3);b=1))' +typeset -A -C l +printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l[4] +[[ $(typeset -p l) == "$expected" ]] || err_exit 'read -C for associative array of compound variables not working' + +unset x +compound x=( z="a=b c") +exp=$'typeset -C x=(z=a\\=\'b c\')' +got=$(typeset -p x) +[[ $got == "$exp" ]] || err_exit "typeset -p failed -- expected '$exp', got '$got'" + +x=(typeset -C -a y;float z=2) +got=$(print -C x) +expected='(typeset -C -a y;typeset -l -E z=2)' +[[ $expected == "$got" ]] || err_exit "print -C x exects '$expected' got '$got'" + +unset vx vy +compound vx=( + compound -a va=( + [3][17]=( + integer -A ar=( [aa]=4 [bb]=9 ) + ) + ) +) +eval "vy=$(print -C vx)" +[[ $vx == "$vy" ]] || err_exit 'print -C with multi-dimensional array not working' +eval "vy=$(print -v vx)" +[[ $vx == "$vy" ]] || err_exit 'print -v with multi-dimensional array not working' + +unset x +typeset -C -A x=( [0]=(a=1) [1]=(b=2) ) +expected=$'(\n\t[0]=(\n\t\ta=1\n\t)\n\t[1]=(\n\t\tb=2\n\t)\n)' +[[ $(print -v x) == "$expected" ]] || err_exit 'print -v not formatting correctly' + +compound -a x=( [0]=(a=1) [1]=(b=2) ) +typeset -m "z=x[1]" +[[ $(typeset -p z 2>/dev/null) == 'typeset -C z=(b=2)' ]] || err_exit 'typeset -m not working with commpound -a variable' + +unset x z +compound -A x=( [0]=(a=1) [1]=(b=2) ) +typeset -m "z=x[1]" +[[ $(typeset -p z 2>/dev/null) == 'typeset -C z=(b=2)' ]] || err_exit 'typeset -m not working with commpound -a variable' +typeset -m "x[1]=x[0]" +typeset -m "x[0]=z" +exp='([0]=(b=2) [1]=(a=1))' +[[ $(print -C x) == "$exp" ]] || err_exit 'typeset -m not working for associative arrays' + +unset z r +z=(a b c) +r=(x=3 y=4) +typeset -m z[1]=r +exp='typeset -a z=(a (x=3;y=4) c)' +[[ $(typeset -p z) == "$exp" ]] || err_exit 'moving compound variable into indexed array fails' + +unset c +compound c +compound -a c.a=( [1]=( aa=1 ) ) +compound -a c.b=( [2]=( bb=2 ) ) +typeset -m "c.b[9]=c.a[1]" +exp='typeset -C c=(typeset -C -a a;typeset -C -a b=( [2]=(bb=2;)[9]=(aa=1));)' +[[ $(typeset -p c) == "$exp" ]] || err_exit 'moving compound indexed array element to another index fails' + +unset c +compound c +compound -a c.a=( [1]=( aa=1 ) ) +compound -A c.b=( [2]=( bb=2 ) ) +typeset -m "c.b[9]=c.a[1]" +exp='typeset -C c=(typeset -C -a a;typeset -C -A b=( [2]=(bb=2;)[9]=(aa=1));)' +[[ $(typeset -p c) == "$exp" ]] || err_exit 'moving compound indexed array element to a compound associative array element fails' + +zzz=( + foo=( + bar=4 + ) +) +[[ $(set | grep "^zzz\.") ]] && err_exit 'set displays compound variables incorrectly' + +typeset -A stats +stats[1]=(a=1 b=2) +stats[2]=(a=1 b=2) +stats[1]=(c=3 d=4) +(( ${#stats[@]} == 2 )) || err_exit "stats[1] should contain 2 element not ${#stats[@]}" + +integer i=1 +foo[i++]=(x=3 y=4) +[[ ${foo[1].x} == 3 ]] || err_exit "\${foo[1].x} should be 3" +[[ ${foo[1].y} == 4 ]] || err_exit "\${foo[1].y} should be 4" + +# ${!x.} caused core dump in ks93u and earlier +{ $SHELL -c 'compound x=(y=1); : ${!x.}' ; ((!$?));} || err_exit '${!x.} not working' + +$SHELL -c 'typeset -A a=([b]=c)' 2> /dev/null || err_exit 'typeset -A a=([b]=c) fails' + +compound -a a +compound c=( name="container1" ) +a[4]=c +[[ ${a[4]} == $'(\n\tname=container1\n)' ]] || err_exit 'assignment of compound variable to compound array element not working' + +unset c +compound c +compound -a c.board +for ((i=2; i < 4; i++)) +do c.board[1][$i]=(foo=bar) +done +exp=$'(\n\ttypeset -C -a board=(\n\t\t[1]=(\n\t\t\t[2]=(\n\t\t\t\tfoo=bar\n\t\t\t)\n\t\t\t[3]=(\n\t\t\t\tfoo=bar\n\t\t\t)\n\t\t)\n\t)\n)' +[[ "$(print -v c)" == "$exp" ]] || err_exit 'compound variable assignment to two dimensional array not working' + +unset zz +zz=() +zz.[foo]=abc +zz.[2]=def +exp='typeset -C zz=([2]=def;foo=abc)' +[[ $(typeset -p zz) == "$exp" ]] || err_exit 'expansion of compound variables with non-identifiers not working' +( + typeset -i zz.[3]=123 + exec 2>& 3- + exp='typeset -C zz=([2]=def;typeset -i [3]=123;foo=abc)' + [[ $(typeset -p zz) == "$exp" ]] || err_exit 'expansion of compound variables with non-identifiers not working in subshells' +) 3>&2 2> /dev/null || err_exit 'syntax errors expansion of compound variables with non-identifiers' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/comvario.sh b/src/cmd/ksh93/tests/comvario.sh new file mode 100644 index 0000000..8ed803a --- /dev/null +++ b/src/cmd/ksh93/tests/comvario.sh @@ -0,0 +1,686 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# Roland Mainz <roland.mainz@nrubsig.org> # +# # +######################################################################## + +# test setup +function err_exit +{ + print -u2 -n '\t' + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +# "nounset" disabled for now +#set -o nounset +Command=${0##*/} +integer Errors=0 HAVE_signbit=0 + +if typeset -f .sh.math.signbit >/dev/null && (( signbit(-NaN) )) +then HAVE_signbit=1 +else print -u2 "$0: warning: -lm does not support signbit(-NaN)" +fi + +compound bracketstat=( + integer bopen=0 + integer bclose=0 +) + +function count_brackets +{ + typeset x="$1" + typeset c + + integer i + (( bracketstat.bopen=0 , bracketstat.bclose=0 )) + + for (( i=0 ; i < ${#x} ; i++ )) ; do + c="${x:i:1}" + [[ "$c" == '(' ]] && (( bracketstat.bopen++ )) + [[ "$c" == ')' ]] && (( bracketstat.bclose++ )) + done + + (( bracketstat.bopen != bracketstat.bclose )) && return 1 + + return 0 +} + +# compound variable "cat" nr.1, using $ print "%B\n" ... # +function cpvcat1 +{ + set -o errexit + compound tmp + + while read -C tmp ; do printf '%B\n' tmp ; done + return 0 +} + +# compound variable "cat" nr.2, using $ print "%#B\n" ... # +function cpvcat2 +{ + set -o errexit + compound tmp + + while read -C tmp ; do printf '%#B\n' tmp ; done + return 0 +} + +# compound variable "cat" nr.3, using $ print -C ... # +function cpvcat3 +{ + set -o errexit + compound tmp + + while read -C tmp ; do print -C tmp ; done + return 0 +} + +# compound variable "cat" nr.4, using $ print -v ... # +function cpvcat4 +{ + set -o errexit + compound tmp + + while read -C tmp ; do print -v tmp ; done + return 0 +} + +typeset s + +# Test 1: +# Check whether "read -C" leaves the file pointer at the next line +# (and does not read beyond that point). +# Data layout is: +# -- snip -- +# <compound var> +# hello +# -- snip -- +# (additionally we test some extra stuff like bracket count) +s=${ + compound x=( + a=1 b=2 + typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) + typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) + typeset -A myarray3=( + [a]=( + float m1=0.5 + float m2=0.6 + foo="hello" + ) + [b]=( + foo="bar" + ) + ["c d"]=( + integer at=90 + ) + [e]=( + compound nested_cpv=( + typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) + typeset str=$'a \'string' + ) + ) + [f]=( + typeset g="f" + ) + [a_nan]=( + float my_nan=-nan + ) + [a_hexfloat]=( + typeset -X my_hexfloat=1.1 + ) + ) + ) + + { + printf "%B\n" x + print "hello" + } | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | { + read -C y + read s + } + print "x${s}x" +} || err_exit "test returned exit code $?" + +[[ "${s}" == "xhellox" ]] || err_exit "Expected 'xhellox', got ${s}" +count_brackets "$y" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v y)" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C y)" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" + +# cleanup +unset x y || err_exit "unset failed" +[[ "$x" == '' ]] || err_exit "cleanup failed for x" +[[ "$y" == '' ]] || err_exit "cleanup failed for y" + + +# Test 2: +# Same as test 1 except one more compound var following the "hello" +# line. +# Data layout is: +# -- snip -- +# <compound var> +# hello +# <compound var> +# -- snip -- +s=${ + compound x=( + a=1 b=2 + typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) + typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) + compound -A myarray3=( + [a]=( + float m1=0.5 + float m2=0.6 + foo="hello" + ) + [b]=( + foo="bar" + ) + ["c d"]=( + integer at=90 + ) + [e]=( + compound nested_cpv=( + typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) + typeset str=$'a \'string' + ) + ) + [f]=( + typeset g="f" + ) + [a_nan]=( + float my_nan=-nan + ) + [a_hexfloat]=( + typeset -X my_hexfloat=1.1 + ) + ) + ) + + { + printf "%B\n" x + print "hello" + printf "%B\n" x + } | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | { + read -C y1 + read s + read -C y2 + } + + print "x${s}x" +} || err_exit "test returned exit code $?" + +[[ "${s}" == "xhellox" ]] || err_exit "Expected 'xhellox', got ${s}." +[[ "${y1.myarray3[b].foo}" == "bar" ]] || err_exit "y1.myarray3[b].foo != bar" +[[ "${y2.myarray3[b].foo}" == "bar" ]] || err_exit "y2.myarray3[b].foo != bar" +[[ "$y1" != "" ]] || err_exit "y1 is empty" +[[ "$y2" != "" ]] || err_exit "y2 is empty" +(( ${#y1.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in y1.myarray3[e].nested_cpv, got ${#y1.myarray3[e].nested_cpv[@]}" +(( ${#y2.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in y2.myarray3[e].nested_cpv, got ${#y2.myarray3[e].nested_cpv[@]}" +(( isnan(y1.myarray3[a_nan].my_nan) )) || err_exit "y1.myarray3[a_nan].my_nan not a NaN" +(( isnan(y2.myarray3[a_nan].my_nan) )) || err_exit "y2.myarray3[a_nan].my_nan not a NaN" +if (( HAVE_signbit )) +then (( signbit(y1.myarray3[a_nan].my_nan) )) || err_exit "y1.myarray3[a_nan].my_nan not negative" + (( signbit(y2.myarray3[a_nan].my_nan) )) || err_exit "y2.myarray3[a_nan].my_nan not negative" +fi +count_brackets "$y1" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v y1)" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C y1)" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$y2" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v y2)" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C y2)" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +[[ "$y1" == "$y2" ]] || err_exit "Expected $(printf "%q\n" "${y1}") == $(printf "%q\n" "${y2}")." +[[ "$x" == "$y1" ]] || err_exit "Expected $(printf "%q\n" "${x}") == $(printf "%q\n" "${y}")." + +# cleanup +unset x y1 y2 || err_exit "unset failed" +[[ "$x" == '' ]] || err_exit "cleanup failed for x" +[[ "$y1" == '' ]] || err_exit "cleanup failed for y1" +[[ "$y2" == '' ]] || err_exit "cleanup failed for y2" + + +# Test 3: Test compound variable copy operator vs. "read -C" +compound x=( + a=1 b=2 + typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) + typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) + compound -A myarray3=( + [a]=( + float m1=0.5 + float m2=0.6 + foo="hello" + ) + [b]=( + foo="bar" + ) + ["c d"]=( + integer at=90 + ) + [e]=( + compound nested_cpv=( + typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) + typeset str=$'a \'string' + ) + ) + [f]=( + typeset g="f" + ) + [a_nan]=( + float my_nan=-nan + ) + [a_hexfloat]=( + typeset -X my_hexfloat=1.1 + ) + ) +) + +compound x_copy=x || err_exit "x_copy copy failed" +[[ "${x_copy}" != "" ]] || err_exit "x_copy should not be empty" +count_brackets "${x_copy}" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v x_copy)" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C x_copy)" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" + +compound nested_cpv_copy + +nested_cpv_copy=x.myarray3[e].nested_cpv || err_exit "x.myarray3[e].nested_cpv copy failed" +(( ${#nested_cpv_copy.myarray[@]} == 10 )) || err_exit "Expected 10 elements in nested_cpv_copy.myarray, got ${#nested_cpv_copy.myarray[@]}" + +# unset branch "x.myarray3[e].nested_cpv" of the variable tree "x" ... +unset x.myarray3[e].nested_cpv || err_exit "unset x.myarray3[e].nested_cpv failed" +[[ "${x.myarray3[e].nested_cpv}" == "" ]] || err_exit "x.myarray3[e].nested_cpv still has a value" + +# ... and restore it from the saved copy +printf "%B\n" nested_cpv_copy | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | read -C x.myarray3[e].nested_cpv || err_exit "read failed" + +# compare copy of the original tree and the modified one +[[ "${x}" == "${x_copy}" ]] || err_exit "x != x_copy" +count_brackets "${x}" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -v x)" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +count_brackets "$(print -C x)" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" +(( ${#x.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in x.myarray3[e].nested_cpv, got ${#x.myarray3[e].nested_cpv[@]}" +(( isnan(x.myarray3[a_nan].my_nan) )) || err_exit "x.myarray3[a_nan].my_nan not a NaN" +if (( HAVE_signbit )) +then (( signbit(x.myarray3[a_nan].my_nan) )) || err_exit "x.myarray3[a_nan].my_nan not negative" +fi + +# cleanup +unset x x_copy nested_cpv_copy || err_exit "unset failed" + + +# Test 4: Test "read -C" failure for missing bracket at the end +typeset s +s=$($SHELL -c 'compound myvar ; print "( unfinished=1" | read -C myvar 2>'/dev/null' || print "error $?"') || err_exit 'shell failed' +[[ "$s" == 'error 3' ]] || err_exit "compound_read: expected error 3, got ${s}" + + +# Test 5: Test "read -C" failure for missing bracket at the beginning +typeset s +s=$($SHELL -c 'compound myvar ; print " unfinished=1 )" | read -C myvar 2>'/dev/null' || print "error $?"') || err_exit 'shell failed' +[[ "$s" == 'error 3' ]] || err_exit "compound_read: expected error 3, got ${s}" + + +# test6: Derived from the test2 for CR #6944386 +# ("compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -C v prints trash") +# which caused compound variables to be corrupted like this: +# -- snip -- +# ksh93 -c 'compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -v v' +# ( +# typeset -A -l -i ar=( +# [aa]=$'\004' +# [bb]=$'\t' +# ) +# ) +# -- snip -- + +function test6 +{ + compound out=( typeset stdout stderr ; integer res ) + compound val + integer testid + + compound -r -a tests=( + # subtests1: + ( cmd='compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -C v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='ar' ) + ( cmd='compound v=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -C v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='ar' ) + ( cmd='compound v=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -C v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='ar' ) + ( cmd='compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -v v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='ar' ) + ( cmd='compound v=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -v v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='ar' ) + ( cmd='compound v=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -v v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='ar' ) + + # subtests2: Same as subtests1 but variable "v" is inside "vx" + ( cmd='compound vx=( compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='v.ar' ) + ( cmd='compound vx=( compound v=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='v.ar' ) + ( cmd='compound vx=( compound v=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='v.ar' ) + ( cmd='compound vx=( compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='v.ar' ) + ( cmd='compound vx=( compound v=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='v.ar' ) + ( cmd='compound vx=( compound v=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='v.ar' ) + + # subtests3: Same as subtests1 but variable "va" is an indexed array + ( cmd='compound vx=( compound -a va=( [3]=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[3].ar' ) + ( cmd='compound vx=( compound -a va=( [3]=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[3].ar' ) + ( cmd='compound vx=( compound -a va=( [3]=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='va[3].ar' ) + ( cmd='compound vx=( compound -a va=( [3]=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[3].ar' ) + ( cmd='compound vx=( compound -a va=( [3]=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[3].ar' ) + ( cmd='compound vx=( compound -a va=( [3]=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='va[3].ar' ) + + # subtests4: Same as subtests1 but variable "va" is an 2d indexed array + ( cmd='compound vx=( compound -a va=( [3][17]=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[3][17].ar' ) + ( cmd='compound vx=( compound -a va=( [3][17]=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[3][17].ar' ) + ( cmd='compound vx=( compound -a va=( [3][17]=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='va[3][17].ar' ) + ( cmd='compound vx=( compound -a va=( [3][17]=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[3][17].ar' ) + ( cmd='compound vx=( compound -a va=( [3][17]=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[3][17].ar' ) + ( cmd='compound vx=( compound -a va=( [3][17]=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='va[3][17].ar' ) + + # subtests5: Same as subtests1 but variable "va" is an associative array + ( cmd='compound vx=( compound -A va=( [l]=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[l].ar' ) + ( cmd='compound vx=( compound -A va=( [l]=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[l].ar' ) + ( cmd='compound vx=( compound -A va=( [l]=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='va[l].ar' ) + ( cmd='compound vx=( compound -A va=( [l]=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[l].ar' ) + ( cmd='compound vx=( compound -A va=( [l]=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='va[l].ar' ) + ( cmd='compound vx=( compound -A va=( [l]=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='va[l].ar' ) + ) + + for testid in "${!tests[@]}" ; do + nameref test=tests[testid] + typeset testname="test2/${testid}" + + out.stderr="${ { out.stdout="${ ${SHELL} -c "${test.cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" + + (( out.res == 0 )) || err_exit "${testname}: Test shell returned with exit code ${out.res}" + [[ "${out.stdout}" == ${test.stdoutpattern} ]] || err_exit "${testname}: Expected match for ${test.stdoutpattern}, got $(printf "%q\n" "${out.stdout}")" + [[ "${out.stderr}" == "" ]] || err_exit "${testname}: Expected empty stderr, got $(printf "%q\n" "${out.stderr}")" + + read -C val <<<"${out.stdout}" || err_exit "${testname}: read -C val failed with exit code $?" + nameref ar="val.${test.arrefname}" + (( ar[aa] == 4 )) || err_exit "${testname}: Expected ar[aa] == 4, got ${ar[aa]}" + (( ar[bb] == 9 )) || err_exit "${testname}: Expected ar[bb] == 9, got ${ar[bb]}" + done + + return 0 +} + +test6 + +function test_3D_array_read_C +{ + compound out=( typeset stdout stderr ; integer res ) + integer i + typeset -r -a tests=( + # ast-ksh.2010-03-09 will print "ksh93[1]: read: line 4: 0[0]: invalid variable name" for 3D arrays passed to read -C + 'compound c=( typeset -a x ) ; for (( i=0 ; i < 3 ; i++ )) ; do for (( j=0 ; j < 3 ; j++ )) ; do for (( k=0 ; k < 3 ; k++ )) ; do c.x[i][j][k]="$i$j$k" ; done; done; done ; unset c.x[2][0][1] ; print -v c | read -C dummy' + + # same test, 4D, fails with 'ksh[1]: read: line 4: 0: invalid variable name' + 'compound c=( typeset -a x ) ; for (( i=0 ; i < 3 ; i++ )) ; do for (( j=0 ; j < 3 ; j++ )) ; do for (( k=0 ; k < 3 ; k++ )) ; do for (( l=0 ; l < 3 ; l++ )) ; do c.x[i][j][k][l]="$i$j$k$l" ; done; done; done ; done ; unset c.x[2][0][1][2] ; print -v c | read -C dummy' + ) + + for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do + out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${tests[i]}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" + + [[ "${out.stdout}" == '' ]] || err_exit "$0/${i}: Expected empty stdout, got $(printf '%q\n' "${out.stdout}")" + [[ "${out.stderr}" == '' ]] || err_exit "$0/${i}: Expected empty stderr, got $(printf '%q\n' "${out.stderr}")" + done + + return 0 +} + + +function test_access_2Darray_in_type_in_compound +{ + compound out=( typeset stdout stderr ; integer res ) + integer i + typeset -r -a tests=( + # ast-ksh.2010-03-09 will print 'ksh: line 1: l.c.x[i][j]=: no parent' + 'typeset -T c_t=(typeset -a x) ; compound l=( c_t c ) ; for ((i=0;i<3;i++));do for ((j=0;j<3;j++));do l.c.x[i][j]="" ; done; done; print -v l | read -C dummy' + ) + + for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do + out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${tests[i]}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" + + [[ "${out.stdout}" == '' ]] || err_exit "$0/${i}: Expected empty stdout, got $(printf '%q\n' "${out.stdout}")" + [[ "${out.stderr}" == '' ]] || err_exit "$0/${i}: Expected empty stderr, got $(printf '%q\n' "${out.stderr}")" + done + + return 0 +} + +function test_read_type_crash +{ + compound out=( typeset stdout stderr ; integer res ) + typeset -r test=' +typeset -T field_t=( + typeset -a f + + function reset + { + integer i j + + for (( i=0 ; i < 3 ; i++ )) ; do + for (( j=0 ; j < 3 ; j++ )) ; do + _.f[i][j]="" + done + done + return 0 + } + + function enumerate_empty_fields + { + integer i j + + for (( i=0 ; i < 3 ; i++ )) ; do + for (( j=0 ; j < 3 ; j++ )) ; do + [[ "${_.f[i][j]}" == "" ]] && printf "[%d][%d]\n" i j + done + done + return 0 + } + + function setf + { + _.f[$1][$2]="$3" + } +) + +set -o nounset + +compound c1=( field_t x ) + +c1.x.reset + +print -v c1 | read -C c2 +print -v c2 +' + + out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${test}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" + + [[ "${out.stdout}" != '' ]] || err_exit "$0: Expected nonempty stdout." + [[ "${out.stderr}" == '' ]] || err_exit "$0: Expected empty stderr, got $(printf '%q\n' "${out.stderr}")" + + if [[ -f 'core' && -x '/usr/bin/pstack' ]] ; then + pstack 'core' + rm 'core' + fi + + return 0 +} + + +function test_read_C_into_array +{ + compound out=( typeset stdout stderr ; integer res ) + # fixme: + # - The tests should cover 3D and 5D indexed arrays and namerefs to sub-dimensions of a 5D indexed array + compound -r -a tests=( + ( cmd=' typeset -a -C l ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l[4] ; print -v l' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)' ) ) + ( cmd=' typeset -a -C l ; nameref l4=l[4] ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l4 ; print -v l' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)' ) ) + + ( cmd=' typeset -a -C l ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l[4][6] ; print -v l' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)&(.+\[6\].+)' ) ) + ( cmd=' typeset -a -C l ; nameref l4=l[4][6] ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l4 ; print -v l' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)&(.+\[6\].+)' ) ) + + ( cmd=' typeset -a -C l ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l[4][6][9][11][15] ; print -v l' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)&(.+\[6\].+)' '~(X)(.+\[9\].+)&(.+\[11\].+)&(.+\[15\].+)' ) ) + ( cmd=' typeset -a -C l ; nameref l4=l[4][6][9][11][15] ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l4 ; print -v l' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)&(.+\[6\].+)' '~(X)(.+\[9\].+)&(.+\[11\].+)&(.+\[15\].+)' ) ) + + ( cmd=' typeset -A -C l ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l[4] ; print -v l' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)' ) ) + ( cmd=' typeset -A -C l ; nameref l4=l[4] ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l4 ; print -v l' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)' ) ) + ( cmd='compound c ; typeset -a -C c.l ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C c.l[4] ; print -v c' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)' ) ) + ( cmd='compound c ; typeset -a -C c.l ; nameref l4=c.l[4] ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l4 ; print -v c' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)' ) ) + + ( cmd='compound c ; typeset -a -C c.l ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C c.l[4][6] ; print -v c' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)&(.+\[6\].+)' ) ) + ( cmd='compound c ; typeset -a -C c.l ; nameref l4=c.l[4][6] ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l4 ; print -v c' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)&(.+\[6\].+)' ) ) + + ( cmd='compound c ; typeset -a -C c.l ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C c.l[4][6][9][11][15] ; print -v c' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)&(.+\[6\].+)' '~(X)(.+\[9\].+)&(.+\[11\].+)&(.+\[15\].+)' ) ) + ( cmd='compound c ; typeset -a -C c.l ; nameref l4=c.[4][6][9][11][15] ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l4 ; print -v c' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)&(.+\[6\].+)' '~(X)(.+\[9\].+)&(.+\[11\].+)&(.+\[15\].+)' ) ) + + ( cmd='compound c ; typeset -A -C c.l ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C c.l[4] ; print -v c' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)' ) ) + ( cmd='compound c ; typeset -A -C c.l ; nameref l4=c.l[4] ; printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l4 ; print -v c' typeset -a stdoutpattern=( '~(X)(.+b=1.+)&(.+\[4\].+)' ) ) + ) + typeset cmd + typeset pat + integer i + + compound -a test_variants + + # build list of variations of the tests above + for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do + nameref tst=tests[i] + + # plain test + cmd="${tst.cmd}" + test_variants+=( testname="${0}/${i}/plain" cmd="$cmd" typeset -a stdoutpattern=( "${tst.stdoutpattern[@]}" ) ) + + # test with "read -C" in a function + cmd="${tst.cmd/~(E)read[[:space:]]+-C[[:space:]]+([[:alnum:]]+)[[:space:]]+\;/{ function rf { nameref val=\$1 \; read -C val \; } \; rf \1 \; } \; }" + test_variants+=( testname="${0}/${i}/read_in_function" cmd="$cmd" typeset -a stdoutpattern=( "${tst.stdoutpattern[@]}" ) ) + + # test with "read -C" in a nested function + cmd="${tst.cmd/~(E)read[[:space:]]+-C[[:space:]]+([[:alnum:]]+)[[:space:]]+\;/{ function rf2 { nameref val=\$1 \; read -C val \; } \; function rf { nameref val=\$1 \; rf2 val \; } \; rf \1 \; } \; }" + test_variants+=( testname="${0}/${i}/read_in_nested_function" cmd="$cmd" typeset -a stdoutpattern=( "${tst.stdoutpattern[@]}" ) ) + + # test with "read -C" in a nested function with target variable + # being a function-local variable of function "main" + cmd='function rf2 { nameref val=$1 ; read -C val ; } ; function rf { nameref val=$1 ; rf2 val ; } ; function main { ' + cmd+="${tst.cmd/~(E)read[[:space:]]+-C[[:space:]]+([[:alnum:]]+)[[:space:]]+\;/rf \1 \; }" + cmd+=' ; } ; main' + test_variants+=( testname="${0}/${i}/read_into_localvar_in_nested_function" cmd="$cmd" typeset -a stdoutpattern=( "${tst.stdoutpattern[@]}" ) ) + done + + # run test variants + for (( i=0 ; i < ${#test_variants[@]} ; i++ )) ; do + nameref tv=test_variants[i] + + out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -o errexit -c "${tv.cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" + + for pat in "${tv.stdoutpattern[@]}" ; do + [[ "${out.stdout}" == ${pat} ]] || err_exit "${tv.testname}: Expected stdout of $(printf '%q\n' "${tv.cmd}") to match $(printf '%q\n' "${pat}"), got $(printf '%q\n' "${out.stdout}")" + done + [[ "${out.stderr}" == '' ]] || err_exit "${tv.testname}: Expected empty stderr for $(printf '%q\n' "${tv.cmd}"), got $(printf '%q\n' "${out.stderr}")" + (( out.res == 0 )) || err_exit "${tv.testname}: Unexpected exit code ${out.res} for $(printf '%q\n' "${tv.cmd}")" + done + + return 0 +} + + +# This test checks whether reading a compound variable value with +# "read -C var" which contains special shell keywords or aliases +# like "functions", "alias", "!" etc. in a string array causes the +# shell to produce errors like this: +# -- snip -- +# $ ksh93 -c 'print "( compound -A a1=( [4]=( typeset -a x=( alias ) ) ) ; +# compound -A a2=( [4]=( typeset -a x=( ! ! ! alias ) ) ) )" | read -C c ; print -v c' 1>/dev/null +# ksh93[1]: alias: c.a1[4].x: compound assignment requires sub-variable name +# -- snip -- +# A 2nd issue indirectly tested here was that simple indexed string array +# declarations in a function with the same special keywords did not work +# either. +# This happened in ast-ksh.2010-11-12 or older. +function test_read_C_special_shell_keywords +{ + typeset -r -a testcmdpatterns=( + # this was the original testcase + 'print "( compound -A a1=( [4]=( typeset -a x=( %keyword% ) ) ) ; compound -A a2=( [4]=( typeset -a x=( ! ! ! alias ) ) ) )" | read -C c ; print "X${c.a1[4].x[0]}X"' + # same as above but uses indexed arrays instead of associative arrays + 'print "( compound -a a1=( [4]=( typeset -a x=( %keyword% ) ) ) ; compound -a a2=( [4]=( typeset -a x=( ! ! ! alias ) ) ) )" | read -C c ; print "X${c.a1[4].x[0]}X"' + # same as first testcase but uses a blank in the array index value + $'print "( compound -A a1=( [\'hello world\']=( typeset -a x=( %keyword% ) ) ) ; compound -A a2=( [\'hello world\']=( typeset -a x=( ! ! ! alias ) ) ) )" | read -C c ; print "X${c.a1[\'hello world\'].x[0]}X"' + ) + typeset -r -a shell_special_words=( + 'alias' + 'compound' + 'function' + 'functions' + 'integer' + 'local' + 'namespace' + 'typeset' + 'SECONDS' + '.sh.version' + '!' + ) + integer spwi # shell_special_words index + integer tcpi # testcmdpatterns index + typeset testcmd + typeset testname + typeset shkeyword + compound out=( typeset stdout stderr ; integer res ) + + for (( tcpi=0 ; tcpi < ${#testcmdpatterns[@]} ; tcpi++ )) ; do + for (( spwi=0 ; spwi < ${#shell_special_words[@]} ; spwi++ )) ; do + shkeyword=${shell_special_words[spwi]} + testcmd="${testcmdpatterns[tcpi]//%keyword%/${shkeyword}}" + testname="${0}/${tcpi}/${spwi}/" + + out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -o errexit -c "${testcmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" + + [[ "${out.stdout}" == "X${shkeyword}X" ]] || err_exit "${testname}: Expected stdout to match $(printf '%q\n' "X${shkeyword}X"), got $(printf '%q\n' "${out.stdout}")" + [[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got $(printf '%q\n' "${out.stderr}")" + (( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}" + done + done + + return 0 +} + + +test_3D_array_read_C +test_access_2Darray_in_type_in_compound +test_read_type_crash +test_read_C_into_array +test_read_C_special_shell_keywords + + +# tests done +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/coprocess.sh b/src/cmd/ksh93/tests/coprocess.sh new file mode 100755 index 0000000..749f691 --- /dev/null +++ b/src/cmd/ksh93/tests/coprocess.sh @@ -0,0 +1,360 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +# test the behavior of co-processes +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +if [[ -d /cygdrive ]] +then err_exit cygwin detected - coprocess tests disabled - enable at the risk of wedging your system + exit $((Errors)) +fi + +bintrue=$(whence -p true) + +function ping # id +{ + integer x=0 + while ((x++ < 5)) + do read -r + print -r "$1 $REPLY" + done +} + +cat |& +print -p "hello" +read -p line +[[ $line == hello ]] || err_exit 'coprocessing fails' +exec 5>&p 6<&p +print -u5 'hello again' || err_exit 'write on u5 fails' +read -u6 line +[[ $line == 'hello again' ]] || err_exit 'coprocess after moving fds fails' +exec 5<&- 6<&- +wait $! + +ping three |& +exec 3>&p +ping four |& +exec 4>&p +ping pipe |& + +integer count +for i in three four pipe four pipe four three pipe pipe three pipe +do case $i in + three) to=-u3;; + four) to=-u4;; + pipe) to=-p;; + esac + (( count++ )) + print $to $i $count +done + +while ((count > 0)) +do (( count-- )) + read -p + set -- $REPLY + if [[ $1 != $2 ]] + then err_exit "$1 does not match $2" + fi + case $1 in + three) ;; + four) ;; + pipe) ;; + *) err_exit "unknown message +|$REPLY|+" ;; + esac +done +kill $(jobs -p) 2>/dev/null + +file=$tmp/regress +cat > $file <<\! +/bin/cat |& +! +chmod +x $file +sleep 10 |& +$file 2> /dev/null || err_exit "parent coprocess prevents script coprocess" +exec 5<&p 6>&p +exec 5<&- 6>&- +kill $(jobs -p) 2>/dev/null + +${SHELL-ksh} |& +cop=$! +exp=Done +print -p $'print hello | cat\nprint '$exp +read -t 5 -p +read -t 5 -p +got=$REPLY +if [[ $got != $exp ]] +then err_exit "${SHELL-ksh} coprocess io failed -- got '$got', expected '$exp'" +fi +exec 5<&p 6>&p +exec 5<&- 6>&- +{ sleep 4; kill $cop; } 2>/dev/null & +spy=$! +if wait $cop 2>/dev/null +then kill $spy 2>/dev/null +else err_exit "coprocess hung after 'exec 5<&p 6>&p; exec 5<&- 6>&-'" +fi +wait + +{ +echo line1 | grep 'line2' +echo line2 | grep 'line1' +} |& +SECONDS=0 count=0 +while read -p -t 10 line +do ((count++)) +done +if (( SECONDS > 8 )) +then err_exit "read -p hanging (SECONDS=$SECONDS count=$count)" +fi +wait $! + +( sleep 3 |& sleep 1 && kill $!; sleep 1; sleep 3 |& sleep 1 && kill $! ) || + err_exit "coprocess cleanup not working correctly" +{ : |& } 2>/dev/null || + err_exit "subshell coprocess lingers in parent" +wait $! + +unset N r e +integer N=5 +e=12345 +( + integer i + for ((i = 1; i <= N; i++)) + do print $i |& + read -p r + print -n $r + wait $! + done + print +) 2>/dev/null | read -t 10 r +[[ $r == $e ]] || err_exit "coprocess timing bug -- expected $e, got '$r'" +r= +( + integer i + for ((i = 1; i <= N; i++)) + do print $i |& + sleep 0.01 + r=$r$(cat <&p) + wait $! + done + print $r +) 2>/dev/null | read -t 10 r +[[ $r == $e ]] || err_exit "coprocess command substitution bug -- expected $e, got '$r'" + +( + /bin/cat |& + sleep 0.01 + exec 6>&p + print -u6 ok + exec 6>&- + sleep 2 + kill $! 2> /dev/null +) && err_exit 'coprocess with subshell would hang' +for sig in IOT ABRT +do if ( trap - $sig ) 2> /dev/null + then if [[ $( { sig=$sig $SHELL 2> /dev/null <<- '++EOF++' + cat |& + pid=$! + trap "print TRAP" $sig + ( + sleep 2 + kill -$sig $$ + sleep 2 + kill -$sig $$ + kill $pid + sleep 2 + kill $$ + ) & + while read -p || (($? > 256)) + do : + done + ++EOF++ + } ) != $'TRAP\nTRAP' ]] 2> /dev/null + then err_exit 'traps when reading from coprocess not working' + fi + break + fi +done + +trap 'sleep_pid=; kill $pid; err_exit "coprocess 1 hung"' TERM +{ sleep 5; kill $$; } & +sleep_pid=$! +builtin cat +cat |& +pid=$! +exec 5<&p 6>&p +exp=hi +print -u6 $exp; read -u5 +[[ $REPLY == "$exp" ]] || err_exit "REPLY failed -- expected '$exp', got '$REPLY'" +exec 6>&- +wait $pid +trap - TERM +[[ $sleep_pid ]] && kill $sleep_pid + +trap 'sleep_pid=; kill $pid; err_exit "coprocess 2 hung"' TERM +{ sleep 5; kill $$; } & +sleep_pid=$! +cat |& +pid=$! +print foo >&p 2> /dev/null || err_exit 'first write of foo to coprocess failed' +print foo >&p 2> /dev/null || err_exit 'second write of foo to coprocess failed' +kill $pid +wait $pid 2> /dev/null +trap - TERM +[[ $sleep_pid ]] && kill $sleep_pid + +trap 'sleep_pid=; kill $pid; err_exit "coprocess 3 hung"' TERM +{ sleep 5; kill $$; } & +sleep_pid=$! +cat |& +pid=$! +print -p foo +print -p bar +read <&p || err_exit 'first read from coprocess failed' +[[ $REPLY == foo ]] || err_exit "first REPLY is $REPLY not foo" +read <&p || err_exit 'second read from coprocess failed' +[[ $REPLY == bar ]] || err_exit "second REPLY is $REPLY not bar" +kill $pid +wait $pid 2> /dev/null +trap - TERM +[[ $sleep_pid ]] && kill $sleep_pid + +exp=ksh +got=$(print -r $'#00315 +COATTRIBUTES=\'label=make \' +# @(#)$Id: libcoshell (AT&T Research) 2008-04-28 $ +_COSHELL_msgfd=5 +{ { (eval \'function fun { trap \":\" 0; return 1; }; trap \"exit 0\" 0; fun; exit 1\') && PATH= print -u$_COSHELL_msgfd ksh; } || { times && echo bsh >&$_COSHELL_msgfd; } || { echo osh >&$_COSHELL_msgfd; }; } >/dev/null 2>&1' | $SHELL 5>&1) +[[ $got == $exp ]] || err_exit "coshell(3) identification sequence failed -- expected '$exp', got '$got'" + +function cop +{ + read + print ok +} + +exp=ok + +cop |& +pid=$! +if print -p yo 2>/dev/null +then read -p got +else got='no coprocess' +fi +[[ $got == $exp ]] || err_exit "main coprocess main query failed -- expected $exp, got '$got'" +kill $pid 2>/dev/null +wait + +cop |& +pid=$! +( +if print -p yo 2>/dev/null +then read -p got +else got='no coprocess' +fi +[[ $got == $exp ]] || err_exit "main coprocess subshell query failed -- expected $exp, got '$got'" +) +kill $pid 2>/dev/null +wait + +exp='no coprocess' + +( +cop |& +print $! > $tmp/pid +) +pid=$(<$tmp/pid) +if print -p yo 2>/dev/null +then read -p got +else got=$exp +fi +[[ $got == $exp ]] || err_exit "subshell coprocess main query failed -- expected $exp, got '$got'" +kill $pid 2>/dev/null +wait + +( +cop |& +print $! > $tmp/pid +) +pid=$(<$tmp/pid) +( +if print -p yo 2>/dev/null +then read -p got +else got=$exp +fi +[[ $got == $exp ]] || err_exit "subshell coprocess subshell query failed -- expected $exp, got '$got'" +kill $pid 2>/dev/null +wait +) + +function mypipe +{ + read; read + print -r -- "$REPLY" +} + +mypipe |& +print -p "hello" +z="$( $bintrue $($bintrue) )" +{ print -p "world";} 2> /dev/null +read -p +[[ $REPLY == world ]] || err_exit "expected 'world' got '$REPLY'" +kill $pid 2>/dev/null +wait + + +function cop +{ + read + print ok +} +exp=ok +cop |& +pid=$! +( +if print -p yo 2>/dev/null +then read -p got +else got='no coprocess' +fi +[[ $got == $exp ]] || err_exit "main coprocess subshell query failed -- expected $exp, got '$got'" +) +kill $pid 2>/dev/null +wait + +tee=$(whence -p tee) +ls -l |& +pid=$! +$tee -a /dev/null <&p > /dev/null +wait $pid +x=$? +[[ $x == 0 ]] || err_exit "coprocess exitval should be 0, not $x" + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/cubetype.sh b/src/cmd/ksh93/tests/cubetype.sh new file mode 100755 index 0000000..dbe4e8b --- /dev/null +++ b/src/cmd/ksh93/tests/cubetype.sh @@ -0,0 +1,213 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 +integer n=2 + +typeset -T Box_t=( + float -h 'height in inches' x=2 + float -h 'width in inches' y=4 + comvar=(top=8 bottom=9) + integer -S count=0 + items=(foo bar) + colors=([wall]=blue [floor]=red) + typeset name=unknown + typeset -L6 status=INIT + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y))) + (( _.count++)) + } + typeset -fh 'distance from the origin' len + depth() + { + print 0 + } + float x=3 +) + +for ((i=0; i < n; i++)) +do +Box_t b=(name=box1) +exp=3 got=${b.x} +[[ "$got" == "$exp" ]] || err_exit "\${b.x} incorrect for iteration $i -- expected $exp, got '$got'" +exp=5 got=$(( b.len )) +(( got == exp )) || err_exit "b.len incorrect for iteration $i -- expected $exp, got '$got = sqrt(${b.x}*${b.x}+${b.y}*${b.y})'" +exp=5 got=${b.len} +[[ "$got" == "$exp" ]] || err_exit "\${b.len} incorrect for iteration $i -- expected $exp, got '$got = sqrt(${b.x}*${b.x}+${b.y}*${b.y})'" +exp=box1 got=${b.name} +[[ "$got" == "${exp}" ]] || err_exit "\${b.name} incorrect for iteration $i -- expected $exp, got '$got'" +exp=2 got=$(( b.count )) +(( got == exp )) || err_exit "b.count incorrect for iteration $i -- expected $exp, got '$got'" +exp=2 got=${b.count} +[[ "$got" == "$exp" ]] || err_exit "\${b.ccount} incorrect for iteration $i -- expected $exp, got '$got'" +b.colors[wall]=green +b.colors[door]=white +exp=3 got=${#b.colors[@]} +[[ "$got" == "$exp" ]] || err_exit "\${#b.colors[@]} incorrect for iteration $i -- expected $exp, got '$got'" +b.comvar.bottom=11 +b.items[1]=bam +b.items[2]=extra +exp=3 got=${#b.items[@]} +[[ ${#b.items[@]} == 3 ]] || err_exit "\${#b.items[@]} incorrect for iteration $i -- expected $exp, got '$got'" +Box_t bb=b +bb.colors[desk]=orange +exp=4 got=${#b.colors[@]} +[[ ${#bb.colors[@]} == 4 ]] || err_exit "\${#bb.colors[@]} incorrect for iteration $i -- expected $exp, got '$got'" +unset b.colors +exp=2 got=${#b.colors[@]} +[[ ${#b.colors[@]} == 2 ]] || err_exit "\${#b.colors[@]} incorrect for iteration $i -- expected $exp, got '$got'" +unset b.items +exp=2 got=${#b.items[@]} +[[ ${#b.items[@]} == 2 ]] || err_exit "\${#b.items[@]} incorrect for iteration $i -- expected $exp, got '$got'" +unset bb.colors +exp=2 got=${#bb.colors[@]} +[[ ${#bb.colors[@]} == 2 ]] || err_exit "\${#bb.colors[@]} incorrect for iteration $i -- expected $exp, got '$got'" +unset bb.items +exp=2 got=${#bb.items[@]} +[[ ${#bb.items[@]} == 2 ]] || err_exit "\${#bb.items[@]} incorrect for iteration $i -- expected $exp, got '$got'" +[[ $b == "$bb" ]] || err_exit "\$b='$b' != \$bb='$bb'" +b.count=0 +unset b bb +done + +typeset -T Cube_t=( + Box_t _=(y=5) + float z=1 + depth() + { + print -r -- $((_.z)) + } + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y + _.z*_.z))) + (( _.count++)) + } + float x=8 + fun() + { + print 'hello world' + } +) + + +for ((i=0; i < n; i++)) +do +Box_t b=(name=box2) +[[ ${b.name} == box2 ]] || err_exit "\${b.name} incorrect -- expected box2, got '${b.name}'" +(( b.len == 5 )) || err_exit "b.len incorrect for box2 -- expected 5, got '$(( b.len ))'" +(( b.count == 1 )) || err_exit "b.count incorrect -- expected 1, got '$(( b.count ))'" +Cube_t c=(name=cube1) +[[ $c == $'(\n\ttypeset -l -E x=8\n\ttypeset -l -E y=5\n\tcomvar=(\n\t\ttop=8\n\t\tbottom=9\n\t)\n\ttypeset -S -l -i count=1\n\ttypeset -a items=(\n\t\tfoo\n\t\tbar\n\t)\n\ttypeset -A colors=(\n\t\t[floor]=red\n\t\t[wall]=blue\n\t)\n\tname=cube1\n\ttypeset -L 6 status=INIT\n\ttypeset -l -E z=1\n)' ]] || err_exit '$c not correct' +[[ ${c.x} == 8 ]] || err_exit '${c.x} != 8' +[[ ${c.depth} == 1 ]] || err_exit '${c.depth} != 1' +[[ ${c.name} == cube1 ]] || err_exit '${c.name} != cube1 ' +[[ $(c.fun) == 'hello world' ]] || err_exit '$(c.fun) != "hello world"' +[[ ${c.fun} == 'hello world' ]] || err_exit '${c.fun} != "hello world"' +(( abs(c.len - sqrt(90)) < 1e-10 )) || err_exit 'c.len != sqrt(90)' +(( c.count == 2 )) || err_exit 'c.count != 2' +(( c.count == b.count )) || err_exit 'c.count != b.count' +c.count=0 +Cube_t d=c +[[ $d == "$c" ]] || err_exit '$d != $c' +eval "Cube_t zzz=$c" +[[ $zzz == "$c" ]] || err_exit '$zzz != $c' +Cube_t zzz=c +[[ $zzz == "$c" ]] || err_exit '$zzz != $c without eval' +xxx=$(typeset -p c) +eval "${xxx/c=/ccc=}" +[[ $ccc == "$c" ]] || err_exit '$ccc != $c' +unset b c d zzz xxx ccc +done +for ((i=0; i < n; i++)) +do +Cube_t cc +cc[2]=(x=2 y=3 name=two colors+=([table]=white) items+=(pencil) z=6) +[[ ${cc[0].x} == 8 ]] || err_exit 'cc[0].x !=8' +[[ ${cc[2].y} == 3 ]] || err_exit '${cc[2].y} != 3' +(( cc[2].y == 3 )) || err_exit '(( cc[2].y != 3))' +[[ ${cc[2].colors[table]} == white ]] || err_exit '${cc[2].colors[table]} != white' +[[ ${cc[2].items[2]} == pencil ]] || err_exit '${cc[2].items[2]} != pencil' +(( cc[2].len == 7 )) || err_exit '(( cc[2].len != 7 ))' +[[ $(cc[2].len) == 7 ]] || err_exit '$(cc[2].len) != 7 ))' +[[ ${cc[2].len} == 7 ]] || err_exit '${cc[2].len} != 7 ))' +(( cc[2].count == 2 )) || err_exit 'cc[2].count != 2' +unset cc[2].x cc[2].y cc[2].z +(( cc[2].len == cc[0].len )) || err_exit 'cc[2].len != cc[0].len' +(( cc[2].len == cc.len )) || err_exit 'cc[2].len != cc.len' +(( cc[2].count == 6 )) || err_exit 'cc[2].count != 6' +unset cc[2].name cc[2].colors cc[2].items +[[ $cc == "${cc[2]}" ]] || err_exit '$cc != ${cc[2]}' +cc.count=0 +unset cc +Cube_t -A cc +cc[two]=(x=2 y=3 name=two colors+=([table]=white) items+=(pencil) z=6) +Cube_t cc[one] +[[ ${#cc[@]} == 2 ]] || err_exit '${#cc[@]} != 2' +[[ ${cc[two].y} == 3 ]] || err_exit '${cc[two].y} != 3' +(( cc[two].y == 3 )) || err_exit '(( cc[two].y != 3))' +[[ ${cc[two].colors[table]} == white ]] || err_exit '${cc[two].colors[table]} != white' +[[ ${cc[two].items[2]} == pencil ]] || err_exit '${cc[two].items[2]} != pencil' +(( cc[two].len == 7 )) || err_exit '(( cc[two].len != 7 ))' +[[ $(cc[two].len) == 7 ]] || err_exit '$(cc[two].len) != 7 ))' +[[ ${cc[two].len} == 7 ]] || err_exit '${cc[two].len} != 7 ))' +(( cc[two].count == 2 )) || err_exit 'cc[two].count != 2' +unset cc[two].x cc[two].y cc[two].z +(( cc[two].len == cc[one].len )) || err_exit 'cc[two].len != cc[one].len' +(( cc[two].count == 4 )) || err_exit 'cc[two].count != 4' +unset cc[two].name unset cc[two].colors cc[two].items +[[ ${cc[one]} == "${cc[two]}" ]] || err_exit '${cc[one]} != ${cc[two]}' +cc[two].count=0 +unset cc +Cube_t cc=( + [one]= + [two]=(x=2 y=3 name=two colors+=([table]=white) z=6) +) +[[ ${#cc[@]} == 2 ]] || err_exit '${#cc[@]} != 2' +[[ ${cc[two].y} == 3 ]] || err_exit '${cc[two].y} != 3' +(( cc[two].y == 3 )) || err_exit '(( cc[two].y != 3))' +[[ ${cc[two].colors[table]} == white ]] || err_exit '${cc[two].colors[table]} != white' +(( cc[two].len == 7 )) || err_exit '(( cc[two].len != 7 ))' +[[ $(cc[two].len) == 7 ]] || err_exit '$(cc[two].len) != 7 ))' +[[ ${cc[two].len} == 7 ]] || err_exit '${cc[two].len} != 7 ))' +(( cc[two].count == 2 )) || err_exit 'cc[two].count != 2' +unset cc[two].x cc[two].y cc[two].z +(( cc[two].len == cc[one].len )) || err_exit 'cc[two].len != cc[one].len' +(( cc[two].count == 4 )) || err_exit 'cc[two].count != 4' +cc[three]=cc[two] +[[ ${cc[two]} == "${cc[three]}" ]] || err_exit "\${cc[two]}='${cc[two]}' != \${cc[three]}='${cc[three]}'" +[[ $cc[two] == "${cc[three]}" ]] || err_exit "\$cc[two]='${cc[two]}' != \${cc[three]}='${cc[three]}'" +exp=3 +got=${#cc[@]} +[[ $got == $exp ]] || err_exit "\${#cc[@]} failed -- expected '$exp', got '$got'" +unset cc[two].name unset cc[two].colors +cc[two].count=0 +unset cc +done + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/enum.sh b/src/cmd/ksh93/tests/enum.sh new file mode 100755 index 0000000..134a0a3 --- /dev/null +++ b/src/cmd/ksh93/tests/enum.sh @@ -0,0 +1,68 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 +enum Color_t=(red green blue orange yellow) +enum -i Sex_t=(Male Female) +for ((i=0; i < 1000; i++)) +do +Color_t x +[[ $x == red ]] || err_exit 'Color_t does not default to red' +x=orange +[[ $x == orange ]] || err_exit '$x should be orange' +( x=violet) 2> /dev/null && err_exit 'x=violet should fail' +x[2]=green +[[ ${x[2]} == green ]] || err_exit '${x[2]} should be green' +(( x[2] == 1 )) || err_exit '((x[2]!=1))' +[[ $((x[2])) == 1 ]] || err_exit '$((x[2]))!=1' +[[ $x == orange ]] || err_exit '$x is no longer orange' +Color_t -A y +y[foo]=yellow +[[ ${y[foo]} == yellow ]] || err_exit '${y[foo]} != yellow' +(( y[foo] == 4 )) || err_exit '(( y[foo] != 4))' +unset y +typeset -a [Color_t] z +z[green]=xyz +[[ ${z[green]} == xyz ]] || err_exit '${z[green]} should be xyz' +[[ ${z[1]} == xyz ]] || err_exit '${z[1]} should be xyz' +z[orange]=bam +[[ ${!z[@]} == 'green orange' ]] || err_exit '${!z[@]} == "green orange"' +unset x +Sex_t x +[[ $x == Male ]] || err_exit 'Sex_t not defaulting to Male' +x=female +[[ $x == Female ]] || err_exit 'Sex_t not case sensitive' +unset x y z +done +( +typeset -T X_t=( typeset name=aha ) +typeset -a[X_t] arr +) 2> /dev/null +[[ $? == 1 ]] || err_exit 'typeset -a[X_t] should generate an error message when X-t is not an enumeriation type' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/exit.sh b/src/cmd/ksh93/tests/exit.sh new file mode 100755 index 0000000..d2b91b7 --- /dev/null +++ b/src/cmd/ksh93/tests/exit.sh @@ -0,0 +1,80 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +function abspath +{ + base=$(basename $SHELL) + cd ${SHELL%/$base} + newdir=$(pwd) + cd ~- + print $newdir/$base +} +#test for proper exit of shell +builtin getconf +ABSHELL=$(abspath) +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } +print exit 0 >.profile +${ABSHELL} <<! +HOME=$PWD \ +PATH=$PATH \ +SHELL=$ABSSHELL \ +$( + v=$(getconf LIBPATH) + for v in ${v//,/ } + do v=${v#*:} + v=${v%%:*} + eval [[ \$$v ]] && eval print -n \" \"\$v=\"\$$v\" + done +) \ +exec -c -a -ksh ${ABSHELL} -c "exit 1" 1>/dev/null 2>&1 +! +status=$(echo $?) +if [[ -o noprivileged && $status != 0 ]] +then err_exit 'exit in .profile is ignored' +elif [[ -o privileged && $status == 0 ]] +then err_exit 'privileged .profile not ignored' +fi +if [[ $(trap 'code=$?; echo $code; trap 0; exit $code' 0; exit 123) != 123 ]] +then err_exit 'exit not setting $?' +fi +cat > run.sh <<- "EOF" + trap 'code=$?; echo $code; trap 0; exit $code' 0 + ( trap 0; exit 123 ) +EOF +if [[ $($SHELL ./run.sh) != 123 ]] +then err_exit 'subshell trap on exit overwrites parent trap' +fi +cd ~- || err_exit "cd back failed" +$SHELL -c 'builtin -f cmd getconf; getconf --"?-version"; exit 0' >/dev/null 2>&1 || err_exit 'ksh plugin exit failed -- was ksh built with CCFLAGS+=$(CC.EXPORT.DYNAMIC)?' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/expand.sh b/src/cmd/ksh93/tests/expand.sh new file mode 100755 index 0000000..2547be8 --- /dev/null +++ b/src/cmd/ksh93/tests/expand.sh @@ -0,0 +1,126 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$Line]: "$@" + ((Errors++)) +} + +integer Errors=0 +Command=${0##*/} + +# {...} expansion tests -- ignore if not supported + +[[ $(print a{0,1}z) == "a0z a1z" ]] || exit 0 + +integer Line=$LINENO+1 +set -- \ + 'ff{c,b,a}' 'ffc ffb ffa' \ + 'f{d,e,f}g' 'fdg feg ffg' \ + '{l,n,m}xyz' 'lxyz nxyz mxyz' \ + '{abc\,def}' '{abc,def}' \ + '{"abc,def"}' '{abc,def}' \ + "{'abc,def'}" '{abc,def}' \ + '{abc}' '{abc}' \ + '\{a,b,c,d,e}' '{a,b,c,d,e}' \ + '{x,y,\{a,b,c}}' 'x} y} {a} b} c}' \ + '{x\,y,\{abc\},trie}' 'x,y {abc} trie' \ + '/usr/{ucb/{ex,edit},lib/{ex,how_ex}}' '/usr/ucb/ex /usr/ucb/edit /usr/lib/ex /usr/lib/how_ex' \ + 'XXXX\{a,b,c\}' 'XXXX{a,b,c}' \ + '{}' '{}' \ + '{ }' '{ }' \ + '}' '}' \ + '{' '{' \ + 'abcd{efgh' 'abcd{efgh' \ + 'foo {1,2} bar' 'foo 1 2 bar' \ + '`print -r -- foo {1,2} bar`' 'foo 1 2 bar' \ + '$(print -r -- foo {1,2} bar)' 'foo 1 2 bar' \ + '{1..10}' '1 2 3 4 5 6 7 8 9 10' \ + '{0..10,braces}' '0..10 braces' \ + '{{0..10},braces}' '0 1 2 3 4 5 6 7 8 9 10 braces' \ + 'x{{0..10},braces}y' 'x0y x1y x2y x3y x4y x5y x6y x7y x8y x9y x10y xbracesy' \ + '{3..3}' '3' \ + 'x{3..3}y' 'x3y' \ + '{10..1}' '10 9 8 7 6 5 4 3 2 1' \ + '{10..1}y' '10y 9y 8y 7y 6y 5y 4y 3y 2y 1y' \ + 'x{10..1}y' 'x10y x9y x8y x7y x6y x5y x4y x3y x2y x1y' \ + '{a..f}' 'a b c d e f' \ + '{f..a}' 'f e d c b a' \ + '{a..A}' '{a..A}' \ + '{A..a}' '{A..a}' \ + '{f..f}' 'f' \ + '{1..f}' '{1..f}' \ + '{f..1}' '{f..1}' \ + '0{1..9} {10..20}' '01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20' \ + '{-1..-10}' '-1 -2 -3 -4 -5 -6 -7 -8 -9 -10' \ + '{-19..0}' '-19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0' \ + '{0..10}' '0 1 2 3 4 5 6 7 8 9 10' \ + '{0..10..1}' '0 1 2 3 4 5 6 7 8 9 10' \ + '{0..10..2}' '0 2 4 6 8 10' \ + '{0..10..3}' '0 3 6 9' \ + '{0..10..0}' '{0..10..0}' \ + '{0..10..-1}' '0' \ + '{10..0}' '10 9 8 7 6 5 4 3 2 1 0' \ + '{10..0..-1}' '10 9 8 7 6 5 4 3 2 1 0' \ + '{10..0..-2}' '10 8 6 4 2 0' \ + '{10..0..-3}' '10 7 4 1' \ + '{10..0..0}' '{10..0..0}' \ + '{10..0..1}' '10' \ + '{a..z..2}' 'a c e g i k m o q s u w y' \ + '{y..b..-3}' 'y v s p m j g d' \ + '{0..0x1000..0x200}' '0 512 1024 1536 2048 2560 3072 3584 4096' \ + '{a,b}{0..2}{z,y}' 'a0z a0y a1z a1y a2z a2y b0z b0y b1z b1y b2z b2y' \ + '{0..0100..8%03o}' '000 010 020 030 040 050 060 070 100' \ + '{0..0100..040%020o}' '00000000000000000000 00000000000000000040 00000000000000000100' \ + '{0..7%03..2u}' '000 001 010 011 100 101 110 111' \ + '{0..10%llu}' '{0..10%llu}' \ + '{0..10%s}' '{0..10%s}' \ + '{0..10%dl}' '{0..10%dl}' \ + '{a,b}{0..3%02..2u}{y,z}' 'a00y a00z a01y a01z a10y a10z a11y a11z b00y b00z b01y b01z b10y b10z b11y b11z' \ + +while (($#>1)) +do ((Line++)) + pattern=$1 + shift + expected=$1 + shift + got=$(eval print -r -- "$pattern") + [[ $got == $expected ]] || err_exit "'$pattern' failed -- expected '$expected' got '$got'" + #print -r -- " '$pattern' '$got' \\" +done + +# ~(N) no expand glob pattern option +set -- ~(N)/dev/null +[[ $# == 1 && $1 == /dev/null ]] || err_exit "~(N)/dev/null not matching /dev/null" +set -- ~(N)/dev/non_existant_file +[[ $# == 0 ]] || err_exit "~(N)/dev/nonexistant not empty" +set -- ""~(N)/dev/non_existant_file +[[ $# == 1 && ! $1 ]] || err_exit '""~(N)/dev/nonexistant not null argument' +set -- ~(N)/dev/non_existant_file"" +[[ $# == 1 && ! $1 ]] || err_exit '~(N)/dev/nonexistent"" not null argument' +for i in ~(N)/dev/non_existent_file +do err_exit "~(N)/dev/non_existent_file in for loop is $i" +done +for i in ""~(N)/dev/non_existent_file +do [[ ! $i ]] || err_exit '""~(N)/dev/non_existent_file not null' +done + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/functions.sh b/src/cmd/ksh93/tests/functions.sh new file mode 100755 index 0000000..fcf3755 --- /dev/null +++ b/src/cmd/ksh93/tests/functions.sh @@ -0,0 +1,1157 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +integer Errors=0 +Command=${0##*/} + +ulimit -c 0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +integer foo=33 +bar=bye +# check for global variables and $0 +function foobar +{ + case $1 in + 1) print -r - "$foo" "$bar";; + 2) print -r - "$0";; + 3) typeset foo=foo + integer bar=10 + print -r - "$foo" "$bar";; + 4) trap 'foo=36' EXIT + typeset foo=20;; + esac +} +function print +{ + command print hi +} +if [[ $(print) != hi ]] +then err_exit "command print not working inside print function" +fi +unset -f print + +if [[ $(foobar 1) != '33 bye' ]] +then err_exit 'global variables not correct' +fi + +if [[ $(foobar 2) != 'foobar' ]] +then err_exit '$0 not correct' +fi + +if [[ $(bar=foo foobar 1) != '33 foo' ]] +then err_exit 'environment override not correct' +fi +if [[ $bar == foo ]] +then err_exit 'scoping error' +fi + +if [[ $(foobar 3) != 'foo 10' ]] +then err_exit non-local variables +fi + +foobar 4 +if [[ $foo != 36 ]] +then err_exit EXIT trap in wrong scope +fi +unset -f foobar || err_exit "cannot unset function foobar" +typeset -f foobar>/dev/null && err_exit "typeset -f has incorrect exit status" + +function foobar +{ + (return 0) +} +> $tmp/test1 +{ +foobar +if [ -r $tmp/test1 ] +then rm -r $tmp/test1 +else err_exit 'return within subshell inside function error' +fi +} +abc() print hi +if [[ $(abc) != hi ]] +then err_exit 'abc() print hi not working' +fi +( unset -f abc ) +if [[ $(abc 2>/dev/null) != hi ]] +then err_exit 'abc() print hi not working after subshell unset' +fi +( + function f + { + exit 1 + } + f + err_exit 'exit from function not working' +) +unset -f foo +function foo +{ + x=2 + ( + x=3 + cd $tmp + print bar + ) + if [[ $x != 2 ]] + then err_exit 'value of x not restored after subshell inside function' + fi +} +x=1 +dir=$PWD +if [[ $(foo) != bar ]] +then err_exit 'cd inside nested subshell not working' +fi +if [[ $PWD != "$dir" ]] +then err_exit 'cd inside nested subshell changes $PWD' +fi +fun() /bin/echo hello +if [[ $(fun) != hello ]] +then err_exit one line functions not working +fi +cat > $tmp/script <<-\! + print -r -- "$1" +! +chmod +x $tmp/script +function passargs +{ + $tmp/script "$@" +} +if [[ $(passargs one) != one ]] +then err_exit 'passing args from functions to scripts not working' +fi +cat > $tmp/script <<-\! + trap 'exit 0' EXIT + function foo + { + /tmp > /dev/null 2>&1 + } + foo +! +if ! $tmp/script +then err_exit 'exit trap incorrectly triggered' +fi +if ! $SHELL -c $tmp/script +then err_exit 'exit trap incorrectly triggered when invoked with -c' +fi +$SHELL -c "trap 'rm $tmp/script' EXIT" +if [[ -f $tmp/script ]] +then err_exit 'exit trap not triggered when invoked with -c' +fi +cat > $tmp/script <<- \EOF + foobar() + { + return + } + shift + foobar + print -r -- "$1" +EOF +chmod +x $tmp/script +if [[ $( $SHELL $tmp/script arg1 arg2) != arg2 ]] +then err_exit 'arguments not restored by posix functions' +fi +function foo +{ + print hello +} +( + function foo + { + print bar + } + if [[ $(foo) != bar ]] + then err_exit 'function definitions inside subshells not working' + fi +) +if [[ $(foo) != hello ]] +then err_exit 'function definitions inside subshells not restored' +fi +unset -f foo bar +function bar +{ + print "$y" +} + +function foo +{ + typeset x=3 + y=$x bar +} +x=1 +if [[ $(foo) != 3 ]] +then err_exit 'variable assignment list not using parent scope' +fi +unset -f foobar +cat > $tmp/foobar <<! +function foobar +{ + print foo +} +! +chmod +x $tmp/foobar +FPATH=$tmp +autoload foobar +if [[ $(foobar 2>/dev/null) != foo ]] +then err_exit 'autoload not working' +fi +unset -f foobar +function foobar +{ + typeset -r x=3 + return 0 +} +( foobar ) 2> /dev/null || err_exit "cannot unset readonly variable in function" +if $SHELL -n 2> /dev/null <<-! + abc() + ! +then err_exit 'abc() without a function body is not a syntax error' +fi +function winpath +{ + usage='q pathname ...' + typeset var format=s + while getopts "$usage" var + do case $var in + q) format=q;; + esac + done + print done +} +if [[ $( (winpath --man 2>/dev/null); print ok) != ok ]] +then err_exit 'getopts --man in functions not working' +fi +if [[ $( (winpath -z 2>/dev/null); print ok) != ok ]] +then err_exit 'getopts with bad option in functions not working' +fi +unset -f x +function x +{ + print "$@" +} +typeset -ft x +if [[ $(x x=y 2>/dev/null) != x=y ]] +then err_exit 'name=value pair args not passed to traced functions' +fi +function bad +{ + false +} +trap 'val=false' ERR +val=true +bad +if [[ $val != false ]] +then err_exit 'set -e not working for functions' +fi +function bad +{ + false + return 0 +} +val=true +bad +if [[ $val != true ]] +then err_exit 'set -e not disabled for functions' +fi +bad() +{ + false + return 0 +} +val=true +bad +if [[ $val != false ]] +then err_exit 'set -e not inherited for posix functions' +fi +trap - ERR + +function myexport +{ + nameref var=$1 + if (( $# > 1 )) + then export $1=$2 + fi + if (( $# > 2 )) + then print $(myexport "$1" "$3" ) + return + fi + typeset val + val=$(export | grep "^$1=") + print ${val#"$1="} +} +export dgk=base +val=$(myexport dgk fun) +if [[ $val != fun ]] +then err_exit "export inside function not working -- expected 'fun', got '$val'" +fi +val=$(export | sed -e '/^dgk=/!d' -e 's/^dgk=//') +if [[ $val != base ]] +then err_exit "export not restored after function call -- expected 'base', got '$val'" +fi +val=$(myexport dgk fun fun2) +if [[ $val != fun2 ]] +then err_exit "export inside function not working with recursive function -- expected 'fun2', got '$val'" +fi +val=$(export | sed -e '/^dgk=/!d' -e 's/^dgk=//') +if [[ $val != base ]] +then err_exit "export not restored after recursive function call -- expected 'base', got '$val'" +fi +val=$(dgk=try3 myexport dgk) +if [[ $val != try3 ]] +then err_exit "name=value not added to export list with function call -- expected 'try3', got '$val'" +fi +val=$(export | sed -e '/^dgk=/!d' -e 's/^dgk=//') +if [[ $val != base ]] +then err_exit "export not restored name=value function call -- expected 'base', got '$val'" +fi +unset zzz +val=$(myexport zzz fun) +if [[ $val != fun ]] +then err_exit "export inside function not working -- expected 'fun', got '$val'" +fi +val=$(export | sed -e '/^zzz=/!d' -e 's/^zzz=//') +if [[ $val ]] +then err_exit "unset varaible exported after function call -- expected '', got '$val'" +fi + +unset zzz +typeset -u zzz +function foo +{ + zzz=abc + print $zzz +} +if [[ $(foo)$(foo) != ABCABC ]] +then err_exit 'attributes on unset variables not saved/restored' +fi +function xpd { + typeset i j=$1 + for i + do print i=$i j=$j + [[ $i == a ]] && xpd b + done + } +if [[ $(xpd a c) != $'i=a j=a\ni=b j=b\ni=c j=a' ]] +then err_exit 'for loop function optimization error' +fi + +typeset -A visited +integer level=0 +function closure +{ + (( $# > 5 )) && return 1 + ((level < 2)) && ((level++)) + typeset tmp r=0 + visited[$1]=1 + + for tmp in $level _$level + do + [[ ${visited[$tmp]} == 1 ]] && continue + closure $tmp $* || r=1 + done + return $r +} +closure 0 || err_exit -u2 'for loop function optimization bug2' +dir=$tmp/dir +mkdir $dir +cd $dir || { err_exit "cd $dir failed"; exit 1; } + +( + function a { + print a + } + function b { + print 1 + a + print 2 + } > /dev/null + typeset -ft a b + PS4=X + b +) > file 2>&1 +[[ $(<file) == *'Xprint 2'* ]] || err_exit 'function trace disabled by function call' +rm -f file + +print 'false' > try +chmod +x try +cat > tst <<- EOF + function ignore + { + ./try + return 0 + } + trap "print error; exit 1" ERR + ignore +EOF +if [[ $($SHELL < tst) == error ]] +then err_exit 'ERR trap not cleared' +fi +FPATH=$dir +print ': This does nothing' > foobar +chmod +x foobar +unset -f foobar +{ foobar; } 2>/dev/null +got=$? +exp=126 +if [[ $got != $exp ]] +then err_exit "function file without function definition processes wrong error -- expected '$exp', got '$got'" +fi +print 'set a b c' > dotscript +[[ $(PATH=$PATH: $SHELL -c '. dotscript;print $#') == 3 ]] || err_exit 'positional parameters not preserved with . script without arguments' +cd ~- || err_exit "cd back failed" +function errcheck +{ + trap 'print ERR; return 1' ERR + false + print ok +} +err=$(errcheck) +[[ $err == ERR ]] || err_exit 'trap on ERR not working in a function' +x="$( + function foobar + { + print ok + } + typeset -f foobar +)" +eval "$x" || err_exit 'typeset -f generates syntax error' +[[ $(foobar) != ok ]] && err_exit 'typeset -f not generating function' +unset -f a b c +a() +{ + b + b + print ${.sh.fun} +} +b() { : ;} +[[ $(a) == a ]] || err_exit '.sh.fun not set correctly in a function' +print $'a(){\ndate\n}' | $SHELL 2> /dev/null || err_exit 'parser error in a(){;date;}' +cat > $tmp/data1 << '++EOF' + 1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 2 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 4 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 8 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 13 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 14 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 15 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 16 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 17 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 18 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 19 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + 20 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +++EOF +cat > $tmp/script << '++EOF' +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +f() +{ +cat <<\M +++EOF +cat $tmp/data1 >> $tmp/script +printf 'M\n}\n\nf\n\n' >> $tmp/script +$SHELL -c $tmp/script > $tmp/data2 +cmp -s $tmp/data[12] || err_exit 'error with long functions' +v=1 +function f +{ + typeset i + for i in 0 1 + do typeset v + v=$i + [[ $v == $i ]] || return 1 + done +} +f || err_exit "typeset optimization bug" +function f +{ + print -r -- "$foo$bar" +} +function g +{ + print -r -- $(bar=bam f) +} +unset foo bar +[[ $(foo=hello g) == hellobam ]] || err_exit 'function exports not passed on' +[[ $(bar=hello g) == bam ]] || err_exit 'function exports not overridden' +unset -f foo +function foo +{ + typeset line=$1 + set +n + while [[ $line ]] + do if [[ ! $varname ]] + then varname=${line%% *} + line=${line##"$varname"?( )} + [[ $line ]] && continue + else print ok + return + fi + varname= + done +} +[[ $(foo 'NUMBERED RECORDSIZE') == ok ]] || err_exit 'optimization error with undefined variable' +unset x +x=$( + set -e + integer count=0 + function err_f + { + if ((count++==3)) + then print failed + else false + fi + } + trap 'err_f' ERR + false +) +[[ $x == failed ]] && err_exit 'ERR trap executed multiple times' +export environment +typeset global +function f +{ + typeset i t local + + for i + do case $i in + [-+]*) set "$@" + continue + ;; + local) local=f + t=$(typeset +f $local) + ;; + global) global=f + t=$(typeset +f $global) + ;; + environment) + environment=f + t=$(typeset +f $environment) + ;; + literal)t=$(typeset +f f) + ;; + positional) + set -- f + t=$(typeset +f $1) + ;; + esac + [[ $t ]] || err_exit "typeset +f \$$i failed" + done +} +f local global environment literal positional +$SHELL -c ' + print exit 0 > '$tmp'/script + chmod +x '$tmp'/script + unset var + var=( ident=1 ) + function fun + { + PATH='$tmp' script + } + fun +' || err_exit "compound variable cleanup before script exec failed" +( $SHELL << \++EOF++ +function main +{ + typeset key + typeset -A entry + entry[a]=( value=aaa ) +} +main +++EOF++ +) 2> /dev/null || err_exit 'function main fails' +optind=$OPTIND +sub() +{ + ( + OPTIND=1 + while getopts :abc OPTION "$@" + do print OPTIND=$OPTIND + done + ) +} +[[ $(sub -a) == OPTIND=2 ]] || err_exit 'OPTIND should be 2' +[[ $(sub -a) == OPTIND=2 ]] || err_exit 'OPTIND should be 2 again' +[[ $OPTIND == "$optind" ]] || err_exit 'OPTIND should be 1' + +function bar +{ + [[ -o nounset ]] && err_exit 'nounset option should not be inherited' +} +function foo +{ + set -o nounset + bar +} +set +o nounset +foo +function red +{ + integer -S d=0 + printf 'red_one %d\n' d + (( d++ )) + return 0 +} +[[ ${ red } != 'red_one 0' ]] && err_exit 'expected red_one 0' +[[ ${ red } != 'red_one 1' ]] && err_exit 'expected red_one 1' +xyz=$0 +function traceback +{ + integer .level=.sh.level + while((--.level>=0)) + do + ((.sh.level = .level)) + [[ $xyz == "$0" ]] || err_exit "\$xyz=$xyz does not match $0 on level ${.level}" + [[ ${.sh.lineno} == "$1" ]] || err_exit "\${.sh.lineno}=${.sh.lineno} does not match $1 on level ${.level}" + done +} + +function foo +{ + typeset xyz=foo + set -- $((LINENO+1)) + bar $LINENO "$1" +} + +function bar +{ + typeset xyz=bar + set -- $((LINENO+2)) + trap 'traceback $LINENO' DEBUG + : $LINENO "$1" +} + +set -- $((LINENO+1)) +foo $LINENO +function .sh.fun.set +{ + print -r -- "${.sh.value}" +} +function abc +{ + : +} +def() +{ + : +} +[[ $(abc) == abc ]] || err_exit '.sh.fun.set not capturing function name' +[[ $(def) == def ]] || err_exit '.sh.fun.set not capturing name()' +unset -f .sh.fun.set + +# tests for debug functions +basefile=${.sh.file} +integer baseline +cat > $tmp/debug << \+++ + : line 1 + + : line 3 ++++ +# Print one line in a call stack +function _Dbg_print_frame +{ + typeset -i pos=$1 + typeset fn=$2 + typeset filename="$3" + typeset -i line=$4 + typeset arg=$5 + shift 5 + if ((pos==0)) + then [[ $filename == "$basefile" ]] || err_exit "filename for level 0 is $filename not $basename" + [[ $arg == DEBUG ]] && ((baseline++)) + [[ $line == "$baseline" ]] || err_exit "line number for level 0 is $line not $baseline" + elif ((pos==1)) + then [[ $filename == "$tmp/debug" ]] || err_exit "filename for level 1 is $filename not $tmp/debug" + [[ $* == 'foo bar' ]] || err_exit "args are '$*', not 'foo bar'" + [[ $line == $arg ]] || err_exit "line number for level 1 is $line not $arg" + else err_exit "level should be 0 or 1 but is $pos" + fi +} + +function _Dbg_debug_trap_handler +{ + + integer .level=.sh.level .max=.sh.level-1 + while((--.level>=0)) + do + ((.sh.level = .level)) + _Dbg_print_frame "${.level}" "$0" "${.sh.file}" "${.sh.lineno}" "${.sh.command##* }" "$@" + done +} + +((baseline=LINENO+2)) +trap '_Dbg_debug_trap_handler' DEBUG +. $tmp/debug foo bar +trap '' DEBUG + +caller() { + integer .level=.sh.level .max=.sh.level-1 + while((--.level>=0)) + do + ((.sh.level = .level)) + print -r -- "${.sh.lineno}" + done +} +bar() { caller;} +set -- $(bar) +[[ $1 == $2 ]] && err_exit ".sh.inline optimization bug" +( $SHELL -c ' function foo { typeset x=$1;print $1;};z=();z=($(foo bar)) ') 2> /dev/null || err_exit 'using a function to set an array in a command sub fails' + +{ +got=$( +s=$(ulimit -s) +if [[ $s == +([[:digit:]]) ]] && (( s < 16384 )) +then ulimit -s 16384 2>/dev/null +fi +$SHELL << \+++ +f() +{ + if (($1>1)) + then x=$(f $(($1-1))) || exit 1 + fi + return 0 +} +f 257 && print ok ++++ +) +} 2>/dev/null +[[ $got == ok ]] || err_exit 'cannot handle comsub depth > 256 in function' + +tmp1=$tmp/job.1 +tmp2=$tmp/job.2 +cat > $tmp1 << +++ +#! $SHELL +print \$\$ ++++ +chmod +x $tmp1 +function foo +{ + typeset pid + $tmp1 > $tmp2 & pid=$! + wait $! + [[ $(< $tmp2) == $pid ]] || err_exit 'wrong pid for & job in function' +} +foo +# make sure compiled functions work +[[ $(tmp=$tmp $SHELL <<- \++++ + cat > $tmp/functions <<- \EOF + function bar + { + print foo + } + function foobar + { + bar + } + EOF + ${SHCOMP:-${SHELL%/*}/shcomp} $tmp/functions > $tmp/foobar + rm -f "$tmp/functions" + chmod +x $tmp/foobar + rm $tmp/!(dir|foobar) + FPATH=$tmp + PATH=$FPATH:$PATH + foobar +++++ +) == foo ]] > /dev/null || err_exit 'functions compiled with shcomp not working' +# tests for compiled . scripts +print $'print hello\nprint world' > $tmp/foo +${SHCOMP:-${SHELL%/*}/shcomp} $tmp/foo > $tmp/foo.sh +val=$(. $tmp/foo.sh) +[[ $val == $'hello\nworld' ]] || err_exit "processing compiled dot files not working correctly val=$val" +# test for functions in shell having side effects. +unset -f foo foobar bar +cd "$tmp" +FPATH=$PWD +PATH=$FPATH:$PATH +cat > foo <<- \EOF + function bar + { + print foobar + } + function foo + { + bar + } +EOF +chmod +x foo +: $(foo) +[[ $(typeset +f) == *foo* ]] && err_exit 'function in subshell leaving side effect of function foo' +unset -f foo bar +: $(foo) +[[ $(typeset +f) == *foo* ]] && err_exit 'function in subshell leaving side effects of function foo after reload' +[[ $(typeset +f) == *bar* ]] && err_exit 'function in subshell leaving side effects of function bar after reload' + +unset -f foo +typeset -A bar +function foo +{ + typeset -i bar[$1].x + bar[$1].x=5 +} +foo sub +[[ ${!bar[@]} == sub ]] || err_exit 'scoping problem with compound array variables' + +function A +{ + trap "> /dev/null;print TRAP A" EXIT + # (( stderr )) && print >&2 +} + +function B +{ + trap "> /dev/null;print TRAP B" EXIT + A +} + +x=$(B) +[[ $x == $'TRAP A\nTRAP B' ]] || err_exit "trap from functions in subshells fails got" $x + +function foo +{ + typeset bar=abc + unset bar +# [[ $bar == bam ]] || err_exit 'unsetting local variable does not expose global variable' + [[ $bar ]] && err_exit 'unsetting local variable exposes global variable' +} +bar=bam +foo + +sleep=$(whence -p sleep) +function gosleep +{ + $sleep 4 +} +x=$( + (sleep 2; pid=; ps | grep sleep | read pid extra; [[ $pid ]] && kill -- $pid) & + gosleep 2> /dev/null + print ok +) +[[ $x == ok ]] || err_exit 'TERM signal sent to last process of function kills the script' + +# verify that $0 does not change with functions defined as fun() +func1() +{ + [[ $0 == "$dol0" ]] || err_exit "\$0 changed in func1() to $0" +} +function func2 +{ + [[ $0 == func2 ]] || err_exit "\$0 changed in func2() to $0" + dol0=func2 + func1 +} +func2 + +{ $SHELL <<- \EOF + function foo + { + typeset rc=0 + unset -f foo + return $rc; + } + foo +EOF +} 2> /dev/null || err_exit 'problem with unset -f foo within function foo' + +val=$($SHELL 2> /dev/null <<- \EOF + .sh.fun.set() { set -x; } + function f1 { print -n ${.sh.fun}; set -o | grep xtrace;} + function f2 { print -n ${.sh.fun}; set -o | grep xtrace;} + f1 + set -o | grep xtrace + f2 +EOF) +[[ $val == f1xtrace*on*off*f2xtrace*on* ]] || err_exit "'.sh.fun.set() { set -x; }' not tracing all functions" + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/glob.sh b/src/cmd/ksh93/tests/glob.sh new file mode 100755 index 0000000..5b7930e --- /dev/null +++ b/src/cmd/ksh93/tests/glob.sh @@ -0,0 +1,374 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -r $'\t'"${Command}[$1] ${@:2}" + ((Errors++)) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer aware=0 contrary=0 Errors=0 ignorant=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +function test_glob +{ + typeset lineno expected drop arg got sep op val add del + lineno=$1 + shift + if [[ $1 == --* ]] + then del=${1#--} + shift + fi + if [[ $1 == ++* ]] + then add=${1#++} + shift + fi + expected=$1 + shift + if (( contrary )) + then if [[ $expected == "<Beware> "* ]] + then expected=${expected#"<Beware> "} + expected="$expected <Beware>" + fi + if [[ $expected == *"<aXb> <abd>"* ]] + then expected=${expected/"<aXb> <abd>"/"<abd> <aXb>"} + fi + fi + for arg + do got="$got$sep<$arg>" + sep=" " + done + if (( ignorant && aware )) + then if [[ $del ]] + then got="<$del> $got" + fi + if [[ $add ]] + then expected="<$add> $expected" + fi + fi + if [[ $got != "$expected" ]] + then 'err_exit' $lineno "glob -- expected '$expected', got '$got'" + fi +} +alias test_glob='test_glob $LINENO' + +function test_case +{ + typeset lineno expected subject pattern got + lineno=$1 expected=$2 subject=$3 pattern=$4 + eval " + case $subject in + $pattern) got='<match>' ;; + *) got='<nomatch>' ;; + esac + " + if [[ $got != "$expected" ]] + then 'err_exit' $lineno "case $subject in $pattern) -- expected '$expected', got '$got'" + fi +} +alias test_case='test_case $LINENO' + +unset undefined + +cd $tmp || { err_exit "cd $tmp failed"; exit 1; } + +export LC_COLLATE=C +touch B b +set -- * +case $* in +'b B') contrary=1 ;; +b|B) ignorant=1 ;; +esac +set -- $(LC_ALL=C /bin/sh -c 'echo [a-c]') +case $* in +B) aware=1 ;; +esac +rm -rf * + +touch a b c d abc abd abe bb bcd ca cb dd de Beware +mkdir bdir + +test_glob '<a> <abc> <abd> <abe> <X*>' a* X* +test_glob '<a> <abc> <abd> <abe>' \a* + +if ( set --nullglob ) 2>/dev/null +then + set --nullglob + + test_glob '<a> <abc> <abd> <abe>' a* X* + + set --nonullglob +fi + +if ( set --failglob ) 2>/dev/null +then + set --failglob + mkdir tmp + touch tmp/l1 tmp/l2 tmp/l3 + + test_glob '' tmp/l[12] tmp/*4 tmp/*3 + test_glob '' tmp/l[12] tmp/*4 tmp/*3 + + rm -r tmp + set --nofailglob +fi + +test_glob '<bdir/>' b*/ +test_glob '<*>' \* +test_glob '<a*>' 'a*' +test_glob '<a*>' a\* +test_glob '<c> <ca> <cb> <a*> <*q*>' c* a\* *q* +test_glob '<**>' "*"* +test_glob '<**>' \** +test_glob '<\.\./*/>' "\.\./*/" +test_glob '<s/\..*//>' 's/\..*//' +test_glob '</^root:/{s/^[!:]*:[!:]*:\([!:]*\).*$/\1/>' "/^root:/{s/^[!:]*:[!:]*:\([!:]*\).*"'$'"/\1/" +test_glob '<abc> <abd> <abe> <bb> <cb>' [a-c]b* +test_glob ++Beware '<abd> <abe> <bb> <bcd> <bdir> <ca> <cb> <dd> <de>' [a-y]*[!c] +test_glob '<abd> <abe>' a*[!c] + +touch a-b aXb + +test_glob '<a-b> <aXb>' a[X-]b + +touch .x .y + +test_glob --Beware '<Beware> <d> <dd> <de>' [!a-c]* + +if mkdir a\*b 2>/dev/null +then + touch a\*b/ooo + + test_glob '<a*b/ooo>' a\*b/* + test_glob '<a*b/ooo>' a\*?/* + test_case '<match>' '!7' '*\!*' + test_case '<match>' 'r.*' '*.\*' + test_glob '<abc>' a[b]c + test_glob '<abc>' a["b"]c + test_glob '<abc>' a[\b]c + test_glob '<abc>' a?c + test_case '<match>' 'abc' 'a"b"c' + test_case '<match>' 'abc' 'a*c' + test_case '<nomatch>' 'abc' '"a?c"' + test_case '<nomatch>' 'abc' 'a\*c' + test_case '<nomatch>' 'abc' 'a\[b]c' + test_case '<match>' '"$undefined"' '""' + test_case '<match>' 'abc' 'a["\b"]c' + + rm -rf mkdir a\*b +fi + +mkdir man +mkdir man/man1 +touch man/man1/sh.1 + +test_glob '<man/man1/sh.1>' */man*/sh.* +test_glob '<man/man1/sh.1>' $(echo */man*/sh.*) +test_glob '<man/man1/sh.1>' "$(echo */man*/sh.*)" + +test_case '<match>' 'abc' 'a***c' +test_case '<match>' 'abc' 'a*****?c' +test_case '<match>' 'abc' '?*****??' +test_case '<match>' 'abc' '*****??' +test_case '<match>' 'abc' '*****??c' +test_case '<match>' 'abc' '?*****?c' +test_case '<match>' 'abc' '?***?****c' +test_case '<match>' 'abc' '?***?****?' +test_case '<match>' 'abc' '?***?****' +test_case '<match>' 'abc' '*******c' +test_case '<match>' 'abc' '*******?' +test_case '<match>' 'abcdecdhjk' 'a*cd**?**??k' +test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??k' +test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??k***' +test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??***k' +test_case '<match>' 'abcdecdhjk' 'a**?**cd**?**??***k**' +test_case '<match>' 'abcdecdhjk' 'a****c**?**??*****' +test_case '<match>' "'-'" '[-abc]' +test_case '<match>' "'-'" '[abc-]' +test_case '<match>' "'\\'" '\\' +test_case '<match>' "'\\'" '[\\]' +test_case '<match>' "'\\'" "'\\'" +test_case '<match>' "'['" '[[]' +test_case '<match>' '[' '[[]' +test_case '<match>' "'['" '[' +test_case '<match>' '[' '[' +test_case '<match>' "'[abc'" "'['*" +test_case '<nomatch>' "'[abc'" '[*' +test_case '<match>' '[abc' "'['*" +test_case '<nomatch>' '[abc' '[*' +test_case '<match>' 'abd' "a[b/c]d" +test_case '<match>' 'a/d' "a[b/c]d" +test_case '<match>' 'acd' "a[b/c]d" +test_case '<match>' "']'" '[]]' +test_case '<match>' "'-'" '[]-]' +test_case '<match>' 'p' '[a-\z]' +test_case '<match>' '"/tmp"' '[/\\]*' +test_case '<nomatch>' 'abc' '??**********?****?' +test_case '<nomatch>' 'abc' '??**********?****c' +test_case '<nomatch>' 'abc' '?************c****?****' +test_case '<nomatch>' 'abc' '*c*?**' +test_case '<nomatch>' 'abc' 'a*****c*?**' +test_case '<nomatch>' 'abc' 'a********???*******' +test_case '<nomatch>' "'a'" '[]' +test_case '<nomatch>' 'a' '[]' +test_case '<nomatch>' "'['" '[abc' +test_case '<nomatch>' '[' '[abc' + +test_glob ++Beware '<b> <bb> <bcd> <bdir>' b* +test_glob '<Beware> <b> <bb> <bcd> <bdir>' [bB]* + +if ( set --nocaseglob ) 2>/dev/null +then + set --nocaseglob + + test_glob '<Beware> <b> <bb> <bcd> <bdir>' b* + test_glob '<Beware> <b> <bb> <bcd> <bdir>' [b]* + test_glob '<Beware> <b> <bb> <bcd> <bdir>' [bB]* + + set --nonocaseglob +fi + +if ( set -f ) 2>/dev/null +then + set -f + + test_glob '<*>' * + + set +f +fi + +if ( set --noglob ) 2>/dev/null +then + set --noglob + + test_glob '<*>' * + + set --glob +fi + +FIGNORE='@(.*|*)' +test_glob '<*>' * + +FIGNORE='@(.*|*c|*e|?)' +test_glob '<a-b> <aXb> <abd> <bb> <bcd> <bdir> <ca> <cb> <dd> <man>' * + +FIGNORE='@(.*|*b|*d|?)' +test_glob '<Beware> <abc> <abe> <bdir> <ca> <de> <man>' * + +FIGNORE= +test_glob '<man/man1/sh.1>' */man*/sh.* + +unset FIGNORE +test_glob '<bb> <ca> <cb> <dd> <de>' ?? +test_glob '<man/man1/sh.1>' */man*/sh.* + +GLOBIGNORE='.*:*' +set -- * +if [[ $1 == '*' ]] +then + GLOBIGNORE='.*:*c:*e:?' + test_glob '<>' * + + GLOBIGNORE='.*:*b:*d:?' + test_glob '<>' * + + unset GLOBIGNORE + test_glob '<>' * + test_glob '<man/man1/sh.1>' */man*/sh.* + + GLOBIGNORE= + test_glob '<man/man1/sh.1>' */man*/sh.* +fi +unset GLOBIGNORE + +function test_sub +{ + x='${subject'$2'}' + eval g=$x + if [[ "$g" != "$3" ]] + then 'err_exit' $1 subject="'$subject' $x failed, expected '$3', got '$g'" + fi +} +alias test_sub='test_sub $LINENO' + +set --noglob --nobraceexpand + +subject='A regular expressions test' + +test_sub '/e/#' 'A r#gular expressions test' +test_sub '//e/#' 'A r#gular #xpr#ssions t#st' +test_sub '/[^e]/#' '# regular expressions test' +test_sub '//[^e]/#' '###e######e###e########e##' +test_sub '/+(e)/#' 'A r#gular expressions test' +test_sub '//+(e)/#' 'A r#gular #xpr#ssions t#st' +test_sub '/@-(e)/#' 'A r#gular expressions test' +test_sub '//@-(e)/#' 'A r#gular #xpr#ssions t#st' +test_sub '/?(e)/#' '#A regular expressions test' +test_sub '//?(e)/#' '#A# #r#g#u#l#a#r# #x#p#r#s#s#i#o#n#s# #t#s#t#' +test_sub '/*(e)/#' '#A regular expressions test' +test_sub '//*(e)/#' '#A# #r#g#u#l#a#r# #x#p#r#s#s#i#o#n#s# #t#s#t#' +test_sub '//@(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//@-(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//+(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//+-(e)/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//@(+(e))/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//@(+-(e))/[\1]' 'A r[e]gular [e]xpr[e]ssions t[e]st' +test_sub '//-(e)/#' 'A regular expressions test' +test_sub '//--(e)/#' 'A regular expressions test' +test_sub '//?(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//{0,1}(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//*(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//{0,}(e)/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//@(?(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//@({0,1}(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//@(*(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '//@({0,}(e))/[\1]' '[]A[] []r[e]g[]u[]l[]a[]r[] [e]x[]p[]r[e]s[]s[]i[]o[]n[]s[] []t[e]s[]t[]' +test_sub '/?-(e)/#' '#A regular expressions test' +test_sub '/@(?-(e))/[\1]' '[]A regular expressions test' +test_sub '/!(e)/#' '#' +test_sub '//!(e)/#' '#' +test_sub '/@(!(e))/[\1]' '[A regular expressions test]' +test_sub '//@(!(e))/[\1]' '[A regular expressions test]' + +subject='e' + +test_sub '/!(e)/#' '#e' +test_sub '//!(e)/#' '#e#' +test_sub '/!(e)/[\1]' '[]e' +test_sub '//!(e)/[\1]' '[]e[]' +test_sub '/@(!(e))/[\1]' '[]e' +test_sub '//@(!(e))/[\1]' '[]e[]' + +subject='a' + +test_sub '/@(!(a))/[\1]' '[]a' +test_sub '//@(!(a))/[\1]' '[]a[]' + +subject='aha' + +test_sub '/@(!(a))/[\1]' '[aha]' +test_sub '//@(!(a))/[\1]' '[aha]' +test_sub '/@(!(aha))/[\1]' '[ah]a' +test_sub '//@(!(aha))/[\1]' '[ah][a]' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/grep.sh b/src/cmd/ksh93/tests/grep.sh new file mode 100755 index 0000000..480f823 --- /dev/null +++ b/src/cmd/ksh93/tests/grep.sh @@ -0,0 +1,105 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +function grep +{ + # + # SHELL VERSION OF GREP + # + vflag= xflag= cflag= lflag= nflag= + set -f + while ((1)) # look for grep options + do case "$1" in + -v*) vflag=1;; + -x*) xflag=1;; + -c*) cflag=1;; + -l*) lflag=1;; + -n*) nflag=1;; + -b*) print 'b option not supported';; + -e*) shift;expr="$1";; + -f*) shift;expr=$(< $1);; + -*) print $0: 'unknown flag';return 2;; + *) + if test "$expr" = '' + then expr="$1";shift + fi + test "$xflag" || expr="*${expr}*" + break;; + esac + shift # next argument + done + noprint=$vflag$cflag$lflag # don't print if these flags are set + integer n=0 c=0 tc=0 nargs=$# # initialize counters + for i in "$@" # go thru the files + do if ((nargs<=1)) + then fname='' + else fname="$i": + fi + test "$i" && exec 0< $i # open file if necessary + while read -r line # read in a line + do let n=n+1 + case "$line" in + $expr) # line matches pattern + test "$noprint" || print -r -- "$fname${nflag:+$n:}$line" + let c=c+1 ;; + *) # not a match + if test "$vflag" + then print -r -- "$fname${nflag:+$n:}$line" + fi;; + esac + done + if test "$lflag" && ((c)) + then print -r -- "$i" + fi + let tc=tc+c n=0 c=0 + done + test "$cflag" && print $tc # print count if cflag is set + let tc # set the return value +} + +cat > $tmp/grep <<\! +this is a food bar test +to see how many lines find both foo and bar. +Some line contain foo only, +and some lines contain bar only. +However, many lines contain both foo and also bar. +A line containing foobar should also be counted. +There should be six lines with foo and bar. +There are only two line with out foo but with bar. +! + +if (( $(grep -c 'foo*bar' $tmp/grep ) != 6)) +then err_exit +fi + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/heredoc.sh b/src/cmd/ksh93/tests/heredoc.sh new file mode 100755 index 0000000..a8d8a72 --- /dev/null +++ b/src/cmd/ksh93/tests/heredoc.sh @@ -0,0 +1,496 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +f=$tmp/here1 +g=$tmp/here2 +cat > $f <<! +hello world +! +if [[ $(<$f) != 'hello world' ]] +then err_exit "'hello world' here doc not working" +fi +cat > $g <<\! +hello world +! +cmp $f $g 2> /dev/null || err_exit "'hello world' quoted here doc not working" +cat > $g <<- ! + hello world +! +cmp $f $g 2> /dev/null || err_exit "'hello world' tabbed here doc not working" +cat > $g <<- \! + hello world +! +cmp $f $g 2> /dev/null || err_exit "'hello world' quoted tabbed here doc not working" +x=hello +cat > $g <<! +$x world +! +cmp $f $g 2> /dev/null || err_exit "'$x world' here doc not working" +cat > $g <<! +$(print hello) world +! +cmp $f $g 2> /dev/null || err_exit "'$(print hello) world' here doc not working" +cat > $f <<\!! +!@#$%%^^&*()_+~"::~;'`<>?/.,{}[] +!! +if [[ $(<$f) != '!@#$%%^^&*()_+~"::~;'\''`<>?/.,{}[]' ]] +then err_exit "'hello world' here doc not working" +fi +cat > $g <<!! +!@#\$%%^^&*()_+~"::~;'\`<>?/.,{}[] +!! +cmp $f $g 2> /dev/null || err_exit "unquoted here doc not working" +exec 3<<! + foo +! +if [[ $(<&3) != ' foo' ]] +then err_exit "leading tabs stripped with <<!" +fi +$SHELL -c " +eval `echo 'cat <<x'` "|| err_exit "eval `echo 'cat <<x'` core dumps" +cat > /dev/null <<EOF # comments should not cause core dumps +abc +EOF +cat >$g << : +: +: +cmp /dev/null $g 2> /dev/null || err_exit "empty here doc not working" +x=$(print $( cat <<HUP +hello +HUP +) +) +if [[ $x != hello ]] +then err_exit "here doc inside command sub not working" +fi +y=$(cat <<! +${x:+${x}} +! +) +if [[ $y != "${x:+${x}}" ]] +then err_exit '${x:+${x}} not working in here document' +fi +$SHELL -c ' +x=0 +while (( x < 100 )) +do ((x = x+1)) + cat << EOF +EOF +done +' 2> /dev/null || err_exit '100 empty here docs fails' +{ + print 'builtin -d cat + cat <<- EOF' + for ((i=0; i < 100; i++)) + do print XXXXXXXXXXXXXXXXXXXX + done + print ' XXX$(date)XXXX + EOF' +} > $f +chmod +x "$f" +$SHELL "$f" > /dev/null || err_exit "large here-doc with command substitution fails" +x=$(/bin/cat <<! +$0 +! +) +[[ "$x" == "$0" ]] || err_exit '$0 not correct inside here documents' +$SHELL -c 'x=$( +cat << EOF +EOF)' 2> /dev/null || err_exit 'here-doc cannot be terminated by )' +if [[ $( IFS=:;cat <<-! + $IFS$(print hi)$IFS + !) != :hi: ]] +then err_exit '$IFS unset by command substitution in here docs' +fi +if x=$($SHELL -c 'cat <<< "hello world"' 2> /dev/null) +then [[ $x == 'hello world' ]] || err_exit '<<< documents not working' + x=$($SHELL -c 'v="hello world";cat <<< $v' 2> /dev/null) + [[ $x == 'hello world' ]] || err_exit '<<< documents with $x not working' + x=$($SHELL -c 'v="hello world";cat <<< "$v"' 2> /dev/null) + [[ $x == 'hello world' ]] || err_exit '<<< documents with $x not working' +else err_exit '<<< syntax not supported' +fi +if [[ $(cat << EOF #testing +#abc +abc +EOF) != $'#abc\nabc' ]] +then err_exit 'comments not preserved in here-documents' +fi +cat > "$f" <<- '!!!!' + builtin cat + : << EOF + $PWD + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + EOF + command exec 3>&- 4>&- 5>&- 6>&- 7>&- 8>&- 9>&- + x=abc + cat << EOF + $x + EOF +!!!! +chmod 755 "$f" +if [[ $($SHELL "$f") != abc ]] +then err_exit 'here document descritor was closed' +fi +cat > "$f" <<- '!!!!' + exec 0<&- + foobar() + { + /bin/cat <<- ! + foobar + ! + } + : << EOF + $PWD + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + EOF + print -r -- "$(foobar)" +!!!! +if [[ $($SHELL "$f") != foobar ]] +then err_exit 'here document with stdin closed failed' +fi +printf $'cat <<# \\!!!\n\thello\n\t\tworld\n!!!' > $f +[[ $($SHELL "$f") == $'hello\n\tworld' ]] || err_exit "<<# not working for quoted here documents" +printf $'w=world;cat <<# !!!\n\thello\n\t\t$w\n!!!' > $f +[[ $($SHELL "$f") == $'hello\n\tworld' ]] || err_exit "<<# not working for non-quoted here documents" +[[ $( $SHELL <<- \++++ + S=( typeset a ) + function S.a.get + { + .sh.value=$__a + } + __a=1234 + cat <<-EOF + ${S.a} + EOF +++++ +) == 1234 ]] 2> /dev/null || err_exit 'here document with get discipline failed' +[[ $($SHELL -c 'g(){ print ok;}; cat <<- EOF + ${ g;} + EOF + ' 2> /dev/null) == ok ]] || err_exit '${ command;} not working in heredoc' +script=$f +{ +for ((i=0; i < 406; i++)) +do print ': 23456789012345678' +done +print : 123456789123 +cat <<- \EOF +eval "$( + { cat ; } <<MARKER + print hello + MARKER +)" +EOF +} > $script +chmod +x $script +[[ $($SHELL $script) == hello ]] 2> /dev/null || err_exit 'heredoc embeded in command substitution fails at buffer boundary' + +got=$( cat << EOF +\ +abc +EOF) +[[ $got == abc ]] || err_exit 'line continuation at start of buffer not working' + +tmpfile1=$tmp/file1 +tmpfile2=$tmp/file2 +function gendata +{ + typeset -RZ3 i + for ((i=0; i < 500; i++)) + do print -r -- "=====================This is line $i=============" + done +} + +cat > $tmpfile1 <<- +++ + function foobar + { + cat << XXX + $(gendata) + XXX + } + cat > $tmpfile2 <<- EOF + \$(foobar) + $(gendata) +EOF ++++ +chmod +x $tmpfile1 +$SHELL $tmpfile1 +set -- $(wc < $tmpfile2) +(( $1 == 1000 )) || err_exit "heredoc $1 lines, should be 1000 lines" +(( $2 == 4000 )) || err_exit "heredoc $2 words, should be 4000 words" + +# comment with here document looses line number count +integer line=$((LINENO+5)) +function tst +{ + [[ $1 == $2 ]] || echo expected $1, got $2 +} +tst $line $LINENO <<"!" # this comment affects LINENO # +1 +! +(( (line+=3) == LINENO )) || err_exit "line number=$LINENO should be $line" + +[[ $($SHELL -c 'wc -c <<< ""' 2> /dev/null) == *1 ]] || err_exit '<<< with empty string not working' + +mkdir $tmp/functions +cat > $tmp/functions/t2 <<\!!! +function t2 +{ +cat <<EOF | sed 's/1234567890/qwertyuiopasdfghj/' +${1} +EOF +} +!!! + +FPATH=$tmp/functions +foo=${ +cat <<EOF +1 34567890 $(t2 1234567890 ) 0123456789012345678901234567890123 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111 1 + +2 34567890 $(t2 1234567890 ) 0123456789012345678901234567890123 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222222 +222222222222222222222222222222222222222222222222222222222222 2 + +3 34567890 $(t2 1234567890 ) 0123456789012345678901234567890123 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333333 +333333333333333333333333333333333333333333333333333333333333 3 + +4 34567890 $(t2 1234567890 ) 0123456789012345678901234567890123 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444444 +444444444444444444444444444444444444444444444444444444444444 4 + +5 34567890 $(t2 1234567890 ) 0123456789012345678901234567890123 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555555 +555555555555555555555555555555555555555555555555555555555555 5 + +6 34567890 $(t2 1234567890 ) 0123456789012345678901234567890123 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666666 +666666666666666666666666666666666666666666666666666666666666 6 + +7 34567890 $(t2 1234567890 ) 0123456789012345678901234567890123 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777777 +777777777777777777777777777777777777777777777777777777777777 7 + +8 34567890 $(t2 1234567890 ) 0123456789012345678901234567890123 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888888 +888888888888888888888888888888888888888888888888888888888888 8 + +9 34567890 $(t2 1234567890 ) 0123456789012345678901234567890123 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999999 +999999999999999999999999999999999999999999999999999999999999 9 + +10 4567890 $(t2 1234567890 ) 0123456789012345678901234567890123 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +101010101010101010101010101010101010101010101010101010101010103 +1010101010101010101010101010101010101010101010101010101010 END + +EOF +} +[[ ${#foo} == 10238 ]] || err_exit 'large here docs containing command subs of dynamically loaded functions fails' + +{ + print $'FOO=1\nBAR=foobarbaz' + print -- 'cat <<#EOF' + integer i + for ((i=0; i < 50000; i++)) + do print -r -- ' $(($FOO + 1))' + print -r -- ' $BAR meep' + done + print EOF +} > $f +$SHELL $f > $g +[[ $(grep meep $g | grep -v foobar) != '' ]] && err_exit 'here-doc loosing $var expansions on boundaries in rare cases' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/io.sh b/src/cmd/ksh93/tests/io.sh new file mode 100755 index 0000000..bed0fd4 --- /dev/null +++ b/src/cmd/ksh93/tests/io.sh @@ -0,0 +1,484 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +unset HISTFILE + +function fun +{ + while command exec 3>&1 + do break + done 2> /dev/null + print -u3 good +} +print 'read -r a; print -r -u$1 -- "$a"' > $tmp/mycat +chmod 755 $tmp/mycat +for ((i=3; i < 10; i++)) +do + eval "a=\$(print foo | $tmp/mycat" $i $i'>&1 > /dev/null |cat)' 2> /dev/null + [[ $a == foo ]] || err_exit "bad file descriptor $i in comsub script" +done +exec 3> /dev/null +[[ $(fun) == good ]] || err_exit 'file 3 closed before subshell completes' +exec 3>&- +cd $tmp || { err_exit "cd $tmp failed"; exit ; } +print foo > file1 +print bar >> file1 +if [[ $(<file1) != $'foo\nbar' ]] +then err_exit 'append (>>) not working' +fi +set -o noclobber +exec 3<> file1 +read -u3 line +exp=foo +if [[ $line != $exp ]] +then err_exit "read on <> fd failed -- expected '$exp', got '$line'" +fi +if ( 4> file1 ) 2> /dev/null +then err_exit 'noclobber not causing exclusive open' +fi +set +o noclobber + +FDFS=( + ( dir=/proc/self/fd semantics='open' ) + ( dir=/proc/$$/fd semantics='open' ) + ( dir=/dev/fd semantics='open|dup' ) + ( dir=/dev/fd semantics='dup' ) +) +for ((fdfs=0; fdfs<${#FDFS[@]}-1; fdfs++)) +do [[ -e ${FDFS[fdfs].dir} ]] && { command : > ${FDFS[fdfs].dir}/1; } 2>/dev/null >&2 && break +done + +exec 3<> file1 +if command exec 4< ${FDFS[fdfs].dir}/3 +then read -u3 got + read -u4 got + exp='foo|bar' + case $got in + foo) semantics='open' ;; + bar) semantics='dup' ;; + *) semantics='failed' ;; + esac + [[ $semantics == @(${FDFS[fdfs].semantics}) ]] || err_exit "'4< ${FDFS[fdfs].dir}/3' $semantics semantics instead of ${FDFS[fdfs].semantics} -- expected '$exp', got '$got'" +fi + +# 2004-11-25 ancient /dev/fd/N redirection bug fix +got=$( + { + print -n 1 + print -n 2 > ${FDFS[fdfs].dir}/2 + print -n 3 + print -n 4 > ${FDFS[fdfs].dir}/2 + } 2>&1 +) +exp='1234|4' +case $got in +1234) semantics='dup' ;; +4) semantics='open' ;; +*) semantics='failed' ;; +esac +[[ $semantics == @(${FDFS[fdfs].semantics}) ]] || err_exit "${FDFS[fdfs].dir}/N $semantics semantics instead of ${FDFS[fdfs].semantics} -- expected '$exp', got '$got'" + +cat > close0 <<\! +exec 0<&- +echo $(./close1) +! +print "echo abc" > close1 +chmod +x close0 close1 +x=$(./close0) +if [[ $x != "abc" ]] +then err_exit "picked up file descriptor zero for opening script file" +fi +cat > close0 <<\! + for ((i=0; i < 1100; i++)) + do exec 4< /dev/null + read -u4 + done + exit 0 +! +./close0 2> /dev/null || err_exit "multiple exec 4< /dev/null can fail" +$SHELL -c ' + trap "rm -f in out" EXIT + for ((i = 0; i < 1000; i++)) + do print -r -- "This is a test" + done > in + > out + exec 1<> out + builtin cat + print -r -- "$(<in)" + cmp -s in out' 2> /dev/null +[[ $? == 0 ]] || err_exit 'builtin cat truncates files' +cat >| script <<-\! +print hello +( exec 3<&- 4<&-) +exec 3<&- 4<&- +print world +! +chmod +x script +[[ $( $SHELL ./script) == $'hello\nworld' ]] || err_exit 'closing 3 & 4 causes script to fail' +cd ~- || err_exit "cd back failed" +( exec > '' ) 2> /dev/null && err_exit '> "" does not fail' +unset x +( exec > ${x} ) 2> /dev/null && err_exit '> $x, where x null does not fail' +exec <<! +foo +bar +! +( exec 0< /dev/null) +read line +if [[ $line != foo ]] +then err_exit 'file descriptor not restored after exec in subshell' +fi +exec 3>&- 4>&- +[[ $( { + read -r line; print -r -- "$line" + ( + read -r line; print -r -- "$line" + ) & wait + while read -r line + do print -r -- "$line" + done + } << ! +line 1 +line 2 +line 3 +!) == $'line 1\nline 2\nline 3' ]] || err_exit 'read error with subshells' +# 2004-05-11 bug fix +cat > $tmp/1 <<- ++EOF++ + script=$tmp/2 + trap "rm -f \$script" EXIT + exec 9> \$script + for ((i=3; i<9; i++)) + do eval "while read -u\$i; do : ; done \$i</dev/null" + print -u9 "exec \$i< /dev/null" + done + for ((i=0; i < 60; i++)) + do print -u9 -f "%.80c\n" ' ' + done + print -u9 'print ok' + exec 9<&- + chmod +x \$script + \$script +++EOF++ +chmod +x $tmp/1 +[[ $($SHELL $tmp/1) == ok ]] || err_exit "parent i/o causes child script to fail" +# 2004-12-20 redirection loss bug fix +cat > $tmp/1 <<- \++EOF++ + function a + { + trap 'print ok' EXIT + : > /dev/null + } + a +++EOF++ +chmod +x $tmp/1 +[[ $($tmp/1) == ok ]] || err_exit "trap on EXIT loses last command redirection" +print > /dev/null {n}> $tmp/1 +[[ ! -s $tmp/1 ]] && newio=1 +if [[ $newio && $(print hello | while read -u$n; do print $REPLY; done {n}<&0) != hello ]] +then err_exit "{n}<&0 not working with for loop" +fi +[[ $({ read -r; read -u3 3<&0; print -- "$REPLY" ;} <<! +hello +world +!) == world ]] || err_exit 'I/O not synchronized with <&' +x="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNSPQRSTUVWXYZ1234567890" +for ((i=0; i < 62; i++)) +do printf "%.39c\n" ${x:i:1} +done > $tmp/seek +if command exec 3<> $tmp/seek +then (( $(3<#) == 0 )) || err_exit "not at position 0" + (( $(3<# ((EOF))) == 40*62 )) || err_exit "not at end-of-file" + command exec 3<# ((40*8)) || err_exit "absolute seek fails" + read -u3 + [[ $REPLY == +(i) ]] || err_exit "expected iiii..., got $REPLY" + [[ $(3<#) == $(3<# ((CUR)) ) ]] || err_exit '$(3<#)!=$(3<#((CUR)))' + command exec 3<# ((CUR+80)) + read -u3 + [[ $REPLY == {39}(l) ]] || err_exit "expected lll..., got $REPLY" + command exec 3<# ((EOF-80)) + read -u3 + [[ $REPLY == +(9) ]] || err_exit "expected 999..., got $REPLY" + command exec 3># ((80)) + print -u3 -f "%.39c\n" @ + command exec 3># ((80)) + read -u3 + [[ $REPLY == +(@) ]] || err_exit "expected @@@..., got $REPLY" + read -u3 + [[ $REPLY == +(d) ]] || err_exit "expected ddd..., got $REPLY" + command exec 3># ((EOF)) + print -u3 -f "%.39c\n" ^ + (( $(3<# ((CUR-0))) == 40*63 )) || err_exit "not at extended end-of-file" + command exec 3<# ((40*62)) + read -u3 + [[ $REPLY == +(^) ]] || err_exit "expected ddd..., got $REPLY" + command exec 3<# ((0)) + command exec 3<# *jjjj* + read -u3 + [[ $REPLY == {39}(j) ]] || err_exit "<# pattern failed" + [[ $(command exec 3<## *llll*) == {39}(k) ]] || err_exit "<## pattern not saving standard output" + read -u3 + [[ $REPLY == {39}(l) ]] || err_exit "<## pattern failed to position" + command exec 3<# *abc* + read -u3 && err_exit "not found pattern not positioning at eof" + cat $tmp/seek | read -r <# *WWW* + [[ $REPLY == *WWWWW* ]] || err_exit '<# not working for pipes' + { < $tmp/seek <# ((2358336120)) ;} 2> /dev/null || err_exit 'long seek not working' +else err_exit "$tmp/seek: cannot open for reading" +fi +command exec 3<&- || 'cannot close 3' +for ((i=0; i < 62; i++)) +do printf "%.39c\n" ${x:i:1} +done > $tmp/seek +if command exec {n}<> $tmp/seek +then { command exec {n}<#((EOF)) ;} 2> /dev/null || err_exit '{n}<# not working' + if $SHELL -c '{n}</dev/null' 2> /dev/null + then (( $({n}<#) == 40*62)) || err_exit '$({n}<#) not working' + else err_exit 'not able to parse {n}</dev/null' + fi +fi +$SHELL -ic ' +{ + print -u2 || exit 2 + print -u3 || exit 3 + print -u4 || exit 4 + print -u5 || exit 5 + print -u6 || exit 6 + print -u7 || exit 7 + print -u8 || exit 8 + print -u9 || exit 9 +} 3> /dev/null 4> /dev/null 5> /dev/null 6> /dev/null 7> /dev/null 8> /dev/null 9> /dev/null' > /dev/null 2>&1 +exitval=$? +(( exitval )) && err_exit "print to unit $exitval failed" +$SHELL -c "{ > $tmp/1 ; date;} >&- 2> /dev/null" > $tmp/2 +[[ -s $tmp/1 || -s $tmp/2 ]] && err_exit 'commands with standard output closed produce output' +$SHELL -c "$SHELL -c ': 3>&1' 1>&- 2>/dev/null" && err_exit 'closed standard output not passed to subshell' +[[ $(cat <<- \EOF | $SHELL + do_it_all() + { + dd 2>/dev/null # not a ksh93 buildin + return $? + } + do_it_all ; exit $? + hello world +EOF) == 'hello world' ]] || err_exit 'invalid readahead on stdin' +$SHELL -c 'exec 3>; /dev/null' 2> /dev/null && err_exit '>; with exec should be an error' +$SHELL -c ': 3>; /dev/null' 2> /dev/null || err_exit '>; not working with at all' +print hello > $tmp/1 +if ! $SHELL -c "false >; $tmp/1" 2> /dev/null +then [[ $(<$tmp/1) == hello ]] || err_exit '>; not preserving file on failure' +fi +if ! $SHELL -c "sed -e 's/hello/hello world/' $tmp/1" >; $tmp/1 2> /dev/null +then [[ $(<$tmp/1) == 'hello world' ]] || err_exit '>; not updating file on success' +fi + +$SHELL -c 'exec 3<>; /dev/null' 2> /dev/null && err_exit '<>; with exec should be an error' +$SHELL -c ': 3<>; /dev/null' 2> /dev/null || err_exit '<>; not working with at all' +print $'hello\nworld' > $tmp/1 +if ! $SHELL -c "false <>; $tmp/1" 2> /dev/null +then [[ $(<$tmp/1) == $'hello\nworld' ]] || err_exit '<>; not preserving file on failure' +fi +if ! $SHELL -c "head -1 $tmp/1" <>; $tmp/1 2> /dev/null +then [[ $(<$tmp/1) == hello ]] || err_exit '<>; not truncating file on success of head' +fi +print $'hello\nworld' > $tmp/1 +if ! $SHELL -c head < $tmp/1 <#((6)) <>; $tmp/1 2> /dev/null +then [[ $(<$tmp/1) == world ]] || err_exit '<>; not truncating file on success of behead' +fi + +unset y +read -n1 y <<! +abc +! +if [[ $y != a ]] +then err_exit 'read -n1 not working' +fi +unset a +{ read -N3 a; read -N1 b;} <<! +abcdefg +! +[[ $a == abc ]] || err_exit 'read -N3 here-document not working' +[[ $b == d ]] || err_exit 'read -N1 here-document not working' +read -n3 a <<! +abcdefg +! +[[ $a == abc ]] || err_exit 'read -n3 here-document not working' +(print -n a; sleep 1; print -n bcde) | { read -N3 a; read -N1 b;} +[[ $a == abc ]] || err_exit 'read -N3 from pipe not working' +[[ $b == d ]] || err_exit 'read -N1 from pipe not working' +(print -n a; sleep 1; print -n bcde) |read -n3 a +[[ $a == a ]] || err_exit 'read -n3 from pipe not working' +if mkfifo $tmp/fifo 2> /dev/null +then (print -n a; sleep 2; print -n bcde) > $tmp/fifo & + { + read -u5 -n3 -t3 a || err_exit 'read -n3 from fifo timed out' + read -u5 -n1 -t3 b || err_exit 'read -n1 from fifo timed out' + } 5< $tmp/fifo + exp=a + got=$a + [[ $got == "$exp" ]] || err_exit "read -n3 from fifo failed -- expected '$exp', got '$got'" + exp=b + got=$b + [[ $got == "$exp" ]] || err_exit "read -n1 from fifo failed -- expected '$exp', got '$got'" + rm -f $tmp/fifo + wait + mkfifo $tmp/fifo 2> /dev/null + (print -n a; sleep 2; print -n bcde) > $tmp/fifo & + { + read -u5 -N3 -t3 a || err_exit 'read -N3 from fifo timed out' + read -u5 -N1 -t3 b || err_exit 'read -N1 from fifo timed out' + } 5< $tmp/fifo + exp=abc + got=$a + [[ $got == "$exp" ]] || err_exit "read -N3 from fifo failed -- expected '$exp', got '$got'" + exp=d + got=$b + [[ $got == "$exp" ]] || err_exit "read -N1 from fifo failed -- expected '$exp', got '$got'" + wait +fi +( + print -n 'prompt1: ' + sleep .1 + print line2 + sleep .1 + print -n 'prompt2: ' + sleep .1 +) | { + read -t2 -n 1000 line1 + read -t2 -n 1000 line2 + read -t2 -n 1000 line3 + read -t2 -n 1000 line4 +} +[[ $? == 0 ]] && err_exit 'should have timed out' +[[ $line1 == 'prompt1: ' ]] || err_exit "line1 should be 'prompt1: '" +[[ $line2 == line2 ]] || err_exit "line2 should be line2" +[[ $line3 == 'prompt2: ' ]] || err_exit "line3 should be 'prompt2: '" +[[ ! $line4 ]] || err_exit "line4 should be empty" + +if $SHELL -c "export LC_ALL=C.UTF-8; c=$'\342\202\254'; [[ \${#c} == 1 ]]" 2>/dev/null +then lc_utf8=C.UTF-8 +else lc_utf8='' +fi + +typeset -a e o=(-n2 -N2) +integer i +set -- \ + 'a' 'bcd' 'a bcd' 'ab cd' \ + 'ab' 'cd' 'ab cd' 'ab cd' \ + 'abc' 'd' 'ab cd' 'ab cd' \ + 'abcd' '' 'ab cd' 'ab cd' +while (( $# >= 3 )) +do a=$1 + b=$2 + e[0]=$3 + e[1]=$4 + shift 4 + for ((i = 0; i < 2; i++)) + do for lc_all in C $lc_utf8 + do g=$(LC_ALL=$lc_all $SHELL -c "{ print -n '$a'; sleep 0.2; print -n '$b'; sleep 0.2; } | { read ${o[i]} a; print -n \$a; read a; print -n \ \$a; }") + [[ $g == "${e[i]}" ]] || err_exit "LC_ALL=$lc_all read ${o[i]} from pipe '$a $b' failed -- expected '${e[i]}', got '$g'" + done + done +done + +if [[ $lc_utf8 ]] +then export LC_ALL=$lc_utf8 + typeset -a c=( '' 'A' $'\303\274' $'\342\202\254' ) + integer i w + typeset o + if (( ${#c[2]} == 1 && ${#c[3]} == 1 )) + then for i in 1 2 3 + do for o in n N + do for w in 1 2 3 + do print -nr "${c[w]}" | read -${o}${i} g + if [[ $o == N ]] && (( i > 1 )) + then e='' + else e=${c[w]} + fi + [[ $g == "$e" ]] || err_exit "read -${o}${i} failed for '${c[w]}' -- expected '$e', got '$g'" + done + done + done + fi +fi + +exec 3<&2 +file=$tmp/file +redirect 5>$file 2>&5 +print -u5 -f 'This is a test\n' +print -u2 OK +exec 2<&3 +exp=$'This is a test\nOK' +got=$(< $file) +[[ $got == $exp ]] || err_exit "output garbled when stderr is duped -- expected $(printf %q "$exp"), got $(printf %q "$got")" +print 'hello world' > $file +1<>; $file 1># ((5)) +(( $(wc -c < $file) == 5 )) || err_exit "$file was not truncate to 5 bytes" + +$SHELL -c "PS4=':2:' + exec 1> $tmp/21.out 2> $tmp/22.out + set -x + printf ':1:A:' + print \$(:) + print :1:Z:" 1> $tmp/11.out 2> $tmp/12.out +[[ -s $tmp/11.out ]] && err_exit "standard output leaked past redirection" +[[ -s $tmp/12.out ]] && err_exit "standard error leaked past redirection" +exp=$':1:A:\n:1:Z:' +got=$(<$tmp/21.out) +[[ $exp == "$got" ]] || err_exit "standard output garbled -- expected $(printf %q "$exp"), got $(printf %q "$got")" +exp=$':2:printf :1:A:\n:2::\n:2:print\n:2:print :1:Z:' +got=$(<$tmp/22.out) +[[ $exp == "$got" ]] || err_exit "standard error garbled -- expected $(printf %q "$exp"), got $(printf %q "$got")" + +tmp=$tmp $SHELL 2> /dev/null -c 'exec 3<&1 ; exec 1<&- ; exec > $tmp/outfile;print foobar' || err_exit 'exec 1<&- causes failure' +[[ $(<$tmp/outfile) == foobar ]] || err_exit 'outfile does not contain foobar' + +print hello there world > $tmp/foobar +sed -e 's/there //' $tmp/foobar >; $tmp/foobar +[[ $(<$tmp/foobar) == 'hello world' ]] || err_exit '>; redirection not working on simple command' +print hello there world > $tmp/foobar +{ sed -e 's/there //' $tmp/foobar;print done;} >; $tmp/foobar +[[ $(<$tmp/foobar) == $'hello world\ndone' ]] || err_exit '>; redirection not working for compound command' +print hello there world > $tmp/foobar +$SHELL -c "sed -e 's/there //' $tmp/foobar >; $tmp/foobar" +[[ $(<$tmp/foobar) == 'hello world' ]] || err_exit '>; redirection not working with -c on a simple command' + +rm -f "$tmp/junk" +for (( i=1; i < 50; i++ )) +do out=$(/bin/ls "$tmp/junk" 2>/dev/null) + if (( $? == 0 )) + then err_exit 'wrong error code with redirection' + break + fi +done + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/leaks.sh b/src/cmd/ksh93/tests/leaks.sh new file mode 100755 index 0000000..8d89b05 --- /dev/null +++ b/src/cmd/ksh93/tests/leaks.sh @@ -0,0 +1,68 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +builtin vmstate 2>/dev/null || exit 0 + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +# test for variable reset leak # + +function test_reset +{ + integer i n=$1 + + for ((i = 0; i < n; i++)) + do u=$i + done +} + +n=1000 + +# one round to get to steady state -- sensitive to -x + +test_reset $n +a=0$(vmstate --format='+%(size)u') +b=0$(vmstate --format='+%(size)u') + +test_reset $n +a=0$(vmstate --format='+%(size)u') +test_reset $n +b=0$(vmstate --format='+%(size)u') + +if (( b > a )) +then err_exit "variable value reset memory leak -- $((b-a)) bytes after $n iterations" +fi + +# buffer boundary tests + +for exp in 65535 65536 +do got=$($SHELL -c 'x=$(printf "%.*c" '$exp' x); print ${#x}' 2>&1) + [[ $got == $exp ]] || err_exit "large command substitution failed -- expected $exp, got $got" +done + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/locale.sh b/src/cmd/ksh93/tests/locale.sh new file mode 100755 index 0000000..60209dc --- /dev/null +++ b/src/cmd/ksh93/tests/locale.sh @@ -0,0 +1,319 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +unset LANG ${!LC_*} + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT +cd $tmp || exit + +a=$($SHELL -c '/' 2>&1 | sed -e "s,.*: *,," -e "s, *\[.*,,") +b=$($SHELL -c '(LC_ALL=debug / 2>/dev/null); /' 2>&1 | sed -e "s,.*: *,," -e "s, *\[.*,,") +[[ "$b" == "$a" ]] || err_exit "locale not restored after subshell -- expected '$a', got '$b'" +b=$($SHELL -c '(LC_ALL=debug; / 2>/dev/null); /' 2>&1 | sed -e "s,.*: *,," -e "s, *\[.*,,") +[[ "$b" == "$a" ]] || err_exit "locale not restored after subshell -- expected '$a', got '$b'" + +# test shift-jis \x81\x40 ... \x81\x7E encodings +# (shift char followed by 7 bit ascii) + +typeset -i16 chr +for locale in $(PATH=/bin:/usr/bin locale -a 2>/dev/null | grep -i jis) +do export LC_ALL=$locale + for ((chr=0x40; chr<=0x7E; chr++)) + do c=${chr#16#} + for s in \\x81\\x$c \\x$c + do b="$(printf "$s")" + eval n=\$\'$s\' + [[ $b == "$n" ]] || err_exit "LC_ALL=$locale printf difference for \"$s\" -- expected '$n', got '$b'" + u=$(print -- $b) + q=$(print -- "$b") + [[ $u == "$q" ]] || err_exit "LC_ALL=$locale quoted print difference for \"$s\" -- $b => '$u' vs \"$b\" => '$q'" + done + done +done + +# this locale is supported by ast on all platforms +# EU for { decimal_point="," thousands_sep="." } + +locale=C_EU.UTF-8 + +export LC_ALL=C + +# test multibyte value/trace format -- $'\303\274' is UTF-8 u-umlaut + +c=$(LC_ALL=C $SHELL -c "printf $':%2s:\n' $'\303\274'") +u=$(LC_ALL=$locale $SHELL -c "printf $':%2s:\n' $'\303\274'" 2>/dev/null) +if [[ "$c" != "$u" ]] +then LC_ALL=$locale + x=$'+2+ typeset item.text\ ++3+ item.text=\303\274\ ++4+ print -- \303\274\ +\303\274\ ++5+ eval $\'arr[0]=(\\n\\ttext=\\303\\274\\n)\' ++2+ arr[0].text=ü\ ++6+ print -- \303\274\ +ü\ ++7+ eval txt=$\'(\\n\\ttext=\\303\\274\\n)\' ++2+ txt.text=\303\274\ ++8+ print -- \'(\' text=$\'\\303\\274\' \')\'\ +( text=\303\274 )' + u=$(LC_ALL=$locale PS4='+$LINENO+ ' $SHELL -x -c " + item=(typeset text) + item.text=$'\303\274' + print -- \"\${item.text}\" + eval \"arr[0]=\$item\" + print -- \"\${arr[0].text}\" + eval \"txt=\${arr[0]}\" + print -- \$txt + " 2>&1) + [[ "$u" == "$x" ]] || err_exit LC_ALL=$locale multibyte value/trace format failed + + x=$'00fc\n20ac' + u=$(LC_ALL=$locale $SHELL -c $'printf "%04x\n" \$\'\"\303\274\"\' \$\'\"\xE2\x82\xAC\"\'') + [[ $u == $x ]] || err_exit LC_ALL=$locale multibyte %04x printf format failed +fi + +if (( $($SHELL -c $'export LC_ALL='$locale$'; print -r "\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254" | wc -m' 2>/dev/null) == 10 )) +then LC_ALL=$locale $SHELL -c b1=$'"\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254"; [[ ${b1:4:1} == w ]]' || err_exit 'multibyte ${var:offset:len} not working correctly' +fi + +#$SHELL -c 'export LANG='$locale'; printf "\u[20ac]\u[20ac]" > $tmp/two_euro_chars.txt' +printf $'\342\202\254\342\202\254' > $tmp/two_euro_chars.txt +exp="6 2 6" +set -- $($SHELL -c " + unset LC_CTYPE + export LANG=$locale + export LC_ALL=C + command wc -C < $tmp/two_euro_chars.txt + unset LC_ALL + command wc -C < $tmp/two_euro_chars.txt + export LC_ALL=C + command wc -C < $tmp/two_euro_chars.txt +") +got=$* +[[ $got == $exp ]] || err_exit "command wc LC_ALL default failed -- expected '$exp', got '$got'" +set -- $($SHELL -c " + if builtin wc 2>/dev/null || builtin -f cmd wc 2>/dev/null + then unset LC_CTYPE + export LANG=$locale + export LC_ALL=C + wc -C < $tmp/two_euro_chars.txt + unset LC_ALL + wc -C < $tmp/two_euro_chars.txt + export LC_ALL=C + wc -C < $tmp/two_euro_chars.txt + fi +") +got=$* +[[ $got == $exp ]] || err_exit "builtin wc LC_ALL default failed -- expected '$exp', got '$got'" + +# multibyte char straddling buffer boundary + +{ + unset i + integer i + for ((i = 0; i < 163; i++)) + do print "#234567890123456789012345678901234567890123456789" + done + printf $'%-.*c\n' 15 '#' + for ((i = 0; i < 2; i++)) + do print $': "\xe5\xae\x9f\xe8\xa1\x8c\xe6\xa9\x9f\xe8\x83\xbd\xe3\x82\x92\xe8\xa1\xa8\xe7\xa4\xba\xe3\x81\x97\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82" :' + done +} > ko.dat + +LC_ALL=$locale $SHELL < ko.dat 2> /dev/null || err_exit "script with multibyte char straddling buffer boundary fails" + +# exp LC_ALL LC_NUMERIC LANG +set -- \ + 2,5 $locale C '' \ + 2.5 C $locale '' \ + 2,5 $locale '' C \ + 2,5 '' $locale C \ + 2.5 C '' $locale \ + 2.5 '' C $locale \ + +unset a b c +unset LC_ALL LC_NUMERIC LANG +integer a b c +while (( $# >= 4 )) +do exp=$1 + unset H V + typeset -A H + typeset -a V + [[ $2 ]] && V[0]="export LC_ALL=$2;" + [[ $3 ]] && V[1]="export LC_NUMERIC=$3;" + [[ $4 ]] && V[2]="export LANG=$4;" + for ((a = 0; a < 3; a++)) + do for ((b = 0; b < 3; b++)) + do if (( b != a )) + then for ((c = 0; c < 3; c++)) + do if (( c != a && c != b )) + then T=${V[$a]}${V[$b]}${V[$c]} + if [[ ! ${H[$T]} ]] + then H[$T]=1 + got=$($SHELL -c "${T}print \$(( $exp ))" 2>&1) + [[ $got == $exp ]] || err_exit "${T} sequence failed -- expected '$exp', got '$got'" + fi + fi + done + fi + done + done + shift 4 +done + +# setocale(LC_ALL,"") after setlocale() initialization + +printf 'f1\357\274\240f2\n' > input1 +printf 't2\357\274\240f1\n' > input2 +printf '\357\274\240\n' > delim +print "export LC_ALL=$locale +join -j1 1 -j2 2 -o 1.1 -t \$(cat delim) input1 input2 > out" > script +$SHELL -c 'unset LANG ${!LC_*}; $SHELL ./script' || +err_exit "join test script failed -- exit code $?" +exp="f1" +got="$(<out)" +[[ $got == "$exp" ]] || err_exit "LC_ALL test script failed -- expected '$exp', got '$got'" + +# multibyte identifiers + +exp=OK +got=$(LC_ALL=C.UTF-8 $SHELL -c $'\u[5929]=OK; print ${\u[5929]}' 2>&1) +[[ $got == "$exp" ]] || err_exit "multibyte variable definition/expansion failed -- expected '$exp', got '$got'" +got=$(LC_ALL=C.UTF-8 $SHELL -c $'function \u[5929]\n{\nprint OK;\n}; \u[5929]' 2>&1) +[[ $got == "$exp" ]] || err_exit "multibyte ksh function definition/execution failed -- expected '$exp', got '$got'" +got=$(LC_ALL=C.UTF-8 $SHELL -c $'\u[5929]()\n{\nprint OK;\n}; \u[5929]' 2>&1) +[[ $got == "$exp" ]] || err_exit "multibyte posix function definition/execution failed -- expected '$exp', got '$got'" + +# this locale is supported by ast on all platforms +# mainly used to debug multibyte and message translation code +# however wctype is not supported but that's ok for these tests + +locale=debug + +if [[ "$(LC_ALL=$locale $SHELL <<- \+EOF+ + x=a<1z>b<2yx>c + print ${#x} + +EOF+)" != 5 + ]] +then err_exit '${#x} not working with multibyte locales' +fi + +dir=_not_found_ +exp=2 +for cmd in \ + "cd $dir; export LC_ALL=debug; cd $dir" \ + "cd $dir; LC_ALL=debug cd $dir" \ + +do got=$($SHELL -c "$cmd" 2>&1 | sort -u | wc -l) + (( ${got:-0} == $exp )) || err_exit "'$cmd' sequence failed -- error message not localized" +done +exp=121 +for lc in LANG LC_MESSAGES LC_ALL +do for cmd in "($lc=$locale;cd $dir)" "$lc=$locale;cd $dir;unset $lc" "function tst { typeset $lc=$locale;cd $dir; }; tst" + do tst="$lc=C;cd $dir;$cmd;cd $dir;:" + $SHELL -c "unset LANG \${!LC_*}; $SHELL -c '$tst'" > out 2>&1 || + err_exit "'$tst' failed -- exit status $?" + integer id=0 + unset msg + typeset -A msg + got= + while read -r line + do line=${line##*:} + if [[ ! ${msg[$line]} ]] + then msg[$line]=$((++id)) + fi + got+=${msg[$line]} + done < out + [[ $got == $exp ]] || err_exit "'$tst' failed -- expected '$exp', got '$got'" + done +done + +exp=123 +got=$(LC_ALL=debug $SHELL -c "a<2A@>z=$exp; print \$a<2A@>z") +[[ $got == $exp ]] || err_exit "multibyte debug locale \$a<2A@>z failed -- expected '$exp', got '$got'" + +unset LC_ALL LC_MESSAGES +export LANG=debug +function message +{ + print -r $"An error occurred." +} +exp=$'(libshell,3,46)\nAn error occurred.\n(libshell,3,46)' +alt=$'(debug,message,libshell,An error occurred.)\nAn error occurred.\n(debug,message,libshell,An error occurred.)' +got=$(message; LANG=C message; message) +[[ $got == "$exp" || $got == "$alt" ]] || { + EXP=$(printf %q "$exp") + ALT=$(printf %q "$alt") + GOT=$(printf %q "$got") + err_exit "LANG change not seen by function -- expected $EXP or $ALT, got $GOT" +} + +a_thing=fish +got=$(print -r aa$"\\ahello \" /\\${a_thing}/\\"zz) +exp='aa(debug,'$Command',libshell,\ahello " /\fish/\)zz' +[[ $got == "$exp" ]] || err_exit "$\"...\" containing expansions fails: expected $exp, got $got" + +exp='(debug,'$Command',libshell,This is a string\n)' +typeset got=$"This is a string\n" +[[ $got == "$exp" ]] || err_exit "$\"...\" in assignment expansion fails: expected $exp got $got" + +unset LANG + +LC_ALL=C +x=$"hello" +[[ $x == hello ]] || err_exit 'assignment of message strings not working' + +# tests for multibyte characteer at buffer boundary +{ + print 'cat << \\EOF' + for ((i=1; i < 164; i++)) + do print 123456789+123456789+123456789+123456789+123456789 + done + print $'next character is multibyte<2b|>c<3d|\>foo' + for ((i=1; i < 10; i++)) + do print 123456789+123456789+123456789+123456789+123456789 + done + print EOF +} > script$$.1 +chmod +x script$$.1 +x=$( LC_ALL=debug $SHELL ./script$$.1) +[[ ${#x} == 8641 ]] || err_exit 'here doc contains wrong number of chars with multibyte locale' +[[ $x == *$'next character is multibyte<2b|>c<3d|\>foo'* ]] || err_exit "here_doc doesn't contain line with multibyte chars" + + +x=$(LC_ALL=debug $SHELL -c 'x="a<2b|>c";print -r -- ${#x}') +(( x == 3 )) || err_exit 'character length of multibyte character should be 3' +x=$(LC_ALL=debug $SHELL -c 'typeset -R10 x="a<2b|>c";print -r -- "${x}"') +[[ $x == ' a<2b|>c' ]] || err_exit 'typeset -R10 should begin with three spaces' +x=$(LC_ALL=debug $SHELL -c 'typeset -L10 x="a<2b|>c";print -r -- "${x}"') +[[ $x == 'a<2b|>c ' ]] || err_exit 'typeset -L10 should end in three spaces' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/math.sh b/src/cmd/ksh93/tests/math.sh new file mode 100644 index 0000000..59884f5 --- /dev/null +++ b/src/cmd/ksh93/tests/math.sh @@ -0,0 +1,202 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors < 127 && Errors++ )) +} +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + +set -o nounset + +typeset tmp + +# create temporary test directory +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT +cd $tmp || exit + +function test_arithmetric_expression_accesss_array_element_through_nameref +{ + compound out=( typeset stdout stderr ; integer res ) + compound -r -a tests=( + ( + cmd='@@TYPE@@ -a @@VAR@@ ; @@VAR@@[1]=90 ; function x { nameref nz=$1 ; print " $(( round(nz) ))==$(( round($nz) ))" ; } ; x @@VAR@@[1]' ; stdoutpattern=' 90==90' + ) + ( + cmd='@@TYPE@@ -a @@VAR@@=( [1]=90 ) ; function x { nameref nz=$1 ; print " $(( round(nz) ))==$(( round($nz) ))" ; } ; x @@VAR@@[1]' ; stdoutpattern=' 90==90' + ) + ( + cmd='@@TYPE@@ -a @@VAR@@ ; @@VAR@@[1][3]=90 ; function x { nameref nz=$1 ; print " $(( round(nz) ))==$(( round($nz) ))" ; } ; x @@VAR@@[1][3]' ; stdoutpattern=' 90==90' + ) + ( + cmd='@@TYPE@@ -a @@VAR@@=( [1][3]=90 ) ; function x { nameref nz=$1 ; print " $(( round(nz) ))==$(( round($nz) ))" ; } ; x @@VAR@@[1][3]' ; stdoutpattern=' 90==90' + ) + ( + cmd='@@TYPE@@ -a @@VAR@@ ; @@VAR@@[1][3][5]=90 ; function x { nameref nz=$1 ; print " $(( round(nz) ))==$(( round($nz) ))" ; } ; x @@VAR@@[1][3][5]' ; stdoutpattern=' 90==90' + ) + ( + cmd='@@TYPE@@ -a @@VAR@@=( [1][3][5]=90 ) ; function x { nameref nz=$1 ; print " $(( round(nz) ))==$(( round($nz) ))" ; } ; x @@VAR@@[1][3][5]' ; stdoutpattern=' 90==90' + ) + ( + cmd='@@TYPE@@ -a @@VAR@@ ; @@VAR@@[1][3][5]=90 ; function x { nameref nz=${1}[$2][$3][$4] ; print " $(( round(nz) ))==$(( round($nz) ))" ; } ; x @@VAR@@ 1 3 5' ; stdoutpattern=' 90==90' + ) + ( + cmd='@@TYPE@@ -A @@VAR@@ ; @@VAR@@[1]=90 ; function x { nameref nz=$1 ; print " $(( round(nz) ))==$(( round($nz) ))" ; } ; x @@VAR@@[1]' ; stdoutpattern=' 90==90' + ) + ( + cmd='@@TYPE@@ -A @@VAR@@=( [1]=90 ) ; function x { nameref nz=$1 ; print " $(( round(nz) ))==$(( round($nz) ))" ; } ; x @@VAR@@[1]' ; stdoutpattern=' 90==90' + ) + ) + + typeset testname + integer i + typeset mode + typeset cmd + + for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do + # fixme: This list should include "typeset -lX" and "typeset -X" but ast-ksh.2010-03-09 fails like this: + # 'typeset -X -a z ; z[1][3]=90 ; function x { nameref nz=$1 ; print " $(( nz ))==$(( $nz ))" ; } ; x z[1][3]' + # + typeset -X -a z + # + z[1][3]=90 + # + x 'z[1][3]' + # /home/test001/bin/ksh[1]: x: line 1: x1.68000000000000000000000000000000p: no parent + for ty in \ + 'typeset' \ + 'integer' \ + 'float' \ + 'typeset -i' \ + 'typeset -si' \ + 'typeset -li' \ + 'typeset -E' \ + 'typeset -F' \ + 'typeset -X' \ + 'typeset -lE' \ + 'typeset -lX' \ + 'typeset -lF' ; do + for mode in \ + 'plain' \ + 'in_compound' \ + 'in_indexed_compound_array' \ + 'in_2d_indexed_compound_array' \ + 'in_4d_indexed_compound_array' \ + 'in_associative_compound_array' \ + 'in_compound_nameref' \ + 'in_indexed_compound_array_nameref' \ + 'in_2d_indexed_compound_array_nameref' \ + 'in_4d_indexed_compound_array_nameref' \ + 'in_associative_compound_array_nameref' \ + ; do + nameref tst=tests[i] + + cmd="${tst.cmd//@@TYPE@@/${ty}}" + + case "${mode}" in + 'plain') + cmd="${cmd//@@VAR@@/z}" + ;; + + 'in_compound') + cmd="compound c ; ${cmd//@@VAR@@/c.z}" + ;; + 'in_indexed_compound_array') + cmd="compound -a c ; ${cmd//@@VAR@@/c[11].z}" + ;; + 'in_2d_indexed_compound_array') + cmd="compound -a c ; ${cmd//@@VAR@@/c[17][19].z}" + ;; + 'in_4d_indexed_compound_array') + cmd="compound -a c ; ${cmd//@@VAR@@/c[17][19][23][27].z}" + ;; + 'in_associative_compound_array') + cmd="compound -A c ; ${cmd//@@VAR@@/c[info].z}" + ;; + + 'in_compound_nameref') + cmd="compound c ; nameref ncr=c.z ; ${cmd//@@VAR@@/ncr}" + ;; + 'in_indexed_compound_array_nameref') + cmd="compound -a c ; nameref ncr=c[11].z ; ${cmd//@@VAR@@/ncr}" + ;; + 'in_2d_indexed_compound_array_nameref') + cmd="compound -a c ; nameref ncr=c[17][19].z ; ${cmd//@@VAR@@/ncr}" + ;; + 'in_4d_indexed_compound_array_nameref') + cmd="compound -a c ; nameref ncr=c[17][19][23][27].z ; ${cmd//@@VAR@@/ncr}" + ;; + 'in_associative_compound_array_nameref') + cmd="compound -A c ; nameref ncr=c[info].z ; ${cmd//@@VAR@@/ncr}" + ;; + *) + err_exit "Unexpected mode ${mode}" + ;; + esac + + testname="${0}/${cmd}" +#set -x + out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -o errexit -c "${cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" +#set +x + + [[ "${out.stdout}" == ${tst.stdoutpattern} ]] || err_exit "${testname}: Expected stdout to match $(printf '%q\n' "${tst.stdoutpattern}"), got $(printf '%q\n' "${out.stdout}")" + [[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got $(printf '%q\n' "${out.stderr}")" + (( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}" + done + done + done + + return 0 +} + +function test_has_iszero +{ + typeset str + integer i + + typeset -r -a tests=( + '(( iszero(0) )) && print "OK"' + '(( iszero(0.) )) && print "OK"' + '(( iszero(-0) )) && print "OK"' + '(( iszero(-0.) )) && print "OK"' + 'float n=0. ; (( iszero(n) )) && print "OK"' + 'float n=+0. ; (( iszero(n) )) && print "OK"' + 'float n=-0. ; (( iszero(n) )) && print "OK"' + 'float n=1. ; (( iszero(n) )) || print "OK"' + 'float n=1. ; (( iszero(n-1.) )) && print "OK"' + 'float n=-1. ; (( iszero(n+1.) )) && print "OK"' + ) + + for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do + str="$( ${SHELL} -o errexit -c "${tests[i]}" 2>&1 )" || err_exit "test $i: returned non-zero exit code $?" + [[ "${str}" == 'OK' ]] || err_exit "test $i: expected 'OK', got '${str}'" + done + + return 0 +} + +# run tests +test_arithmetric_expression_accesss_array_element_through_nameref +test_has_iszero + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/nameref.sh b/src/cmd/ksh93/tests/nameref.sh new file mode 100755 index 0000000..7eb0b21 --- /dev/null +++ b/src/cmd/ksh93/tests/nameref.sh @@ -0,0 +1,658 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +function checkref +{ + nameref foo=$1 bar=$2 + if [[ $foo != $bar ]] + then err_exit "foo=$foo != bar=$bar" + fi + foo=hello + if [[ $foo != $bar ]] + then err_exit "foo=$foo != bar=$bar" + fi + foo.child=child + if [[ ${foo.child} != ${bar.child} ]] + then err_exit "foo.child=${foo.child} != bar=${bar.child}" + fi +} + +name=first +checkref name name +name.child=second +checkref name name +.foo=top +.foo.bar=next +checkref .foo.bar .foo.bar +if [[ ${.foo.bar} != hello ]] +then err_exit ".foo.bar=${.foo.bar} != hello" +fi +if [[ ${.foo.bar.child} != child ]] +then err_exit ".foo.bar.child=${.foo.bar.child} != child" +fi +function func1 +{ + nameref color=$1 + func2 color +} + +function func2 +{ + nameref color=$1 + set -s -- ${!color[@]} + print -r -- "$@" +} + +typeset -A color +color[apple]=red +color[grape]=purple +color[banana]=yellow +if [[ $(func1 color) != 'apple banana grape' ]] +then err_exit "nameref or nameref not working" +fi +nameref x=.foo.bar +if [[ ${!x} != .foo.bar ]] +then err_exit "${!x} not working" +fi +typeset +n x $(typeset +n) +unset x +nameref x=.foo.bar +function x.set +{ + [[ ${.sh.value} ]] && print hello +} +if [[ $(.foo.bar.set) != $(x.set) ]] +then err_exit "function references not working" +fi +if [[ $(typeset +n) != x ]] +then err_exit "typeset +n doesn't list names of reference variables" +fi +if [[ $(typeset -n) != x=.foo.bar ]] +then err_exit "typeset +n doesn't list values of reference variables" +fi +file=$tmp/test +typeset +n foo bar 2> /dev/null +unset foo bar +export bar=foo +nameref foo=bar +if [[ $foo != foo ]] +then err_exit "value of nameref foo != $foo" +fi +cat > $file <<\! +print -r -- $foo +! +chmod +x "$file" +y=$( $file) +if [[ $y != '' ]] +then err_exit "reference variable not cleared" +fi +{ + command nameref xx=yy + command nameref yy=xx +} 2> /dev/null && err_exit "self reference not detected" +typeset +n foo bar +unset foo bar +set foo +nameref bar=$1 +foo=hello +if [[ $bar != hello ]] +then err_exit 'nameref of positional paramters outside of function not working' +fi +unset foo bar +bar=123 +function foobar +{ + typeset -n foo=bar + typeset -n foo=bar +} +foobar 2> /dev/null || err_exit 'nameref not unsetting previous reference' +( + nameref short=verylong + short=( A=a B=b ) + if [[ ${verylong.A} != a ]] + then err_exit 'nameref short to longname compound assignment error' + fi +) 2> /dev/null|| err_exit 'nameref short to longname compound assignment error' +unset x +if [[ $(var1=1 var2=2 + for i in var1 var2 + do nameref x=$i + print $x + done) != $'1\n2' ]] +then err_exit 'for loop nameref optimization error' +fi +if [[ $(typeset -A var1 var2 + var1[sub1]=1 var2[sub2]=1 + for i in var1 var2 + do + typeset -n array=$i + print ${!array[*]} + done) != $'sub1\nsub2' ]] +then err_exit 'for loop nameref optimization test2 error' +fi + +unset -n x foo bar +if [[ $(nameref x=foo;for x in foo bar;do print ${!x};done) != $'foo\nbar' ]] +then err_exit 'for loop optimization with namerefs not working' +fi +if [[ $( + p=(x=(r=3) y=(r=4)) + for i in x y + do nameref x=p.$i + print ${x.r} + done +) != $'3\n4' ]] +then err_exit 'nameref optimization error' +fi +[[ $( +unset x y var +var=(foo=bar) +for i in y var +do typeset -n x=$i + if [[ ${!x.@} ]] + then print ok + fi + typeset +n x +done) != ok ]] && err_exit 'invalid for loop optimization of name references' +function setval # name value +{ + nameref arg=$1 + nameref var=arg.bar + var=$2 +} +foo=( integer bar=0) +setval foo 5 +(( foo.bar == 5)) || err_exit 'nested nameref not working' +function selfref +{ + typeset -n ps=$1 + print -r -- "${ps}" +} +ps=(a=1 b=2) +[[ $(selfref ps) == *a=1* ]] || err_exit 'local nameref cannot reference global variable of the same name' +function subref +{ + typeset -n foo=$1 + print -r -- ${foo.a} +} +[[ $(subref ps) == 1 ]] || err_exit 'local nameref cannot reference global variable child' + +function local +{ + typeset ps=(typeset -i a=3 b=4) + [[ $(subref ps) == 3 ]] || err_exit 'local nameref cannot reference caller compound variable' +} +local +unset -f local +function local +{ + qs=(integer a=3; integer b=4) +} +local 2> /dev/null || err_exit 'function local has non-zero exit status' +[[ ${qs.a} == 3 ]] || err_exit 'function cannot set compound global variable' +unset fun i +foo=(x=hi) +function fun +{ + nameref i=$1 + print -r -- "${i.x}" +} +i=foo +[[ $(fun $i) == hi ]] || err_exit 'nameref for compound variable with in function name of caller fails' +unset -n foo bar +typeset -A foo +foo[x.y]=(x=3 y=4) +nameref bar=foo[x.y] +[[ ${bar.x} == 3 ]] || err_exit 'nameref to subscript containing . fails' +[[ ${!bar} == 'foo[x.y]' ]] || err_exit '${!var} not correct for nameref to an array instance' +typeset +n bar +nameref bar=foo +[[ ${!bar} == foo ]] || err_exit '${!var} not correct for nameref to array variable' +$SHELL -c 'function bar { nameref x=foo[++];};typeset -A foo;bar' 2> /dev/null ||err_exit 'nameref of associative array tries to evaluate subscript' +i=$($SHELL -c 'nameref foo=bar; bar[2]=(x=3 y=4); nameref x=foo[2].y;print -r -- $x' 2> /dev/null) +[[ $i == 4 ]] || err_exit 'creating reference from subscripted variable whose name is a reference failed' +[[ $($SHELL 2> /dev/null <<- '+++EOF' + function bar + { + nameref x=$1 + print -r -- "$x" + } + function foo + { + typeset var=( foo=hello) + bar var + } + foo ++++EOF +) == *foo=hello* ]] || err_exit 'unable to display compound variable from name reference of local variable' +#set -x +for c in '=' '[' ']' '\' "'" '"' '<' '=' '(' +do [[ $($SHELL 2> /dev/null <<- ++EOF++ + i=\\$c;typeset -A a; a[\$i]=foo;typeset -n x=a[\$i]; print "\$x" + ++EOF++ +) != foo ]] && err_exit 'nameref x=a[$c] '"not working for c=$c" +done +for c in '=' '[' ']' '\' "'" '"' '<' '=' '(' +do [[ $($SHELL 2> /dev/null <<- ++EOF++ + i=\\$c;typeset -A a; a[\$i]=foo;b=a[\$i];typeset -n x=\$b; print "\$x" + ++EOF++ +) != foo ]] && err_exit 'nameref x=$b with b=a[$c] '"not working for c=$c" +done + +unset -n foo x +unset foo x +typeset -A foo +nameref x=foo[xyz] +foo[xyz]=ok +[[ $x == ok ]] || err_exit 'nameref to unset subscript not working' +function function2 +{ + nameref v=$1 + v.x=19 v.y=20 +} +function function1 +{ + typeset compound_var=() + function2 compound_var + printf "x=%d, y=%d\n" compound_var.x compound_var.y +} +x="$(function1)" +[[ "$x" != 'x=19, y=20' ]] && err_exit "expected 'x=19, y=20', got '${x}'" +typeset +n bar +unset foo bar +[[ $(function a +{ + for i in foo bar + do typeset -n v=$i + print $v + done | cat +} +foo=1 bar=2;a) == $'1\n2' ]] 2> /dev/null || err_exit 'nameref in pipeline broken' +function a +{ + typeset -n v=vars.data._1 + print "${v.a} ${v.b}" +} +vars=(data=()) +vars.data._1.a=a.1 +vars.data._1.b=b.1 +[[ $(a) == 'a.1 b.1' ]] || err_exit 'nameref choosing wrong scope -- ' +typeset +n bam zip foo +unset bam zip foo +typeset -A foo +foo[2]=bar +typeset -n bam=foo[2] +typeset -n zip=bam +[[ $zip == bar ]] || err_exit 'nameref to another nameref to array element fails' +[[ -R zip ]] || err_exit '[[ -R zip ]] should detect that zip is a reference' +[[ -R bam ]] || err_exit '[[ -R bam ]] should detect that bam is a reference' +[[ -R zip ]] || err_exit '[[ -v zip ]] should detect that zip is set' +[[ -v bam ]] || err_exit '[[ -v bam ]] should detect that bam is set' +[[ -R 123 ]] && err_exit '[[ -R 123 ]] should detect that 123 is not a reference' +[[ -v 123 ]] && err_exit '[[ -v 123 ]] should detect that 123 is not set' + +unset ref x +typeset -n ref +x=3 +function foobar +{ + typeset xxx=3 + ref=xxx + return 0 +} +foobar 2> /dev/null && err_exit 'invalid reference should cause foobar to fail' +[[ -v ref ]] && err_exit '$ref should be unset' +ref=x +[[ $ref == 3 ]] || err_exit "\$ref is $ref, it should be 3" +function foobar +{ + typeset fvar=() + typeset -n ref=fvar.foo + ref=ok + print -r $ref +} +[[ $(foobar) == ok ]] 2> /dev/null || err_exit 'nameref in function not creating variable in proper scope' +function foobar +{ + nameref doc=docs + nameref bar=doc.num + [[ $bar == 2 ]] || err_exit 'nameref scoping error' +} + +docs=(num=2) +foobar + +typeset +n x y +unset x y +typeset -A x +x[a]=(b=c) +typeset -n y=x[a] +[[ ${!y.@} == 'x[a].b' ]] || err_exit 'reference to array element not expanded with ${!y.@}' + +typeset +n v +v=() +k=a.b.c/d +command typeset -n n=v.${k//['./']/_} 2> /dev/null || err_exit 'patterns with quotes not handled correctly with name reference assignment' + +typeset _n sp +nameref sp=addrsp +sp[14]=( size=1 ) +[[ -v sp[19] ]] && err_exit '[[ -v sp[19] ]] where sp is a nameref should not be set' + +function fun2 +{ + nameref var=$1 + var.foo=bar +} + +function fun1 +{ + compound -S container + fun2 container + [[ $container == *foo=bar* ]] || err_exit 'name references to static compound variables in parent scope not working' +} +fun1 + +function fun2 +{ + nameref var=$1 + var.foo=bar +} + +typeset -T container_t=( + typeset foo +) + +function fun1 +{ + container_t -S container + fun2 container + [[ $container == *foo=bar* ]] || err_exit 'name references to static type variables in parent scope not working' +} +fun1 + +function fun2 +{ + nameref var=$1 + nameref node=var.foo + node=bar +} +function fun3 +{ + fun2 container #2> /dev/null +} +compound container +fun3 +[[ $container == *foo=bar* ]] || err_exit 'name reference to a name reference variable in a function not working' + +typeset -A x=( [a]=1 ) +nameref c=x[h] +[[ -v x[h] ]] && err_exit 'creating reference to non-existant associative array element causes element to get added' + +unset a +function x +{ + nameref a=a + (( $# > 0 )) && typeset -A a + a[a b]=${1-99} # this was cauing a syntax on the second call +} +x 7 +x 2> /dev/null +[[ ${a[a b]} == 99 ]] || err_exit 'nameref not handling subscript correctly' + +nameref sizes=baz +typeset -A -i sizes +sizes[bar]=1 +[[ ${sizes[*]} == 1 ]] || err_exit 'adding -Ai attribute to name referenced variable not working' + +$SHELL 2> /dev/null -c 'nameref foo=bar; typeset -A foo; (( (x=foo[a])==0 ))' || err_exit 'references inside arithmetic expressions not working' +: + +unset ar z +integer -a ar +nameref z=ar[0] +(( z[2]=3)) +[[ ${ar[0][2]} == 3 ]] || err_exit "\${ar[0][2]} is '${ar[0][2]}' but should be 3" +(( ar[0][2] == 3 )) || err_exit "ar[0][2] is '${ar[0][2]}' but should be 3" + +unset c x +typeset +n c x +compound c=( typeset -a x ) +nameref x=c.x +x[4]=1 +[[ ${ typeset -p c.x ;} == *-C* ]] && err_exit 'c.x should not have -C attributes' + +{ $SHELL 2> /dev/null <<- \EOF + typeset -T xxx_t=( + float x=1 y=2 + typeset name=abc + ) + xxx_t x + nameref r=x.y + [[ $r == 2 ]] || exit 1 + unset x + [[ ${!r} == .deleted ]] || exit 2 +EOF +} 2> /dev/null #|| print -u2 bad +exitval=$? +if [[ $(kill -l $exitval) == SEGV ]] +then print -u2 'name reference to unset type instance causes segmentation violation' +else if((exitval)) + then print -u2 'name reference to unset type instance not redirected to .deleted' + fi +fi + +typeset +n nr +unset c nr +compound c +compound -A c.a +nameref nr=c.a[hello] +[[ ${!nr} == "c.a[hello]" ]] || err_exit 'name reference nr to unset associative array instance does not expand ${!nr} correctly.' + +typeset +n nr +compound -a c.b +nameref nr=c.b[2] +[[ ${!nr} == "c.b[2]" ]] || err_exit 'name reference nr to unset indexed array instance does not expand ${!nr} correctly.' + +typeset +n a b +unset a b +typeset -n a=ls[0] b=ls[1] +read line << \! +3 4 +! +set -A ls -- $line +[[ $a == 3 ]] || err_exit 'name reference to ls[0] when ls is not an array fails' + +$SHELL 2> /dev/null <<-\EOF || err_exit 'nameref to array element fails' + set -o errexit + function bf { + nameref treename=$1 + nodepath="treename" ; + nameref x="$nodepath" + compound -A x.nodes + nameref node=treename.nodes[4] + node=() + typeset +p node.elements + } + compound c + bf c +EOF + +function add_compound +{ + nameref arr=$1 + arr[34]+=( float val=1.1 ) +} +compound -a rootcpv +nameref mycpv=rootcpv[4][8][16][32][64] +compound -a mycpv.myindexedcompoundarray +add_compound mycpv.myindexedcompoundarray +(( mycpv.myindexedcompoundarray[34].val == 1.1 )) || err_exit 'nameref scoping error' + +function add_file_to_tree +{ + nameref node=$1 + compound -A node.elements + node.elements[/]=(filepath=foobar) +} +function main +{ + compound filetree + add_file_to_tree filetree +} +main 2> /dev/null +[[ $? == 0 ]] || err_exit 'nameref binding to calling function compound variable failed' + +unset l +typeset -a -C l +printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l[4][6] +exp=$(print -v l) +unset l +typeset -a -C l +nameref l4=l[4] +printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l4[6] +[[ $(print -v l) == "$exp" ]] || err_exit 'nameref l4=l[4] not working' +unset l +typeset -a -C l +nameref l46=l[4][6] +printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | read -C l46 +[[ $(print -v l) == "$exp" ]] || err_exit 'nameref l46=l[4][6] not working' + +exp=$'(\n\t[4]=(\n\t\ttypeset -a ar=(\n\t\t\t1\n\t\t\t2\n\t\t)\n\t\tb=1\n\t)\n)' +unset l +typeset +n l4 +typeset -a -C l +nameref l4=l[4] +printf "( typeset -a ar=( 1\n2\n) b=1 )\n" | read -C l4 +[[ $(print -v l) == "$exp" ]] || err_exit 'nameref l4=l[4] not working with indexed array read' + +unset l +typeset +n l4 +typeset -A -C l +nameref l4=l[4] +printf "( typeset -a ar=( 1\n2\n) b=1 )\n" | read -C l4 +[[ $(print -v l) == "$exp" ]] || err_exit 'nameref l4=l[4] not working with associative array read' + +exp=$'(\n\t[9]=(\n\t\tfish=4\n\t)\n)' +function add_eval +{ + nameref pos=$1 + source /dev/stdin <<<"$2" + typeset -m pos=addvar +} +function do_local_plain +{ + compound -A local_tree + add_eval local_tree[9].fish "typeset -i addvar=4" + [[ $(print -v local_tree) == "$exp" ]] || err_exit 'do_local_plain failed' +} +function do_global_throughnameref +{ + nameref tr=global_tree + add_eval tr[9].fish "typeset -i addvar=4" + [[ $(print -v tr) == "$exp" ]] || err_exit 'do_global_throughnameref failed' +} +function do_local_throughnameref +{ + compound -A local_tree + nameref tr=local_tree + add_eval tr[9].fish "typeset -i addvar=4" + [[ $(print -v tr) == "$exp" ]] || err_exit 'do_local_throughnameref failed' +} +compound -A global_tree +do_global_throughnameref +do_local_throughnameref +do_local_plain + +unset ar +compound -a ar +function read_c +{ + nameref v=$1 + read -C v +} +print "( typeset -i x=36 ) " | read_c ar[5][9][2] +exp=$'(\n\t[5]=(\n\t\t[9]=(\n\t\t\t[2]=(\n\t\t\t\ttypeset -i x=36\n\t\t\t)\n\t\t)\n\t)\n)' +[[ $(print -v ar) == "$exp" ]] || err_exit 'read into nameref of global array instance from within a function fails' + +function read_c +{ + nameref v=$1 + read -C v +} +function main +{ + compound -a ar + nameref nar=ar + print "( typeset -i x=36 ) " | read_c nar[5][9][2] + exp=$'(\n\t[5]=(\n\t\t[9]=(\n\t\t\t[2]=(\n\t\t\t\ttypeset -i x=36\n\t\t\t)\n\t\t)\n\t)\n)' + [[ $(print -v nar) == "$exp" ]] || err_exit 'read from a nameref variable from calling scope fails' +} +main + +function rf2 +{ + nameref val=$1 + read -C val +} +function rf +{ + nameref val=$1 + rf2 val +} +function main +{ + compound c + typeset -A -C c.l + nameref l4=c.l[4] + printf "( typeset -a ar=( 1\n2\n3\n) b=1 )\n" | rf l4 + exp=$'(\n\ttypeset -C -A l=(\n\t\t[4]=(\n\t\t\ttypeset -a ar=(\n\t\t\t\t1\n\t\t\t\t2\n\t\t\t\t3\n\t\t\t)\n\t\t\tb=1\n\t\t)\n\t)\n)' + [[ $(print -v c) == "$exp" ]] || err_exit 'read -C with nameref to array element fails' +} +main + +# bug reported by ek +cfg=( alarms=(type=3)) +function a +{ + typeset -n y=$1 + print -- ${y.type} +} +function b +{ + a $1 +} +[[ $(a cfg.alarms) == 3 ]] || err_exit "nameref scoping error in function" +[[ $(b cfg.alarms) == 3 ]] || err_exit "nameref scoping error in nested function" + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/options.sh b/src/cmd/ksh93/tests/options.sh new file mode 100755 index 0000000..c5b4c2e --- /dev/null +++ b/src/cmd/ksh93/tests/options.sh @@ -0,0 +1,544 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +unset HISTFILE +export LC_ALL=C ENV= + +ulimit -c 0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +if [[ $( ${SHELL-ksh} -s hello<<-\! + print $1 + ! + ) != hello ]] +then err_exit "${SHELL-ksh} -s not working" +fi +x=$( + set -e + false && print bad + print good +) +if [[ $x != good ]] +then err_exit 'sh -e not working' +fi +[[ $($SHELL -D -c 'print hi; print $"hello"') == '"hello"' ]] || err_exit 'ksh -D not working' + +env=$tmp/.env +print $'(print -u1 aha) &>/dev/null\n(print -u2 aha) &>/dev/null' > $env +rc=$tmp/.kshrc +print $'PS1=""\nfunction env_hit\n{\n\tprint OK\n}' > $rc + +export ENV=/.$env +if [[ ! -o privileged ]] +then + got=$($SHELL -E -c : 2>/dev/null) + if [[ $g ]] + then + got=$(printf %q "$got") + err_exit "\$ENV file &>/dev/null does not redirect stdout -- expected '', got $got" + fi + got=$($SHELL -E -c : 2>&1 >/dev/null) + if [[ $got != *nonstandard* || $got == *$'\n'* ]] + then + got=$(printf %q "$got") + err_exit "\$ENV file &>/dev/null does not redirect stderr -- expected one diagnostic line, got $got" + fi +fi + +export ENV=/.$rc +if [[ -o privileged ]] +then + [[ $(print env_hit | $SHELL 2>&1) == "OK" ]] && + err_exit 'privileged nointeractive shell reads $ENV file' + [[ $(print env_hit | $SHELL -E 2>&1) == "OK" ]] && + err_exit 'privileged -E reads $ENV file' + [[ $(print env_hit | $SHELL +E 2>&1) == "OK" ]] && + err_exit 'privileged +E reads $ENV file' + [[ $(print env_hit | $SHELL --rc 2>&1) == "OK" ]] && + err_exit 'privileged --rc reads $ENV file' + [[ $(print env_hit | $SHELL --norc 2>&1) == "OK" ]] && + err_exit 'privileged --norc reads $ENV file' +else + [[ $(print env_hit | $SHELL 2>&1) == "OK" ]] && + err_exit 'nointeractive shell reads $ENV file' + [[ $(print env_hit | $SHELL -E 2>&1) == "OK" ]] || + err_exit '-E ignores $ENV file' + [[ $(print env_hit | $SHELL +E 2>&1) == "OK" ]] && + err_exit '+E reads $ENV file' + [[ $(print env_hit | $SHELL --rc 2>&1) == "OK" ]] || + err_exit '--rc ignores $ENV file' + [[ $(print env_hit | $SHELL --norc 2>&1) == "OK" ]] && + err_exit '--norc reads $ENV file' + [[ $(print env_hit | $SHELL -i 2>&1) == "OK" ]] || + err_exit '-i ignores $ENV file' +fi + +export ENV= +if [[ -o privileged ]] +then + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && + err_exit 'privileged nointeractive shell reads $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] && + err_exit 'privileged -E ignores empty $ENV' + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && + err_exit 'privileged +E reads $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] && + err_exit 'privileged --rc ignores empty $ENV' + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && + err_exit 'privileged --norc reads $HOME/.kshrc file' +else + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && + err_exit 'nointeractive shell reads $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] && + err_exit '-E ignores empty $ENV' + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && + err_exit '+E reads $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] && + err_exit '--rc ignores empty $ENV' + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && + err_exit '--norc reads $HOME/.kshrc file' +fi + +unset ENV +if [[ -o privileged ]] +then + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && + err_exit 'privileged nointeractive shell reads $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] && + err_exit 'privileged -E reads $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && + err_exit 'privileged +E reads $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] && + err_exit 'privileged --rc reads $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && + err_exit 'privileged --norc reads $HOME/.kshrc file' +else + [[ $(print env_hit | HOME=$tmp $SHELL 2>&1) == "OK" ]] && + err_exit 'nointeractive shell reads $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL -E 2>&1) == "OK" ]] || + err_exit '-E ignores $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL +E 2>&1) == "OK" ]] && + err_exit '+E reads $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL --rc 2>&1) == "OK" ]] || + err_exit '--rc ignores $HOME/.kshrc file' + [[ $(print env_hit | HOME=$tmp $SHELL --norc 2>&1) == "OK" ]] && + err_exit '--norc reads $HOME/.kshrc file' +fi + +rm -rf $tmp/.kshrc + +if command set -G 2> /dev/null +then cd $tmp + mkdir bar foo + > bar.c > bam.c + > bar/foo.c > bar/bam.c + > foo/bam.c + set -- **.c + expected='bam.c bar.c' + [[ $* == $expected ]] || + err_exit "-G **.c failed -- expected '$expected', got '$*'" + set -- ** + expected='bam.c bar bar.c bar/bam.c bar/foo.c foo foo/bam.c' + [[ $* == $expected ]] || + err_exit "-G ** failed -- expected '$expected', got '$*'" + set -- **/*.c + expected='bam.c bar.c bar/bam.c bar/foo.c foo/bam.c' + [[ $* == $expected ]] || + err_exit "-G **/*.c failed -- expected '$expected', got '$*'" + set -- **/bam.c + expected='bam.c bar/bam.c foo/bam.c' + [[ $* == $expected ]] || + err_exit "-G **/bam.c failed -- expected '$expected', got '$*'" + cd ~- +fi + +cd $tmp +t="<$$>.profile.<$$>" +echo "echo '$t'" > .profile +cp $SHELL ./-ksh +if [[ -o privileged ]] +then + [[ $(HOME=$PWD $SHELL -l </dev/null 2>&1) == *$t* ]] && + err_exit 'privileged -l reads .profile' + [[ $(HOME=$PWD $SHELL --login </dev/null 2>&1) == *$t* ]] && + err_exit 'privileged --login reads .profile' + [[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>&1) == *$t* ]] && + err_exit 'privileged --login-shell reads .profile' + [[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>&1) == *$t* ]] && + err_exit 'privileged --login_shell reads .profile' + [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>&1) == *$t* ]] && + err_exit 'privileged exec -a -ksh ksh reads .profile' + [[ $(HOME=$PWD ./-ksh -i </dev/null 2>&1) == *$t* ]] && + err_exit 'privileged ./-ksh reads .profile' + [[ $(HOME=$PWD ./-ksh -ip </dev/null 2>&1) == *$t* ]] && + err_exit 'privileged ./-ksh -p reads .profile' +else + [[ $(HOME=$PWD $SHELL -l </dev/null 2>&1) == *$t* ]] || + err_exit '-l ignores .profile' + [[ $(HOME=$PWD $SHELL --login </dev/null 2>&1) == *$t* ]] || + err_exit '--login ignores .profile' + [[ $(HOME=$PWD $SHELL --login-shell </dev/null 2>&1) == *$t* ]] || + err_exit '--login-shell ignores .profile' + [[ $(HOME=$PWD $SHELL --login_shell </dev/null 2>&1) == *$t* ]] || + err_exit '--login_shell ignores .profile' + [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>/dev/null) == *$t* ]] || + err_exit 'exec -a -ksh ksh 2>/dev/null ignores .profile' + [[ $(HOME=$PWD exec -a -ksh $SHELL </dev/null 2>&1) == *$t* ]] || + err_exit 'exec -a -ksh ksh 2>&1 ignores .profile' + [[ $(HOME=$PWD ./-ksh -i </dev/null 2>&1) == *$t* ]] || + err_exit './-ksh ignores .profile' + [[ $(HOME=$PWD ./-ksh -ip </dev/null 2>&1) == *$t* ]] && + err_exit './-ksh -p does not ignore .profile' +fi +cd ~- +rm -rf $tmp/.profile + +# { exec interactive login_shell restricted xtrace } in the following test + +for opt in \ + allexport all-export all_export \ + bgnice bg-nice bg_nice \ + clobber emacs \ + errexit err-exit err_exit \ + glob \ + globstar glob-star glob_star \ + gmacs \ + ignoreeof ignore-eof ignore_eof \ + keyword log markdirs monitor notify \ + pipefail pipe-fail pipe_fail \ + trackall track-all track_all \ + unset verbose vi \ + viraw vi-raw vi_raw +do old=$opt + if [[ ! -o $opt ]] + then old=no$opt + fi + + set --$opt || err_exit "set --$opt failed" + [[ -o $opt ]] || err_exit "[[ -o $opt ]] failed" + [[ -o no$opt ]] && err_exit "[[ -o no$opt ]] failed" + [[ -o no-$opt ]] && err_exit "[[ -o no-$opt ]] failed" + [[ -o no_$opt ]] && err_exit "[[ -o no_$opt ]] failed" + [[ -o ?$opt ]] || err_exit "[[ -o ?$opt ]] failed" + [[ -o ?no$opt ]] || err_exit "[[ -o ?no$opt ]] failed" + [[ -o ?no-$opt ]] || err_exit "[[ -o ?no-$opt ]] failed" + [[ -o ?no_$opt ]] || err_exit "[[ -o ?no_$opt ]] failed" + + set --no$opt || err_exit "set --no$opt failed" + [[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed" + [[ -o $opt ]] && err_exit "[[ -o $opt ]] failed" + + set --no-$opt || err_exit "set --no-$opt failed" + [[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed" + [[ -o $opt ]] && err_exit "[[ -o $opt ]] failed" + + set --no_$opt || err_exit "set --no_$opt failed" + [[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed" + [[ -o $opt ]] && err_exit "[[ -o $opt ]] failed" + + set -o $opt || err_exit "set -o $opt failed" + [[ -o $opt ]] || err_exit "[[ -o $opt ]] failed" + set -o $opt=1 || err_exit "set -o $opt=1 failed" + [[ -o $opt ]] || err_exit "[[ -o $opt ]] failed" + set -o no$opt=0 || err_exit "set -o no$opt=0 failed" + [[ -o $opt ]] || err_exit "[[ -o $opt ]] failed" + set --$opt=1 || err_exit "set --$opt=1 failed" + [[ -o $opt ]] || err_exit "[[ -o $opt ]] failed" + set --no$opt=0 || err_exit "set --no$opt=0 failed" + [[ -o $opt ]] || err_exit "[[ -o $opt ]] failed" + + set -o no$opt || err_exit "set -o no$opt failed" + [[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed" + set -o $opt=0 || err_exit "set -o $opt=0 failed" + [[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed" + set -o no$opt=1 || err_exit "set -o no$opt=1 failed" + [[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed" + set --$opt=0 || err_exit "set --$opt=0 failed" + [[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed" + set --no$opt=1 || err_exit "set --no$opt=1 failed" + [[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed" + + set -o no-$opt || err_exit "set -o no-$opt failed" + [[ -o no-$opt ]] || err_exit "[[ -o no-$opt ]] failed" + + set -o no_$opt || err_exit "set -o no_$opt failed" + [[ -o no_$opt ]] || err_exit "[[ -o no_$opt ]] failed" + + set +o $opt || err_exit "set +o $opt failed" + [[ -o no$opt ]] || err_exit "[[ -o no$opt ]] failed" + + set +o no$opt || err_exit "set +o no$opt failed" + [[ -o $opt ]] || err_exit "[[ -o $opt ]] failed" + + set +o no-$opt || err_exit "set +o no-$opt failed" + [[ -o $opt ]] || err_exit "[[ -o $opt ]] failed" + + set +o no_$opt || err_exit "set +o no_$opt failed" + [[ -o $opt ]] || err_exit "[[ -o $opt ]] failed" + + set --$old +done + +for opt in \ + exec interactive login_shell login-shell logi privileged \ + rc restricted xtrace +do [[ -o $opt ]] + y=$? + [[ -o no$opt ]] + n=$? + case $y$n in + 10|01) ;; + *) err_exit "[[ -o $opt ]] == [[ -o no$opt ]]" ;; + esac +done + +for opt in \ + foo foo-bar foo_bar +do if [[ -o ?$opt ]] + then err_exit "[[ -o ?$opt ]] should fail" + fi + if [[ -o ?no$opt ]] + then err_exit "[[ -o ?no$opt ]] should fail" + fi +done + +[[ $(set +o) == $(set --state) ]] || err_exit "set --state different from set +o" +set -- $(set --state) +[[ $1 == set && $2 == --default ]] || err_exit "set --state failed -- expected 'set --default *', got '$1 $2 *'" +shift +restore=$* +shift +off= +for opt +do case $opt in + --not*) opt=${opt/--/--no} ;; + --no*) opt=${opt/--no/--} ;; + --*) opt=${opt/--/--no} ;; + esac + off="$off $opt" +done +set $off +state=$(set --state) +default=$(set --default --state) +[[ $state == $default ]] || err_exit "set --state for default options failed: expected '$default', got '$state'" +set $restore +state=$(set --state) +[[ $state == "set $restore" ]] || err_exit "set --state after restore failed: expected 'set $restore', got '$state'" + +typeset -a pipeline +pipeline=( + ( nopipefail=0 pipefail=1 command='false|true|true' ) + ( nopipefail=0 pipefail=1 command='true|false|true' ) + ( nopipefail=1 pipefail=1 command='true|true|false' ) + ( nopipefail=1 pipefail=1 command='false|false|false' ) + ( nopipefail=0 pipefail=0 command='true|true|true' ) + ( nopipefail=0 pipefail=0 command='print hi|(sleep 1;/bin/cat)>/dev/null' ) +) +set --nopipefail +for ((i = 0; i < ${#pipeline[@]}; i++ )) +do eval ${pipeline[i].command} + status=$? + expected=${pipeline[i].nopipefail} + [[ $status == $expected ]] || + err_exit "--nopipefail '${pipeline[i].command}' exit status $status -- expected $expected" +done +ftt=0 +set --pipefail +for ((i = 0; i < ${#pipeline[@]}; i++ )) +do eval ${pipeline[i].command} + status=$? + expected=${pipeline[i].pipefail} + if [[ $status != $expected ]] + then err_exit "--pipefail '${pipeline[i].command}' exit status $status -- expected $expected" + (( i == 0 )) && ftt=1 + fi +done +if (( ! ftt )) +then exp=10 + got=$(for((n=1;n<exp;n++))do $SHELL --pipefail -c '(sleep 0.1;false)|true|true' && break; done; print $n) + [[ $got == $exp ]] || err_exit "--pipefail -c '(sleep 0.1;false)|true|true' fails with exit status 0 (after $got/$exp iterations)" +fi + +echo=$(whence -p echo) +for ((i=0; i < 20; i++)) +do if ! x=$(true | $echo 123) + then err_exit 'command substitution with wrong exit status with pipefai' + break + fi +done +( + set -o pipefail + false | true + (( $? )) || err_exit 'pipe not failing in subshell with pipefail' +) | wc >/dev/null +$SHELL -c 'set -o pipefail; false | $(whence -p true);' && err_exit 'pipefail not returning failure with sh -c' +exp='1212 or 1221' +got=$( + set --pipefail + pipe() { date | cat > /dev/null ;} + print $'1\n2' | + while read i + do if pipe $tmp + then { print -n $i; sleep 2; print -n $i; } & + fi + done + wait +) +[[ $got == @((12|21)(12|21)) ]] || err_exit "& job delayed by --pipefail, expected '$exp', got '$got'" +$SHELL -c '[[ $- == *c* ]]' || err_exit 'option c not in $-' +> $tmp/.profile +for i in i l r s D E a b e f h k n t u v x B C G H +do HOME=$tmp ENV= $SHELL -$i >/dev/null 2>&1 <<- ++EOF++ || err_exit "option $i not in \$-" + [[ \$- == *$i* ]] || exit 1 + ++EOF++ +done +letters=ilrabefhknuvxBCGE +integer j=0 +for i in interactive login restricted allexport notify errexit \ + noglob trackall keyword noexec nounset verbose xtrace braceexpand \ + noclobber globstar rc +do HOME=$tmp ENV= $SHELL -o $i >/dev/null 2>&1 <<- ++EOF++ || err_exit "option $i not equivalent to ${letters:j:1}" + [[ \$- == *${letters:j:1}* ]] || exit 1 + ++EOF++ + ((j++)) +done + +export ENV= PS1="(:$$:)" +histfile=$tmp/history +exp=$(HISTFILE=$histfile $SHELL -c $'function foo\n{\ncat\n}\ntype foo') +for var in HISTSIZE HISTFILE +do got=$( ( HISTFILE=$histfile $SHELL +E -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ) 2>&1 ) + got=${got##*"$PS1"} + [[ $got == "$exp" ]] || err_exit "function definition inside (...) with $var unset fails -- got '$got', expected '$exp'" + got=$( { HISTFILE=$histfile $SHELL +E -ic $'unset '$var$'\nfunction foo\n{\ncat\n}\ntype foo\nexit' ;} 2>&1 ) + got=${got##*"$PS1"} + [[ $got == "$exp" ]] || err_exit "function definition inside {...;} with $var unset fails -- got '$got', expected '$exp'" +done +( unset HISTFILE; $SHELL -ic "HISTFILE=$histfile" 2>/dev/null ) || err_exit "setting HISTFILE when not in environment fails" + +# the next tests loop on all combinations of +# { SUB PAR CMD ADD } + +SUB=( + ( BEG='$( ' END=' )' ) + ( BEG='${ ' END='; }' ) +) +PAR=( + ( BEG='( ' END=' )' ) + ( BEG='{ ' END='; }' ) +) +CMD=( command-kill script-kill ) +ADD=( '' '; :' ) + +cd $tmp +print $'#!'$SHELL$'\nkill -KILL $$' > command-kill +print $'kill -KILL $$' > script-kill +chmod +x command-kill script-kill +export PATH=.:$PATH +exp='Killed' +for ((S=0; S<${#SUB[@]}; S++)) +do for ((P=0; P<${#PAR[@]}; P++)) + do for ((C=0; C<${#CMD[@]}; C++)) + do for ((A=0; A<${#ADD[@]}; A++)) + do cmd="${SUB[S].BEG}${PAR[P].BEG}${CMD[C]}${PAR[P].END} 2>&1${ADD[A]}${SUB[S].END}" + eval got="$cmd" + got=${got##*': '} + got=${got%%'('*} + [[ $got == "$exp" ]] || err_exit "$cmd failed -- got '$got', expected '$exp'" + done + done + done +done + +$SHELL 2> /dev/null -c '{; true ;}' || err_exit 'leading ; causes syntax error in brace group' +$SHELL 2> /dev/null -c '(; true ;)' || err_exit 'leading ; causes syntax error in parenthesis group' + +print 'for ((i = 0; i < ${1:-10000}; i++ )); do printf "%.*c\n" 15 x; done' > pipefail +chmod +x pipefail +$SHELL --pipefail -c './pipefail 10000 | sed 1q' >/dev/null 2>&1 & +tst=$! +{ sleep 4; kill $tst; } 2>/dev/null & +spy=$! +wait $tst 2>/dev/null +status=$? +if [[ $status == 0 || $(kill -l $status) == PIPE ]] +then kill $spy 2>/dev/null +else err_exit "pipefail pipeline bypasses SIGPIPE and hangs" +fi +wait + +[[ $($SHELL -uc '[[ "${d1.u[z asd].revents}" ]]' 2>&1) == *'d1.u[z asd].revents'* ]] || err_exit 'name of unset parameter not in error message' + +[[ $($SHELL 2> /dev/null -xc $'set --showme\nprint 1\n; print 2') == 1 ]] || err_exit 'showme option with xtrace not working correctly' + +$SHELL -uc 'var=foo;unset var;: ${var%foo}' >/dev/null 2>&1 && err_exit '${var%foo} should fail with set -u' +$SHELL -uc 'var=foo;unset var;: ${!var}' >/dev/null 2>&1 && err_exit '${!var} should fail with set -u' +$SHELL -uc 'var=foo;unset var;: ${#var}' >/dev/null 2>&1 && err_exit '${#var} should fail with set -u' +$SHELL -uc 'var=foo;unset var;: ${var-OK}' >/dev/null 2>&1 || err_exit '${var-OK} should not fail with set -u' +$SHELL -uc 'var=foo;nset var;: ${var:-OK}' >/dev/null 2>&1 || err_exit '${var:-OK} should not fail with set -u' + +z=$($SHELL 2>&1 -uc 'print ${X23456789012345}') +[[ $z == *X23456789012345:* ]] || err_exit "error message garbled with set -u got $z" + +# pipe hang bug fixed 2011-03-15 +float start=SECONDS toolong=3 +( $SHELL <<-EOF + set -o pipefail + (sleep $toolong;kill \$\$> /dev/null) & + cat $SHELL | for ((i=0; i < 5; i++)) + do + date | wc > /dev/null + $SHELL -c 'read -N1' + done +EOF +) 2> /dev/null +(( (SECONDS-start) > (toolong-0.5) )) && err_exit "pipefail causes script to hang" + +# showme with arithmetic for loops +$SHELL -n -c $'for((;1;))\ndo ; nothing\ndone' 2>/dev/null || err_exit 'showme commands give syntax error inside arithmetic for loops' + +#set -x +float t1=SECONDS +set -o pipefail +print | while read +do if { date | true;} ; true + then sleep 2 & + fi +done +(( (SECONDS-t1) > .5 )) && err_exit 'pipefail should not wait for background processes' + +# process source files from profiles as profile files +print '. ./dotfile' > envfile +print $'alias print=:\nprint foobar' > dotfile +[[ $(ENV=$PWD/envfile $SHELL -i -c : 2>/dev/null) == foobar ]] && err_exit 'files source from profile does not process aliases correctly' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/path.sh b/src/cmd/ksh93/tests/path.sh new file mode 100755 index 0000000..3fd16e9 --- /dev/null +++ b/src/cmd/ksh93/tests/path.sh @@ -0,0 +1,375 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +cd $tmp || exit +type /xxxxxx > out1 2> out2 +[[ -s out1 ]] && err_exit 'type should not write on stdout for not found case' +[[ -s out2 ]] || err_exit 'type should write on stderr for not found case' +mkdir dir1 dir2 +cat > dir1/foobar << '+++' +foobar() { print foobar1;} +function dir1 { print dir1;} ++++ +cat > dir2/foobar << '+++' +foobar() { print foobar2;} +function dir2 { print dir2;} ++++ +chmod +x dir[12]/foobar +p=$PATH +FPATH=$PWD/dir1 +PATH=$FPATH:$p +[[ $( foobar) == foobar1 ]] || err_exit 'foobar should output foobar1' +FPATH=$PWD/dir2 +PATH=$FPATH:$p +[[ $(foobar) == foobar2 ]] || err_exit 'foobar should output foobar2' +FPATH=$PWD/dir1 +PATH=$FPATH:$p +[[ $(foobar) == foobar1 ]] || err_exit 'foobar should output foobar1 again' +FPATH=$PWD/dir2 +PATH=$FPATH:$p +[[ ${ foobar;} == foobar2 ]] || err_exit 'foobar should output foobar2 with ${}' +[[ ${ dir2;} == dir2 ]] || err_exit 'should be dir2' +[[ ${ dir1;} == dir1 ]] 2> /dev/null && err_exit 'should not be be dir1' +FPATH=$PWD/dir1 +PATH=$FPATH:$p +[[ ${ foobar;} == foobar1 ]] || err_exit 'foobar should output foobar1 with ${}' +[[ ${ dir1;} == dir1 ]] || err_exit 'should be dir1' +[[ ${ dir2;} == dir2 ]] 2> /dev/null && err_exit 'should not be be dir2' +FPATH=$PWD/dir2 +PATH=$FPATH:$p +[[ ${ foobar;} == foobar2 ]] || err_exit 'foobar should output foobar2 with ${} again' +PATH=$p +(PATH="/bin") +[[ $($SHELL -c 'print -r -- "$PATH"') == "$PATH" ]] || err_exit 'export PATH lost in subshell' +cat > bug1 <<- EOF + print print ok > $tmp/ok + /bin/chmod 755 $tmp/ok + function a + { + typeset -x PATH=$tmp + ok + } + path=\$PATH + unset PATH + a + PATH=\$path +} +EOF +[[ $($SHELL ./bug1 2>/dev/null) == ok ]] || err_exit "PATH in function not working" +cat > bug1 <<- \EOF + function lock_unlock + { + typeset PATH=/usr/bin + typeset -x PATH='' + } + + PATH=/usr/bin + : $(PATH=/usr/bin getconf PATH) + typeset -ft lock_unlock + lock_unlock +EOF +($SHELL ./bug1) 2> /dev/null || err_exit "path_delete bug" +mkdir tdir +if $SHELL tdir > /dev/null 2>&1 +then err_exit 'not an error to run ksh on a directory' +fi + +print 'print hi' > ls +if [[ $($SHELL ls 2> /dev/null) != hi ]] +then err_exit "$SHELL name not executing version in current directory" +fi +if [[ $(ls -d . 2>/dev/null) == . && $(PATH=/bin:/usr/bin:$PATH ls -d . 2>/dev/null) != . ]] +then err_exit 'PATH export in command substitution not working' +fi +pwd=$PWD +# get rid of leading and trailing : and trailing :. +PATH=${PATH%.} +PATH=${PATH%:} +PATH=${PATH#.} +PATH=${PATH#:} +path=$PATH +var=$(whence date) +dir=$(basename "$var") +for i in 1 2 3 4 5 6 7 8 9 0 +do if ! whence notfound$i 2> /dev/null + then cmd=notfound$i + break + fi +done +print 'print hello' > date +chmod +x date +print 'print notfound' > $cmd +chmod +x "$cmd" +> foo +chmod 755 foo +for PATH in $path :$path $path: .:$path $path: $path:. $PWD::$path $PWD:.:$path $path:$PWD $path:.:$PWD +do +# print path=$PATH $(whence date) +# print path=$PATH $(whence "$cmd") + date + "$cmd" +done > /dev/null 2>&1 +builtin -d date 2> /dev/null +if [[ $(PATH=:/usr/bin; date) != 'hello' ]] +then err_exit "leading : in path not working" +fi +( + PATH=$PWD: + builtin chmod + print 'print cannot execute' > noexec + chmod 644 noexec + if [[ ! -x noexec ]] + then noexec > /dev/null 2>&1 + else exit 126 + fi +) +status=$? +[[ $status == 126 ]] || err_exit "exit status of non-executable is $status -- 126 expected" +builtin -d rm 2> /dev/null +chmod=$(whence chmod) +rm=$(whence rm) +d=$(dirname "$rm") + +chmod=$(whence chmod) + +for cmd in date foo +do exp="$cmd found" + print print $exp > $cmd + $chmod +x $cmd + got=$($SHELL -c "unset FPATH; PATH=/dev/null; $cmd" 2>&1) + [[ $got == $exp ]] && err_exit "$cmd as last command should not find ./$cmd with PATH=/dev/null" + got=$($SHELL -c "unset FPATH; PATH=/dev/null; $cmd" 2>&1) + [[ $got == $exp ]] && err_exit "$cmd should not find ./$cmd with PATH=/dev/null" + exp=$PWD/./$cmd + got=$(unset FPATH; PATH=/dev/null; whence ./$cmd) + [[ $got == $exp ]] || err_exit "whence $cmd should find ./$cmd with PATH=/dev/null" + exp=$PWD/$cmd + got=$(unset FPATH; PATH=/dev/null; whence $PWD/$cmd) + [[ $got == $exp ]] || err_exit "whence \$PWD/$cmd should find ./$cmd with PATH=/dev/null" +done + +exp='' +got=$($SHELL -c "unset FPATH; PATH=/dev/null; whence ./notfound" 2>&1) +[[ $got == $exp ]] || err_exit "whence ./$cmd failed -- expected '$exp', got '$got'" +got=$($SHELL -c "unset FPATH; PATH=/dev/null; whence $PWD/notfound" 2>&1) +[[ $got == $exp ]] || err_exit "whence \$PWD/$cmd failed -- expected '$exp', got '$got'" + +unset FPATH +PATH=/dev/null +for cmd in date foo +do exp="$cmd found" + print print $exp > $cmd + $chmod +x $cmd + got=$($cmd 2>&1) + [[ $got == $exp ]] && err_exit "$cmd as last command should not find ./$cmd with PATH=/dev/null" + got=$($cmd 2>&1; :) + [[ $got == $exp ]] && err_exit "$cmd should not find ./$cmd with PATH=/dev/null" + exp=$PWD/./$cmd + got=$(whence ./$cmd) + [[ $got == $exp ]] || err_exit "whence ./$cmd should find ./$cmd with PATH=/dev/null" + exp=$PWD/$cmd + got=$(whence $PWD/$cmd) + [[ $got == $exp ]] || err_exit "whence \$PWD/$cmd should find ./$cmd with PATH=/dev/null" +done +exp='' +got=$(whence ./notfound) +[[ $got == $exp ]] || err_exit "whence ./$cmd failed -- expected '$exp', got '$got'" +got=$(whence $PWD/notfound) +[[ $got == $exp ]] || err_exit "whence \$PWD/$cmd failed -- expected '$exp', got '$got'" + +PATH=$d: +cp "$rm" kshrm +if [[ $(whence kshrm) != $PWD/kshrm ]] +then err_exit 'trailing : in pathname not working' +fi +cp "$rm" rm +PATH=:$d +if [[ $(whence rm) != $PWD/rm ]] +then err_exit 'leading : in pathname not working' +fi +PATH=$d: whence rm > /dev/null +if [[ $(whence rm) != $PWD/rm ]] +then err_exit 'pathname not restored after scoping' +fi +mkdir bin +print 'print ok' > bin/tst +chmod +x bin/tst +if [[ $(PATH=$PWD/bin tst 2>/dev/null) != ok ]] +then err_exit '(PATH=$PWD/bin foo) does not find $PWD/bin/foo' +fi +cd / +if whence ls > /dev/null +then PATH= + if [[ $(whence rm) ]] + then err_exit 'setting PATH to Null not working' + fi + unset PATH + if [[ $(whence rm) != /*rm ]] + then err_exit 'unsetting path not working' + fi +fi +PATH=/dev:$tmp +x=$(whence rm) +typeset foo=$(PATH=/xyz:/abc :) +y=$(whence rm) +[[ $x != "$y" ]] && err_exit 'PATH not restored after command substitution' +whence getconf > /dev/null && err_exit 'getconf should not be found' +builtin /bin/getconf +PATH=/bin +PATH=$(getconf PATH) +x=$(whence ls) +PATH=.:$PWD:${x%/ls} +[[ $(whence ls) == "$x" ]] || err_exit 'PATH search bug when .:$PWD in path' +PATH=$PWD:.:${x%/ls} +[[ $(whence ls) == "$x" ]] || err_exit 'PATH search bug when :$PWD:. in path' +cd "${x%/ls}" +[[ $(whence ls) == /* ]] || err_exit 'whence not generating absolute pathname' +status=$($SHELL -c $'trap \'print $?\' EXIT;/xxx/a/b/c/d/e 2> /dev/null') +[[ $status == 127 ]] || err_exit "not found command exit status $status -- expected 127" +status=$($SHELL -c $'trap \'print $?\' EXIT;/dev/null 2> /dev/null') +[[ $status == 126 ]] || err_exit "non executable command exit status $status -- expected 126" +status=$($SHELL -c $'trap \'print $?\' ERR;/xxx/a/b/c/d/e 2> /dev/null') +[[ $status == 127 ]] || err_exit "not found command with ERR trap exit status $status -- expected 127" +status=$($SHELL -c $'trap \'print $?\' ERR;/dev/null 2> /dev/null') +[[ $status == 126 ]] || err_exit "non executable command ERR trap exit status $status -- expected 126" + +# universe via PATH + +builtin getconf +getconf UNIVERSE - att # override sticky default 'UNIVERSE = foo' + +[[ $(PATH=/usr/ucb/bin:/usr/bin echo -n ucb) == 'ucb' ]] || err_exit "ucb universe echo ignores -n option" +[[ $(PATH=/usr/xpg/bin:/usr/bin echo -n att) == '-n att' ]] || err_exit "att universe echo does not ignore -n option" + +PATH=$path + +scr=$tmp/script +exp=126 + +: > $scr +chmod a=x $scr +{ got=$($scr; print $?); } 2>/dev/null +[[ "$got" == "$exp" ]] || err_exit "unreadable empty script should fail -- expected $exp, got $got" +{ got=$(command $scr; print $?); } 2>/dev/null +[[ "$got" == "$exp" ]] || err_exit "command of unreadable empty script should fail -- expected $exp, got $got" +[[ "$(:; $scr; print $?)" == "$exp" ]] 2>/dev/null || err_exit "unreadable empty script in [[ ... ]] should fail -- expected $exp" +[[ "$(:; command $scr; print $?)" == "$exp" ]] 2>/dev/null || err_exit "command unreadable empty script in [[ ... ]] should fail -- expected $exp" +got=$($SHELL -c "$scr; print \$?" 2>/dev/null) +[[ "$got" == "$exp" ]] || err_exit "\$SHELL -c of unreadable empty script should fail -- expected $exp, got" $got +got=$($SHELL -c "command $scr; print \$?" 2>/dev/null) +[[ "$got" == "$exp" ]] || err_exit "\$SHELL -c of command of unreadable empty script should fail -- expected $exp, got" $got + +rm -f $scr +print : > $scr +chmod a=x $scr +{ got=$($scr; print $?); } 2>/dev/null +[[ "$got" == "$exp" ]] || err_exit "unreadable non-empty script should fail -- expected $exp, got $got" +{ got=$(command $scr; print $?); } 2>/dev/null +[[ "$got" == "$exp" ]] || err_exit "command of unreadable non-empty script should fail -- expected $exp, got $got" +[[ "$(:; $scr; print $?)" == "$exp" ]] 2>/dev/null || err_exit "unreadable non-empty script in [[ ... ]] should fail -- expected $exp" +[[ "$(:; command $scr; print $?)" == "$exp" ]] 2>/dev/null || err_exit "command unreadable non-empty script in [[ ... ]] should fail -- expected $exp" +got=$($SHELL -c "$scr; print \$?" 2>/dev/null) +[[ "$got" == "$exp" ]] || err_exit "\$SHELL -c of unreadable non-empty script should fail -- expected $exp, got" $got +got=$($SHELL -c "command $scr; print \$?" 2>/dev/null) +[[ "$got" == "$exp" ]] || err_exit "\$SHELL -c of command of unreadable non-empty script should fail -- expected $exp, got" $got + +# whence -a bug fix +cd "$tmp" +ifs=$IFS +IFS=$'\n' +PATH=$PATH: +> ls +chmod +x ls +ok= +for i in $(whence -a ls) +do if [[ $i == *"$PWD/ls" ]] + then ok=1 + break; + fi +done +[[ $ok ]] || err_exit 'whence -a not finding all executables' +rm -f ls +PATH=${PATH%:} + +#whence -p bug fix +function foo +{ + : +} +[[ $(whence -p foo) == foo ]] && err_exit 'whence -p foo should not find function foo' + +# whence -q bug fix +$SHELL -c 'whence -q cat' & pid=$! +sleep 3 +kill $! 2> /dev/null && err_exit 'whence -q appears to be hung' + +FPATH=$PWD +print 'function foobar { :;}' > foobar +autoload foobar; +exec {m}< /dev/null +for ((i=0; i < 25; i++)) +do ( foobar ) +done +exec {m}<& - +exec {n}< /dev/null +(( n > m )) && err_exit 'autoload function in subshell leaves file open' + +# whence -a bug fix +rmdir=rmdir +if mkdir "$rmdir" +then rm=${ whence rm;} + cp "$rm" "$rmdir" + { PATH=:${rm%/rm} $SHELL -c "cd \"$rmdir\";whence -a rm";} > /dev/null 2>&1 + exitval=$? + (( exitval==0 )) || err_exit "whence -a has exitval $exitval" +fi + +[[ ! -d bin ]] && mkdir bin +[[ ! -d fun ]] && mkdir fun +print 'FPATH=../fun' > bin/.paths +cat <<- \EOF > fun/myfun + function myfun + { + print myfun + } +EOF +x=$(FPATH= PATH=$PWD/bin $SHELL -c ': $(whence less);myfun') 2> /dev/null +[[ $x == myfun ]] || err_exit 'function myfun not found' + +cp $(whence -p echo) user_to_group_relationship.hdr.query +FPATH=/foobar: +PATH=$FPATH:$PATH:. +[[ $(user_to_group_relationship.hdr.query foobar) == foobar ]] 2> /dev/null || err_exit 'Cannot execute command with . in name when PATH and FPATH end in :.' + +exit $((Errors<125?Errors:125)) + diff --git a/src/cmd/ksh93/tests/pointtype.sh b/src/cmd/ksh93/tests/pointtype.sh new file mode 100755 index 0000000..b0a5333 --- /dev/null +++ b/src/cmd/ksh93/tests/pointtype.sh @@ -0,0 +1,138 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +typeset -T Pt_t=( + float x=1 + float y=0 + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y))) + } +) + +for ((i=0; i < 100; i++)) +do +Pt_t p +[[ ${p.x} == 1 ]] || err_exit '${p[x]} is not 1' +(( p.x == 1 )) || err_ext 'p[x] is not 1' +[[ $(p.len) == 1 ]] || err_exit '$(p.len) != 1' +[[ ${p.len} == 1 ]] || err_exit '${p.len} != 1' +(( p.len == 1 )) || err_exit '((p.len != 1))' +Pt_t q=(y=2) +(( q.x == 1 )) || err_exit 'q.x is not 1' +(( (q.len - sqrt(5)) < 10e-10 )) || err_exit 'q.len != sqrt(5)' +q.len() +{ + print -r $((abs(_.x)+abs(_.y) )) +} +(( q.len == 3 )) || err_exit 'q.len is not 3' +p=q +[[ ${p.y} == 2 ]] || err_exit '${p[y]} is not 2' +[[ ${@p} == Pt_t ]] || err_exit 'type of p is not Pt_t' +[[ ${@q} == Pt_t ]] || err_exit 'type of q is not Pt_t' +(( p.len == 3 )) || err_exit 'p.len is not 3' +unset p q +Pt_t pp=( ( x=3 y=4) ( x=5 y=12) (y=2) ) +(( pp[0].len == 5 )) || err_exit 'pp[0].len != 5' +(( pp[1].len == 13 )) || err_exit 'pp[0].len != 12' +(( (pp[2].len - sqrt(5)) < 10e-10 )) || err_exit 'pp[2].len != sqrt(5)' +[[ ${pp[1]} == $'(\n\ttypeset -l -E x=5\n\ttypeset -l -E y=12\n)' ]] || err_exit '${pp[1] is not correct' +[[ ${!pp[@]} == '0 1 2' ]] || err_exit '${pp[@] != "0 1 2"' +pp+=( x=6 y=8) +(( pp[3].len == 10 )) || err_exit 'pp[3].len != 10' +[[ ${!pp[@]} == '0 1 2 3' ]] || err_exit '${pp[@] != "0 1 2 3"' +pp[4]=pp[1] +[[ ${pp[4]} == $'(\n\ttypeset -l -E x=5\n\ttypeset -l -E y=12\n)' ]] || err_exit '${pp[4] is not correct' +unset pp +Pt_t pp=( [one]=( x=3 y=4) [two]=( x=5 y=12) [three]=(y=2) ) +(( pp[one].len == 5 )) || err_exit 'pp[one].len != 5' +(( pp[two].len == 13 )) || err_exit 'pp[two].len != 12' +[[ ${pp[two]} == $'(\n\ttypeset -l -E x=5\n\ttypeset -l -E y=12\n)' ]] || err_exit '${pp[two] is not correct' +[[ ${!pp[@]} == 'one three two' ]] || err_exit '${pp[@] != "one three two"' +[[ ${@pp[1]} == Pt_t ]] || err_exit 'type of pp[1] is not Pt_t' +unset pp +done +# redefinition of point +typeset -T Pt_t=( + Pt_t _=(x=3 y=6) + float z=2 + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y + _.z*_.z))) + } +) +Pt_t p +[[ ${p.y} == 6 ]] || err_exit '${p.y} != 6' +(( p.len == 7 )) || err_exit '((p.len !=7))' + +z=() +Pt_t -a z.p +z.p[1]=(y=2) +z.p[2]=(y=5) +z.p[3]=(x=6 y=4) +eval y="$z" +[[ $y == "$z" ]] || err_exit 'expansion of indexed array of types is incorrect' +eval "$(typeset -p y)" +[[ $y == "$z" ]] || err_exit 'typeset -p z for indexed array of types is incorrect' +unset z y +z=() +Pt_t -A z.p +z.p[1]=(y=2) +z.p[2]=(y=5) +z.p[3]=(x=6 y=4) +eval y="$z" +[[ $y == "$z" ]] || err_exit 'expansion of associative array of types is incorrect' +eval "$(typeset -p y)" +[[ $y == "$z" ]] || err_exit 'typeset -p z for associative of types is incorrect' +unset z y + +typeset -T A_t=( + Pt_t -a b +) +typeset -T B_t=( + Pt_t -A b +) +A_t r +r.b[1]=(y=2) +r.b[2]=(y=5) +eval s="$r" +[[ $r == "$s" ]] || err_exit 'expansion of type containing index array of types is incorrect' +eval "$(typeset -p s)" +[[ $y == "$z" ]] || err_exit 'typeset -p z for type containing index of types is incorrect' +unset r s +B_t r +r.b[1]=(y=2) +r.b[2]=(y=5) +eval s="$r" +[[ $r == "$s" ]] || err_exit 'expansion of type containing index array of types is incorrect' +eval "$(typeset -p s)" +[[ $y == "$z" ]] || err_exit 'typeset -p z for type containing index of types is incorrect' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/pty.sh b/src/cmd/ksh93/tests/pty.sh new file mode 100755 index 0000000..71eaef5 --- /dev/null +++ b/src/cmd/ksh93/tests/pty.sh @@ -0,0 +1,442 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +: : generated by mkptytests from "posix-sh-*-c.pty" : : + +# the trickiest part of the tests is avoiding typeahead +# in the pty dialogue + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} + +alias err_exit='err_exit $lineno' + +Command=${0##*/} +integer Errors=0 lineno=1 + +whence -q pty || { lineno=$LINENO; err_exit "pty command not found -- tests skipped"; exit 0; } + +bintrue=$(whence -p true) + +x=$( $SHELL <<- \EOF + trap 'exit 0' EXIT + bintrue=$(whence -p true) + set -o monitor + { + eval $'set -o vi\npty $bintrue' + } < /dev/null & pid=$! + #sleep 1 + jobs + kill $$ + EOF +) +[[ $x == *Stop* ]] && err_exit 'monitor mode enabled incorrectly causes job to stop' + +if [[ -o xtrace ]] +then debug=--debug=1 +else debug= +fi + +function tst +{ + integer lineno=$1 offset + typeset text + + pty $debug --dialogue --messages='/dev/fd/1' $SHELL | + while read -r text + do if [[ $text == *debug* ]] + then print -u2 -r -- "$text" + else offset=${text/*: line +([[:digit:]]):*/\1} + err_exit "${text/: line $offset:/: line $(( lineno + offset)):}" + fi + done +} + +export PS1=':test-!: ' PS2='> ' PS4=': ' ENV= EXINIT= HISTFILE= TERM=dumb VISUAL=vi LC_ALL=C + +if ! pty $bintrue < /dev/null +then err_exit pty command hangs on $bintrue -- tests skipped + exit 0 +fi + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 026(C) + +# If the User Portability Utilities Option is supported: When the +# POSIX locale is specified and a background job is suspended by a +# SIGTSTP signal then the <state> field in the output message is set to +# Stopped, Suspended, Stopped(SIGTSTP) or Suspended(SIGTSTP). + +I ^\r?\n$ +p :test-1: +w sleep 60 & +u [[:digit:]]\r?\n$ +s 100 +p :test-2: +w kill -TSTP $! +u (Stopped|Suspended) +p :test-3: +w kill -KILL $! +w wait +u (Killed|Done) +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 028(C) + +# If the User Portability Utilities Option is supported: When the +# POSIX locale is specified and a background job is suspended by a +# SIGTTIN signal then the <state> field in the output message is set to +# Stopped(SIGTTIN) or Suspended(SIGTTIN). + +I ^\r?\n$ +p :test-1: +w sleep 60 & +u [[:digit:]]\r?\n$ +s 100 +p :test-2: +w kill -TTIN $! +u (Stopped|Suspended) \(SIGTTIN\) +p :test-3: +w kill -KILL $! +w wait +u (Killed|Done) +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 029(C) + +# If the User Portability Utilities Option is supported: When the +# POSIX locale is specified and a background job is suspended by a +# SIGTTOU signal then the <state> field in the output message is set to +# Stopped(SIGTTOU) or Suspended(SIGTTOU). + +I ^\r?\n$ +p :test-1: +w sleep 60 & +u [[:digit:]]\r?\n$ +s 100 +p :test-2: +w kill -TTOU $! +u (Stopped|Suspended) \(SIGTTOU\) +p :test-3: +w kill -KILL $! +w wait +u (Killed|Done) +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 091(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in insert mode an entered +# character other than <newline>, erase, interrupt, kill, control-V, +# control-W, backslash \ (followed by erase or kill), end-of-file and +# <ESC> is inserted in the current command line. + +c echo h +c ell +w o +u ^hello\r?\n$ +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 093(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: After termination of a previous +# command, sh is entered in insert mode. + +w echo hello +u ^hello\r?\n$ +c echo goo +c dby +w e +u ^goodbye\r?\n$ +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 094(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in insert mode an <ESC> +# switches sh into command mode. + +c echo he\E +s 400 +w allo +u ^hello\r?\n$ +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 096(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in command mode the +# interrupt character causes sh to terminate command line editing on +# the current command line, re-issue the prompt on the next line of the +# terminal and to reset the command history so that the command that +# was interrupted is not entered in the history. + +I ^\r?\n$ +p :test-1: +w echo first +p :test-2: +w stty intr ^C +p :test-3: +c echo bad\E +s 400 +c \cC +w echo scrambled +p :test-4: +w history +u echo first +r stty intr \^C +r echo +r history +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 097(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in insert mode a <newline> +# causes the current command line to be executed. + +c echo ok\n +u ^ok\r?\n$ +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 099(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in insert mode the interrupt +# character causes sh to terminate command line editing on the current +# command line, re-issue the prompt on the next line of the terminal +# and to reset the command history so that the command that was +# interrupted is not entered in the history. + +I ^\r?\n$ +p :test-1: +w echo first +u ^first +p :test-2: +w stty intr ^C +r +p :test-3: +c echo bad\cC +w echo last +p :test-4: +w history +u echo first +r stty intr \^C +r echo last +r history +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 100(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in insert mode the kill +# character clears all the characters from the input line. + +p :test-1: +w stty kill ^X +p :test-2: +c echo bad\cX +w echo ok +u ^ok\r?\n$ +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 101(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in insert mode a control-V +# causes the next character to be inserted even in the case that the +# character is a special insert mode character. +# Testing Requirements: The assertion must be tested with at least the +# following set of characters: <newline>, erase, interrupt, kill, +# control-V, control-W, end-of-file, backslash \ (followed by erase or +# kill) and <ESC>. + +d 10 +p :test-1: +w stty erase ^H intr ^C kill ^X +p :test-2: +w echo erase=:\cV\cH: +u ^erase=:\r?\n$ +p :test-3: +w echo kill=:\cV\cX: +u ^kill=:\cX:\r?\n$ +p :test-4: +w echo control-V=:\cV\cV: +u ^control-V=:\cV:\r?\n$ +p :test-5: +w echo control-W:\cV\cW: +u ^control-W:\cW:\r?\n$ +p :test-6: +w echo EOF=:\cV\cD: +u ^EOF=:\004:\r?\n$ +p :test-7: +w echo backslash-erase=:\\\cH: +u ^backslash-erase=:\r?\n$ +p :test-8: +w echo backslash-kill=:\\\cX: +u ^backslash-kill=:\cX:\r?\n$ +p :test-9: +w echo ESC=:\cV\E: +u ^ESC=:\E:\r?\n$ +p :test-10: +w echo interrupt=:\cV\cC: +u ^interrupt=:\cC:\r?\n$ +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 104(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in insert mode an +# end-of-file at the beginning of an input line is interpreted as the +# end of input. + +p :test-1: +w trap 'echo done >&2' EXIT +p :test-2: +s 100 +c \cD +u ^done\r?\n$ +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 111(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in command mode, # inserts +# the character # at the beginning of the command line and causes the +# line to be treated as a comment and the line is entered in the +# command history. + +p :test-1: +c echo save\E +s 400 +c # +p :test-2: +w history +u #echo save +r history +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 137(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in command mode, then v +# invokes the vi editor to edit the current command line in a temporary +# file. When the editor exits, the commands in the temporary file are +# executed. + +p :test-1: +c echo hello\E +s 400 +c v +u /tmp/ +c A world\E +s 400 +w :wq +u ^hello world\r?\n$ +! + +# err_exit # +tst $LINENO <<"!" +L POSIX sh 251(C) + +# If the User Portability Utilities Option is supported and shell +# command line editing is supported: When in command mode, then the +# command N repeats the most recent / or ? command, reversing the +# direction of the search. + +p :test-1: +w echo repeat-1 +u ^repeat-1\r?\n$ +p :test-2: +w echo repeat-2 +u ^repeat-2\r?\n$ +p :test-3: +s 100 +c \E +s 400 +w /rep +u echo repeat-2 +c n +r echo repeat-1 +c N +r echo repeat-2 +w dd +p :test-3: +w echo repeat-3 +u ^repeat-3\r?\n$ +p :test-4: +s 100 +c \E +s 400 +w ?rep +r echo repeat-2 +c N +r echo repeat-1 +c n +r echo repeat-2 +c n +r echo repeat-3 +! + +# err_exit # +whence -q less && +TERM=vt100 tst $LINENO <<"!" +L process/terminal group exercise + +w m=yes; while true; do echo $m-$m; done | less +u :$|:\E|lines +c \cZ +r Stopped +w fg +u yes-yes +! + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/quoting.sh b/src/cmd/ksh93/tests/quoting.sh new file mode 100755 index 0000000..01aae0d --- /dev/null +++ b/src/cmd/ksh93/tests/quoting.sh @@ -0,0 +1,369 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 +if [[ 'hi there' != "hi there" ]] +then err_exit "single quotes not the same as double quotes" +fi +x='hi there' +if [[ $x != 'hi there' ]] +then err_exit "$x not the same as 'hi there'" +fi +if [[ $x != "hi there" ]] +then err_exit "$x not the same as \"hi there \"" +fi +if [[ \a\b\c\*\|\"\ \\ != 'abc*|" \' ]] +then err_exit " \\ differs from '' " +fi +if [[ "ab\'\"\$(" != 'ab\'\''"$(' ]] +then err_exit " \"\" differs from '' " +fi +if [[ $(print -r - 'abc*|" \') != 'abc*|" \' ]] +then err_exit "\$(print -r - '') differs from ''" +fi +if [[ $(print -r - "abc*|\" \\") != 'abc*|" \' ]] +then err_exit "\$(print -r - '') differs from ''" +fi +if [[ "$(print -r - 'abc*|" \')" != 'abc*|" \' ]] +then err_exit "\"\$(print -r - '')\" differs from ''" +fi +if [[ "$(print -r - "abc*|\" \\")" != 'abc*|" \' ]] +then err_exit "\"\$(print -r - "")\" differs from ''" +fi +if [[ $(print -r - $(print -r - 'abc*|" \')) != 'abc*|" \' ]] +then err_exit "nested \$(print -r - '') differs from ''" +fi +if [[ "$(print -r - $(print -r - 'abc*|" \'))" != 'abc*|" \' ]] +then err_exit "\"nested \$(print -r - '')\" differs from ''" +fi +if [[ $(print -r - "$(print -r - 'abc*|" \')") != 'abc*|" \' ]] +then err_exit "nested \"\$(print -r - '')\" differs from ''" +fi +unset x +if [[ ${x-$(print -r - "abc*|\" \\")} != 'abc*|" \' ]] +then err_exit "\${x-\$(print -r - '')} differs from ''" +fi +if [[ ${x-$(print -r - "a}c*|\" \\")} != 'a}c*|" \' ]] +then err_exit "\${x-\$(print -r - '}')} differs from ''" +fi +x=$((echo foo)|(cat)) +if [[ $x != foo ]] +then err_exit "((cmd)|(cmd)) failed" +fi +x=$(print -r -- "\"$HOME\"") +if [[ $x != '"'$HOME'"' ]] +then err_exit "nested double quotes failed" +fi +unset z +: ${z="a{b}c"} +if [[ $z != 'a{b}c' ]] +then err_exit '${z="a{b}c"} not correct' +fi +unset z +: "${z="a{b}c"}" +if [[ $z != 'a{b}c' ]] +then err_exit '"${z="a{b}c"}" not correct' +fi +if [[ $(print -r -- "a\*b") != 'a\*b' ]] +then err_exit '$(print -r -- "a\*b") differs from a\*b' +fi +unset x +if [[ $(print -r -- "a\*b$x") != 'a\*b' ]] +then err_exit '$(print -r -- "a\*b$x") differs from a\*b' +fi +x=hello +set -- ${x+foo bar bam} +if (( $# !=3 )) +then err_exit '${x+foo bar bam} does not yield three arguments' +fi +set -- ${x+foo "bar bam"} +if (( $# !=2 )) +then err_exit '${x+foo "bar bam"} does not yield two arguments' +fi +set -- ${x+foo 'bar bam'} +if (( $# !=2 )) +then err_exit '${x+foo '\''bar bam'\''} does not yield two arguments' +fi +set -- ${x+foo $x bam} +if (( $# !=3 )) +then err_exit '${x+foo $x bam} does not yield three arguments' +fi +set -- ${x+foo "$x" bam} +if (( $# !=3 )) +then err_exit '${x+foo "$x" bam} does not yield three arguments' +fi +set -- ${x+"foo $x bam"} +if (( $# !=1 )) +then err_exit '${x+"foo $x bam"} does not yield one argument' +fi +set -- "${x+foo $x bam}" +if (( $# !=1 )) +then err_exit '"${x+foo $x bam}" does not yield one argument' +fi +set -- ${x+foo "$x "bam} +if (( $# !=2 )) +then err_exit '${x+foo "$x "bam} does not yield two arguments' +fi +x="ab$'cd" +if [[ $x != 'ab$'"'cd" ]] +then err_exit '$'"' inside double quotes not working" +fi +x=`print 'ab$'` +if [[ $x != 'ab$' ]] +then err_exit '$'"' inside `` quotes not working" +fi +unset a +x=$(print -r -- "'\ +\ +") +if [[ $x != "'" ]] +then err_exit 'line continuation in double strings not working' +fi +x=$(print -r -- "'\ +$a\ +") +if [[ $x != "'" ]] +then err_exit 'line continuation in expanded double strings not working' +fi +x='\*' +if [[ $(print -r -- $x) != '\*' ]] +then err_exit 'x="\\*";$x != \*' +fi +x=' hello world ' +set -- $x +if (( $# != 2 )) +then err_exit 'field splitting error' +fi +x=$(print -r -- '1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890 \ +1234567890123456789012345678901234567890123456789012345678901234567890') +if (( ${#x} != (15*73-3) )) +then err_exit "length of x, ${#x}, is incorrect should be $((15*73-3))" +fi +x='$hi' +if [[ $x\$ != '$hi$' ]] +then err_exit ' $x\$, with x=$hi, does not expand to $hi$' +fi +if [[ $x$ != '$hi$' ]] +then err_exit ' $x$, with x=$hi, does not expand to $hi$' +fi +set -- $(/bin/echo foo;sleep 1;/bin/echo bar) +if [[ $# != 2 ]] +then err_exit 'word splitting after command substitution not working' +fi +unset q +if [[ "${q:+'}q${q:+'}" != q ]] +then err_exit 'expansion of "{q:+'\''}" not correct when q unset' +fi +q=1 +if [[ "${q:+'}q${q:+'}" != "'q'" ]] +then err_exit 'expansion of "{q:+'\''}" not correct when q set' +fi +x=$'x\' #y' +if [[ $x != "x' #y" ]] +then err_exit "$'x\' #y'" not working +fi +x=$q$'x\' #y' +if [[ $x != "1x' #y" ]] +then err_exit "$q$'x\' #y'" not working +fi +IFS=, +x='a,b\,c,d' +set -- $x +if [[ $2 != 'b\' ]] +then err_exit "field splitting of $x with IFS=$IFS not working" +fi +foo=bar +bar=$(print -r -- ${foo+\\n\ }) +if [[ $bar != '\n ' ]] +then err_exit '${foo+\\n\ } expansion error' +fi +unset bar +bar=$(print -r -- ${foo+\\n\ $bar}) +if [[ $bar != '\n ' ]] +then err_exit '${foo+\\n\ $bar} expansion error with bar unset' +fi +x='\\(..\\)|&\|\|\\&\\|' +if [[ $(print -r -- $x) != "$x" ]] +then err_exit '$x, where x=\\(..\\)|&\|\|\\&\\| not working' +fi +x='\\(' +if [[ $(print -r -- a${x}b) != a"${x}"b ]] +then err_exit 'a${x}b, where x=\\( not working' +fi +x= +if [[ $(print -r -- $x'\\1') != '\\1' ]] +then err_exit 'backreference inside single quotes broken' +fi +set -- '' +set -- "$@" +if (( $# != 1 )) +then err_exit '"$@" not preserving nulls' +fi +x= +if [[ $(print -r s"!\2${x}\1\a!") != 's!\2\1\a!' ]] +then err_exit 'print -r s"!\2${x}\1\a!" not equal s!\2\1\a!' +fi +if [[ $(print -r $'foo\n\n\n') != foo ]] +then err_exit 'trailing newlines on comsubstitution not removed' +fi +unset x +if [[ ${x:='//'} != '//' ]] +then err_exit '${x:='//'} != "//"' +fi +if [[ $(print -r "\"hi$\"") != '"hi$"' ]] +then err_exit '$\ not correct inside ""' +fi +unset x +if [[ "${x-a\}b}" != 'a}b' ]] +then err_exit '"${x-a\}b}" != "a}b"' +fi +if [[ "\}\]$x\*\{\[\\" != '\}\]\*\{\[\' ]] +then err_exit '"\}\]$x\*\{\[\\" != "\}\]\*\{\[\"' +fi +foo=yes +if [[ $(print -r -- {\$foo}) != '{$foo}' ]] +then err_exit '{\$foo}' not expanded correctly +fi +[[ foo == $( +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +########################################################### +print foo) ]] || err_exit "command subsitution with long comments broken" +subject='some/other/words' +re='@(?*)/@(?*)/@(?*)' +[[ ${subject/${re}/\3} != words ]] && err_exit 'string replacement with \3 not working' +[[ ${subject/${re}/'\3'} != '\3' ]] && err_exit 'string replacement with '"'\3'"' not working' +[[ ${subject/${re}/"\\3"} != '\3' ]] && err_exit 'string replacement with "\\3" not working' +[[ ${subject/${re}/"\3"} != '\3' ]] && err_exit 'string replacement with "\3" not working' +string='\3' +[[ ${subject/${re}/${string}} != words ]] && err_exit 'string replacement with $string not working with string=\3' +[[ $(print -r "${subject/${re}/${string}}") != words ]] && err_exit 'string replacement with $string not working with string=\3 using print' +[[ ${subject/${re}/"${string}"} != '\3' ]] && err_exit 'string replacement with "$string" not working with string=\3' +[[ $(print -r "${subject/${re}/"${string}"}") != '\3' ]] && err_exit 'string replacement with "$string" not working with string=\3 using print' +string='\\3' +[[ ${subject/${re}/${string}} != '\3' ]] && err_exit 'string replacement with $string not working with string=\\3' +[[ ${subject/${re}/"${string}"} != '\\3' ]] && err_exit 'string replacement with "$string" not working with string=\\3' +[[ ${subject/${re}/\4} != '\4' ]] && err_exit 'string replacement with \4 not working' +[[ ${subject/${re}/'\4'} != '\4' ]] && err_exit 'string replacement with '\4' not working' +string='\4' +[[ ${subject/${re}/${string}} != '\4' ]] && err_exit 'string replacement with $string not working with string=\4' +[[ ${subject/${re}/"${string}"} != '\4' ]] && err_exit 'string replacement with "$string" not working with string=\4' +string='&foo' +[[ ${subject/${re}/${string}} != '&foo' ]] && err_exit 'string replacement with $string not working with string=&foo' +[[ ${subject/${re}/"${string}"} != '&foo' ]] && err_exit 'string replacement with "$string" not working with string=&foo' +{ +x=x +x=${x:-`id | sed 's/^[^(]*(\([^)]*\)).*/\1/'`} +} 2> /dev/null || err_exit 'skipping over `` failed' +[[ $x == x ]] || err_exit 'assignment ${x:=`...`} failed' +[[ $($SHELL -c 'print a[') == 'a[' ]] || err_exit "unbalanced '[' in command arg fails" +$SHELL -c $'false && (( `wc -l /dev/null | nawk \'{print $1}\'` > 2 )) && true;:' 2> /dev/null || err_exit 'syntax error with ` in arithmetic expression' +{ $SHELL -c '(( 1`: "{ }"` ))' ;} 2> /dev/null || err_exit 'problem with ` inside (())' +varname=foobarx +x=`print '"\$'${varname}'"'` +[[ $x == '"$foobarx"' ]] || err_exit $'\\$\' not handled correctly inside ``' + +copy1=5 copynum=1 +foo="`eval echo "$"{copy$copynum"-0}"`" +[[ $foo == "$copy1" ]] || err_exit '$"..." not being ignored inside ``' + +[[ $($SHELL -c 'set -- ${1+"$@"}; print $#' cmd '') == 1 ]] || err_exit '${1+"$@"} with one empty argument fails' +[[ $($SHELL -c 'set -- ${1+"$@"}; print $#' cmd foo '') == 2 ]] || err_exit '${1+"$@"} with one non-empty and on empty argument fails' +[[ $($SHELL -c 'set -- ${1+"$@"}; print $#' cmd "" '') == 2 ]] || err_exit '${1+"$@"} with two empty arguments fails' +[[ $($SHELL -c 'set -- ${1+"$@"}; print $#' cmd "" '' '') == 3 ]] || err_exit '${1+"$@"} with three empty arguments fails' +[[ $($SHELL -c 'set -- "$@"; print $#' cmd '') == 1 ]] || err_exit '"$@" with one empty argument fails' +[[ $($SHELL -c 'set -- "${@:2}"; print $#' cmd '') == 0 ]] || err_exit '"$@" with one empty argument fails' +[[ $($SHELL -c 'set -- "$@"; print $#' cmd foo '') == 2 ]] || err_exit '"$@" with one non-empty and on empty argument fails' +[[ $($SHELL -c 'set -- "$@"; print $#' cmd "" '') == 2 ]] || err_exit '"$@" with two empty arguments fails' +[[ $($SHELL -c 'set -- "$@"; print $#' cmd "" '' '') == 3 ]] || err_exit '"$@" with three empty arguments fails' +args=('') +set -- "${args[@]}" +[[ $# == 1 ]] || err_exit '"${args[@]}"} with one empty argument fails' +set -- ${1+"${args[@]}"} +[[ $# == 1 ]] || err_exit '${1+"${args[@]}"} with one empty argument fails' +args=(foo '') +set -- "${args[@]}" +[[ $# == 2 ]] || err_exit '"${args[@]}"} with one non-empty and one empty argument fails' +set -- ${1+"${args[@]}"} +[[ $# == 2 ]] || err_exit '${1+"${args[@]}"} with one non-empty and one empty argument fails' + +unset ARGS +set -- +ARGS=("$@") +set -- "${ARGS[@]}" +(( $# )) && err_exit 'set -- "${ARGS[@]}" for empty array should not produce arguments' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/quoting2.sh b/src/cmd/ksh93/tests/quoting2.sh new file mode 100755 index 0000000..bc7380d --- /dev/null +++ b/src/cmd/ksh93/tests/quoting2.sh @@ -0,0 +1,215 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 +set -o noglob +if [[ 'hi there' != "hi there" ]] +then err_exit "single quotes not the same as double quotes" +fi +x='hi there' +if [[ $x != 'hi there' ]] +then err_exit "$x not the same as 'hi there'" +fi +if [[ $x != "hi there" ]] +then err_exit "$x not the same as \"hi there \"" +fi +if [[ \a\b\c\*\|\"\ \\ != 'abc*|" \' ]] +then err_exit " \\ differs from '' " +fi +if [[ "ab\'\"\$(" != 'ab\'\''"$(' ]] +then err_exit " \"\" differs from '' " +fi +if [[ $(print -r - 'abc*|" \') != 'abc*|" \' ]] +then err_exit "\$(print -r - '') differs from ''" +fi +if [[ $(print -r - "abc*|\" \\") != 'abc*|" \' ]] +then err_exit "\$(print -r - '') differs from ''" +fi +if [[ "$(print -r - 'abc*|" \')" != 'abc*|" \' ]] +then err_exit "\"\$(print -r - '')\" differs from ''" +fi +if [[ "$(print -r - "abc*|\" \\")" != 'abc*|" \' ]] +then err_exit "\"\$(print -r - "")\" differs from ''" +fi +if [[ $(print -r - "$(print -r - 'abc*|" \')") != 'abc*|" \' ]] +then err_exit "nested \$(print -r - '') differs from ''" +fi +if [[ "$(print -r - $(print -r - 'abc*|" \'))" != 'abc*|" \' ]] +then err_exit "\"nested \$(print -r - '')\" differs from ''" +fi +if [[ $(print -r - "$(print -r - 'abc*|" \')") != 'abc*|" \' ]] +then err_exit "nested \"\$(print -r - '')\" differs from ''" +fi +unset x +if [[ ${x-$(print -r - "abc*|\" \\")} != 'abc*|" \' ]] +then err_exit "\${x-\$(print -r - '')} differs from ''" +fi +if [[ ${x-$(print -r - "a}c*|\" \\")} != 'a}c*|" \' ]] +then err_exit "\${x-\$(print -r - '}')} differs from ''" +fi +x=$((echo foo)|(cat)) +if [[ $x != foo ]] +then err_exit "((cmd)|(cmd)) failed" +fi +x=$(print -r -- "\"$HOME\"") +if [[ $x != '"'$HOME'"' ]] +then err_exit "nested double quotes failed" +fi +unset z +: ${z="a{b}c"} +if [[ $z != 'a{b}c' ]] +then err_exit '${z="a{b}c"} not correct' +fi +unset z +: "${z="a{b}c"}" +if [[ $z != 'a{b}c' ]] +then err_exit '"${z="a{b}c"}" not correct' +fi +if [[ $(print -r -- "a\*b") != 'a\*b' ]] +then err_exit '$(print -r -- "a\*b") differs from a\*b' +fi +unset x +if [[ $(print -r -- "a\*b$x") != 'a\*b' ]] +then err_exit '$(print -r -- "a\*b$x") differs from a\*b' +fi +x=hello +set -- ${x+foo bar bam} +if (( $# !=3 )) +then err_exit '${x+foo bar bam} does not yield three arguments' +fi +set -- ${x+foo "bar bam"} +if (( $# !=2 )) +then err_exit '${x+foo "bar bam"} does not yield two arguments' +fi +set -- ${x+foo 'bar bam'} +if (( $# !=2 )) +then err_exit '${x+foo '\''bar bam'\''} does not yield two arguments' +fi +set -- ${x+foo $x bam} +if (( $# !=3 )) +then err_exit '${x+foo $x bam} does not yield three arguments' +fi +set -- ${x+foo "$x" bam} +if (( $# !=3 )) +then err_exit '${x+foo "$x" bam} does not yield three arguments' +fi +set -- ${x+"foo $x bam"} +if (( $# !=1 )) +then err_exit '${x+"foo $x bam"} does not yield one argument' +fi +set -- "${x+foo $x bam}" +if (( $# !=1 )) +then err_exit '"${x+foo $x bam}" does not yield one argument' +fi +set -- ${x+foo "$x "bam} +if (( $# !=2 )) +then err_exit '${x+foo "$x "bam} does not yield two arguments' +fi +x="ab$'cd" +if [[ $x != 'ab$'"'cd" ]] +then err_exit '$'"' inside double quotes not working" +fi +x=`print 'ab$'` +if [[ $x != 'ab$' ]] +then err_exit '$'"' inside `` quotes not working" +fi +unset a +x=$(print -r -- "'\ +\ +") +if [[ $x != "'" ]] +then err_exit 'line continuation in double strings not working' +fi +x=$(print -r -- "'\ +$a\ +") +if [[ $x != "'" ]] +then err_exit 'line continuation in expanded double strings not working' +fi +x='\*' +if [[ $(print -r -- $x) != '\*' ]] +then err_exit 'x="\\*";$x != \*' +fi +if [[ $(print -r -- "\}" ) != '\}' ]] +then err_exit '(print -r -- "\}"' not working +fi +if [[ $(print -r -- "\{" ) != '\{' ]] +then err_exit 'print -r -- "\{"' not working +fi +# The following caused a syntax error on earlier versions +foo=foo x=- +if [[ `eval print \\${foo$x}` != foo* ]] +then err_exit '`eval print \\${foo$x}`' not working +fi +if [[ "`eval print \\${foo$x}`" != foo* ]] +then err_exit '"`eval print \\${foo$x}`"' not working +fi +if ( [[ $() != '' ]] ) +then err_exit '$() not working' +fi +x=a:b:c +set -- $( IFS=:; print $x) +if (( $# != 3)) +then err_exit 'IFS not working correctly with command substitution' +fi +$SHELL -n 2> /dev/null << \! || err_exit '$(...) bug with ( in comment' +y=$( + # ( this line is a bug fix + print hi +) +! +x= +for j in glob noglob +do for i in 'a\*b' 'a\ b' 'a\bc' 'a\*b' 'a\"b' + do eval [[ '$('print -r -- \'$i\'\$x')' != "'$i'" ]] && err_exit "quoting of $i\$x with $j enabled failed" + eval [[ '$('print -r -- \'$i\'\${x%*}')' != "'$i'" ]] && err_exit "quoting of $i\${x%*} with $j enabled failed" + if [[ $j == noglob ]] + then eval [[ '$('print -r -- \'$i\'\${x:-*}')' != "'$i''*'" ]] && err_exit "quoting of $i\${x:-*} with $j enabled failed" + fi + done + set -f +done +foo=foo +[[ "$" == '$' ]] || err_exit '"$" != $' +[[ "${foo}$" == 'foo$' ]] || err_exit 'foo=foo;"${foo}$" != foo$' +[[ "${foo}${foo}$" == 'foofoo$' ]] || err_exit 'foo=foo;"${foo}${foo}$" != foofoo$' +foo='$ ' +[[ "$foo" == ~(Elr)(\\\$|#)\ ]] || err_exit $'\'$ \' not matching RE \\\\\\$|#\'' +[[ "$foo" == ~(Elr)('\$'|#)\ ]] || err_exit $'\'$ \' not matching RE \'\\$\'|#\'' +foo='# ' +[[ "$foo" == ~(Elr)(\\\$|#)\ ]] || err_exit $'\'# \' not matching RE \\'\$|#\'' +[[ "$foo" == ~(Elr)('\$'|#)\ ]] || err_exit $'\'# \' not matching RE \'\\$\'|#\'' +[[ '\$' == '\$'* ]] || err_exit $'\'\\$\' not matching \'\\$\'*' +[[ a+a == ~(E)a\+a ]] || err_exit '~(E)a\+a not matching a+a' +[[ a+a =~ a\+a ]] || err_exit 'RE a\+a not matching a+a' + +exp='ac' +got=$'a\0b'c +[[ $got == "$exp" ]] || err_exit "\$'a\\0b'c expansion failed -- expected '$exp', got '$got'" + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/readcsv.sh b/src/cmd/ksh93/tests/readcsv.sh new file mode 100644 index 0000000..9dd6d9c --- /dev/null +++ b/src/cmd/ksh93/tests/readcsv.sh @@ -0,0 +1,65 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +tmp1=$tmp/tmp1.csv +tmp2=$tmp/tmp2.csv +cat > $tmp1 <<- \EOF + CAT,"CVE CCODE","NECA OCN",ST,LATA,AP,"New InterState + Orig","New Inter""""State + Term","New IntraState + Orig","New IntraState + Term"
+ CLEC,XXXX,AAAA,RB,ABC,comp," 0.2 "," 0.4 "," 0.6 "," 0.8 "
+ CLEC,YYYY,QQQQ,SX,123,mmmm," 0.3 "," 0.5 "," 0.7 "," 0.9 "
+EOF +integer count=0 nfields +IFS=${2-,} +typeset -a arr +while read -A -S arr +do ((nfields=${#arr[@]})) + if ((++count==1)) + then ((nfields==10)) || err_exit 'first record should contain 10 fields' + [[ ${arr[7]} == $'New Inter""State\nTerm' ]] || err_exit $'7th field of record 1 should contain New Inter""State\nTerm' + fi + for ((i=0; i < nfields;i++)) + do delim=$IFS + if ((i == nfields-1)) + then delim=$'\r\n' + fi + printf "%#q%s" "${arr[i]}" "$delim" + done +done < $tmp1 > $tmp2 +diff "$tmp1" "$tmp2" >/dev/null 2>&1 || err_exit "files $tmp1 and $tmp2 differ" + +exit $((Errors<125?Errors:125)) + diff --git a/src/cmd/ksh93/tests/recttype.sh b/src/cmd/ksh93/tests/recttype.sh new file mode 100755 index 0000000..9f41d92 --- /dev/null +++ b/src/cmd/ksh93/tests/recttype.sh @@ -0,0 +1,70 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +typeset -T Pt_t=( + float x=1 + float y=0 + len() + { + print -r $((sqrt(_.x*_.x + _.y*_.y))) + } +) + +typeset -T Rect_t=( + Pt_t ll=(x=0 y=0) + Pt_t ur=(x=1 y=1) + area() + { + print -r $(( abs((_.ur.x-_.ll.x)*(_.ur.y-_.ll.y)) )) + } +) + +for ((i=0; i < 100; i++)) +do +Rect_t r +[[ ${r.area} == 1 ]] || err_exit '${r.area} != 1' +Rect_t s=( + Pt_t ur=(x=9 y=9) + Pt_t ll=(x=7 y=7) +) +[[ ${s.ur.x} == 9 ]] || err_exit ' ${s.ur.x} != 9' +(( s.ur.x == 9 ))|| err_exit ' ((s.ur.x)) != 9' +[[ ${s.ll.y} == 7 ]] || err_exit '${s.ll.y} != 7' +(( s.area == 4 )) || err_exit 'area of s should be 4' +[[ ${s.area} == 4 ]] || err_exit '${s.area} != 4' +unset r s +done +Rect_t -A r +r[one]=(ur=(x=4 y=4)) +(( r[one].area == 16 )) || err_exit 'area of r[one] should be 16' +[[ ${r[one].area} == 16 ]] || err_exit '${r[one].area} should be 16' +unset r + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/restricted.sh b/src/cmd/ksh93/tests/restricted.sh new file mode 100755 index 0000000..5699105 --- /dev/null +++ b/src/cmd/ksh93/tests/restricted.sh @@ -0,0 +1,83 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +# test restricted shell +pwd=$PWD +case $SHELL in +/*) ;; +*/*) SHELL=$pwd/$SHELL;; +*) SHELL=$(whence "$SHELL");; +esac +function check_restricted +{ + rm -f out + LC_MESSAGES=C rksh -c "$@" 2> out > /dev/null + grep restricted out > /dev/null 2>&1 +} + +[[ $SHELL != /* ]] && SHELL=$pwd/$SHELL +cd $tmp || err_exit "cd $tmp failed" +ln -s $SHELL rksh +PATH=$PWD:$PATH +rksh -c '[[ -o restricted ]]' || err_exit 'restricted option not set' +[[ $(rksh -c 'print hello') == hello ]] || err_exit 'unable to run print' +check_restricted /bin/echo || err_exit '/bin/echo not resticted' +check_restricted ./echo || err_exit './echo not resticted' +check_restricted 'SHELL=ksh' || err_exit 'SHELL asignment not resticted' +check_restricted 'PATH=/bin' || err_exit 'PATH asignment not resticted' +check_restricted 'FPATH=/bin' || err_exit 'FPATH asignment not resticted' +check_restricted 'ENV=/bin' || err_exit 'ENV asignment not resticted' +check_restricted 'print > file' || err_exit '> file not restricted' +> empty +check_restricted 'print <> empty' || err_exit '<> file not restricted' +print 'echo hello' > script +chmod +x ./script +! check_restricted script || err_exit 'script without builtins should run in restricted mode' +check_restricted ./script || err_exit 'script with / in name should not run in restricted mode' +print '/bin/echo hello' > script +! check_restricted script || err_exit 'script with pathnames should run in restricted mode' +print 'echo hello> file' > script +! check_restricted script || err_exit 'script with output redirection should run in restricted mode' +print 'PATH=/bin' > script +! check_restricted script || err_exit 'script with PATH assignment should run in restricted mode' +cat > script <<! +#! $SHELL +print hello +! +! check_restricted 'script;:' || err_exit 'script with #! pathname should run in restricted mode' +! check_restricted 'script' || err_exit 'script with #! pathname should run in restricted mode even if last command in script' +for i in PATH ENV FPATH +do check_restricted "function foo { typeset $i=foobar;};foo" || err_exit "$i can be changed in function by using typeset" +done + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/return.sh b/src/cmd/ksh93/tests/return.sh new file mode 100755 index 0000000..8c243f5 --- /dev/null +++ b/src/cmd/ksh93/tests/return.sh @@ -0,0 +1,183 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +# test the behavior of return and exit with functions + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +unset HISTFILE + +foo=NOVAL bar=NOVAL +file=$tmp/test +function foo +{ + typeset foo=NOEXIT + trap "foo=EXIT;rm -f $file" EXIT + > $file + if (( $1 == 0 )) + then return $2 + elif (( $1 == 1 )) + then exit $2 + else bar "$@" + fi +} + +function bar +{ + typeset bar=NOEXIT + trap 'bar=EXIT' EXIT + if (( $1 == 2 )) + then return $2 + elif (( $1 == 3 )) + then exit $2 + fi +} + +function funcheck +{ + [[ $foo == EXIT ]] || err_exit "foo "$@" : exit trap not set" + if [[ -f $file ]] + then rm -r $file + err_exit "foo $@: doesn't remove $file" + fi + foo=NOVAL bar=NOVAL +} + +(exit 0) || err_exit "exit 0 is not zero" +(return 0) || err_exit "return 0 is not zero" +(exit) || err_exit "default exit value is not zero" +(return) || err_exit "default return value is not zero" +(exit 35) +ret=$? +if (( $ret != 35 )) +then err_exit "exit 35 is $ret not 35" +fi +(return 35) +ret=$? +if (( $ret != 35 )) +then err_exit "return 35 is $ret not 35" +fi + +foo 0 0 || err_exit "foo 0 0: incorrect return" +funcheck 0 0 +foo 0 3 +ret=$? +if (( $ret != 3 )) +then err_exit "foo 0 3: return is $ret not 3" +fi +funcheck 0 3 +foo 2 0 || err_exit "foo 2 0: incorrect return" +[[ $bar == EXIT ]] || err_exit "foo 2 0: bar exit trap not set" +funcheck 2 0 +foo 2 3 +ret=$? +if (( $ret != 3 )) +then err_exit "foo 2 3: return is $ret not 3" +fi +[[ $bar == EXIT ]] || err_exit "foo 2 3: bar exit trap not set" +funcheck 2 3 +(foo 3 3) +ret=$? +if (( $ret != 3 )) +then err_exit "foo 3 3: return is $ret not 3" +fi +foo=EXIT +funcheck 3 3 +cat > $file <<! +return 3 +exit 4 +! +( . $file ) +ret=$? +if (( $ret != 3 )) +then err_exit "return in dot script is $ret should be 3" +fi +chmod 755 $file +( $file ) +ret=$? +if (( $ret != 3 )) +then err_exit "return in script is $ret should be 3" +fi +cat > $file <<! +: line 1 +# next line should fail and cause an exit +: > / +exit 4 +! +( . $file ; exit 5 ) 2> /dev/null +ret=$? +if (( $ret != 1 )) +then err_exit "error in dot script is $ret should be 1" +fi +( $file; exit 5 ) 2> /dev/null +ret=$? +if (( $ret != 5 )) +then err_exit "error in script is $ret should be 5" +fi +cat > $file <<\! +print -r -- "$0" +! +x=$( . $file) +if [[ $x != $0 ]] +then err_exit "\$0 in a dot script is $x. Should be $0" +fi +x=$($SHELL -i --norc 2> /dev/null <<\! +typeset -i x=1/0 +print hello +! +) +if [[ $x != hello ]] +then err_exit "interactive shell terminates with error in bltin" +fi +x=$( set -e + false + print bad + ) +if [[ $x != '' ]] +then err_exit "set -e doesn't terminate script on error" +fi +x=$( set -e + trap 'exit 0' EXIT + false + print bad + ) +if (( $? != 0 )) +then err_exit "exit 0 in trap should doesn't set exit value to 0" +fi +$SHELL <<\! +trap 'exit 8' EXIT +exit 1 +! +if (( $? != 8 )) +then err_exit "exit 8 in trap should set exit value to 8" +fi + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/select.sh b/src/cmd/ksh93/tests/select.sh new file mode 100755 index 0000000..07d0bde --- /dev/null +++ b/src/cmd/ksh93/tests/select.sh @@ -0,0 +1,67 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +PS3='ABC ' + +cat > $tmp/1 <<\! +1) foo +2) bar +3) bam +! + +select i in foo bar bam +do case $i in + foo) break;; + *) err_exit "select 1 not working" + break;; + esac +done 2> /dev/null <<! +1 +! + +unset i +select i in foo bar bam +do case $i in + foo) err_exit "select foo not working" 2>&3 + break;; + *) if [[ $REPLY != foo ]] + then err_exit "select REPLY not correct" 2>&3 + fi + ( set -u; : $i ) || err_exit "select: i not set to null" 2>&3 + break;; + esac +done 3>&2 2> $tmp/2 <<! +foo +! + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/shtests b/src/cmd/ksh93/tests/shtests new file mode 100755 index 0000000..5815aab --- /dev/null +++ b/src/cmd/ksh93/tests/shtests @@ -0,0 +1,235 @@ +: ksh regression test harness : + +USAGE_LICENSE="[-author?David Korn <dgk@research.att.com>][-author?Glenn Fowler <gsf@research.att.com>][-copyright?Copyright (c) 2000-2011 AT&T Intellectual Property][-license?http://www.opensource.org/licenses/cpl1.0.txt]" + +command=shtests + +setslocale='*@(locale).sh' +timesensitive='*@(options|sigchld|subshell).sh' + +USAGE=$' +[-s8? +@(#)$Id: shtests (AT&T Research) 2011-08-08 $ +] +'$USAGE_LICENSE$' +[+NAME?shtests - ksh regression test harness] +[+DESCRIPTION?\bshtests\b is the \bksh\b(1) regression test harness for + \b$SHELL\b or \bksh\b if \bSHELL\b is not defined and exported. If + none of the \b--posix --utf8 --compile\b options are specified then + all three are enabled.] +[+INPUT FILES?\bshtests\b regression test files are shell scripts that + run in an environment controlled by \bshtests\b. An identification + message is printed before and after each test on the standard output. + The default environment settings are:] + { + [+unset LANG] + [+unset LC_ALL] + [+LC_NUMERIC=C?\b.\b radix point assumed by all test scripts.] + [+VMALLOC_OPTIONS=abort?\bvmalloc\b(1) arena checking enabled + with \babort(2)\b on error.] + } +[c:compile?Run test scripts using \bshcomp\b(1).] +[d:debug?Enable \bshtests\b execution trace.] +[l:locale?Disable \b--utf8\b and run the \b--posix\b and \b--compile\b + tests, if enabled, in the locale of the caller. This may cause invalid + regressions, especially for locales where \b.\b is not the radix + point.] +[p:posix?Run the test scripts in the posix/C locale.] +[t!:time?Include the current date/time in the test identification + messages.] +[u:utf8?Run the test scripts in the ast-specific C.UTF-8 locale.] +[v!:vmalloc_options?Run tests with \bVMALLOC_OPTIONS=abort\b. Test + script names matching \b'$timesensitive$'\b are run with + \bVMALLOC_OPTIONS\b unset.] +[x:trace?Enable script execution trace.] + +[ test.sh ... ] [ name=value ... ] + +[+SEE ALSO?\bksh\b(1), \bregress\b(1), \brt\b(1)] +' + +function usage +{ + OPTIND=0 + getopts -a $command "$USAGE" OPT '--??long' + exit 2 +} + +unset DISPLAY ENV FIGNORE HISTFILE +trap + PIPE # unadvertized -- set SIGPIPE to SIG_DFL # + +integer compile=0 debug=0 locale=0 posix=0 time=1 utf8=0 +typeset vmalloc_options=abort trace= +vmalloc_options= #XXX# until multi-region vmalloc trace fixed #XXX# + +while getopts -a $command "$USAGE" OPT +do case $OPT in + c) if (( $OPTARG )) + then compile=2 + else compile=0 + fi + ;; + d) debug=$OPTARG + ;; + l) locale=$OPTARG + ;; + p) posix=$OPTARG + ;; + t) time=$OPTARG + ;; + u) utf8=$OPTARG + ;; + v) if (( OPTARG )) + then vmalloc_options=abort + else vmalloc_options= + fi + ;; + x) trace=-x + ;; + *) usage + ;; + esac +done +shift $OPTIND-1 + +if (( debug )) || [[ $trace ]] +then export PS4=':$LINENO: ' + if (( debug )) + then set -x + fi +fi + +while [[ $1 == *=* ]] +do eval export "$1" + shift +done + +if (( !compile && !posix && !utf8 )) +then compile=1 + posix=1 + utf8=1 +fi +if (( locale )) +then utf8=0 + if [[ $LC_ALL ]] + then export LANG=$LC_ALL + fi +else unset LANG LC_ALL + export LC_NUMERIC=C +fi +if [[ $VMALLOC_OPTIONS ]] +then vmalloc_options=$VMALLOC_OPTIONS +else VMALLOC_OPTIONS=$vmalloc_options +fi +[[ $VMALLOC_OPTIONS ]] || timesensitive=. +export PATH PWD SHCOMP SHELL VMALLOC_OPTIONS +PWD=$(pwd) +SHELL=${SHELL-ksh} +case $0 in +/*) d=$(dirname $0);; +*/*) d=$PWD/$(dirname $0);; +*) d=$PWD;; +esac +case $SHELL in +/*) ;; +*/*) SHELL=$d/$SHELL;; +*) SHELL=$(whence $SHELL);; +esac +PATH=/bin:/usr/bin +if [[ -d /usr/ucb ]] +then PATH=$PATH:/usr/ucb +fi +PATH=$PATH:$d +if [[ $INSTALLROOT && -r $INSTALLROOT/bin/.paths ]] +then PATH=$INSTALLROOT/bin:$PATH +fi +if [[ ${SHELL%/*} != $INSTALLROOT/bin ]] +then PATH=${SHELL%/*}:$PATH +fi +if [[ ! $SHCOMP ]] +then s=${SHELL:##*sh} + s=${SHELL:%/*}/shcomp$s + if [[ -x $s ]] + then SHCOMP=$s + elif [[ -x ${s%-g} ]] + then SHCOMP=${s%-g} + else SHCOMP=shcomp + fi +fi +if (( compile )) +then if whence $SHCOMP > /dev/null + then tmp=$(mktemp -dt) || { echo mktemp -dt failed >&2; exit 1; } + trap "cd /; rm -rf $tmp" EXIT + elif (( compile > 1 )) + then echo $0: --compile: $SHCOMP not found >&2 + exit 1 + else compile=0 + fi +fi +typeset -A tests +for i in ${*-*.sh} +do if [[ ! -r $i ]] + then echo $0: $i: not found >&2 + continue + fi + t=$(grep -c err_exit $i) + if (( t > 2 )) + then (( t = t - 2 )) + fi + tests[$i]=$t + T=test + if (( t != 1 )) + then T=${T}s + fi + u=${i##*/} + u=${u%.sh} + if [[ $i == $timesensitive ]] + then VMALLOC_OPTIONS= + fi + if (( posix || utf8 )) + then locales= + (( posix )) && locales+=" ${LANG:-C}" + [[ $utf8 == 0 || $i == $setslocale ]] || locales+=" C.UTF-8" + for lang in $locales + do o=$u + if [[ $lang == C ]] + then lang= + else o="$o($lang)" + lang=LANG=$lang + fi + echo test $o begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} + E=error + if eval $lang \$SHELL \$trace \$i + then echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]" + else e=$? + if (( e != 1 )) + then E=${E}s + fi + echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]" + fi + done + fi + if (( compile )) + then c=$tmp/shcomp-$u.ksh + o="$u(shcomp)" + echo test $o begins ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} + E=error + if $SHCOMP $i > $c + then if $SHELL $trace $c + then echo test $o passed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} "[ $t $T 0 ${E}s ]" + else e=$? + if (( e != 1 )) + then E=${E}s + fi + echo test $o failed ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T $e $E ]" + fi + else e=$? + t=1 + T=test + echo test $o failed to compile ${time:+"at $(date +%Y-%m-%d+%H:%M:%S)"} with exit code $e "[ $t $T 1 $E ]" + fi + if [[ $i == $timesensitive ]] + then VMALLOC_OPTIONS=$vmalloc_options + fi + fi +done diff --git a/src/cmd/ksh93/tests/sigchld.sh b/src/cmd/ksh93/tests/sigchld.sh new file mode 100755 index 0000000..d4dcee6 --- /dev/null +++ b/src/cmd/ksh93/tests/sigchld.sh @@ -0,0 +1,160 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +float DELAY=${1:-0.2} +integer FOREGROUND=10 BACKGROUND=2 Errors=0 + +s=$($SHELL -c ' +integer i foreground=0 background=0 +float delay='$DELAY' d=0 s=0 + +set --errexit + +trap "(( background++ ))" CHLD + +(( d = delay )) +for ((i = 0; i < '$BACKGROUND'; i++)) +do sleep $d & + (( d *= 4 )) + (( s += d )) +done +for ((i = 0; i < '$FOREGROUND'; i++)) +do (( foreground++ )) + sleep $delay + (( s -= delay )) + $SHELL -c : > /dev/null # foreground does not generate SIGCHLD +done +if (( (s += delay) < 1 )) +then (( s = 1 )) +fi +sleep $s +wait +print foreground=$foreground background=$background +') || err_exit "test loop failed" + +eval $s + +(( foreground == FOREGROUND )) || err_exit "expected '$FOREGROUND foreground' -- got '$foreground' (DELAY=$DELAY)" +(( background == BACKGROUND )) || err_exit "expected '$BACKGROUND background' -- got '$background' (DELAY=$DELAY)" + +set --noerrexit + +if [[ ${.sh.version} == Version?*([[:upper:]])J* ]] +then + + jobmax=4 + got=$($SHELL -c ' + JOBMAX='$jobmax' JOBCOUNT=$(('$jobmax'*2)) + integer running=0 maxrunning=0 + trap "((running--))" CHLD + for ((i=0; i<JOBCOUNT; i++)) + do sleep 1 & + if ((++running > maxrunning)) + then ((maxrunning=running)) + fi + done + wait + print running=$running maxrunning=$maxrunning + ') + exp='running=0 maxrunning='$jobmax + [[ $got == $exp ]] || err_exit "SIGCHLD trap queueing failed -- expected '$exp', got '$got'" + + got=$($SHELL -c ' + typeset -A proc + + trap " + print \${proc[\$!].name} \${proc[\$!].status} \$? + unset proc[\$!] + " CHLD + + { sleep 3; print a; exit 1; } & + proc[$!]=( name=a status=1 ) + + { sleep 2; print b; exit 2; } & + proc[$!]=( name=b status=2 ) + + { sleep 1; print c; exit 3; } & + proc[$!]=( name=c status=3 ) + + while (( ${#proc[@]} )) + do sleep -s + done + ') + exp='c\nc 3 3\nb\nb 2 2\na\na 1 1' + [[ $got == $exp ]] || err_exit "SIGCHLD trap queueing failed -- expected $(printf %q "$exp"), got $(printf %q "$got")" + +fi + +{ +got=$( ( sleep 1;print $'\n') | $SHELL -c 'function handler { : ;} + trap handler CHLD; sleep .3 & IFS= read; print good') +} 2> /dev/null +[[ $got == good ]] || err_exit 'SIGCLD handler effects read behavior' + +set -- $( + ( + $SHELL -xc $' + trap \'wait $!; print $! $?\' CHLD + { sleep 0.1; exit 9; } & + print $! + sleep 0.5 + ' + ) 2>/dev/null; print $? +) +if (( $# != 4 )) +then err_exit "CHLD trap failed -- expected 4 args, got $#" +elif (( $4 != 0 )) +then err_exit "CHLD trap failed -- exit code $4" +elif (( $1 != $2 )) +then err_exit "child pid mismatch -- got '$1' != '$2'" +elif (( $3 != 9 )) +then err_exit "child status mismatch -- expected '9', got '$3'" +fi + +trap '' CHLD +integer d +for ((d=0; d < 2000; d++)) +do if print foo | grep bar + then break + fi +done +(( d==2000 )) || err_exit "trap '' CHLD causes side effects d=$d" +trap - CHLD + +tmp=$(mktemp -dt) +trap 'rm -rf $tmp' EXIT +x=$($SHELL 2> /dev/null -ic '/bin/notfound; sleep .5 & sleep 1;jobs') +[[ $x == *Done* ]] || err_exit 'SIGCHLD blocked after notfound' +x=$($SHELL 2> /dev/null -ic 'kill -0 12345678901234567876; sleep .5 & sleep 1;jobs') +[[ $x == *Done* ]] || err_exit 'SIGCHLD blocked after error message' +print 'set -o monitor;sleep .5 & sleep 1;jobs' > $tmp/foobar +chmod +x $tmp/foobar +x=$($SHELL -c "echo | $tmp/foobar") +[[ $x == *Done* ]] || err_exit 'SIGCHLD blocked for script at end of pipeline' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/signal.sh b/src/cmd/ksh93/tests/signal.sh new file mode 100755 index 0000000..c6e150b --- /dev/null +++ b/src/cmd/ksh93/tests/signal.sh @@ -0,0 +1,435 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors++ )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +cd $tmp || err_exit "cd $tmp failed" + +unset n s t +typeset -A SIG +for s in $(kill -l) +do if ! n=$(kill -l $s 2>/dev/null) + then err_exit "'kill -l $s' failed" + elif ! t=$(kill -l $n 2>/dev/null) + then err_exit "'kill -l $n' failed" + elif [[ $s == ?(SIG)$t ]] + then SIG[${s#SIG}]=1 + elif ! m=$(kill -l $t 2>/dev/null) + then err_exit "'kill -l $t' failed" + elif [[ $m != $n ]] + then err_exit "'kill -l $s' => $n, 'kill -l $n' => $t, kill -l $t => $m -- expected $n" + fi +done + +( + set --pipefail + { + $SHELL 2> out2 <<- \EOF + g=false + trap 'print -u2 PIPED; $g && exit 0;g=true' PIPE + while : + do print hello + done + EOF + } | head > /dev/null + (( $? == 0)) || err_exit "SIGPIPE with wrong error code $?" + [[ $(<out2) == $'PIPED\nPIPED' ]] || err_exit 'SIGPIPE output on standard error is not correct' +) & +cop=$! +{ sleep 4; kill $cop; } 2>/dev/null & +spy=$! +if wait $cop 2>/dev/null +then kill $spy 2>/dev/null +else err_exit "pipe with --pipefail PIPE trap hangs" +fi +wait +rm -f out2 + +[[ $( trap 'print -n got_child' SIGCHLD + sleep 2 & + for ((i=0; i < 4; i++)) + do sleep .75 + print -n $i + done) == 01got_child23 ]] || err_exit 'SIGCHLD not working' + +# begin standalone SIGINT test generation + +cat > tst <<'!' +# shell trap tests +# +# tst control script that calls tst-1, must be run by ksh +# tst-1 calls tst-2 +# tst-2 calls tst-3 +# tst-3 defaults or handles and discards/propagates SIGINT +# +# initial -v option lists script entry and SIGINT delivery +# +# three test options +# +# d call next script directly, otherwise via $SHELL -c +# t trap, echo, and kill self on SIGINT, otherwise x or SIGINT default if no x +# x trap, echo on SIGINT, and tst-3 exit 0, tst-2 exit, otherwise SIGINT default +# z trap, echo on SIGINT, and tst-3 exit 0, tst-2 exit 0, otherwise SIGINT default +# +# Usage: tst [-v] [-options] shell-to-test ... + +# "trap + sig" is an unadvertized extension for this test +# if run from nmake SIGINT is set to SIG_IGN +# this call sets it back to SIG_DFL +# semantics w.r.t. function scope must be worked out before +# making it public +trap + INT + +set -o monitor + +function gen +{ + typeset o t x d + for x in - x z + do case $x in + [$1]) for t in - t + do case $t in + [$1]) for d in - d + do case $d in + [$1]) o="$o $x$t$d" + esac + done + esac + done + esac + done + echo '' $o +} + +case $1 in +-v) v=v; shift ;; +-*v*) v=v ;; +*) v= ;; +esac +case $1 in +*' '*) o=$1; shift ;; +-*) o=$(gen $1); shift ;; +*) o=$(gen -txd) ;; +esac +case $# in +0) set ksh bash ksh88 pdksh ash zsh ;; +esac +for f in $o +do case $# in + 1) ;; + *) echo ;; + esac + for sh + do if $sh -c 'exit 0' > /dev/null 2>&1 + then case $# in + 1) printf '%3s ' "$f" ;; + *) printf '%16s %3s ' "$sh" "$f" ;; + esac + $sh tst-1 $v$f $sh > tst.out & + wait + echo $(cat tst.out) + fi + done +done +case $# in +1) ;; +*) echo ;; +esac +! +cat > tst-1 <<'!' +exec 2>/dev/null +case $1 in +*v*) echo 1-main ;; +esac +{ + sleep 2 + case $1 in + *v*) echo "SIGINT" ;; + esac + kill -s INT 0 +} & +case $1 in +*t*) trap ' + echo 1-intr + trap - INT + # omitting the self kill exposes shells that deliver + # the SIGINT trap but exit 0 for -xt + # kill -s INT $$ + ' INT + ;; +esac +case $1 in +*d*) tst-2 $1 $2; status=$? ;; +*) $2 -c "tst-2 $1 $2"; status=$? ;; +esac +printf '1-%04d\n' $status +sleep 2 +! +cat > tst-2 <<'!' +case $1 in +*z*) trap ' + echo 2-intr + exit 0 + ' INT + ;; +*x*) trap ' + echo 2-intr + exit + ' INT + ;; +*t*) trap ' + echo 2-intr + trap - INT + kill -s INT $$ + ' INT + ;; +esac +case $1 in +*v*) echo 2-main ;; +esac +case $1 in +*d*) tst-3 $1 $2; status=$? ;; +*) $2 -c "tst-3 $1 $2"; status=$? ;; +esac +printf '2-%04d\n' $status +! +cat > tst-3 <<'!' +case $1 in +*[xz]*) trap ' + sleep 2 + echo 3-intr + exit 0 + ' INT + ;; +*) trap ' + sleep 2 + echo 3-intr + trap - INT + kill -s INT $$ + ' INT + ;; +esac +case $1 in +*v*) echo 3-main ;; +esac +sleep 5 +printf '3-%04d\n' $? +! +chmod +x tst tst-? + +# end standalone test generation + +export PATH=$PATH: +typeset -A expected +expected[---]="3-intr" +expected[--d]="3-intr" +expected[-t-]="3-intr 2-intr 1-intr 1-0258" +expected[-td]="3-intr 2-intr 1-intr 1-0258" +expected[x--]="3-intr 2-intr 1-0000" +expected[x-d]="3-intr 2-intr 1-0000" +expected[xt-]="3-intr 2-intr 1-intr 1-0000" +expected[xtd]="3-intr 2-intr 1-intr 1-0000" +expected[z--]="3-intr 2-intr 1-0000" +expected[z-d]="3-intr 2-intr 1-0000" +expected[zt-]="3-intr 2-intr 1-intr 1-0000" +expected[ztd]="3-intr 2-intr 1-intr 1-0000" + +tst $SHELL > tst.got + +while read ops out +do [[ $out == ${expected[$ops]} ]] || err_exit "interrupt $ops test failed -- expected '${expected[$ops]}', got '$out'" +done < tst.got + +if [[ ${SIG[USR1]} ]] +then float s=$SECONDS + [[ $(LC_ALL=C $SHELL -c 'trap "print SIGUSR1 ; exit 0" USR1; (trap "" USR1 ; exec kill -USR1 $$ & sleep 5); print done') == SIGUSR1 ]] || err_exit 'subshell ignoring signal does not send signal to parent' + (( (SECONDS-s) < 4 )) && err_exit 'parent does not wait for child to complete before handling signal' + ((s = SECONDS)) + [[ $(LC_ALL=C $SHELL -c 'trap "print SIGUSR1 ; exit 0" USR1; (trap "exit" USR1 ; exec kill -USR1 $$ & sleep 5); print done') == SIGUSR1 ]] || err_exit 'subshell catching signal does not send signal to parent' + (( SECONDS-s < 4 )) && err_exit 'parent completes early' +fi + +yes=$(whence -p yes) +if [[ $yes ]] +then for exp in TERM VTALRM PIPE + do if [[ ${SIG[$exp]} ]] + then { + $SHELL <<- EOF + foo() { return 0; } + trap foo EXIT + { sleep 2; kill -$exp \$\$; sleep 3; kill -0 \$\$ && kill -KILL \$\$; } & + $yes | + while read yes + do (/bin/date; sleep .1) + done > /dev/null + EOF + } 2>> /dev/null + got=$(kill -l $?) + [[ $exp == $got ]] || err_exit "kill -$exp \$\$ failed, required termination by signal '$got'" + fi + done +fi + +SECONDS=0 +$SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; (sleep 5); print finished' > $tmp/sig +e=$? +[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" +x=$(<$tmp/sig) +[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" +(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" + +SECONDS=0 +$SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; sleep 5; print finished' > $tmp/sig +e=$? +[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" +x=$(<$tmp/sig) +[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" +(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" + +SECONDS=0 +{ $SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; (sleep 5); print finished' > $tmp/sig ;} 2> /dev/null +e=$? +[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" +x=$(<$tmp/sig) +[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" +(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" + +SECONDS=0 +{ $SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; sleep 5; print finished' > $tmp/sig ;} 2> /dev/null +e=$? +[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" +x=$(<$tmp/sig) +[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" +(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" + +SECONDS=0 +x=$($SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; (sleep 5); print finished') +e=$? +[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" +[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" +(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" + +SECONDS=0 +x=$($SHELL 2> /dev/null -c 'sleep 2 && kill $$ & trap "print done; exit 3" EXIT; sleep 5; print finished') +e=$? +[[ $e == 3 ]] || err_exit "exit status failed -- expected 3, got $e" +[[ $x == done ]] || err_exit "output failed -- expected 'done', got '$x'" +(( SECONDS > 3.5 )) && err_exit "took $SECONDS seconds, expected around 2" + +trap '' SIGBUS +[[ $($SHELL -c 'trap date SIGBUS; trap -p SIGBUS') ]] && err_exit 'SIGBUS should not have a trap' +trap -- - SIGBUS + +{ + x=$( + $SHELL <<- \++EOF + timeout() + { + trap 'trap - TERM; return' TERM + ( sleep $1; kill -TERM $$ ) >/dev/null 2>&1 & + sleep 3 + } + timeout 1 + print ok +++EOF + ) +} 2> /dev/null +[[ $x == ok ]] || err_exit 'return without arguments in trap not preserving exit status' + +x=$( + $SHELL <<- \++EOF + set -o pipefail + foobar() + { + for ((i=0; i < 10000; i++)) + do print abcdefghijklmnopqrstuvwxyz + done | head > /dev/null + } + foobar + print ok + ++EOF +) +[[ $x == ok ]] || err_exit 'SIGPIPE exit status causes PIPE signal to be propogaged' + +x=$( + $SHELL <<- \EOF + trap "print GNAW" URG + print 1 + ( sleep 1 ; kill -URG $$ ; sleep 1 ; print S1 ; ) + print 2 +EOF +) +[[ $x == $'1\nS1\nGNAW\n2' ]] || err_exit 'signal ignored in subshell not propagated to parent' + +if [[ ${SIG[RTMIN]} ]] +then { + $SHELL <<- \EOF + trap : RTMIN + for ((i=0 ; i < 3 ; i++)) + do sleep 1 + kill -RTMIN $$ 2> /dev/null + done & + wait + EOF + } 2> /dev/null + [[ $? == 0 ]] && err_exit 'wait interrupted by caught signal should have non-zero exit status' + { + $SHELL <<- \EOF + for ((i=0 ; i < 3 ; i++)) + do sleep 1 + kill -RTMIN $$ 2> /dev/null + done & + wait + EOF + } 2> /dev/null + [[ $(kill -l $?) == RTMIN ]] || err_exit 'wait interrupted by signal not caught should exit with the value of that signal+256' +fi + +function b +{ + sleep 3 + endb=1 +} + +function a +{ + trap 'print int' TERM + b + enda=1 +} + +{ /bin/sleep 1;kill -s TERM $$;}& +unset enda endb +a +[[ $endb ]] && err_exit 'TERM signal did not kill function b' +[[ $enda == 1 ]] || err_exit 'TERM signal killed function a' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/statics.sh b/src/cmd/ksh93/tests/statics.sh new file mode 100755 index 0000000..7e67279 --- /dev/null +++ b/src/cmd/ksh93/tests/statics.sh @@ -0,0 +1,690 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +# +# Written by Roland Mainz <roland.mainz@nrubsig.org> +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors < 127 && Errors++ )) +} + +alias err_exit='err_exit $LINENO' + +set -o nounset +Command=${0##*/} +integer Errors=0 + + + +typeset -T test_t=( + typeset name + typeset cmd + typeset expected_output +) + +function testfunc +{ + integer line_number=$1 + typeset cmd="$2" + typeset expected_output="$3" + typeset output + + output="$($SHELL -c "${cmd}" 2>&1 )" + + [[ "${output}" == "${expected_output}" ]] || err_exit ${line_number} "${output} != ${expected_output}" +} + +# test1: basic tests +function test1 +{ + # string + testfunc ${LINENO} '(function l { typeset -S x ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true)' "###" + testfunc ${LINENO} 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true' ">###" + testfunc ${LINENO} 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; (l false) ; l true' ">##" + testfunc ${LINENO} 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false; ( ulimit -c 0 ; l false) ; l true' ">##" + + # integer + # (normal) + testfunc ${LINENO} '(function l { integer -S x ; x+=1 ; $1 && print "$x" ; } ; l false ; l false ; l true )' "3" + testfunc ${LINENO} '(function l { integer -S x ; x+=1 ; $1 && print "$x" ; } ; l false ; (l false) ; l true )' "2" + # (int) + testfunc ${LINENO} '(function l { typeset -S -i x ; x+=1 ; $1 && print "$x" ; } ; l false ; l false ; l true )' "3" + testfunc ${LINENO} '(function l { typeset -S -i x ; x+=1 ; $1 && print "$x" ; } ; l false ; (l false) ; l true )' "2" + # (short) + testfunc ${LINENO} '(function l { typeset -S -s -i x ; x+=1 ; $1 && print "$x" ; } ; l false ; l false ; l true )' "3" + testfunc ${LINENO} '(function l { typeset -S -s -i x ; x+=1 ; $1 && print "$x" ; } ; l false ; (l false) ; l true )' "2" + + # float + testfunc ${LINENO} '(function l { float -S x=0.5 ; (( x+=.5 )) ; $1 && print "$x" ; } ; l false ; l false ; l true )' "2" + testfunc ${LINENO} '(function l { float -S x=0.5 ; (( x+=.5 )) ; $1 && print "$x" ; } ; l false ; (l false) ; l true )' "1.5" + + return 0 +} + +# test2: test the more complex datatypes +function test2 +{ + compound out=( typeset stdout stderr ; integer res ) + integer i + + test_t -r -a tests=( + ( + name='compound' + cmd=$' + function l + { + compound -S s=( + integer a=1 + integer b=2 + ) + + (( s.a++, s.b++ )) + + $1 && printf "a=%d, b=%d\n" s.a s.b + } + (l false ; l false ; l true ; printf ";") + (l false ; l false ; l true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + ( + name='compound_nameref' + cmd=$' + function l_n + { + nameref sn=$2 + (( sn.a++, sn.b++ )) + + $1 && printf "a=%d, b=%d\n" sn.a sn.b + } + function l + { + compound -S s=( a=1 b=2 ) + l_n $1 s + } + (l false ; l false ; l true ; printf ";") + (l false ; l false ; l true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='type' + cmd=$' + typeset -T ab_t=( + integer a=1 + integer b=2 + + function increment + { + (( _.a++, _.b++ )) + } + ) + function l + { + ab_t -S s + + s.increment + + $1 && printf "a=%d, b=%d\n" s.a s.b + } + (l false ; l false ; l true ; printf ";") + (l false ; l false ; l true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='type_nameref' + cmd=$' + typeset -T ab_t=( + integer a=1 + integer b=2 + + function increment + { + (( _.a++, _.b++ )) + } + ) + function l_n + { + nameref sn=$2 + + sn.increment + + $1 && printf "a=%d, b=%d\n" sn.a sn.b + } + function l + { + ab_t -S s + l_n $1 s + } + (l false ; l false ; l true ; printf ";") + (l false ; l false ; l true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='indexed_string_array_appendelement' + cmd=$' + function ar + { + typeset -a -S s=( "hello" ) + + s+=( "an element" ) + + $1 && { printf "%s" "${s[@]}" ; printf "\n" ; } + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'helloan elementan elementan element\n;helloan elementan elementan element\n;' + ) + + ( + name='indexed_string_array_nameref_appendelement' + cmd=$' + function ar_n + { + nameref sn=$2 + sn+=( "an element" ) + + $1 && { printf "%s" "${sn[@]}" ; printf "\n" ; } + } + function ar + { + typeset -a -S s=( "hello" ) + ar_n $1 s + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'helloan elementan elementan element\n;helloan elementan elementan element\n;' + ) + + ( + name='associative_string_array_appendelement' + cmd=$' + function ar + { + typeset -A -S s=( [0]="hello" ) + + s[$(( ${#s[@]} + 1))]="an element" + + $1 && { printf "%s" "${s[@]}" ; printf "\n" ; } + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'helloan elementan elementan element\n;helloan elementan elementan element\n;' + ) + + ( + name='associative_string_array_nameref_appendelement' + cmd=$' + function ar_n + { + nameref sn=$2 + + sn[$(( ${#sn[@]} + 1))]="an element" + + $1 && { printf "%s" "${sn[@]}" ; printf "\n" ; } + } + function ar + { + typeset -A -S s=( [0]="hello" ) + ar_n $1 s + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'helloan elementan elementan element\n;helloan elementan elementan element\n;' + ) + + ( + name='indexed_compound_array_editelement' + cmd=$' + function ar + { + compound -S -a s=( + [5]=( + integer a=1 + integer b=2 + ) + ) + + (( s[5].a++, s[5].b++ )) + $1 && printf "a=%d, b=%d\n" s[5].a s[5].b + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='indexed_compound_array_nameref_editelement' + cmd=$' + function ar_n + { + nameref sn=$2 + + (( sn.a++, sn.b++ )) + $1 && printf "a=%d, b=%d\n" sn.a sn.b + } + function ar + { + compound -S -a s=( + [5]=( + integer a=1 + integer b=2 + ) + ) + + ar_n $1 s[5] + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='2d_indexed_compound_array_editelement' + cmd=$' + function ar + { + compound -S -a s=( + [8][5]=( + integer a=1 + integer b=2 + ) + ) + + (( s[8][5].a++, s[8][5].b++ )) + $1 && printf "a=%d, b=%d\n" s[8][5].a s[8][5].b + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='2d_indexed_compound_array_nameref_editelement' + cmd=$' + function ar_n + { + nameref sn=$2 + + (( sn.a++, sn.b++ )) + $1 && printf "a=%d, b=%d\n" sn.a sn.b + } + function ar + { + compound -S -a s=( + [8][5]=( + integer a=1 + integer b=2 + ) + ) + + ar_n $1 s[8][5] + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + ( + name='4d_indexed_compound_array_editelement' + cmd=$' + function ar + { + compound -S -a s=( + [8][5][0][9]=( + integer a=1 + integer b=2 + ) + ) + + (( s[8][5][0][9].a++, s[8][5][0][9].b++ )) + $1 && printf "a=%d, b=%d\n" s[8][5][0][9].a s[8][5][0][9].b + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='4d_indexed_compound_array_nameref_editelement' + cmd=$' + function ar_n + { + nameref sn=$2 + + (( sn.a++, sn.b++ )) + $1 && printf "a=%d, b=%d\n" sn.a sn.b + } + function ar + { + compound -S -a s=( + [8][5][0][9]=( + integer a=1 + integer b=2 + ) + ) + + ar_n $1 s[8][5][0][9] + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='associative_compound_array_editelement' + cmd=$' + function ar + { + compound -S -A s=( + [5]=( + integer a=1 + integer b=2 + ) + ) + + (( s[5].a++, s[5].b++ )) + $1 && printf "a=%d, b=%d\n" s[5].a s[5].b + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='associative_compound_array_nameref_editelement' + cmd=$' + function ar_n + { + nameref sn=$2 + + (( sn.a++, sn.b++ )) + $1 && printf "a=%d, b=%d\n" sn.a sn.b + } + function ar + { + compound -S -A s=( + [5]=( + integer a=1 + integer b=2 + ) + ) + + ar_n $1 s[5] + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='indexed_type_array_editelement' + cmd=$' + typeset -T ab_t=( + integer a=1 + integer b=2 + + function increment + { + (( _.a++, _.b++ )) + } + ) + + function ar + { + ab_t -S -a s + [[ -v s[5] ]] || s[5]=( ) # how do I init an array of types ? + + s[5].increment + $1 && printf "a=%d, b=%d\n" s[5].a s[5].b + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='indexed_type_array_nameref_editelement' + cmd=$' + typeset -T ab_t=( + integer a=1 + integer b=2 + + function increment + { + (( _.a++, _.b++ )) + } + ) + + function ar_n + { + nameref sn=$2 + + sn.increment + $1 && printf "a=%d, b=%d\n" sn.a sn.b + } + function ar + { + ab_t -S -a s + [[ -v s[5] ]] || s[5]=( ) # how do I init an array of types ? + + ar_n $1 s[5] + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='2d_indexed_type_array_editelement' + cmd=$' + typeset -T ab_t=( + integer a=1 + integer b=2 + + function increment + { + (( _.a++, _.b++ )) + } + ) + + function ar + { + ab_t -S -a s + [[ -v s[9][5] ]] || s[9][5]=( ) # how do I init an array of types ? + + s[9][5].increment + $1 && printf "a=%d, b=%d\n" s[9][5].a s[9][5].b + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='2d_indexed_type_array_nameref_editelement' + cmd=$' + typeset -T ab_t=( + integer a=1 + integer b=2 + + function increment + { + (( _.a++, _.b++ )) + } + ) + + function ar_n + { + nameref sn=$2 + + sn.increment + $1 && printf "a=%d, b=%d\n" sn.a sn.b + } + function ar + { + ab_t -S -a s + [[ -v s[9][5] ]] || s[9][5]=( ) # how do I init an array of types ? + + ar_n $1 s[9][5] + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='associative_type_array_editelement' + cmd=$' + typeset -T ab_t=( + integer a=1 + integer b=2 + + function increment + { + (( _.a++, _.b++ )) + } + ) + + function ar + { + ab_t -S -A s + [[ -v s[5] ]] || s[5]=( ) # how do I init an array of types ? + + s[5].increment + $1 && printf "a=%d, b=%d\n" s[5].a s[5].b + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ( + name='associative_type_array_nameref_editelement' + cmd=$' + typeset -T ab_t=( + integer a=1 + integer b=2 + + function increment + { + (( _.a++, _.b++ )) + } + ) + + function ar_n + { + nameref sn=$2 + + sn.increment + $1 && printf "a=%d, b=%d\n" sn.a sn.b + } + function ar + { + ab_t -S -A s + [[ -v s[5] ]] || s[5]=( ) # how do I init an array of types ? + + ar_n $1 s[5] + } + (ar false ; ar false ; ar true ; printf ";") + (ar false ; ar false ; ar true ; printf ";") + ' + expected_output=$'a=4, b=5\n;a=4, b=5\n;' + ) + + ) + + for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do + nameref currtest=tests[i] + +#print -u2 -- "${currtest.cmd}" + out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${currtest.cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" + + (( out.res == 0 )) || err_exit "${currtest.name}: Test shell returned with exit code ${out.res}" + [[ "${out.stdout}" == "${currtest.expected_output}" ]] || err_exit "${currtest.name}: Expected stdout == $(printf "%q\n" "${currtest.expected_output}"), got $(printf "%q\n" "${out.stdout}")" + [[ "${out.stderr}" == '' ]] || err_exit "${currtest.name}: Expected empty stderr, got $(printf "%q\n" "${out.stderr}")" + done + + return 0 +} + +# run tests +test1 +test2 + + +# Test visibilty of "global" vs. "static" variables. if we have a "static" variable in a +# function and "unset" it we should see a global variable with the same +# name, right ? +integer hx=5 +function test_hx_scope +{ + integer -S hx=9 + $2 && unset hx + $1 && printf 'hx=%d\n' hx +} +test_hx_scope false false +test_hx_scope false false +# first test the "unset" call in a $(...) subshell... +[[ "$( test_hx_scope true true )" == 'hx=5' ]] || err_exit "can't see global variable hx after unsetting static variable hx" +# ... end then test whether the value has changed. +[[ "${ test_hx_scope true false ;}" == 'hx=9' ]] || err_exit "hx variable somehow changed" + +out=$(function fun2 +{ + nameref sn=$1 + (( sn.a++, sn.b++ )) + $2 && printf "a=%d, b=%d\n" sn.a sn.b +} +function fun1 +{ + compound -S s=( a=0 b=0 ) + fun2 s $1 +} +(fun1 false ; fun1 false ; fun1 true) +(fun1 false ; fun1 false ; fun1 true) +) +[[ $out == $'a=3, b=3\na=3, b=3' ]] || err_exit 'static variables in functions with initializers not working' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/subshell.sh b/src/cmd/ksh93/tests/subshell.sh new file mode 100755 index 0000000..819811a --- /dev/null +++ b/src/cmd/ksh93/tests/subshell.sh @@ -0,0 +1,582 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u$Error_fd -n "\t" + print -u$Error_fd -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 Error_fd=2 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +bincat=$(PATH=$(getconf PATH) whence -p cat) + +z=() +z.foo=( [one]=hello [two]=(x=3 y=4) [three]=hi) +z.bar[0]=hello +z.bar[2]=world +z.bar[1]=(x=4 y=5) +val='( + typeset -a bar=( + [0]=hello + [2]=world + [1]=( + x=4 + y=5 + ) + ) + typeset -A foo=( + [one]=hello + [three]=hi + [two]=( + x=3 + y=4 + ) + ) +)' +[[ $z == "$val" ]] || err_exit 'compound variable with mixed arrays not working' +z.bar[1]=yesyes +[[ ${z.bar[1]} == yesyes ]] || err_exit 'reassign of index array compound variable fails' +z.bar[1]=(x=12 y=5) +[[ ${z.bar[1]} == $'(\n\tx=12\n\ty=5\n)' ]] || err_exit 'reassign array simple to compound variable fails' +eval val="$z" +( + z.foo[three]=good + [[ ${z.foo[three]} == good ]] || err_exit 'associative array assignment in subshell not working' +) +[[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment' +eval val="$z" +( + z.foo[two]=ok + [[ ${z.foo[two]} == ok ]] || err_exit 'associative array assignment to compound variable in subshell not working' + z.bar[1]=yes + [[ ${z.bar[1]} == yes ]] || err_exit 'index array assignment to compound variable in subshell not working' +) +[[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment' + +x=( + foo=( qqq=abc rrr=def) + bar=( zzz=no rst=fed) +) +eval val="$x" +( + unset x.foo + [[ ${x.foo.qqq} ]] && err_exit 'x.foo.qqq should be unset' + x.foo=good + [[ ${x.foo} == good ]] || err_exit 'x.foo should be good' +) +[[ $x == "$val" ]] || err_exit 'compound variable changes after unset leaves' +unset l +( + l=( a=1 b="BE" ) +) +[[ ${l+foo} != foo ]] || err_exit 'l should be unset' + +Error_fd=9 +eval "exec $Error_fd>&2 2>/dev/null" + +TEST_notfound=notfound +while whence $TEST_notfound >/dev/null 2>&1 +do TEST_notfound=notfound-$RANDOM +done + + +integer BS=1024 nb=64 ss=60 bs no +for bs in $BS 1 +do $SHELL -c ' + { + sleep '$ss' + kill -KILL $$ + } & + set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs') + print ${#1} + kill $! + ' > $tmp/sub 2>/dev/null + no=$(<$tmp/sub) + (( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs -- expected $((BS*nb)), got ${no:-0}" +done +# this time with redirection on the trailing command +for bs in $BS 1 +do $SHELL -c ' + { + sleep 2 + sleep '$ss' + kill -KILL $$ + } & + set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs' 2>/dev/null) + print ${#1} + kill $! + ' > $tmp/sub 2>/dev/null + no=$(<$tmp/sub) + (( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs and trailing redirection -- expected $((BS*nb)), got ${no:-0}" +done + +# exercise command substitutuion trailing newline logic w.r.t. pipe vs. tmp file io + +set -- \ + 'post-line print' \ + '$TEST_unset; ($TEST_fork; print 1); print' \ + 1 \ + 'pre-line print' \ + '$TEST_unset; ($TEST_fork; print); print 1' \ + $'\n1' \ + 'multiple pre-line print' \ + '$TEST_unset; ($TEST_fork; print); print; ($TEST_fork; print 1); print' \ + $'\n\n1' \ + 'multiple post-line print' \ + '$TEST_unset; ($TEST_fork; print 1); print; ($TEST_fork; print); print' \ + 1 \ + 'intermediate print' \ + '$TEST_unset; ($TEST_fork; print 1); print; ($TEST_fork; print 2); print' \ + $'1\n\n2' \ + 'simple variable' \ + '$TEST_unset; ($TEST_fork; l=2; print "$l"); print $l' \ + 2 \ + 'compound variable' \ + '$TEST_unset; ($TEST_fork; l=(a=2 b="BE"); print "$l"); print $l' \ + $'(\n\ta=2\n\tb=BE\n)' \ + +export TEST_fork TEST_unset + +while (( $# >= 3 )) +do txt=$1 + cmd=$2 + exp=$3 + shift 3 + for TEST_unset in '' 'unset var' + do for TEST_fork in '' 'ulimit -c 0' + do for TEST_shell in "eval" "$SHELL -c" + do if ! got=$($TEST_shell "$cmd") + then err_exit "${TEST_shell/*-c/\$SHELL -c} ${TEST_unset:+unset }${TEST_fork:+fork }$txt print failed" + elif [[ "$got" != "$exp" ]] + then EXP=$(printf %q "$exp") + GOT=$(printf %q "$got") + err_exit "${TEST_shell/*-c/\$SHELL -c} ${TEST_unset:+unset }${TEST_fork:+fork }$txt command substitution failed -- expected $EXP, got $GOT" + fi + done + done + done +done + +r=$( ($SHELL -c ' + { + sleep 32 + kill -KILL $$ + } & + for v in $(set | sed "s/=.*//") + do command unset $v + done + typeset -Z5 I + for ((I = 0; I < 1024; I++)) + do eval A$I=1234567890 + done + a=$(set 2>&1) + print ok + kill -KILL $! +') 2>/dev/null) +[[ $r == ok ]] || err_exit "large subshell command substitution hangs" + +for TEST_command in '' $TEST_notfound +do for TEST_exec in '' 'exec' + do for TEST_fork in '' 'ulimit -c 0;' + do for TEST_redirect in '' '>/dev/null' + do for TEST_substitute in '' ': $' + do + + TEST_test="$TEST_substitute($TEST_fork $TEST_exec $TEST_command $TEST_redirect)" + [[ $TEST_test == '('*([[:space:]])')' ]] && continue + r=$($SHELL -c ' + { + sleep 2 + kill -KILL $$ + } & + '"$TEST_test"' + kill $! + print ok + ') + [[ $r == ok ]] || err_exit "shell hangs on $TEST_test" + + done + done + done + done +done + +$SHELL -c '( autoload xxxxx);print -n' || err_exit 'autoloaded functions in subshells can cause failure' +foo=$($SHELL <<- ++EOF++ + (trap 'print bar' EXIT;print -n foo) + ++EOF++ +) +[[ $foo == foobar ]] || err_exit 'trap on exit when last commands is subshell is not triggered' + +err=$( + $SHELL 2>&1 <<- \EOF + date=$(whence -p date) + function foo + { + x=$( $date > /dev/null 2>&1 ;:) + } + # consume almost all fds to push the test to the fd limit # + integer max=$(ulimit --nofile) + (( max -= 6 )) + for ((i=20; i < max; i++)) + do exec {i}>&1 + done + for ((i=0; i < 20; i++)) + do y=$(foo) + done + EOF +) || { + err=${err%%$'\n'*} + err=${err#*:} + err=${err##[[:space:]]} + err_exit "nested command substitution with redirections failed -- $err" +} + +exp=0 +$SHELL -c $' + function foobar + { + print "hello world" + } + [[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]] + exit '$exp$' +' +got=$? +[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'" +exp=ok +got=$($SHELL -c $' + function foobar + { + print "hello world" + } + [[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]] + print '$exp$' +') +[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'" + +# command substitution variations # +set -- \ + '$(' ')' \ + '${ ' '; }' \ + '$(ulimit -c 0; ' ')' \ + '$( (' ') )' \ + '${ (' '); }' \ + '`' '`' \ + '`(' ')`' \ + '`ulimit -c 0; ' '`' \ + # end of table # +exp=ok +testcase[1]=' + if %sexpr "NOMATCH" : ".*Z" >/dev/null%s + then print error + else print ok + fi + exit %s +' +testcase[2]=' + function bar + { + pipeout=%1$sprintf Ok | tr O o%2$s + print $pipeout + return 0 + } + foo=%1$sbar%2$s || foo="exit status $?" + print $foo + exit %3$s +' +while (( $# >= 2 )) +do for ((TEST=1; TEST<=${#testcase[@]}; TEST++)) + do body=${testcase[TEST]} + for code in 0 2 + do got=${ printf "$body" "$1" "$2" "$code" | $SHELL 2>&1 } + status=$? + if (( status != code )) + then err_exit "test $TEST '$1...$2 exit $code' failed -- exit status $status, expected $code" + elif [[ $got != $exp ]] + then err_exit "test $TEST '$1...$2 exit $code' failed -- got '$got', expected '$exp'" + fi + done + done + shift 2 +done + +# the next tests loop on all combinations of +# { SUB CAT INS TST APP } X { file-sizes } +# where the file size starts at 1Ki and doubles up to and including 1Mi +# +# the tests and timeouts are done in async subshells to prevent +# the test harness from hanging + +SUB=( + ( BEG='$( ' END=' )' ) + ( BEG='${ ' END='; }' ) +) +CAT=( cat $bincat ) +INS=( "" "builtin cat; " "builtin -d cat $bincat; " ": > /dev/null; " ) +APP=( "" "; :" ) +TST=( + ( CMD='print foo | $cat' EXP=3 ) + ( CMD='$cat < $tmp/lin' ) + ( CMD='cat $tmp/lin | $cat' ) + ( CMD='read v < $tmp/buf; print $v' LIM=4*1024 ) + ( CMD='cat $tmp/buf | read v; print $v' LIM=4*1024 ) +) + +if cat /dev/fd/3 3</dev/null >/dev/null 2>&1 || whence mkfifo > /dev/null +then T=${#TST[@]} + TST[T].CMD='$cat <(print foo)' + TST[T].EXP=3 +fi + +# prime the two data files to 512 bytes each +# $tmp/lin has newlines every 16 bytes and $tmp/buf has no newlines +# the outer loop doubles the file size at top + +buf=$'1234567890abcdef' +lin=$'\n1234567890abcde' +for ((i=0; i<5; i++)) +do buf=$buf$buf + lin=$lin$lin +done +print -n "$buf" > $tmp/buf +print -n "$lin" > $tmp/lin + +unset SKIP +for ((n=1024; n<=1024*1024; n*=2)) +do cat $tmp/buf $tmp/buf > $tmp/tmp + mv $tmp/tmp $tmp/buf + cat $tmp/lin $tmp/lin > $tmp/tmp + mv $tmp/tmp $tmp/lin + for ((S=0; S<${#SUB[@]}; S++)) + do for ((C=0; C<${#CAT[@]}; C++)) + do cat=${CAT[C]} + for ((I=0; I<${#INS[@]}; I++)) + do for ((A=0; A<${#APP[@]}; A++)) + do for ((T=0; T<${#TST[@]}; T++)) + do #undent...# + + if [[ ! ${SKIP[S][C][I][A][T]} ]] + then eval "{ x=${SUB[S].BEG}${INS[I]}${TST[T].CMD}${APP[A]}${SUB[S].END}; print \${#x}; } >\$tmp/out &" + m=$! + { sleep 4; kill -9 $m; } & + k=$! + wait $m + h=$? + kill -9 $k + wait $k + got=$(<$tmp/out) + if [[ ! $got ]] && (( h )) + then got=HUNG + fi + if [[ ${TST[T].EXP} ]] + then exp=${TST[T].EXP} + else exp=$n + fi + if [[ $got != $exp ]] + then # on failure skip similar tests on larger files sizes # + SKIP[S][C][I][A][T]=1 + siz=$(printf $'%#i' $exp) + cmd=${TST[T].CMD//\$cat/$cat} + cmd=${cmd//\$tmp\/buf/$siz.buf} + cmd=${cmd//\$tmp\/lin/$siz.lin} + err_exit "'x=${SUB[S].BEG}${INS[I]}${cmd}${APP[A]}${SUB[S].END} && print \${#x}' failed -- expected '$exp', got '$got'" + elif [[ ${TST[T].EXP} ]] || (( TST[T].LIM >= n )) + then SKIP[S][C][I][A][T]=1 + fi + fi + + #...indent# + done + done + done + done + done +done + +# specifics -- there's more? + +{ + cmd='{ exec 5>/dev/null; print "$(eval ls -d . 2>&1 1>&5)"; } >$tmp/out &' + eval $cmd + m=$! + { sleep 4; kill -9 $m; } & + k=$! + wait $m + h=$? + kill -9 $k + wait $k + got=$(<$tmp/out) +} 2>/dev/null +exp='' +if [[ ! $got ]] && (( h )) +then got=HUNG +fi +if [[ $got != $exp ]] +then err_exit "eval '$cmd' failed -- expected '$exp', got '$got'" +fi + +float t1=$SECONDS +sleep=$(whence -p sleep) +if [[ $sleep ]] +then + $SHELL -c "( $sleep 5 </dev/null >/dev/null 2>&1 & );exit 0" | cat + (( (SECONDS-t1) > 4 )) && err_exit '/bin/sleep& in subshell hanging' + ((t1=SECONDS)) +fi +$SHELL -c '( sleep 5 </dev/null >/dev/null 2>&1 & );exit 0' | cat +(( (SECONDS-t1) > 4 )) && err_exit 'sleep& in subshell hanging' + +exp=HOME=$HOME +( HOME=/bin/sh ) +got=$(env | grep ^HOME=) +[[ $got == "$exp" ]] || err_exit "( HOME=/bin/sh ) cleanup failed -- expected '$exp', got '$got'" + +cmd='echo $((case x in x)echo ok;esac);:)' +exp=ok +got=$($SHELL -c "$cmd" 2>&1) +[[ $got == "$exp" ]] || err_exit "'$cmd' failed -- expected '$exp', got '$got'" + +cmd='eval "for i in 1 2; do eval /bin/echo x; done"' +exp=$'x\nx' +got=$($SHELL -c "$cmd") +if [[ $got != "$exp" ]] +then EXP=$(printf %q "$exp") + GOT=$(printf %q "$got") + err_exit "'$cmd' failed -- expected $EXP, got $GOT" +fi + +( +$SHELL -c 'sleep 20 & pid=$!; { x=$( ( seq 60000 ) );kill -9 $pid;}&;wait $pid' +) 2> /dev/null +(( $? )) || err_exit 'nested command substitution with large output hangs' + +(.sh.foo=foobar) +[[ ${.sh.foo} == foobar ]] && err_exit '.sh subvariables in subshells remain set' +[[ $($SHELL -c 'print 1 | : "$(/bin/cat <(/bin/cat))"') ]] && err_exit 'process substitution not working correctly in subshells' + +# config hang bug +integer i +for ((i=1; i < 1000; i++)) +do typeset foo$i=$i +done +{ + : $( (ac_space=' '; set | grep ac_space) 2>&1) +} < /dev/null | cat > /dev/null & +sleep 1.5 +if kill -KILL $! 2> /dev/null +then err_exit 'process timed out with hung comsub' +fi +wait $! 2> /dev/null +(( $? > 128 )) && err_exit 'incorrect exit status with comsub' + +$SHELL 2> /dev/null -c '[[ ${ print foo },${ print bar } == foo,bar ]]' || err_exit '${ print foo },${ print bar } not working' +$SHELL 2> /dev/null -c '[[ ${ print foo; },${ print bar } == foo,bar ]]' || err_exit '${ print foo; },${ print bar } not working' + +src=$'true 2>&1\n: $(true | true)\n: $(true | true)\n: $(true | true)\n'$(whence -p true) +exp=ok +got=$( $SHELL -c "(eval '$src'); echo $exp" ) +[[ $got == "$exp" ]] || err_exit 'subshell eval of pipeline clobbers stdout' + +x=$( { time $SHELL -c date >| /dev/null;} 2>&1) +[[ $x == *real*user*sys* ]] || err_exit 'time { ...;} 2>&1 in $(...) fails' + +x=$($SHELL -c '( function fx { export X=123; } ; fx; ); echo $X') +[[ $x == 123 ]] && err_exit 'global variables set from with functions inside a +subshell can leave side effects in parent shell' + +date=$(whence -p date) +err() { return $1; } +( err 12 ) & pid=$! +: $( $date) +wait $pid +[[ $? == 12 ]] || err_exit 'exit status from subshells not being preserved' + +if cat /dev/fd/3 3</dev/null >/dev/null 2>&1 || whence mkfifo > /dev/null +then x="$(sed 's/^/Hello /' <(print "Fred" | sort))" + [[ $x == 'Hello Fred' ]] || err_exit "process substitution of pipeline in command substitution not working" +fi + +{ +$SHELL <<- \EOF + function foo + { + integer i + print -u2 foobar + for ((i=0; i < 8000; i++)) + do print abcdefghijk + done + print -u2 done + } + out=$(eval "foo | cat" 2>&1) + (( ${#out} == 96011 )) || err_exit "\${#out} is ${#out} should be 96011" +EOF +} & pid=$! +$SHELL -c "{ sleep 2 && kill $pid ;}" 2> /dev/null +(( $? == 0 )) && err_exit 'process has hung' + +{ +x=$( $SHELL <<- \EOF + function func1 { typeset IFS; : $(func2); print END ;} + function func2 { IFS="BAR"; } + func1 + func1 +EOF +) +} 2> /dev/null +[[ $x == $'END\nEND' ]] || err_exit 'bug in save/restore of IFS in subshell' + +true=$(whence -p true) +date=$(whence -p date) +tmpf=$tmp/foo +function fun1 +{ + $true + cd - >/dev/null 2>&1 + print -u2 -- "$($date) SUCCESS" +} + +print -n $(fun1 2> $tmpf) +[[ $(< $tmpf) == *SUCCESS ]] || err_exit 'standard error output lost with command substitution' + + +tmpfile=$tmp/foo +cat > $tmpfile <<-\EOF + $SHELL -c 'function g { IFS= ;};function f { typeset IFS;(g);: $V;};f;f' + EOF +$SHELL 2> /dev/null "$tmpfile" || err_exit 'IFS in subshell causes core dump' + +unset i +if [[ -d /dev/fd ]] +then integer i + for ((i=11; i < 29; i++)) + do if ! [[ -r /dev/fd/$i || -w /dev/fd/$i ]] + then a=$($SHELL -c "[[ -r /dev/fd/$i || -w /dev/fd/$i ]]") + (( $? )) || err_exit "file descriptor $i not close on exec" + fi + done +fi + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/substring.sh b/src/cmd/ksh93/tests/substring.sh new file mode 100755 index 0000000..e79447f --- /dev/null +++ b/src/cmd/ksh93/tests/substring.sh @@ -0,0 +1,628 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 j=4 +base=/home/dgk/foo//bar +string1=$base/abcabcabc +if [[ ${string1:0} != "$string1" ]] +then err_exit "string1:0" +fi +if [[ ${string1: -1} != "c" ]] +then err_exit "string1: -1" +fi +if [[ ${string1:0:1000} != "$string1" ]] +then err_exit "string1:0" +fi +if [[ ${string1:1} != "${string1#?}" ]] +then err_exit "string1:1" +fi +if [[ ${string1:1:4} != home ]] +then err_exit "string1:1:4" +fi +if [[ ${string1: -5:4} != bcab ]] +then err_exit "string1: -5:4" +fi +if [[ ${string1:1:j} != home ]] +then err_exit "string1:1:j" +fi +if [[ ${string1:(j?1:0):j} != home ]] +then err_exit "string1:(j?1:0):j" +fi +if [[ ${string1%*zzz*} != "$string1" ]] +then err_exit "string1%*zzz*" +fi +if [[ ${string1%%*zzz*} != "$string1" ]] +then err_exit "string1%%*zzz*" +fi +if [[ ${string1#*zzz*} != "$string1" ]] +then err_exit "string1#*zzz*" +fi +if [[ ${string1##*zzz*} != "$string1" ]] +then err_exit "string1##*zzz*" +fi +if [[ ${string1%+(abc)} != "$base/abcabc" ]] +then err_exit "string1%+(abc)" +fi +if [[ ${string1%%+(abc)} != "$base/" ]] +then err_exit "string1%%+(abc)" +fi +if [[ ${string1%/*} != "$base" ]] +then err_exit "string1%/*" +fi +if [[ "${string1%/*}" != "$base" ]] +then err_exit '"string1%/*"' +fi +if [[ ${string1%"/*"} != "$string1" ]] +then err_exit 'string1%"/*"' +fi +if [[ ${string1%%/*} != "" ]] +then err_exit "string1%%/*" +fi +if [[ ${string1#*/bar} != /abcabcabc ]] +then err_exit "string1#*bar" +fi +if [[ ${string1##*/bar} != /abcabcabc ]] +then err_exit "string1#*bar" +fi +if [[ "${string1#@(*/bar|*/foo)}" != //bar/abcabcabc ]] +then err_exit "string1#@(*/bar|*/foo)" +fi +if [[ ${string1##@(*/bar|*/foo)} != /abcabcabc ]] +then err_exit "string1##@(*/bar|*/foo)" +fi +if [[ ${string1##*/@(bar|foo)} != /abcabcabc ]] +then err_exit "string1##*/@(bar|foo)" +fi +foo=abc +if [[ ${foo#a[b*} != abc ]] +then err_exit "abc#a[b*} != abc" +fi +if [[ ${foo//[0-9]/bar} != abc ]] +then err_exit '${foo//[0-9]/bar} not expanding correctly' +fi +foo='(abc)' +if [[ ${foo#'('} != 'abc)' ]] +then err_exit "(abc)#( != abc)" +fi +if [[ ${foo%')'} != '(abc' ]] +then err_exit "(abc)%) != (abc" +fi +foo=a123b456c +if [[ ${foo/[0-9]?/""} != a3b456c ]] +then err_exit '${foo/[0-9]?/""} not expanding correctly' +fi +if [[ ${foo//[0-9]/""} != abc ]] +then err_exit '${foo//[0-9]/""} not expanding correctly' +fi +if [[ ${foo/#a/b} != b123b456c ]] +then err_exit '${foo/#a/b} not expanding correctly' +fi +if [[ ${foo/#?/b} != b123b456c ]] +then err_exit '${foo/#?/b} not expanding correctly' +fi +if [[ ${foo/%c/b} != a123b456b ]] +then err_exit '${foo/%c/b} not expanding correctly' +fi +if [[ ${foo/%?/b} != a123b456b ]] +then err_exit '${foo/%?/b} not expanding correctly' +fi +while read -r pattern string expected +do if (( expected )) + then if [[ $string != $pattern ]] + then err_exit "$pattern does not match $string" + fi + if [[ ${string##$pattern} != "" ]] + then err_exit "\${$string##$pattern} not null" + fi + if [ "${string##$pattern}" != '' ] + then err_exit "\"\${$string##$pattern}\" not null" + fi + if [[ ${string/$pattern} != "" ]] + then err_exit "\${$string/$pattern} not null" + fi + else if [[ $string == $pattern ]] + then err_exit "$pattern matches $string" + fi + fi +done <<- \EOF + +(a)*+(a) aabca 1 + !(*.o) foo.o 0 + !(*.o) foo.c 1 +EOF +xx=a/b/c/d/e +yy=${xx#*/} +if [[ $yy != b/c/d/e ]] +then err_exit '${xx#*/} != a/b/c/d/e when xx=a/b/c/d/e' +fi +if [[ ${xx//\//\\} != 'a\b\c\d\e' ]] +then err_exit '${xx//\//\\} not working' +fi +x=[123]def +if [[ "${x//\[@(*)\]/\{\1\}}" != {123}def ]] +then err_exit 'closing brace escape not working' +fi +xx=%28text%29 +if [[ ${xx//%28/abc\)} != 'abc)text%29' ]] +then err_exit '${xx//%28/abc\)} not working' +fi +xx='a:b' +str='(){}[]*?|&^%$#@l' +for ((i=0 ; i < ${#str}; i++)) +do [[ $(eval print -r -- \"\${xx//:/\\${str:i:1}}\") == "a${str:i:1}b" ]] || err_exit "substitution of \\${str:i:1}} failed" + [[ $(eval print -rn -- \"\${xx//:/\'${str:i:1}\'}\") == "a${str:i:1}b" ]] || err_exit "substitution of '${str:i:1}' failed" + [[ $(eval print -r -- \"\${xx//:/\"${str:i:1}\"}\") == "a${str:i:1}b" ]] || err_exit "substitution of \"${str:i:1}\" failed" +done +[[ ${xx//:/\\n} == 'a\nb' ]] || err_exit "substituion of \\\\n failed" +[[ ${xx//:/'\n'} == 'a\nb' ]] || err_exit "substituion of '\\n' failed" +[[ ${xx//:/"\n"} == 'a\nb' ]] || err_exit "substituion of \"\\n\" failed" +[[ ${xx//:/$'\n'} == $'a\nb' ]] || err_exit "substituion of \$'\\n' failed" +unset foo +foo=one/two/three +if [[ ${foo//'/'/_} != one_two_three ]] +then err_exit 'single quoting / in replacements failed' +fi +if [[ ${foo//"/"/_} != one_two_three ]] +then err_exit 'double quoting / in replacements failed' +fi +if [[ ${foo//\//_} != one_two_three ]] +then err_exit 'escaping / in replacements failed' +fi +function myexport +{ + nameref var=$1 + if (( $# > 1 )) + then export $1=$2 + fi + if (( $# > 2 )) + then print $(myexport "$1" "$3" ) + return + fi + typeset val + val=$(export | grep "^$1=") + print ${val#"$1="} + +} +export dgk=base +if [[ $(myexport dgk fun) != fun ]] +then err_exit 'export inside function not working' +fi +val=$(export | grep "^dgk=") +if [[ ${val#dgk=} != base ]] +then err_exit 'export not restored after function call' +fi +if [[ $(myexport dgk fun fun2) != fun2 ]] +then err_exit 'export inside function not working with recursive function' +fi +val=$(export | grep "^dgk=") +if [[ ${val#dgk=} != base ]] +then err_exit 'export not restored after recursive function call' +fi +if [[ $(dgk=try3 myexport dgk) != try3 ]] +then err_exit 'name=value not added to export list with function call' +fi +val=$(export | grep "^dgk=") +if [[ ${val#dgk=} != base ]] +then err_exit 'export not restored name=value function call' +fi +unset zzz +if [[ $(myexport zzz fun) != fun ]] +then err_exit 'export inside function not working for zzz' +fi +if [[ $(export | grep "zzz=") ]] +then err_exit 'zzz exported after function call' +fi +set -- foo/bar bam/yes last/file/done +if [[ ${@/*\/@(*)/\1} != 'bar yes done' ]] +then err_exit '\1 not working with $@' +fi +var=(foo/bar bam/yes last/file/done) +if [[ ${var[@]/*\/@(*)/\1} != 'bar yes done' ]] +then err_exit '\1 not working with ${var[@]}' +fi +var='abc_d2ef.462abc %%' +if [[ ${var/+(\w)/Q} != 'Q.462abc %%' ]] +then err_exit '${var/+(\w)/Q} not workding' +fi +if [[ ${var//+(\w)/Q} != 'Q.Q %%' ]] +then err_exit '${var//+(\w)/Q} not workding' +fi +if [[ ${var//+(\S)/Q} != 'Q Q' ]] +then err_exit '${var//+(\S)/Q} not workding' +fi +var=$($SHELL -c 'v=/vin:/usr/vin r=vin; : ${v//vin/${r//v/b}};typeset -p .sh.match') 2> /dev/null +[[ $var == 'typeset -a .sh.match=((vin vin) )' ]] || err_exit '.sh.match not correct when replacement pattern contains a substring match' +foo='foo+bar+' +[[ $(print -r -- ${foo//+/'|'}) != 'foo|bar|' ]] && err_exit "\${foobar//+/'|'}" +[[ $(print -r -- ${foo//+/"|"}) != 'foo|bar|' ]] && err_exit '${foobar//+/"|"}' +[[ $(print -r -- "${foo//+/'|'}") != 'foo|bar|' ]] && err_exit '"${foobar//+/'"'|'"'}"' +[[ $(print -r -- "${foo//+/"|"}") != 'foo|bar|' ]] && err_exit '"${foobar//+/"|"}"' +unset x +x=abcedfg +: ${x%@(d)f@(g)} +[[ ${.sh.match[0]} == dfg ]] || err_exit '.sh.match[0] not dfg' +[[ ${.sh.match[1]} == d ]] || err_exit '.sh.match[1] not d' +[[ ${.sh.match[2]} == g ]] || err_exit '.sh.match[2] not g' +x=abcedddfg +: ${x%%+(d)f@(g)} +[[ ${.sh.match[1]} == ddd ]] || err_exit '.sh.match[1] not ddd' +unset a b +a='\[abc @(*) def\]' +b='[abc 123 def]' +[[ ${b//$a/\1} == 123 ]] || err_exit "\${var/pattern} not working with \[ in pattern" +unset foo +foo='(win32.i386) ' +[[ ${foo/'('/'(x11-'} == '(x11-win32.i386) ' ]] || err_exit "\${var/pattern} not working with ' in pattern" +$SHELL -c $'v=\'$(hello)\'; [[ ${v//\'$(\'/-I\'$(\'} == -I"$v" ]]' 2> /dev/null || err_exit "\${var/pattern} not working with \$( as pattern" +unset X +$SHELL -c '[[ ! ${X[@]:0:300} ]]' 2> /dev/null || err_exit '${X[@]:0:300} with X undefined fails' +$SHELL -c '[[ ${@:0:300} == "$0" ]]' 2> /dev/null || err_exit '${@:0:300} with no arguments fails' +i=20030704 +[[ ${i#{6}(?)} == 04 ]] || err_exit '${i#{6}(?)} not working' +[[ ${i#{6,6}(?)} == 04 ]] || err_exit '${i#{6,6}(?)} not working' +LC_ALL=posix +i=" ." +[[ $(printf "<%s>\n" ${i#' '}) == '<.>' ]] || err_exit 'printf "<%s>\n" ${i#' '} failed' +unset x +x=foo +[[ "${x%o}(1)" == "fo(1)" ]] || err_exit 'print ${}() treated as pattern' +unset i pattern string +string=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz +integer i +for((i=0; i < ${#string}; i++)) +do pattern+='@(?)' +done +[[ $(string=$string $SHELL -c ": \${string/$pattern/}; print \${.sh.match[26]}") == Z ]] || err_exit -u2 'sh.match[26] not Z' +: ${string/$pattern/} +(( ${#.sh.match[@]} == 53 )) || err_exit '.sh.match has wrong number of elements' +[[ ${.sh.match[@]:2:4} == 'B C D E' ]] || err_exit '${.sh.match[@]:2:4} incorrect' + +D=$';' E=$'\\\\' Q=$'"' S=$'\'' M='nested pattern substitution failed' + +x='-(-)-' +[[ ${x/*%(())*/\1} == '(-)' ]] || err_exit $M +x='-(-)-)-' +[[ ${x/*%(())*/\1} == '(-)' ]] || err_exit $M +x='-(-()-)-' +[[ ${x/*%(())*/\1} == '()' ]] || err_exit $M +x='-(-\)-)-' +[[ ${x/*%(())*/\1} == '(-\)' ]] || err_exit $M +x='-(-\\)-)-' +[[ ${x/*%(())*/\1} == '(-\\)' ]] || err_exit $M +x='-(-(-)-' +[[ ${x/*%(())*/\1} == '(-)' ]] || err_exit $M +x='-(-(-)-)-' +[[ ${x/*%(())*/\1} == '(-)' ]] || err_exit $M +x='-(-[-]-)-' +[[ ${x/*%(()[])*/\1} == '(-[-]-)' ]] || err_exit $M +x='-[-(-)-]-' +[[ ${x/*%(()[])*/\1} == '(-)' ]] || err_exit $M +x='-(-[-)-]-' +[[ ${x/*%(()[])*/\1} == '-(-[-)-]-' ]] || err_exit $M +x='-(-[-]-)-' +[[ ${x/*%([]())*/\1} == '[-]' ]] || err_exit $M +x='-[-(-)-]-' +[[ ${x/*%([]())*/\1} == '[-(-)-]' ]] || err_exit $M +x='-(-[-)-]-' +[[ ${x/*%([]())*/\1} == '-(-[-)-]-' ]] || err_exit $M + +x='-((-))-' +[[ ${x/*%(())*/\1} == '(-)' ]] || err_exit $M +x='-((-))-' +[[ ${x/~(-g)*%(())*/\1} == '((-))-' ]] || err_exit $M +x='-((-))-' +[[ ${x/~(-g:*)*%(())*/\1} == '(-)' ]] || err_exit $M +x='-((-))-' +[[ ${x/~(+g)*%(())*/\1} == '(-)' ]] || err_exit $M +x='-((-))-' +[[ ${x/~(+g:*)*%(())*/\1} == '(-)' ]] || err_exit $M +x='-((-))-' +[[ ${x/*(?)*%(())*(?)*/:\1:\2:\3:} == ':-(:(-):)-:' ]] || err_exit $M +x='-((-))-' +[[ ${x/~(-g)*(?)*%(())*(?)*/:\1:\2:\3:} == '::((-))::-' ]] || err_exit $M +x='-((-))-' +[[ ${x/~(-g:*(?))*%(())*(?)*/:\1:\2:\3:} == '::(-):)-:' ]] || err_exit $M +x='-((-))-' +[[ ${x/~(+g)*(?)*%(())*(?)*/:\1:\2:\3:} == ':-(:(-):)-:' ]] || err_exit $M +x='-((-))-' +[[ ${x/~(+g:*(?))*%(())*(?)*/:\1:\2:\3:} == ':-(:(-):)-:' ]] || err_exit $M +x='call(a+b,x/(c/d),(0));' +[[ ${x/+([[:alnum:]])*([[:space:]])@(*%(()))*/:\1:\2:\3:} == ':call::(a+b,x/(c/d),(0)):' ]] || err_exit $M + +x='-(-;-)-' +[[ ${x/*%(()D${D})*/\1} == '-(-;-)-' ]] || err_exit $M +x='-(-);-' +[[ ${x/*%(()D${D})*/\1} == '(-)' ]] || err_exit $M +x='-(-)\;-' +[[ ${x/*%(()D${D})*/\1} == '(-)' ]] || err_exit $M +x='-(-\;-)-' +[[ ${x/*%(()D${D}E${E})*/\1} == '(-\;-)' ]] || err_exit $M +x='-(-)\;-' +[[ ${x/*%(()D${D}E${E})*/\1} == '(-)' ]] || err_exit $M +x='-(-(-)\;-)-' +[[ ${x/*%(()D${D}E${E})*/\1} == '(-)' ]] || err_exit $M + +x='-(-")"-)-' +[[ ${x/*%(()Q${Q})*/\1} == '(-")"-)' ]] || err_exit $M +x='-(-\")"-)-' +[[ ${x/*%(()Q${Q})*/\1} == '(-\")"-)' ]] || err_exit $M +x='-(-\")\"-)-' +[[ ${x/*%(()Q${Q})*/\1} == '(-\")\"-)' ]] || err_exit $M +x=$'-(-\\\'")\\\'-)-' +[[ ${x/*%(()Q${S}Q${Q})*/\1} == $'(-\\\'")\\\'-)' ]] || err_exit $M +x=$'-(-\\\'")"-)-' +[[ ${x/*%(()Q${S}Q${Q})*/\1} == $'-(-\\\'")"-)-' ]] || err_exit $M +x=$'-(-\\\'")"\'-)-' +[[ ${x/*%(()Q${S}Q${Q})*/\1} == $'(-\\\'")"\'-)' ]] || err_exit $M +x=$'-(-\\"\')\'\\"-)-' +[[ ${x/*%(()Q${S}Q${Q})*/\1} == $'(-\\"\')\'\\"-)' ]] || err_exit $M +x=$'-(-\')\\\'\'-)-' +[[ ${x/*%(()Q${S}Q${Q})*/\1} == $'-(-\')\\\'\'-)-' ]] || err_exit $M +x=$'-(-\'")\'-)-' +[[ ${x/*%(()L${S}Q${Q})*/\1} == $'(-\'")\'-)' ]] || err_exit $M +x=$'-(-\\\'")"-)-' +[[ ${x/*%(()L${S}Q${Q})*/\1} == $'-(-\\\'")"-)-' ]] || err_exit $M +x=$'-(-\\\'")"\'-)-' +[[ ${x/*%(()L${S}Q${Q})*/\1} == $'(-\\\'")"\'-)' ]] || err_exit $M +x=$'-(-\\"\')\'\\"-)-' +[[ ${x/*%(()L${S}Q${Q})*/\1} == $'(-\\"\')\'\\"-)' ]] || err_exit $M +x=$'-(-\')\\\'\'-)-' +[[ ${x/*%(()L${S}Q${Q})*/\1} == $'-(-\')\\\'\'-)-' ]] || err_exit $M +x='-(-")"-)-' +[[ ${x/*%(()Q${Q})*/\1} == '(-")"-)' ]] || err_exit $M +x='-(-\")"-)-' +[[ ${x/*%(()Q${Q})*/\1} == '(-\")"-)' ]] || err_exit $M +x='-(-\")\"-)-' +[[ ${x/*%(()Q${Q})*/\1} == '(-\")\"-)' ]] || err_exit $M + +x='-(-\)-)-' +[[ ${x/*%(()E${E})*/\1} == '(-\)-)' ]] || err_exit $M +x='-(-\\)-)-' +[[ ${x/*%(()E${E})*/\1} == '(-\\)' ]] || err_exit $M +x='-(-\")"-)-' +[[ ${x/*%(()E${E}Q${Q})*/\1} == '(-\")' ]] || err_exit $M +x='-(-\")\"-)-' +[[ ${x/*%(()E${E}Q${Q})*/\1} == '(-\")' ]] || err_exit $M +x=$'-(-\'")"-)-' +[[ ${x/*%(()E${E}Q${S}Q${Q})*/\1} == $'-(-\'")"-)-' ]] || err_exit $M +x=$'-(-\\\'")"-)-' +[[ ${x/*%(()E${E}Q${S}Q${Q})*/\1} == $'(-\\\'")"-)' ]] || err_exit $M +x=$'-(-\\"\')\'\\"-)-' +[[ ${x/*%(()E${E}Q${S}Q${Q})*/\1} == $'(-\\"\')\'\\"-)' ]] || err_exit $M +x=$'-(-\\\'")"-)-' +[[ ${x/*%(()E${E}L${S}Q${Q})*/\1} == $'(-\\\'")"-)' ]] || err_exit $M +x=$'-(-\\"\')\'\\"-)-' +[[ ${x/*%(()E${E}L${S}Q${Q})*/\1} == $'(-\\"\')\'\\"-)' ]] || err_exit $M +x=$'-(-\\"\')\\\'\\"-)-' +[[ ${x/*%(()E${E}L${S}Q${Q})*/\1} == $'(-\\"\')\\\'\\"-)' ]] || err_exit $M +x=$'-(-\\"\')\\\'\\"\'-)-' +[[ ${x/*%(()E${E}L${S}Q${Q})*/\1} == $'-(-\\"\')\\\'\\"\'-)-' ]] || err_exit $M + +x='-(-;-)-' +[[ ${x/*%(()D\;)*/\1} == '-(-;-)-' ]] || err_exit $M +x='-(-);-' +[[ ${x/*%(()D\;)*/\1} == '(-)' ]] || err_exit $M +x='-(-)\;-' +[[ ${x/*%(()D\;)*/\1} == '(-)' ]] || err_exit $M +x='-(-\;-)-' +[[ ${x/*%(()D\;E\\)*/\1} == '(-\;-)' ]] || err_exit $M +x='-(-);-' +[[ ${x/*%(()D\;E\\)*/\1} == '(-)' ]] || err_exit $M +x='-(-)\;-' +[[ ${x/*%(()D\;E\\)*/\1} == '(-)' ]] || err_exit $M +x='-(-(-)\;-)-' +[[ ${x/*%(()D\;E\\)*/\1} == '(-)' ]] || err_exit $M + +x='-(-")"-)-' +[[ ${x/*%(()Q\")*/\1} == '(-")"-)' ]] || err_exit $M +x='-(-\")"-)-' +[[ ${x/*%(()Q\")*/\1} == '(-\")"-)' ]] || err_exit $M +x='-(-\")\"-)-' +[[ ${x/*%(()Q\")*/\1} == '(-\")\"-)' ]] || err_exit $M +x=$'-(-\\\'")\\\'-)-' +[[ ${x/*%(()Q\'Q\")*/\1} == $'(-\\\'")\\\'-)' ]] || err_exit $M +x=$'-(-\\\'")"-)-' +[[ ${x/*%(()Q\'Q\")*/\1} == $'-(-\\\'")"-)-' ]] || err_exit $M +x=$'-(-\\\'")"\'-)-' +[[ ${x/*%(()Q\'Q\")*/\1} == $'(-\\\'")"\'-)' ]] || err_exit $M +x=$'-(-\\"\')\'\\"-)-' +[[ ${x/*%(()Q\'Q\")*/\1} == $'(-\\"\')\'\\"-)' ]] || err_exit $M +x=$'-(-\')\\\'\'-)-' +[[ ${x/*%(()Q\'Q\")*/\1} == $'-(-\')\\\'\'-)-' ]] || err_exit $M +x=$'-(-\'")\'-)-' +[[ ${x/*%(()L\'Q\")*/\1} == $'(-\'")\'-)' ]] || err_exit $M +x=$'-(-\\\'")"-)-' +[[ ${x/*%(()L\'Q\")*/\1} == $'-(-\\\'")"-)-' ]] || err_exit $M +x=$'-(-\\\'")"\'-)-' +[[ ${x/*%(()L\'Q\")*/\1} == $'(-\\\'")"\'-)' ]] || err_exit $M +x=$'-(-\\"\')\'\\"-)-' +[[ ${x/*%(()L\'Q\")*/\1} == $'(-\\"\')\'\\"-)' ]] || err_exit $M +x=$'-(-\')\\\'\'-)-' +[[ ${x/*%(()L\'Q\")*/\1} == $'-(-\')\\\'\'-)-' ]] || err_exit $M +x='-(-")"-)-' +[[ ${x/*%(()Q\")*/\1} == '(-")"-)' ]] || err_exit $M +x='-(-\")"-)-' +[[ ${x/*%(()Q\")*/\1} == '(-\")"-)' ]] || err_exit $M +x='-(-\")\"-)-' +[[ ${x/*%(()Q\")*/\1} == '(-\")\"-)' ]] || err_exit $M + +x='-(-\)-)-' +[[ ${x/*%(()E\\)*/\1} == '(-\)-)' ]] || err_exit $M +x='-(-\\)-)-' +[[ ${x/*%(()E\\)*/\1} == '(-\\)' ]] || err_exit $M +x='-(-\")"-)-' +[[ ${x/*%(()E\\Q\")*/\1} == '(-\")' ]] || err_exit $M +x='-(-\")\"-)-' +[[ ${x/*%(()E\\Q\")*/\1} == '(-\")' ]] || err_exit $M +x=$'-(-\'")"-)-' +[[ ${x/*%(()E\\Q\'Q\")*/\1} == $'-(-\'")"-)-' ]] || err_exit $M +x=$'-(-\\\'")"-)-' +[[ ${x/*%(()E\\Q\'Q\")*/\1} == $'(-\\\'")"-)' ]] || err_exit $M +x=$'-(-\\"\')\'\\"-)-' +[[ ${x/*%(()E\\Q\'Q\")*/\1} == $'(-\\"\')\'\\"-)' ]] || err_exit $M +x=$'-(-\\\'")"-)-' +[[ ${x/*%(()E\\L\'Q\")*/\1} == $'(-\\\'")"-)' ]] || err_exit $M +x=$'-(-\\"\')\'\\"-)-' +[[ ${x/*%(()E\\L\'Q\")*/\1} == $'(-\\"\')\'\\"-)' ]] || err_exit $M +x=$'-(-\\"\')\\\'\\"-)-' +[[ ${x/*%(()E\\L\'Q\")*/\1} == $'(-\\"\')\\\'\\"-)' ]] || err_exit $M +x=$'-(-\\"\')\\\'\\"\'-)-' +[[ ${x/*%(()E\\L\'Q\")*/\1} == $'-(-\\"\')\\\'\\"\'-)-' ]] || err_exit $M + +pattern=00 +var=100 +[[ $( print $(( ${var%%00} )) ) == 1 ]] || err_exit "arithmetic with embeddded patterns fails" +[[ $( print $(( ${var%%$pattern} )) ) == 1 ]] || err_exit "arithmetic with embeddded pattern variables fails" +if [[ ax == @(a)* ]] && [[ ${.sh.match[1]:0:${#.sh.match[1]}} != a ]] +then err_exit '${.sh.match[1]:1:${#.sh.match[1]}} not expanding correctly' +fi + +string='foo(d:\nt\box\something)bar' +expected='d:\nt\box\something' +[[ ${string/*\(+([!\)])\)*/\1} == "$expected" ]] || err_exit "substring expansion failed '${string/*\(+([!\)])\)*/\1}' returned -- '$expected' expected" +if [[ $($SHELL -c $'export LC_ALL=C.UTF-8; print -r "\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254" | wc -m' 2>/dev/null) == 10 ]] +then LC_ALL=C.UTF-8 $SHELL -c b1=$'"\342\202\254\342\202\254\342\202\254\342\202\254w\342\202\254\342\202\254\342\202\254\342\202\254"; [[ ${b1:4:1} == w ]]' || err_exit 'multibyte ${var:offset:len} not working correctly' +fi +{ $SHELL -c 'unset x;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is not set' +{ $SHELL -c 'x=;[[ ${SHELL:$x} == $SHELL ]]';} 2> /dev/null || err_exit '${var:$x} fails when x is null' + +# subject mode pattern result # +set -- \ + 'a$z' 'E' '[$]|#' 'a($)z' \ + 'a#z' 'E' '[$]|#' 'a(#)z' \ + 'a$z' 'Elr' '[$]|#' 'a$z' \ + 'a#z' 'Elr' '[$]|#' 'a#z' \ + 'a$' 'E' '[$]|#' 'a($)' \ + 'a#' 'E' '[$]|#' 'a(#)' \ + 'a$' 'Elr' '[$]|#' 'a$' \ + 'a#' 'Elr' '[$]|#' 'a#' \ + '$z' 'E' '[$]|#' '($)z' \ + '#z' 'E' '[$]|#' '(#)z' \ + '$z' 'Elr' '[$]|#' '$z' \ + '#z' 'Elr' '[$]|#' '#z' \ + '$' 'E' '[$]|#' '($)' \ + '#' 'E' '[$]|#' '(#)' \ + '$' 'Elr' '[$]|#' '($)' \ + '#' 'Elr' '[$]|#' '(#)' \ + 'a$z' 'E' '\$|#' 'a$z()' \ + 'a$z' 'E' '\\$|#' 'a$z' \ + 'a$z' 'E' '\\\$|#' 'a($)z' \ + 'a#z' 'E' '\\\$|#' 'a(#)z' \ + 'a$z' 'Elr' '\\\$|#' 'a$z' \ + 'a#z' 'Elr' '\\\$|#' 'a#z' \ + 'a$' 'E' '\\\$|#' 'a($)' \ + 'a#' 'E' '\\\$|#' 'a(#)' \ + 'a$' 'Elr' '\\\$|#' 'a$' \ + 'a#' 'Elr' '\\\$|#' 'a#' \ + '$z' 'E' '\\\$|#' '($)z' \ + '#z' 'E' '\\\$|#' '(#)z' \ + '$z' 'Elr' '\\\$|#' '$z' \ + '#z' 'Elr' '\\\$|#' '#z' \ + '$' 'E' '\\\$|#' '($)' \ + '#' 'E' '\\\$|#' '(#)' \ + '$' 'Elr' '\\\$|#' '($)' \ + '#' 'Elr' '\\\$|#' '(#)' \ +# do not delete this line # +unset i o +while (( $# >= 4 )) +do i=$1 + eval o="\${i/~($2)$3/\\(\\0\\)}" + if [[ "$o" != "$4" ]] + then err_exit "i='$1'; \${i/~($2)$3/\\(\\0\\)} failed -- expected '$4', got '$o'" + fi + eval o="\${i/~($2)($3)/\\(\\1\\)}" + if [[ "$o" != "$4" ]] + then err_exit "i='$1'; \${i/~($2)($3)/\\(\\1\\)} failed -- expected '$4', got '$o'" + fi + shift 4 +done + +#multibyte locale tests +x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:0:1}" == a || err_exit ${x:0:1} should be a' +x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:1:1}" == "<2b|>" || err_exit ${x:1:1} should be <2b|>' +x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:3:1}" == "<3d|\\>" || err_exit ${x:3:1} should be <3d|\>' +x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:4:1}" == e || err_exit ${x:4:1} should bee' +x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:1}" == "<2b|>c<3d|\\>e" || print -u2 ${x:1}" should be <2b|>c<3d|\>e' +x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x: -1:1}" == e || err_exit ${x: -1:1} should be e' +x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x: -2:1}" == "<3d|\\>" || err_exit ${x: -2:1} == <3d|\>' +x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:1:3}" == "<2b|>c<3d|\\>" || err_exit ${x:1:3} should be <2b|>c<3d|\>' +x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x:1:20}" == "<2b|>c<3d|\\>e" || err_exit ${x:1:20} should be <2b|>c<3d|\>e' +x='a<2b|>c<3d|\>e' LC_ALL=debug $SHELL -c 'test "${x#??}" == "c<3d|\\>e" || err_exit "${x#??} should be c<3d|\>e' + +x='a one and a two' +[[ "${x//~(E)\<.\>/}" == ' one and two' ]] || err_exit "\< and \> not working in with ere's" + +{ +$SHELL -c 'typeset x="123" ; integer i=100 ; print -n "${x:i:5}"' +} 2> /dev/null || err_exit '${x:i:j} fails when i > strlen(x)' + +got=$($SHELL -c 'A=""; B="B"; for I in ${A[@]} ${B[@]}; do echo "\"$I\""; done') +[[ $got == $'"B"' ]] || err_exit '"\"$I\"" fails when $I is empty string' + +A='|' +[[ $A == $A ]] || err_exit 'With A="|", [[ $A == $A ]] does not match' + +x="111 222 333 444 555 666" +[[ $x == ~(E)(...).(...).(...) ]] +[[ -v .sh.match[0] ]] || err_exit '[[ -v .sh.match[0] ]] should be true' +[[ -v .sh.match[3] ]] || err_exit '[[ -v .sh.match[3] ]] should be true' +[[ -v .sh.match[4] ]] && err_exit '[[ -v .sh.match[4] ]] should be false' +[[ ${#.sh.match[@]} == 4 ]] || err_exit "\${#.sh.match[@]} should be 4, not ${#.sh.match[@]}" + +x="foo bar" +dummy=${x/~(E)(*)/} +[[ ${ print -v .sh.match;} ]] && err_exit 'print -v should show .sh.match empty when there are no matches' + +if $SHELL -c 'set 1 2 3 4 5 6 7 8 9 10 11 12; : ${##[0-9]}' 2>/dev/null +then set 1 2 3 4 5 6 7 8 9 10 11 12 + [[ ${##[0-9]} == 2 ]] || err_exit '${##[0-9]} should be 2 with $#==12' + [[ ${###[0-9]} == 2 ]] || err_exit '${###[0-9]} should be 2 with $#==12' + [[ ${#%[0-9]} == 1 ]] || err_exit '${#%[0-9]} should be 1 with $#==12' + [[ ${#%%[0-9]} == 1 ]] || err_exit '${#%%[0-9]} should be 1 with $#==12' +else err_exit '${##[0-9]} give syntax error' +fi + +{ + $SHELL -c 'x="a123 456 789z"; : ${x//{3}(\d)/ }' & + sleep .5; kill $!; wait $! +} 2> /dev/null || err_exit $'tokenizer can\'t handle ${var op {..} }' + + +function foo +{ + typeset x="123 456 789 abc" + typeset dummy="${x/~(E-g)([[:digit:]][[:digit:]])((X)|([[:digit:]]))([[:blank:]])/_}" + exp=$'(\n\t[0]=\'123 \'\n\t[1]=12\n\t[2]=3\n\t[4]=3\n\t[5]=\' \'\n)' + [[ $(print -v .sh.match) == "$exp" ]] || err_exit '.sh.match not correct with alternations' +} +foo + +x="a 1 b" +d=${x/~(E)(([[:digit:]])[[:space:]]*|([[:alpha:]]))/X} +[[ $(print -v .sh.match) == $'(\n\t[0]=a\n\t[1]=a\n\t[3]=a\n)' ]] || err_exit '.sh.match not sparse' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/tilde.sh b/src/cmd/ksh93/tests/tilde.sh new file mode 100755 index 0000000..b044723 --- /dev/null +++ b/src/cmd/ksh93/tests/tilde.sh @@ -0,0 +1,101 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2012 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r $Command: "$@" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +if $SHELL -c '[[ ~root == /* ]]' +then x=$(print -r -- ~root) + [[ $x == ~root ]] || err_exit '~user expanded in subshell prevent ~user from working' +fi + +function home # id +{ + typeset IFS=: pwd=/etc/passwd + set -o noglob + if [[ -f $pwd ]] && grep -c "^$1:" $pwd > /dev/null + then set -- $(grep "^$1:" $pwd) + print -r -- "$6" + else print . + fi +} + +OLDPWD=/bin +if [[ ~ != $HOME ]] +then err_exit '~' not $HOME +fi +x=~ +if [[ $x != $HOME ]] +then err_exit x=~ not $HOME +fi +x=x:~ +if [[ $x != x:$HOME ]] +then err_exit x=x:~ not x:$HOME +fi +if [[ ~+ != $PWD ]] +then err_exit '~' not $PWD +fi +x=~+ +if [[ $x != $PWD ]] +then err_exit x=~+ not $PWD +fi +if [[ ~- != $OLDPWD ]] +then err_exit '~' not $PWD +fi +x=~- +if [[ $x != $OLDPWD ]] +then err_exit x=~- not $OLDPWD +fi +for u in root Administrator +do h=$(home $u) + if [[ $h != . ]] + then [[ ~$u -ef $h ]] || err_exit "~$u not $h" + x=~$u + [[ $x -ef $h ]] || x="~$u not $h" + break + fi +done +x=~g.r.emlin +if [[ $x != '~g.r.emlin' ]] +then err_exit "x=~g.r.emlin failed -- expected '~g.r.emlin', got '$x'" +fi +x=~:~ +if [[ $x != "$HOME:$HOME" ]] +then err_exit "x=~:~ failed, expected '$HOME:$HOME', got '$x'" +fi +HOME=/ +[[ ~ == / ]] || err_exit '~ should be /' +[[ ~/foo == /foo ]] || err_exit '~/foo should be /foo when ~==/' +print $'print ~+\n[[ $1 ]] && $0' > $tmp/tilde +chmod +x $tmp/tilde +nl=$'\n' +[[ $($tmp/tilde foo) == "$PWD$nl$PWD" ]] 2> /dev/null || err_exit 'tilde fails inside a script run by name' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/timetype.sh b/src/cmd/ksh93/tests/timetype.sh new file mode 100755 index 0000000..16453c4 --- /dev/null +++ b/src/cmd/ksh93/tests/timetype.sh @@ -0,0 +1,81 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +typeset -T Time_t=( + integer .=-1 + _='%F+%H:%M' + get() + { + if (( _ < 0 )) + then .sh.value=${ printf "%(${_._})T" now ;} + else .sh.value=${ printf "%(${_._})T" "#$((_))" ;} + fi + } + set() + { + .sh.value=${ printf "%(%#)T" "${.sh.value}";} + } +) + +d=$(printf "%(%F+%H:%M)T" now) +integer s=$(printf "%(%#)T" "$d") +Time_t t=$d +[[ $t == "$d" ]] || err_exit "printf %T != Time_t -- expected '$d', got '$t'" +(( t == s )) || err_exit "numeric Time_t failed -- expected '$s', got '$t'" +t._='%#' +[[ $t == $s ]] || err_exit "t._='%#' failed -- expected '$s', got '$t'" +unset t +Time_t tt=(yesterday today tomorrow) +tt[3]=2pm +[[ ${!tt[@]} == '0 1 2 3' ]] || err_exit "indexed array subscript names failed -- expected '0 1 2 3', got '${!tt[@]}'" +[[ ${tt[0]} == *+00:00 ]] || err_exit "tt[0] failed -- expected 00:00, got '${tt[0]##*+}'" +[[ ${tt[1]} == *+00:00 ]] || err_exit "tt[1] failed -- expected 00:00, got '${tt[1]##*+}'" +[[ ${tt[2]} == *+00:00 ]] || err_exit "tt[2] failed -- expected 00:00, got '${tt[2]##*+}'" +[[ ${tt[3]} == *+14:00 ]] || err_exit "tt[3] failed -- expected 14:00, got '${tt[3]##*+}'" +unset tt +Time_t tt=('2008-08-11+00:00:00,yesterday' '2008-08-11+00:00:00,today' '2008-08-11+00:00:00,tomorrow') +tt[3]=9am +tt[4]=5pm +(( (tt[1] - tt[0]) == 24*3600 )) || err_exit "today-yesterday='$((tt[1] - tt[0]))' != 1 day" +(( (tt[2] - tt[1]) == 24*3600 )) || err_exit "tomorrow-today='$((tt[2] - tt[1]))' != 1 day" +(( (tt[4] - tt[3]) == 8*3600 )) || err_exit "9am..5pm='$((tt[4] - tt[3]))' != 8 hours" +unset tt +Time_t tt=([yesterday]='2008-08-11+00:00:00,yesterday' [today]='2008-08-11+00:00:00,today' [tomorrow]='2008-08-11+00:00:00,tomorrow') +tt[2pm]='2008-08-11+00:00:00,2pm' +[[ ${tt[yesterday]} == *+00:00 ]] || err_exit "tt[yesterday] failed -- expected 00:00, got '${tt[yesterday]##*+}'" +[[ ${tt[today]} == *+00:00 ]] || err_exit "tt[today] failed -- expected 00:00, got '${tt[today]##*+}'" +[[ ${tt[tomorrow]} == *+00:00 ]] || err_exit "tt[tomorrow] failed -- expected 00:00, got '${tt[tomorrow]##*+}'" +[[ ${tt[2pm]} == *+14:00 ]] || err_exit "tt[2pm] failed -- expected 14:00, got '${tt[2pm]##*+}'" +(( (tt[today] - tt[yesterday] ) == 24*3600 )) || err_exit "tt[today]-tt[yesterday] failed -- expected 24*3600, got $(((tt[today]-tt[yesterday])/3600.0))*3600" +(( (tt[tomorrow] - tt[today] ) == 24*3600 )) || err_exit "tt[tomorrow]-tt[today] failed -- expected 24*3600, got $(((tt[tomorrow]-tt[today])/3600.0))*3600" +(( (tt[2pm] - tt[today] ) == 14*3600 )) || err_exit "tt[2pm]-tt[today] failed -- expected 14*3600, got $(((tt[2pm]-tt[today])/3600.0))*3600" +unset tt + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/treemove.sh b/src/cmd/ksh93/tests/treemove.sh new file mode 100755 index 0000000..8e293c0 --- /dev/null +++ b/src/cmd/ksh93/tests/treemove.sh @@ -0,0 +1,163 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# This test checks whether "typeset -m" correctly moves local variables +# into a global variable tree. +# +# This was reported as CR #XXXXXXXX ("XXXX"): +# -- snip -- +#XXXX +# -- snip -- +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +integer Errors=0 + +## test start +typeset -C tree1 tree2 + +# add node to tree which uses "typeset -m" to move a local variable +# into tree1.subtree["a_node"] +function f1 +{ + nameref tr=$1 + typeset -A tr.subtree + typeset -C node + node.one="hello" + node.two="world" + # move local note into the array +false + typeset -m tr.subtree["a_node"]=node + return 0 +} + +# Alternative version which uses "nameref" instead of "typeset -m" +function f2 +{ + nameref tr=$1 + typeset -A tr.subtree + nameref node=tr.subtree["a_node"] + node.one="hello" + node.two="world" + return 0 +} + +f1 tree1 +f2 tree2 + +[[ "${tree1.subtree["a_node"].one}" == "hello" ]] || err_exit "expected tree1.subtree[\"a_node\"].one == 'hello', got ${tree1.subtree["a_node"].one}" +[[ "${tree1.subtree["a_node"].two}" == "world" ]] || err_exit "expected tree1.subtree[\"a_node\"].two == 'world', got ${tree1.subtree["a_node"].two}" +[[ "${tree1}" == "${tree2}" ]] || err_exit "tree1 and tree2 differ:$'\n'" + +unset c +compound c +typeset -C -a c.ar +c.ar[4]=( a4=1 ) +typeset -m "c.ar[5]=c.ar[4]" +exp=$'(\n\ttypeset -C -a ar=(\n\t\t[5]=(\n\t\t\ta4=1\n\t\t)\n\t)\n)' +[[ $(print -v c) == "$exp" ]] || err_exit 'typeset -m "c.ar[5]=c.ar[4]" not working' + +typeset -T x_t=( hello=world ) +function m +{ + compound c + compound -a c.x + x_t c.x[4][5][8].field + x_t x + typeset -m c.x[4][6][9].field=x + exp=$'(\n\ttypeset -C -a x=(\n\t\t[4]=(\n\t\t\t[5]=(\n\t\t\t\t[8]=(\n\t\t\t\t\tx_t field=(\n\t\t\t\t\t\thello=world\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t\t[6]=(\n\t\t\t\t[9]=(\n\t\t\t\t\tx_t field=(\n\t\t\t\t\t\thello=world\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t)\n\t)\n)' + [[ $(print -v c) == "$exp" ]] || err_exit "typeset -m c.x[4][6][9].field=x where x is a type is not working" +} +m + +function moveme +{ + nameref src=$2 dest=$1 + typeset -m dest=src +} +function main +{ + compound a=( aa=1 ) + compound -a ar + moveme ar[4] a 2> /dev/null || err_exit 'function moveme fails' + exp=$'(\n\t[4]=(\n\t\taa=1\n\t)\n)' + [[ $(print -v ar) == "$exp" ]] || err_exit 'typeset -m dest=src where dest and src are name references fails' +} +main + + +{ +$SHELL <<- \EOF + function main + { + compound c=( + compound -a board + ) + for ((i=0 ; i < 2 ; i++ )) ; do + compound el=(typeset id='pawn') + typeset -m "c.board[1][i]=el" + done + exp=$'(\n\ttypeset -C -a board=(\n\t\t[1]=(\n\t\t\t(\n\t\t\t\tid=pawn\n\t\t\t)\n\t\t\t(\n\t\t\t\tid=pawn\n\t\t\t)\n\t\t)\n\t)\n)' + [[ $(print -v c) == "$exp" ]] || exit 1 + } + main +EOF +} 2> /dev/null +if ((exitval=$?)) +then if [[ $(kill -l $exitval) == SEGV ]] + then err_exit 'typeset -m "c.board[1][i]=el" core dumps' + else err_exit 'typeset -m "c.board[1][i]=el" gives wrong value' + fi +fi +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/types.sh b/src/cmd/ksh93/tests/types.sh new file mode 100755 index 0000000..e8f82e1 --- /dev/null +++ b/src/cmd/ksh93/tests/types.sh @@ -0,0 +1,632 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +integer n=2 + +typeset -T Type_t=( + typeset name=foobar + typeset x=(hi=ok bar=yes) + typeset y=(xa=xx xq=89) + typeset -A aa=([one]=abc [two]=def) + typeset -a ia=(abc def) + typeset -i z=5 +) +for ((i=0; i < 10; i++)) +do + Type_t r s + [[ $r == "$s" ]] || err_exit 'r is not equal to s' + typeset -C x=r.x + y=(xa=bb xq=cc) + y2=xyz + z2=xyz + typeset -C z=y + [[ $y == "$z" ]] || err_exit 'y is not equal to z' + typeset -C s.y=z + [[ $y == "${s.y}" ]] || err_exit 'y is not equal to s.y' + .sh.q=$y + typeset -C www=.sh.q + [[ $www == "$z" ]] || err_exit 'www is not equal to z' + typeset -C s.x=r.x + [[ ${s.x} == "${r.x}" ]] || err_exit 's.x is not equal to r.x' + + function foo + { + nameref x=$1 y=$2 + typeset z=$x + y=$x + [[ $x == "$y" ]] || err_exit "x is not equal to y with ${!x}" + } + foo r.y y + [[ $y == "${r.y}" ]] || err_exit 'y is not equal to r.y' + typeset -C y=z + foo y r.y + [[ $y == "${r.y}" ]] || err_exit 'y is not equal to r.y again' + typeset -C y=z + ( + q=${z} + [[ $q == "$z" ]] || err_exit 'q is not equal to z' + z=abc + ) + [[ $z == "$y" ]] || err_exit 'value of z not preserved after subshell' + unset z y r s x z2 y2 www .sh.q +done +typeset -T Frame_t=( typeset file lineno ) +Frame_t frame +[[ $(typeset -p frame) == 'Frame_t frame=(typeset file;typeset lineno)' ]] || err_exit 'empty fields in type not displayed' +x=( typeset -a arr=([2]=abc [4]=(x=1 y=def));zz=abc) +typeset -C y=x +[[ "$x" == "$y" ]] || print -u2 'y is not equal to x' +Type_t z=(y=(xa=bb xq=cc)) +typeset -A arr=([foo]=one [bar]=2) +typeset -A brr=([foo]=one [bar]=2) +[[ "${arr[@]}" == "${brr[@]}" ]] || err_exit 'arr is not brr' +for ((i=0; i < 1; i++)) +do typeset -m zzz=x + [[ $zzz == "$y" ]] || err_exit 'zzz is not equal to y' + typeset -m x=zzz + [[ $x == "$y" ]] || err_exit 'x is not equal to y' + Type_t t=(y=(xa=bb xq=cc)) + typeset -m r=t + [[ $r == "$z" ]] || err_exit 'r is not equal to z' + typeset -m t=r + [[ $t == "$z" ]] || err_exit 't is not equal to z' + typeset -m crr=arr + [[ "${crr[@]}" == "${brr[@]}" ]] || err_exit 'crr is not brr' + typeset -m arr=crr + [[ "${arr[@]}" == "${brr[@]}" ]] || err_exit 'brr is not arr' +done +typeset -m brr[foo]=brr[bar] +[[ ${brr[foo]} == 2 ]] || err_exit 'move an associative array element fails' +[[ ${brr[bar]} ]] && err_exit 'brr[bar] should be unset after move' +unset x y zzz +x=(a b c) +typeset -m x[1]=x[2] +[[ ${x[1]} == c ]] || err_exit 'move an indexed array element fails' +[[ ${x[2]} ]] && err_exit 'x[2] should be unset after move' +cat > $tmp/types <<- \+++ + typeset -T Pt_t=(float x=1. y=0.) + Pt_t p=(y=2) + print -r -- ${p.y} ++++ +expected=2 +got=$(. $tmp/types) 2>/dev/null +[[ "$got" == "$expected" ]] || err_exit "typedefs in dot script failed -- expected '$expected', got '$got'" +typeset -T X_t=( + typeset x=foo y=bar + typeset s=${_.x} + create() + { + _.y=bam + } +) +X_t x +[[ ${x.x} == foo ]] || err_exit 'x.x should be foo' +[[ ${x.y} == bam ]] || err_exit 'x.y should be bam' +[[ ${x.s} == ${x.x} ]] || err_exit 'x.s should be x.x' +typeset -T Y_t=( X_t r ) +Y_t z +[[ ${z.r.x} == foo ]] || err_exit 'z.r.x should be foo' +[[ ${z.r.y} == bam ]] || err_exit 'z.r.y should be bam' +[[ ${z.r.s} == ${z.r.x} ]] || err_exit 'z.r.s should be z.r.x' + +unset xx yy +typeset -T xx=(typeset yy=zz) +xx=yy +{ typeset -T xx=(typeset yy=zz) ;} 2>/dev/null && err_exit 'type redefinition should fail' +$SHELL 2> /dev/null <<- +++ || err_exit 'typedef with only f(){} fails' + typeset -T X_t=( + f() + { + print ok + } + ) ++++ +$SHELL 2> /dev/null <<- +++ || err_exit 'unable to redefine f discipline function' + typeset -T X_t=( + x=1 + f() + { + print ok + } + ) + X_t z=( + function f + { + print override f + } + ) ++++ +$SHELL 2> /dev/null <<- +++ && err_exit 'invalid discipline name should be an error' + typeset -T X_t=( + x=1 + f() + { + print ok + } + ) + X_t z=( + function g + { + print override f + } + ) ++++ +# compound variables containing type variables +Type_t r +var=( + typeset x=foobar + Type_t r + integer z=5 +) +[[ ${var.r} == "$r" ]] || err_exit 'var.r != r' +(( var.z == 5)) || err_exit 'var.z !=5' +[[ "$var" == *x=foobar* ]] || err_exit '$var does not contain x=foobar' + +typeset -T A_t=( + typeset x=aha + typeset b=${_.x} +) +unset x +A_t x +expected=aha +got=${x.b} +[[ "$got" == "$expected" ]] || err_exit "type '_' reference failed -- expected '$expected', got '$got'" + +typeset -T Tst_t=( + function f + { + A_t a + print ${ _.g ${a.x}; } + } + function g + { + print foo + } +) +Tst_t tst +expected=foo +got=${ tst.f;} +[[ "$got" == "$expected" ]] || err_exit "_.g where g is a function in type discipline method failed -- expected '$expected', got '$got'" + +typeset -T B_t=( + integer -a arr + function f + { + (( _.arr[0] = 0 )) + (( _.arr[1] = 1 )) + print ${_.arr[*]} + } +) +unset x +B_t x +expected='0 1' +got=${ x.f;} +[[ "$got" == "$expected" ]] || err_exit "array assignment of subscripts in type discipline arithmetic failed -- expected '$expected', got '$got'" + +typeset -T Fileinfo_t=( + size=-1 + typeset -a text=() + integer mtime=-1 +) +Fileinfo_t -A _Dbg_filenames +Fileinfo_t finfo +function bar +{ + finfo.text=(line1 line2 line3) + finfo.size=${#finfo.text[@]} + _Dbg_filenames[foo]=finfo +} +bar + +expected='Fileinfo_t -A _Dbg_filenames=([foo]=(size=3;typeset -a text=(line1 line2 line3);typeset -l -i mtime=-1))' +got=$(typeset -p _Dbg_filenames) +[[ "$got" == "$expected" ]] || { + got=$(printf %q "$got") + err_exit "copy to associative array of types in function failed -- expected '$expected', got $got" +} + +$SHELL > /dev/null <<- '+++++' || err_exit 'passing _ as nameref arg not working' + function f1 + { + typeset -n v=$1 + print -r -- "$v" + } + typeset -T A_t=( + typeset blah=xxx + function f { f1 _ ;} + ) + A_t a + [[ ${ a.f ./t1;} == "$a" ]] ++++++ +expected='A_t b.a=(name=one)' +[[ $( $SHELL << \+++ + typeset -T A_t=( + typeset name=aha + ) + typeset -T B_t=( + typeset arr + A_t a + f() + { + _.a=(name=one) + typeset -p _.a + } + ) + B_t b + b.f ++++ +) == "$expected" ]] 2> /dev/null || err_exit '_.a=(name=one) not expanding correctly' +expected='A_t x=(name=xxx)' +[[ $( $SHELL << \+++ + typeset -T A_t=( + typeset name + ) + A_t x=(name="xxx") + typeset -p x ++++ +) == "$expected" ]] || err_exit 'empty field in definition does not expand correctly' + +typeset -T Foo_t=( + integer x=3 + integer y=4 + len() { print -r -- $(( sqrt(_.x**2 + _.y**2))) ;} +) +Foo_t foo +[[ ${foo.len} == 5 ]] || err_exit "discipline function len not working" + +typeset -T benchmark_t=( + integer num_iterations +) +function do_benchmarks +{ + nameref tst=b + integer num_iterations + (( num_iterations= int(tst.num_iterations * 1.0) )) + printf "%d\n" num_iterations +} +benchmark_t b=(num_iterations=5) +[[ $(do_benchmarks) == 5 ]] || err_exit 'scoping of nameref of type variables in arithmetic expressions not working' + +function cat_content +{ + cat <<- EOF + ( + foo_t -a foolist=( + ( val=3 ) + ( val=4 ) + ( val=5 ) + ) + ) + EOF + return 0 +} +typeset -T foo_t=( + integer val=-1 + function print + { + print -- ${_.val} + } +) +function do_something +{ + nameref li=$1 # "li" may be an index or associative array + li[2].print +} +cat_content | read -C x +[[ $(do_something x.foolist) == 5 ]] || err_exit 'subscripts not honored for arrays of type with disciplines' + +typeset -T benchcmd_t=( + float x=1 + float y=2 +) +unset x +compound x=( + float o + benchcmd_t -a m + integer h +) +expected=$'(\n\ttypeset -l -i h=0\n\tbenchcmd_t -a m\n\ttypeset -l -E o=0\n)' +[[ $x == "$expected" ]] || err_exit 'compound variable with array of types with no elements not working' + +expected=$'Std_file_t db.file[/etc/profile]=(action=preserve;typeset -A sum=([8242e663d6f7bb4c5427a0e58e2925f3]=1);)' +{ + got=$($SHELL <<- \EOF + MAGIC='stdinstall (at&t research) 2009-08-25' + typeset -T Std_file_t=( + typeset action + typeset -A sum + ) + typeset -T Std_t=( + typeset magic=$MAGIC + Std_file_t -A file + ) + Std_t db=(magic='stdinstall (at&t research) 2009-08-25';Std_file_t -A file=( [/./home/gsf/.env.sh]=(action=preserve;typeset -A sum=([9b67ab407d01a52b3e73e3945b9a3ee0]=1);)[/etc/profile]=(action=preserve;typeset -A sum=([8242e663d6f7bb4c5427a0e58e2925f3]=1);)[/home/gsf/.profile]=(action=preserve;typeset -A sum=([3ce23137335219672bf2865d003a098e]=1);));) + typeset -p db.file[/etc/profile] + EOF) +} 2> /dev/null +[[ $got == "$expected" ]] || err_exit 'types with arrays of types as members fails' + +typeset -T x_t=( + integer dummy + function set + { + [[ ${.sh.name} == v ]] || err_exit "name=${.sh.name} should be v" + [[ ${.sh.subscript} == 4 ]] || err_exit "subscript=${.sh.subscript} should be 4" + [[ ${.sh.value} == hello ]] || err_exit "value=${.sh.value} should be hello" + } +) +x_t -a v +v[4]="hello" + +typeset -T oset=( + typeset -A s +) +oset foo bar +: ${foo.s[a]:=foobar} +: ${bar.s[d]:=foobar} +[[ ${bar.s[a]} == foobar ]] && err_exit '${var:=val} for types assigns to type instead of type instance' + +typeset -T olist=( + typeset -a l +) +olist foo +foo.l[1]=x +[[ ${!foo.l[*]} == *0* ]] && '0-th elment of foo.l should not be set' + +typeset -T oset2=( typeset -A foo ) +oset2 bar +: ${bar.foo[a]} +bar.foo[a]=b +[[ ${#bar.foo[*]} == 1 ]] || err_exit "bar.foo should have 1 element not ${#bar.foo[*]}" +[[ ${bar.foo[*]} == b ]] || err_exit "bar.foo[*] should be 'b' not ${bar.foo[*]}" +[[ ${bar.foo[a]} == b ]] || err_exit "bar.foo[a] should be 'b' not ${bar.foo[*]}" + +{ x=$( $SHELL 2> /dev/null << \++EOF++ + typeset -T ab_t=( + integer a=1 b=2 + function increment + { + (( _.a++, _.b++ )) + } + ) + function ar_n + { + nameref sn=$2 + sn.increment + $1 && printf "a=%d, b=%d\n" sn.a sn.b + } + function ar + { + ab_t -S -a s + [[ -v s[5] ]] || s[5]=( ) + ar_n $1 s[5] + } + x=$(ar false ; ar false ; ar true ; printf ";") + y=$(ar false ; ar false ; ar true ; printf ";") + print -r -- "\"$x\"" == "\"$y\"" +++EOF++ +) ;} 2> /dev/null +[[ $x == *a=4*b=5* ]] || err_exit 'static types in a function not working' +{ eval "[[ $x ]]";} 2> /dev/null || err_exit 'arrays of types leaving side effects in subshells' + +typeset -T y_t=( + typeset dummy + function print_b + { + print "B" + } +) +y_t a b=( + function print_b + { + print "1" + } +) +[[ $(a.print_b) == B ]] || err_exit 'default discipline not working' +[[ $(b.print_b) == 1 ]] || err_exit 'discipline override not working' + +$SHELL 2> /dev/null -c 'true || { typeset -T Type_t=(typeset name=foo); + Type_t z=(name=bar) ;}' || err_exit 'unable to parse type command until typeset -T executes' + +cd "$tmp" +FPATH=$PWD +PATH=$PWD:$PATH +cat > A_t <<- \EOF + typeset -T A_t=( + B_t b + ) +EOF +cat > B_t <<- \EOF + typeset -T B_t=( + integer n=5 + ) +EOF + +unset n +if n=$(FPATH=$PWD PATH=$PWD:$PATH $SHELL 2> /dev/null -c 'A_t a; print ${a.b.n}') +then (( n==5 )) || err_exit 'dynamic loading of types gives wrong result' +else err_exit 'unable to load types dynamically' +fi + +# check that typeset -T reproduces a type. +if $SHELL > /dev/null 2>&1 -c 'typeset -T' +then $SHELL > junk1 <<- \+++EOF + typeset -T foo_t=( + integer x=3 y=4 + float z=1.2 + len() + { + ((.sh.value=sqrt(_.x**2 + _.y**2) )) + } + function count + { + print z=$z + } + ) + typeset -T + print 'typeset -T' + +++EOF + $SHELL -c '. ./junk1;print "typeset -T"' > junk2 + diff junk[12] > /dev/null || err_exit 'typeset -T not idempotent' + $SHELL -c '. ./junk1;print "typeset +f"' > junk2 + [[ -s junk2 ]] || err_exit 'non-discipline-method functions found' +else + err_exit 'typeset -T not supported' +fi + +[[ $($SHELL -c 'typeset -T x=( typeset -a h ) ; x j; print -v j.h') ]] && err_exit 'type with indexed array without elements inserts element 0' + +[[ $($SHELL -c 'typeset -T x=( integer -a s ) ; compound c ; x c.i ; c.i.s[4]=666 ; print -v c') == *'[0]'* ]] && err_exit 'type with indexed array with non-zero element inserts element 0' + + +{ $SHELL -c '(sleep 3;kill $$)& typeset -T x=( typeset -a s );compound c;x c.i;c.i.s[7][5][3]=hello;x c.j=c.i;[[ ${c.i} == "${c.j}" ]]';} 2> /dev/null +exitval=$? +if [[ $(kill -l $exitval) == TERM ]] +then err_exit 'clone of multi-dimensional array timed out' +elif ((exitval)) +then err_exit "c.i and c.j are not the same multi-dimensional array" +fi + +typeset -T foobar_t=( + float x=1 y=0 + slen() + { + print -r -- $((sqrt(_.x**2 + _.y**2))) + } + typeset -fS slen + len() + { + print -r -- $((sqrt(_.x**2 + _.y**2))) + } +) +unset z +foobar_t z=(x=3 y=4) +(( z.len == 5 )) || err_exit 'z.len should be 5' +(( z.slen == 1 )) || err_exit 'z.slen should be 1' +(( .sh.type.foobar_t.slen == 1 )) || err_exit '.sh.type.foobar_t.slen should be 1' +(( .sh.type.foobar_t.len == 1 )) || err_exit '.sh.type.foobar_t.len should be 1' + +typeset -T z_t=( typeset -a ce ) +z_t x1 +x1.ce[3][4]=45 +compound c +z_t -a c.x2 +c.x2[9]=x1 +got=$(typeset +p "c.x2[9].ce") +exp='typeset -a c.x2[9].ce' +[[ $got == "$exp" ]] || err_exit "typeset +p 'c.x2[9].ce' failed -- expected '$exp', got '$got'" + +unset b +typeset -T a_t=( + typeset a="hello" +) +typeset -T b_t=( + a_t b +) +compound b +compound -a b.ca +b_t b.ca[4].b +exp='typeset -C b=(typeset -C -a ca=( [4]=(b_t b=(a_t b=(a=hello))));)' +got=$(typeset -p b) +[[ $got == "$exp" ]] || err_exit 'typeset -p of nested type not correct' + +typeset -T u_t=( + integer dummy + unset() + { + print unset + } +) +unset z +u_t -a x | read z +[[ $z == unset ]] && err_exit 'unset discipline called on type creation' + +{ z=$($SHELL 2> /dev/null 'typeset -T foo; typeset -T') ;} 2> /dev/null +[[ $z == 'typeset -T foo' ]] || err_exit '"typeset -T foo; typeset -T" failed' + +{ z=$($SHELL 2> /dev/null 'typeset -T foo=bar; typeset -T') ;} 2> /dev/null +[[ $z ]] && err_exit '"typeset -T foo=bar" should not creates type foo' + +{ +$SHELL << \EOF + typeset -T board_t=( + compound -a board_y + function binsert + { + nameref figure=$1 + integer y=$2 x=$3 + typeset -m "_.board_y[y].board_x[x].field=figure" + } + ) + function main + { + compound c=( + board_t b + ) + for ((i=0 ; i < 2 ; i++ )) ; do + compound p=( hello=world ) + c.b.binsert p 1 $i + done + exp='typeset -C c=(board_t b=(typeset -a board_y=( [1]=(typeset -a board_x=( [0]=(field=(hello=world;))[1]=(field=(hello=world)));));))' + [[ $(typeset -p c) == "$exp" ]] || exit 1 + } + main +EOF +} 2> /dev/null +if (( exitval=$?)) +then if [[ $(kill -l $exitval) == SEGV ]] + then err_exit 'typeset -m in type discipline causes exception' + else err_exit 'typeset -m in type discipline gives wrong value' + fi +fi + +typeset -T pawn_t=( + print_debug() + { + print 'PAWN' + } +) +function main +{ + compound c=( + compound -a board + ) + + for ((i=2 ; i < 8 ; i++ )) ; do + pawn_t c.board[1][$i] + done + +} +main 2> /dev/null && err_exit 'type assignment to compound array instance should generate an error' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh new file mode 100755 index 0000000..be7c308 --- /dev/null +++ b/src/cmd/ksh93/tests/variables.sh @@ -0,0 +1,665 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + let Errors+=1 +} +alias err_exit='err_exit $LINENO' + +Command=${0##*/} +integer Errors=0 + +tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } +trap "cd /; rm -rf $tmp" EXIT + +[[ ${.sh.version} == "$KSH_VERSION" ]] || err_exit '.sh.version != KSH_VERSION' +unset ss +[[ ${@ss} ]] && err_exit '${@ss} should be empty string when ss is unset' +[[ ${!ss} == ss ]] || err_exit '${!ss} should be ss when ss is unset' +[[ ${#ss} == 0 ]] || err_exit '${#ss} should be 0 when ss is unset' +# RANDOM +if (( RANDOM==RANDOM || $RANDOM==$RANDOM )) +then err_exit RANDOM variable not working +fi +# SECONDS +sleep 3 +if (( SECONDS < 2 )) +then err_exit SECONDS variable not working +fi +# _ +set abc def +if [[ $_ != def ]] +then err_exit _ variable not working +fi +# ERRNO +#set abc def +#rm -f foobar# +#ERRNO= +#2> /dev/null < foobar# +#if (( ERRNO == 0 )) +#then err_exit ERRNO variable not working +#fi +# PWD +if [[ ! $PWD -ef . ]] +then err_exit PWD variable failed, not equivalent to . +fi +# PPID +exp=$$ +got=${ $SHELL -c 'print $PPID'; } +if [[ ${ $SHELL -c 'print $PPID'; } != $$ ]] +then err_exit "PPID variable failed -- expected '$exp', got '$got'" +fi +# OLDPWD +old=$PWD +cd / +if [[ $OLDPWD != $old ]] +then err_exit "OLDPWD variable failed -- expected '$old', got '$OLDPWD'" +fi +cd $old || err_exit cd failed +# REPLY +read <<-! + foobar + ! +if [[ $REPLY != foobar ]] +then err_exit REPLY variable not working +fi +integer save=$LINENO +# LINENO +LINENO=10 +# +# These lines intentionally left blank +# +if (( LINENO != 13)) +then err_exit LINENO variable not working +fi +LINENO=save+10 +IFS=: +x=a::b::c +if [[ $x != a::b::c ]] +then err_exit "word splitting on constants" +fi +set -- $x +if [[ $# != 5 ]] +then err_exit ":: doesn't separate null arguments " +fi +set x +if x$1=0 2> /dev/null +then err_exit "x\$1=value treated as an assignment" +fi +# check for attributes across subshells +typeset -i x=3 +y=1/0 +if ( typeset x=y ) 2> /dev/null +then err_exit "attributes not passed to subshells" +fi +unset x +function x.set +{ + nameref foo=${.sh.name}.save + foo=${.sh.value} + .sh.value=$0 +} +x=bar +if [[ $x != x.set ]] +then err_exit 'x.set does not override assignment' +fi +x.get() +{ + nameref foo=${.sh.name}.save + .sh.value=$foo +} + +if [[ $x != bar ]] +then err_exit 'x.get does not work correctly' +fi +typeset +n foo +unset foo +foo=bar +( + unset foo + set +u + if [[ $foo != '' ]] + then err_exit '$foo not null after unset in subsehll' + fi +) +if [[ $foo != bar ]] +then err_exit 'unset foo in subshell produces side effect ' +fi +unset foo +if [[ $( { : ${foo?hi there} ; } 2>&1) != *'hi there' ]] +then err_exit '${foo?hi there} with foo unset does not print hi there on 2' +fi +x=$0 +set foobar +if [[ ${@:0} != "$x foobar" ]] +then err_exit '${@:0} not expanding correctly' +fi +set -- +if [[ ${*:0:1} != "$0" ]] +then err_exit '${@:0} not expanding correctly' +fi +ACCESS=0 +function COUNT.set +{ + (( ACCESS++ )) +} +COUNT=0 +(( COUNT++ )) +if (( COUNT != 1 || ACCESS!=2 )) +then err_exit " set discipline failure COUNT=$COUNT ACCESS=$ACCESS" +fi +LANG=C > /dev/null 2>&1 +if [[ $LANG != C ]] +then err_exit "C locale not working" +fi +unset RANDOM +unset -n foo +foo=junk +function foo.get +{ + .sh.value=stuff + unset -f foo.get +} +if [[ $foo != stuff ]] +then err_exit "foo.get discipline not working" +fi +if [[ $foo != junk ]] +then err_exit "foo.get discipline not working after unset" +fi +# special variables +set -- 1 2 3 4 5 6 7 8 9 10 +sleep 1000 & +if [[ $(print -r -- ${#10}) != 2 ]] +then err_exit '${#10}, where ${10}=10 not working' +fi +for i in @ '*' ! '#' - '?' '$' +do false + eval foo='$'$i bar='$'{$i} + if [[ ${foo} != "${bar}" ]] + then err_exit "\$$i not equal to \${$i}" + fi + command eval bar='$'{$i%?} 2> /dev/null || err_exit "\${$i%?} gives syntax error" + if [[ $i != [@*] && ${foo%?} != "$bar" ]] + then err_exit "\${$i%?} not correct" + fi + command eval bar='$'{$i#?} 2> /dev/null || err_exit "\${$i#?} gives syntax error" + if [[ $i != [@*] && ${foo#?} != "$bar" ]] + then err_exit "\${$i#?} not correct" + fi + command eval foo='$'{$i} bar='$'{#$i} || err_exit "\${#$i} gives synta +x error" + if [[ $i != @([@*]) && ${#foo} != "$bar" ]] + then err_exit "\${#$i} not correct" + fi +done +kill $! +unset x +CDPATH=/ +x=$(cd ${tmp#/}) +if [[ $x != $tmp ]] +then err_exit 'CDPATH does not display new directory' +fi +CDPATH=/: +x=$(cd ${tmp%/*}; cd ${tmp##*/}) +if [[ $x ]] +then err_exit 'CDPATH displays new directory when not used' +fi +x=$(cd ${tmp#/}) +if [[ $x != $tmp ]] +then err_exit "CDPATH ${tmp#/} does not display new directory" +fi +TMOUT=100 +(TMOUT=20) +if (( TMOUT !=100 )) +then err_exit 'setting TMOUT in subshell affects parent' +fi +unset y +function setdisc # var +{ + eval function $1.get' + { + .sh.value=good + } + ' +} +y=bad +setdisc y +if [[ $y != good ]] +then err_exit 'setdisc function not working' +fi +integer x=$LINENO +: $'\ +' +if (( LINENO != x+3 )) +then err_exit '\<newline> gets linenumber count wrong' +fi +set -- +set -- "${@-}" +if (( $# !=1 )) +then err_exit '"${@-}" not expanding to null string' +fi +for i in : % + / 3b '**' '***' '@@' '{' '[' '}' !! '*a' '$foo' +do (eval : \${"$i"} 2> /dev/null) && err_exit "\${$i} not an syntax error" +done +unset IFS +( IFS=' ' ; read -r a b c <<-! + x y z + ! + if [[ $b ]] + then err_exit 'IFS=" " not causing adjacent space to be null string' + fi +) +read -r a b c <<-! +x y z +! +if [[ $b != y ]] +then err_exit 'IFS not restored after subshell' +fi + +# The next part generates 3428 IFS set/read tests. + +unset IFS x +function split +{ + i=$1 s=$2 r=$3 + IFS=': ' + set -- $i + IFS=' ' + g="[$#]" + while : + do case $# in + 0) break ;; + esac + g="$g($1)" + shift + done + case "$g" in + "$s") ;; + *) err_exit "IFS=': '; set -- '$i'; expected '$s' got '$g'" ;; + esac + print "$i" | IFS=": " read arg rem; g="($arg)($rem)" + case "$g" in + "$r") ;; + *) err_exit "IFS=': '; read '$i'; expected '$r' got '$g'" ;; + esac +} +for str in \ + '-' \ + 'a' \ + '- -' \ + '- a' \ + 'a -' \ + 'a b' \ + '- - -' \ + '- - a' \ + '- a -' \ + '- a b' \ + 'a - -' \ + 'a - b' \ + 'a b -' \ + 'a b c' +do + IFS=' ' + set x $str + shift + case $# in + 0) continue ;; + esac + f1=$1 + case $f1 in + '-') f1='' ;; + esac + shift + case $# in + 0) for d0 in '' ' ' + do + for d1 in '' ' ' ':' ' :' ': ' ' : ' + do + case $f1$d1 in + '') split "$d0$f1$d1" "[0]" "()()" ;; + ' ') ;; + *) split "$d0$f1$d1" "[1]($f1)" "($f1)()" ;; + esac + done + done + continue + ;; + esac + f2=$1 + case $f2 in + '-') f2='' ;; + esac + shift + case $# in + 0) for d0 in '' ' ' + do + for d1 in ' ' ':' ' :' ': ' ' : ' + do + case ' ' in + $f1$d1|$d1$f2) continue ;; + esac + for d2 in '' ' ' ':' ' :' ': ' ' : ' + do + case $f2$d2 in + '') split "$d0$f1$d1$f2$d2" "[1]($f1)" "($f1)()" ;; + ' ') ;; + *) split "$d0$f1$d1$f2$d2" "[2]($f1)($f2)" "($f1)($f2)" ;; + esac + done + done + done + continue + ;; + esac + f3=$1 + case $f3 in + '-') f3='' ;; + esac + shift + case $# in + 0) for d0 in '' ' ' + do + for d1 in ':' ' :' ': ' ' : ' + do + case ' ' in + $f1$d1|$d1$f2) continue ;; + esac + for d2 in ' ' ':' ' :' ': ' ' : ' + do + case $f2$d2 in + ' ') continue ;; + esac + case ' ' in + $f2$d2|$d2$f3) continue ;; + esac + for d3 in '' ' ' ':' ' :' ': ' ' : ' + do + case $f3$d3 in + '') split "$d0$f1$d1$f2$d2$f3$d3" "[2]($f1)($f2)" "($f1)($f2)" ;; + ' ') ;; + *) x=$f2$d2$f3$d3 + x=${x#' '} + x=${x%' '} + split "$d0$f1$d1$f2$d2$f3$d3" "[3]($f1)($f2)($f3)" "($f1)($x)" + ;; + esac + done + done + done + done + continue + ;; + esac +done +unset IFS + +if [[ $( (print ${12345:?}) 2>&1) != *12345* ]] +then err_exit 'incorrect error message with ${12345?}' +fi +unset foobar +if [[ $( (print ${foobar:?}) 2>&1) != *foobar* ]] +then err_exit 'incorrect error message with ${foobar?}' +fi +unset bar +if [[ $( (print ${bar:?bam}) 2>&1) != *bar*bam* ]] +then err_exit 'incorrect error message with ${foobar?}' +fi +{ $SHELL -c ' +function foo +{ + typeset SECONDS=0 + sleep 1.5 + print $SECONDS + +} +x=$(foo) +(( x >1 && x < 2 )) +' +} 2> /dev/null || err_exit 'SECONDS not working in function' +cat > $tmp/script <<-\! + posixfun() + { + unset x + nameref x=$1 + print -r -- "$x" + } + function fun + { + nameref x=$1 + print -r -- "$x" + } + if [[ $1 ]] + then file=${.sh.file} + else print -r -- "${.sh.file}" + fi +! +chmod +x $tmp/script +. $tmp/script 1 +[[ $file == $tmp/script ]] || err_exit ".sh.file not working for dot scripts" +[[ $($SHELL $tmp/script) == $tmp/script ]] || err_exit ".sh.file not working for scripts" +[[ $(posixfun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for posix functions" +[[ $(fun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for functions" +[[ $(posixfun .sh.fun) == posixfun ]] || err_exit ".sh.fun not working for posix functions" +[[ $(fun .sh.fun) == fun ]] || err_exit ".sh.fun not working for functions" +[[ $(posixfun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for posix functions" +[[ $(fun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for functions" +( + [[ $(posixfun .sh.subshell) == 2 ]] || err_exit ".sh.subshell not working for posix functions in subshells" + [[ $(fun .sh.subshell) == 2 ]] || err_exit ".sh.subshell not working for functions in subshells" + (( .sh.subshell == 1 )) || err_exit ".sh.subshell not working in a subshell" +) +TIMEFORMAT='this is a test' +[[ $({ { time :;} 2>&1;}) == "$TIMEFORMAT" ]] || err_exit 'TIMEFORMAT not working' +: ${.sh.version} +[[ $(alias integer) == *.sh.* ]] && err_exit '.sh. prefixed to alias name' +: ${.sh.version} +[[ $(whence rm) == *.sh.* ]] && err_exit '.sh. prefixed to tracked alias name' +: ${.sh.version} +[[ $(cd /bin;env | grep PWD=) == *.sh.* ]] && err_exit '.sh. prefixed to PWD' +# unset discipline bug fix +dave=dave +function dave.unset +{ + unset dave +} +unset dave +[[ $(typeset +f) == *dave.* ]] && err_exit 'unset discipline not removed' + +print 'print ${VAR}' > $tmp/script +unset VAR +VAR=new $tmp/script > $tmp/out +got=$(<$tmp/out) +[[ $got == new ]] || err_exit "previously unset environment variable not passed to script, expected 'new', got '$got'" +[[ ! $VAR ]] || err_exit "previously unset environment variable set after script, expected '', got '$VAR'" +unset VAR +VAR=old +VAR=new $tmp/script > $tmp/out +got=$(<$tmp/out) +[[ $got == new ]] || err_exit "environment variable covering local variable not passed to script, expected 'new', got '$got'" +[[ $VAR == old ]] || err_exit "previously set local variable changed after script, expected 'old', got '$VAR'" +unset VAR +export VAR=old +VAR=new $tmp/script > $tmp/out +got=$(<$tmp/out) +[[ $got == new ]] || err_exit "environment variable covering environment variable not passed to script, expected 'new', got '$got'" +[[ $VAR == old ]] || err_exit "previously set environment variable changed after script, expected 'old', got '$VAR'" + +( + unset dave + function dave.append + { + .sh.value+=$dave + dave= + } + dave=foo; dave+=bar + [[ $dave == barfoo ]] || exit 2 +) 2> /dev/null +case $? in +0) ;; +1) err_exit 'append discipline not implemented';; +*) err_exit 'append discipline not working';; +esac +.sh.foobar=hello +{ + function .sh.foobar.get + { + .sh.value=world + } +} 2> /dev/null || err_exit "cannot add get discipline to .sh.foobar" +[[ ${.sh.foobar} == world ]] || err_exit 'get discipline for .sh.foobar not working' +x='a|b' +IFS='|' +set -- $x +[[ $2 == b ]] || err_exit '$2 should be b after set' +exec 3>&2 2> /dev/null +set -x +( IFS= ) 2> /dev/null +set +x +exec 2>&3- +set -- $x +[[ $2 == b ]] || err_exit '$2 should be b after subshell' +: & pid=$! +( : & ) +[[ $pid == $! ]] || err_exit '$! value not preserved across subshells' +unset foo +typeset -A foo +function foo.set +{ + case ${.sh.subscript} in + bar) if ((.sh.value > 1 )) + then .sh.value=5 + foo[barrier_hit]=yes + fi + ;; + barrier_hit) + if [[ ${.sh.value} == yes ]] + then foo[barrier_not_hit]=no + else foo[barrier_not_hit]=yes + fi + ;; + esac +} +foo[barrier_hit]=no +foo[bar]=1 +(( foo[bar] == 1 )) || err_exit 'foo[bar] should be 1' +[[ ${foo[barrier_hit]} == no ]] || err_exit 'foo[barrier_hit] should be no' +[[ ${foo[barrier_not_hit]} == yes ]] || err_exit 'foo[barrier_not_hit] should be yes' +foo[barrier_hit]=no +foo[bar]=2 +(( foo[bar] == 5 )) || err_exit 'foo[bar] should be 5' +[[ ${foo[barrier_hit]} == yes ]] || err_exit 'foo[barrier_hit] should be yes' +[[ ${foo[barrier_not_hit]} == no ]] || err_exit 'foo[barrier_not_hit] should be no' +unset x +typeset -i x +function x.set +{ + typeset sub=${.sh.subscript} + (( sub > 0 )) && (( x[sub-1]= x[sub-1] + .sh.value )) +} +x[0]=0 x[1]=1 x[2]=2 x[3]=3 +[[ ${x[@]} == '12 8 5 3' ]] || err_exit 'set discipline for indexed array not working correctly' +float seconds +((SECONDS=3*4)) +seconds=SECONDS +(( seconds < 12 || seconds > 12.1 )) && err_exit "SECONDS is $seconds and should be close to 12" +unset a +function a.set +{ + print -r -- "${.sh.name}=${.sh.value}" +} +[[ $(a=1) == a=1 ]] || err_exit 'set discipline not working in subshell assignment' +[[ $(a=1 :) == a=1 ]] || err_exit 'set discipline not working in subshell command' + +[[ ${.sh.subshell} == 0 ]] || err_exit '${.sh.subshell} should be 0' +( + [[ ${.sh.subshell} == 1 ]] || err_exit '${.sh.subshell} should be 1' + ( + [[ ${.sh.subshell} == 2 ]] || err_exit '${.sh.subshell} should be 2' + ) +) + +set -- {1..32768} +(( $# == 32768 )) || err_exit "\$# failed -- expected 32768, got $#" +set -- + +unset r v x +path=$PATH +x=foo +for v in EDITOR VISUAL OPTIND CDPATH FPATH PATH ENV LINENO RANDOM SECONDS _ +do nameref r=$v + unset $v + if ( $SHELL -c "unset $v; : \$$v" ) 2>/dev/null + then [[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'" + r=$x + [[ $r == $x ]] || err_exit "$v=$x failed -- expected '$x', got '$r'" + else err_exit "unset $v; : \$$v failed" + fi +done + +x=x +for v in LC_ALL LC_CTYPE LC_MESSAGES LC_COLLATE LC_NUMERIC +do nameref r=$v + unset $v + [[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'" + d=$($SHELL -c "$v=$x" 2>&1) + [[ $d ]] || err_exit "$v=$x failed -- expected locale diagnostic" + { g=$( r=$x; print -- $r ); } 2>/dev/null + [[ $g == '' ]] || err_exit "$v=$x failed -- expected '', got '$g'" + { g=$( r=C; r=$x; print -- $r ); } 2>/dev/null + [[ $g == 'C' ]] || err_exit "$v=C; $v=$x failed -- expected 'C', got '$g'" +done +PATH=$path + +cd $tmp + +print print -n zzz > zzz +chmod +x zzz +exp='aaazzz' +got=$($SHELL -c 'unset SHLVL; print -n aaa; ./zzz' 2>&1) >/dev/null 2>&1 +[[ $got == "$exp" ]] || err_exit "unset SHLVL causes script failure -- expected '$exp', got '$got'" + +mkdir glean +for cmd in date ok +do exp="$cmd ok" + rm -f $cmd + print print $exp > glean/$cmd + chmod +x glean/$cmd + got=$(CDPATH=:.. $SHELL -c "PATH=:/bin:/usr/bin; date > /dev/null; cd glean && ./$cmd" 2>&1) + [[ $got == "$exp" ]] || err_exit "cd with CDPATH after PATH change failed -- expected '$exp', got '$got'" +done + +v=LC_CTYPE +unset $v +[[ -v $v ]] && err_exit "unset $v; [[ -v $v ]] failed" +eval $v=C +[[ -v $v ]] || err_exit "$v=C; [[ -v $v ]] failed" + +cmd='set --nounset; unset foo; : ${!foo*}' +$SHELL -c "$cmd" 2>/dev/null || err_exit "'$cmd' exit status $?, expected 0" + +SHLVL=1 +level=$($SHELL -c $'$SHELL -c \'print -r "$SHLVL"\'') +[[ $level == 3 ]] || err_exit "SHLVL should be 3 not $level" + +[[ $($SHELL -c '{ x=1; : ${x.};print ok;}' 2> /dev/null) == ok ]] || err_exit '${x.} where x is a simple variable causes shell to abort' + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/vartree1.sh b/src/cmd/ksh93/tests/vartree1.sh new file mode 100755 index 0000000..d558dc6 --- /dev/null +++ b/src/cmd/ksh93/tests/vartree1.sh @@ -0,0 +1,215 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +# +# variable tree test #001 +# Propose of this test is whether ksh93 handles global variable trees +# and function-local variable trees the same way, including "nameref" +# and "unset" handling. +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +function build_tree +{ +#set -o errexit -o xtrace + typeset index + typeset s + typeset i + typeset dummy + typeset a b c d e f + + nameref dest_tree="$1" # destination tree + nameref srcdata="$2" # source data + typeset tree_mode="$3" # mode to define the type of leads + + typeset -A dest_tree.l1 + + for index in "${!srcdata.hashnodes[@]}" ; do + nameref node=srcdata.hashnodes["${index}"] + + for i in "${node.xlfd[@]}" ; do + IFS='-' read dummy a b c d e f <<<"$i" + + if [[ "$a" == "" ]] ; then + a="$dummy" + fi + + [[ "$a" == "" ]] && a='-' + [[ "$b" == "" ]] && b='-' + [[ "$c" == "" ]] && c='-' + + if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"]) ; then + typeset -A dest_tree.l1["$a"].l2 + fi + + if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3 + fi + + if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries + fi + + #dest_tree.l1["$a"].l2["$b"].l3["$c"].entries+=( "$index" ) + typeset new_index + if [[ "${tree_mode}" == "leaf_name" ]] ; then + new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) + else + new_index="${node.name}" + + # skip if the leaf node already exists + if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then + continue + fi + fi + + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" + done + done + + return 0 +} + +function add_tree_leaf +{ + nameref tree_leafnode="$1" + nameref data_node=srcdata.hashnodes["$2"] + typeset add_mode="$3" + + case "${add_mode}" in + "leaf_name") + tree_leafnode="${data_node.name}" + return 0 + ;; + "leaf_compound") + tree_leafnode=( + typeset name="${data_node.name}" + typeset -a filenames=( "${data_node.filenames[@]}" ) + typeset -a comments=( "${data_node.comments[@]}" ) + typeset -a xlfd=( "${data_node.xlfd[@]}" ) + ) + return 0 + ;; + *) + print -u2 -f "ERROR: Unknown mode %s in add_tree_leaf\n" "${add_mode}" + return 1 + ;; + esac + + # not reached + return 1 +} + +# "mysrcdata_local" and "mysrcdata_global" must be identical +typeset mysrcdata_global=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) +) + +mytree_global=() + +function main +{ + # "mysrcdata_local" and "mysrcdata_global" must be identical + typeset mysrcdata_local=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) + ) + + # build tree using global tree variables + build_tree mytree_global mysrcdata_global leaf_compound || \ + err_exit 'build_tree mytree_global mysrcdata_global leaf_compound returned an error' + + (( $(print -r -- "${mytree_global}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global' too small" + + # build tree using local tree variables + mytree_local=() + build_tree mytree_local mysrcdata_local leaf_compound || \ + err_exit 'build_tree mytree_local mysrcdata_local leaf_compound returned an error' + + (( $(print -r -- "${mytree_local}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local' too small" + + # Compare trees + if [[ "${mytree_global}" != "${mytree_local}" ]] ; then + err_exit "compound trees 'mytree_local' and 'mytree_global' not identical" + fi + + unset 'mytree_global.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + err_exit "variable 'mytree_global.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + + [[ "${mytree_global}" != "${mytree_local}" ]] || err_exit "mytree_global and mytree_local should differ" + + unset 'mytree_local.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + err_exit "variable 'mytree_local.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + + # Compare trees (after "unset") + if [[ "${mytree_global}" != "${mytree_local}" ]] ; then + err_exit "compound trees 'mytree_local' and 'mytree_global' not identical after unset" + fi +} + +main + +exit $((Errors<125?Errors:125)) diff --git a/src/cmd/ksh93/tests/vartree2.sh b/src/cmd/ksh93/tests/vartree2.sh new file mode 100755 index 0000000..e3e4cff --- /dev/null +++ b/src/cmd/ksh93/tests/vartree2.sh @@ -0,0 +1,335 @@ +######################################################################## +# # +# This software is part of the ast package # +# Copyright (c) 1982-2011 AT&T Intellectual Property # +# and is licensed under the # +# Eclipse Public License, Version 1.0 # +# by AT&T Intellectual Property # +# # +# A copy of the License is available at # +# http://www.eclipse.org/org/documents/epl-v10.html # +# (with md5 checksum b35adb5213ca9657e911e9befb180842) # +# # +# Information and Software Systems Research # +# AT&T Research # +# Florham Park NJ # +# # +# David Korn <dgk@research.att.com> # +# # +######################################################################## +# +# variable tree test #002 +# Propose of this test is whether ksh93 handles global variable trees +# and function-local variable trees the same way, including "nameref" +# and "unset" handling. +# + +function err_exit +{ + print -u2 -n "\t" + print -u2 -r ${Command}[$1]: "${@:2}" + (( Errors+=1 )) +} + +alias err_exit='err_exit $LINENO' + +# "built_tree1" and "built_tree2" are identical except the way how they test +# whether a variable exists: +# - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable +# as non-zero length content +# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell +function build_tree1 +{ +#set -o errexit -o xtrace + typeset index + typeset s + typeset i + typeset dummy + typeset a b c d e f + + nameref dest_tree="$1" # destination tree + nameref srcdata="$2" # source data + typeset tree_mode="$3" # mode to define the type of leads + + typeset -A dest_tree.l1 + + for index in "${!srcdata.hashnodes[@]}" ; do + nameref node=srcdata.hashnodes["${index}"] + + for i in "${node.xlfd[@]}" ; do + IFS='-' read dummy a b c d e f <<<"$i" + + if [[ "$a" == "" ]] ; then + a="$dummy" + fi + + [[ "$a" == "" ]] && a='-' + [[ "$b" == "" ]] && b='-' + [[ "$c" == "" ]] && c='-' + + if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"]) ; then + typeset -A dest_tree.l1["$a"].l2 + fi + + if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then + #if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3 + fi + + if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries + fi + + typeset new_index + if [[ "${tree_mode}" == "leaf_name" ]] ; then + new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) + else + new_index="${node.name}" + + # skip if the leaf node already exists + if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then + continue + fi + fi + + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" + done + done + + return 0 +} + +# "built_tree1" and "built_tree2" are identical except the way how they test +# whether a variable exists: +# - "built_tree1" uses "${varname}" != "", e.g. looking whether the variable +# as non-zero length content +# - "built_tree2" uses "! (unset varname)", e.g. "unset" in a subshell +function build_tree2 +{ +#set -o errexit -o xtrace + typeset index + typeset s + typeset i + typeset dummy + typeset a b c d e f + + nameref dest_tree="$1" # destination tree + nameref srcdata="$2" # source data + typeset tree_mode="$3" # mode to define the type of leads + + typeset -A dest_tree.l1 + + for index in "${!srcdata.hashnodes[@]}" ; do + nameref node=srcdata.hashnodes["${index}"] + + for i in "${node.xlfd[@]}" ; do + IFS='-' read dummy a b c d e f <<<"$i" + + if [[ "$a" == "" ]] ; then + a="$dummy" + fi + + [[ "$a" == "" ]] && a='-' + [[ "$b" == "" ]] && b='-' + [[ "$c" == "" ]] && c='-' + + #if [[ "${dest_tree.l1["$a"]}" == "" ]] ; then + if ! (unset dest_tree.l1["$a"]) ; then + typeset -A dest_tree.l1["$a"].l2 + fi + + #if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then + if ! (unset dest_tree.l1["$a"].l2["$b"]) ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3 + fi + + if [[ "${!dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[*]}" == "" ]] ; then + typeset -A dest_tree.l1["$a"].l2["$b"].l3["$c"].entries + fi + + typeset new_index + if [[ "${tree_mode}" == "leaf_name" ]] ; then + new_index=$(( ${#dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[@]}+1 )) + else + new_index="${node.name}" + + # skip if the leaf node already exists + if [[ "${dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}]}" != "" ]] ; then + continue + fi + fi + + add_tree_leaf dest_tree.l1["$a"].l2["$b"].l3["$c"].entries[${new_index}] "${index}" "${tree_mode}" + done + done + + return 0 +} + + +function add_tree_leaf +{ + nameref tree_leafnode="$1" + nameref data_node=srcdata.hashnodes["$2"] + typeset add_mode="$3" + + case "${add_mode}" in + "leaf_name") + tree_leafnode="${data_node.name}" + return 0 + ;; + "leaf_compound") + tree_leafnode=( + typeset name="${data_node.name}" + typeset -a filenames=( "${data_node.filenames[@]}" ) + typeset -a comments=( "${data_node.comments[@]}" ) + typeset -a xlfd=( "${data_node.xlfd[@]}" ) + ) + return 0 + ;; + *) + print -u2 -f "ERROR: Unknown mode %s in add_tree_leaf\n" "${add_mode}" + return 1 + ;; + esac + + # not reached + return 1 +} + +# "mysrcdata_local" and "mysrcdata_global" must be identical +typeset mysrcdata_global=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) +) + +mytree_global1=() +mytree_global2=() + +function main +{ + # "mysrcdata_local" and "mysrcdata_global" must be identical + typeset mysrcdata_local=( + typeset -A hashnodes=( + [abcd]=( + name='abcd' + typeset -a xlfd=( + '-urw-itc zapfchancery-medium-i-normal--0-0-0-0-p-0-iso8859-1' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-adobe-fontspecific' + '-urw-itc zapfdingbats-medium-r-normal--0-0-0-0-p-0-sun-fontspecific' + ) + typeset -a comments=( + 'comment 1' + 'comment 2' + 'comment 3' + ) + typeset -a filenames=( + '/home/foo/abcd_1' + '/home/foo/abcd_2' + '/home/foo/abcd_3' + ) + ) + ) + ) + + #### Build tree using global tree variables + build_tree1 mytree_global1 mysrcdata_global leaf_compound || \ + err_exit 'build_tree1 mytree_global1 mysrcdata_global leaf_compound returned an error' + (( $(print -r -- "${mytree_global1}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global1' too small" + + build_tree2 mytree_global2 mysrcdata_global leaf_compound || \ + err_exit 'build_tree2 mytree_global2 mysrcdata_global leaf_compound returned an error' + (( $(print -r -- "${mytree_global2}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_global2' too small" + + + #### build tree using local tree variables + mytree_local1=() + mytree_local2=() + + build_tree1 mytree_local1 mysrcdata_local leaf_compound || \ + err_exit 'build_tree1 mytree_local1 mysrcdata_local leaf_compound returned an error' + (( $(print -r -- "${mytree_local1}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local1' too small" + + build_tree2 mytree_local2 mysrcdata_local leaf_compound || \ + err_exit 'build_tree2 mytree_local2 mysrcdata_local leaf_compound returned an error' + (( $(print -r -- "${mytree_local2}" | wc -l) > 10 )) || err_exit "compound tree 'mytree_local2' too small" + + + #### Compare treess + if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then + err_exit "compound trees 'mytree_global1' and 'mytree_local1' not identical" + fi + + if [[ "${mytree_global1}" != "${mytree_global2}" ]] ; then + err_exit "compound trees 'mytree_global1' and 'mytree_global2' not identical" + fi + + if [[ "${mytree_local1}" != "${mytree_local2}" ]] ; then + err_exit "compound trees 'mytree_local1' and 'mytree_local2' not identical" + fi + + + #### test "unset" in a subshell + ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ + err_exit "try 1: variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found" + ( unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ) || \ + err_exit "try 2: variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found" + + # remove parent node (array element) and then check whether the child is gone, too: + ( + unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' + [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]'} ]] + ) && err_exit "global: parent node removed (array element), child still exists" + ( + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats]' + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] + ) && err_exit "local: parent node removed (array element), child still exists" + + # remove parent node (array variable) and then check whether the child is gone, too: + ( + unset 'mytree_local1.l1[urw].l2' + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] + ) && err_exit "global: parent node removed (array variable), child still exists" + ( + unset 'mytree_local1.l1[urw].l2' + [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] + ) && err_exit "local: parent node removed (array variable), child still exists" + + + #### test "unset" and compare trees + unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + err_exit "variable 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + + [[ "${mytree_global1}" != "${mytree_local1}" ]] || err_exit "mytree_global1 and mytree_local1 should differ" + + unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' || + err_exit "variable 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' not found" + + # Compare trees (after "unset") + if [[ "${mytree_global1}" != "${mytree_local1}" ]] ; then + err_exit "compound trees 'mytree_local1' and 'mytree_global1' not identical after unset" + fi +} + +main + +exit $((Errors<125?Errors:125)) |