1######################################################################## 2# # 3# This software is part of the ast package # 4# Copyright (c) 1982-2010 AT&T Intellectual Property # 5# and is licensed under the # 6# Common Public License, Version 1.0 # 7# by AT&T Intellectual Property # 8# # 9# A copy of the License is available at # 10# http://www.opensource.org/licenses/cpl1.0.txt # 11# (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) # 12# # 13# Information and Software Systems Research # 14# AT&T Research # 15# Florham Park NJ # 16# # 17# David Korn <dgk@research.att.com> # 18# # 19######################################################################## 20function err_exit 21{ 22 print -u2 -n "\t" 23 print -u2 -r ${Command}[$1]: "${@:2}" 24 let Errors+=1 25} 26alias err_exit='err_exit $LINENO' 27 28Command=${0##*/} 29integer Errors=0 30 31tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; } 32trap "cd /; rm -rf $tmp" EXIT 33 34[[ ${.sh.version} == "$KSH_VERSION" ]] || err_exit '.sh.version != KSH_VERSION' 35unset ss 36[[ ${@ss} ]] && err_exit '${@ss} should be empty string when ss is unset' 37[[ ${!ss} == ss ]] || err_exit '${!ss} should be ss when ss is unset' 38[[ ${#ss} == 0 ]] || err_exit '${#ss} should be 0 when ss is unset' 39# RANDOM 40if (( RANDOM==RANDOM || $RANDOM==$RANDOM )) 41then err_exit RANDOM variable not working 42fi 43# SECONDS 44sleep 3 45if (( SECONDS < 2 )) 46then err_exit SECONDS variable not working 47fi 48# _ 49set abc def 50if [[ $_ != def ]] 51then err_exit _ variable not working 52fi 53# ERRNO 54#set abc def 55#rm -f foobar# 56#ERRNO= 57#2> /dev/null < foobar# 58#if (( ERRNO == 0 )) 59#then err_exit ERRNO variable not working 60#fi 61# PWD 62if [[ ! $PWD -ef . ]] 63then err_exit PWD variable failed, not equivalent to . 64fi 65# PPID 66exp=$$ 67got=${ $SHELL -c 'print $PPID'; } 68if [[ ${ $SHELL -c 'print $PPID'; } != $$ ]] 69then err_exit "PPID variable failed -- expected '$exp', got '$got'" 70fi 71# OLDPWD 72old=$PWD 73cd / 74if [[ $OLDPWD != $old ]] 75then err_exit "OLDPWD variable failed -- expected '$old', got '$OLDPWD'" 76fi 77cd $old || err_exit cd failed 78# REPLY 79read <<-! 80 foobar 81 ! 82if [[ $REPLY != foobar ]] 83then err_exit REPLY variable not working 84fi 85integer save=$LINENO 86# LINENO 87LINENO=10 88# 89# These lines intentionally left blank 90# 91if (( LINENO != 13)) 92then err_exit LINENO variable not working 93fi 94LINENO=save+10 95IFS=: 96x=a::b::c 97if [[ $x != a::b::c ]] 98then err_exit "word splitting on constants" 99fi 100set -- $x 101if [[ $# != 5 ]] 102then err_exit ":: doesn't separate null arguments " 103fi 104set x 105if x$1=0 2> /dev/null 106then err_exit "x\$1=value treated as an assignment" 107fi 108# check for attributes across subshells 109typeset -i x=3 110y=1/0 111if ( typeset x=y ) 2> /dev/null 112then err_exit "attributes not passed to subshells" 113fi 114unset x 115function x.set 116{ 117 nameref foo=${.sh.name}.save 118 foo=${.sh.value} 119 .sh.value=$0 120} 121x=bar 122if [[ $x != x.set ]] 123then err_exit 'x.set does not override assignment' 124fi 125x.get() 126{ 127 nameref foo=${.sh.name}.save 128 .sh.value=$foo 129} 130 131if [[ $x != bar ]] 132then err_exit 'x.get does not work correctly' 133fi 134typeset +n foo 135unset foo 136foo=bar 137( 138 unset foo 139 set +u 140 if [[ $foo != '' ]] 141 then err_exit '$foo not null after unset in subsehll' 142 fi 143) 144if [[ $foo != bar ]] 145then err_exit 'unset foo in subshell produces side effect ' 146fi 147unset foo 148if [[ $( { : ${foo?hi there} ; } 2>&1) != *'hi there' ]] 149then err_exit '${foo?hi there} with foo unset does not print hi there on 2' 150fi 151x=$0 152set foobar 153if [[ ${@:0} != "$x foobar" ]] 154then err_exit '${@:0} not expanding correctly' 155fi 156set -- 157if [[ ${*:0:1} != "$0" ]] 158then err_exit '${@:0} not expanding correctly' 159fi 160ACCESS=0 161function COUNT.set 162{ 163 (( ACCESS++ )) 164} 165COUNT=0 166(( COUNT++ )) 167if (( COUNT != 1 || ACCESS!=2 )) 168then err_exit " set discipline failure COUNT=$COUNT ACCESS=$ACCESS" 169fi 170LANG=C > /dev/null 2>&1 171if [[ $LANG != C ]] 172then err_exit "C locale not working" 173fi 174unset RANDOM 175unset -n foo 176foo=junk 177function foo.get 178{ 179 .sh.value=stuff 180 unset -f foo.get 181} 182if [[ $foo != stuff ]] 183then err_exit "foo.get discipline not working" 184fi 185if [[ $foo != junk ]] 186then err_exit "foo.get discipline not working after unset" 187fi 188# special variables 189set -- 1 2 3 4 5 6 7 8 9 10 190sleep 1000 & 191if [[ $(print -r -- ${#10}) != 2 ]] 192then err_exit '${#10}, where ${10}=10 not working' 193fi 194for i in @ '*' ! '#' - '?' '$' 195do false 196 eval foo='$'$i bar='$'{$i} 197 if [[ ${foo} != "${bar}" ]] 198 then err_exit "\$$i not equal to \${$i}" 199 fi 200 command eval bar='$'{$i%?} 2> /dev/null || err_exit "\${$i%?} gives syntax error" 201 if [[ $i != [@*] && ${foo%?} != "$bar" ]] 202 then err_exit "\${$i%?} not correct" 203 fi 204 command eval bar='$'{$i#?} 2> /dev/null || err_exit "\${$i#?} gives syntax error" 205 if [[ $i != [@*] && ${foo#?} != "$bar" ]] 206 then err_exit "\${$i#?} not correct" 207 fi 208 command eval foo='$'{$i} bar='$'{#$i} || err_exit "\${#$i} gives synta 209x error" 210 if [[ $i != @([@*]) && ${#foo} != "$bar" ]] 211 then err_exit "\${#$i} not correct" 212 fi 213done 214kill $! 215unset x 216CDPATH=/ 217x=$(cd ${tmp#/}) 218if [[ $x != $tmp ]] 219then err_exit 'CDPATH does not display new directory' 220fi 221CDPATH=/: 222x=$(cd ${tmp%/*}; cd ${tmp##*/}) 223if [[ $x ]] 224then err_exit 'CDPATH displays new directory when not used' 225fi 226x=$(cd ${tmp#/}) 227if [[ $x != $tmp ]] 228then err_exit "CDPATH ${tmp#/} does not display new directory" 229fi 230TMOUT=100 231(TMOUT=20) 232if (( TMOUT !=100 )) 233then err_exit 'setting TMOUT in subshell affects parent' 234fi 235unset y 236function setdisc # var 237{ 238 eval function $1.get' 239 { 240 .sh.value=good 241 } 242 ' 243} 244y=bad 245setdisc y 246if [[ $y != good ]] 247then err_exit 'setdisc function not working' 248fi 249integer x=$LINENO 250: $'\ 251' 252if (( LINENO != x+3 )) 253then err_exit '\<newline> gets linenumber count wrong' 254fi 255set -- 256set -- "${@-}" 257if (( $# !=1 )) 258then err_exit '"${@-}" not expanding to null string' 259fi 260for i in : % + / 3b '**' '***' '@@' '{' '[' '}' !! '*a' '$foo' 261do (eval : \${"$i"} 2> /dev/null) && err_exit "\${$i} not an syntax error" 262done 263unset IFS 264( IFS=' ' ; read -r a b c <<-! 265 x y z 266 ! 267 if [[ $b ]] 268 then err_exit 'IFS=" " not causing adjacent space to be null string' 269 fi 270) 271read -r a b c <<-! 272x y z 273! 274if [[ $b != y ]] 275then err_exit 'IFS not restored after subshell' 276fi 277 278# The next part generates 3428 IFS set/read tests. 279 280unset IFS x 281function split 282{ 283 i=$1 s=$2 r=$3 284 IFS=': ' 285 set -- $i 286 IFS=' ' 287 g="[$#]" 288 while : 289 do case $# in 290 0) break ;; 291 esac 292 g="$g($1)" 293 shift 294 done 295 case "$g" in 296 "$s") ;; 297 *) err_exit "IFS=': '; set -- '$i'; expected '$s' got '$g'" ;; 298 esac 299 print "$i" | IFS=": " read arg rem; g="($arg)($rem)" 300 case "$g" in 301 "$r") ;; 302 *) err_exit "IFS=': '; read '$i'; expected '$r' got '$g'" ;; 303 esac 304} 305for str in \ 306 '-' \ 307 'a' \ 308 '- -' \ 309 '- a' \ 310 'a -' \ 311 'a b' \ 312 '- - -' \ 313 '- - a' \ 314 '- a -' \ 315 '- a b' \ 316 'a - -' \ 317 'a - b' \ 318 'a b -' \ 319 'a b c' 320do 321 IFS=' ' 322 set x $str 323 shift 324 case $# in 325 0) continue ;; 326 esac 327 f1=$1 328 case $f1 in 329 '-') f1='' ;; 330 esac 331 shift 332 case $# in 333 0) for d0 in '' ' ' 334 do 335 for d1 in '' ' ' ':' ' :' ': ' ' : ' 336 do 337 case $f1$d1 in 338 '') split "$d0$f1$d1" "[0]" "()()" ;; 339 ' ') ;; 340 *) split "$d0$f1$d1" "[1]($f1)" "($f1)()" ;; 341 esac 342 done 343 done 344 continue 345 ;; 346 esac 347 f2=$1 348 case $f2 in 349 '-') f2='' ;; 350 esac 351 shift 352 case $# in 353 0) for d0 in '' ' ' 354 do 355 for d1 in ' ' ':' ' :' ': ' ' : ' 356 do 357 case ' ' in 358 $f1$d1|$d1$f2) continue ;; 359 esac 360 for d2 in '' ' ' ':' ' :' ': ' ' : ' 361 do 362 case $f2$d2 in 363 '') split "$d0$f1$d1$f2$d2" "[1]($f1)" "($f1)()" ;; 364 ' ') ;; 365 *) split "$d0$f1$d1$f2$d2" "[2]($f1)($f2)" "($f1)($f2)" ;; 366 esac 367 done 368 done 369 done 370 continue 371 ;; 372 esac 373 f3=$1 374 case $f3 in 375 '-') f3='' ;; 376 esac 377 shift 378 case $# in 379 0) for d0 in '' ' ' 380 do 381 for d1 in ':' ' :' ': ' ' : ' 382 do 383 case ' ' in 384 $f1$d1|$d1$f2) continue ;; 385 esac 386 for d2 in ' ' ':' ' :' ': ' ' : ' 387 do 388 case $f2$d2 in 389 ' ') continue ;; 390 esac 391 case ' ' in 392 $f2$d2|$d2$f3) continue ;; 393 esac 394 for d3 in '' ' ' ':' ' :' ': ' ' : ' 395 do 396 case $f3$d3 in 397 '') split "$d0$f1$d1$f2$d2$f3$d3" "[2]($f1)($f2)" "($f1)($f2)" ;; 398 ' ') ;; 399 *) x=$f2$d2$f3$d3 400 x=${x#' '} 401 x=${x%' '} 402 split "$d0$f1$d1$f2$d2$f3$d3" "[3]($f1)($f2)($f3)" "($f1)($x)" 403 ;; 404 esac 405 done 406 done 407 done 408 done 409 continue 410 ;; 411 esac 412done 413unset IFS 414 415if [[ $( (print ${12345:?}) 2>&1) != *12345* ]] 416then err_exit 'incorrect error message with ${12345?}' 417fi 418unset foobar 419if [[ $( (print ${foobar:?}) 2>&1) != *foobar* ]] 420then err_exit 'incorrect error message with ${foobar?}' 421fi 422unset bar 423if [[ $( (print ${bar:?bam}) 2>&1) != *bar*bam* ]] 424then err_exit 'incorrect error message with ${foobar?}' 425fi 426{ $SHELL -c ' 427function foo 428{ 429 typeset SECONDS=0 430 sleep 1.5 431 print $SECONDS 432 433} 434x=$(foo) 435(( x >1 && x < 2 )) 436' 437} 2> /dev/null || err_exit 'SECONDS not working in function' 438cat > $tmp/script <<-\! 439 posixfun() 440 { 441 unset x 442 nameref x=$1 443 print -r -- "$x" 444 } 445 function fun 446 { 447 nameref x=$1 448 print -r -- "$x" 449 } 450 if [[ $1 ]] 451 then file=${.sh.file} 452 else print -r -- "${.sh.file}" 453 fi 454! 455chmod +x $tmp/script 456. $tmp/script 1 457[[ $file == $tmp/script ]] || err_exit ".sh.file not working for dot scripts" 458[[ $($SHELL $tmp/script) == $tmp/script ]] || err_exit ".sh.file not working for scripts" 459[[ $(posixfun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for posix functions" 460[[ $(fun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for functions" 461[[ $(posixfun .sh.fun) == posixfun ]] || err_exit ".sh.fun not working for posix functions" 462[[ $(fun .sh.fun) == fun ]] || err_exit ".sh.fun not working for functions" 463[[ $(posixfun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for posix functions" 464[[ $(fun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for functions" 465( 466 [[ $(posixfun .sh.subshell) == 2 ]] || err_exit ".sh.subshell not working for posix functions in subshells" 467 [[ $(fun .sh.subshell) == 2 ]] || err_exit ".sh.subshell not working for functions in subshells" 468 (( .sh.subshell == 1 )) || err_exit ".sh.subshell not working in a subshell" 469) 470TIMEFORMAT='this is a test' 471[[ $({ { time :;} 2>&1;}) == "$TIMEFORMAT" ]] || err_exit 'TIMEFORMAT not working' 472: ${.sh.version} 473[[ $(alias integer) == *.sh.* ]] && err_exit '.sh. prefixed to alias name' 474: ${.sh.version} 475[[ $(whence rm) == *.sh.* ]] && err_exit '.sh. prefixed to tracked alias name' 476: ${.sh.version} 477[[ $(cd /bin;env | grep PWD=) == *.sh.* ]] && err_exit '.sh. prefixed to PWD' 478# unset discipline bug fix 479dave=dave 480function dave.unset 481{ 482 unset dave 483} 484unset dave 485[[ $(typeset +f) == *dave.* ]] && err_exit 'unset discipline not removed' 486 487print 'print ${VAR}' > $tmp/script 488unset VAR 489VAR=new $tmp/script > $tmp/out 490got=$(<$tmp/out) 491[[ $got == new ]] || err_exit "previously unset environment variable not passed to script, expected 'new', got '$got'" 492[[ ! $VAR ]] || err_exit "previously unset environment variable set after script, expected '', got '$VAR'" 493unset VAR 494VAR=old 495VAR=new $tmp/script > $tmp/out 496got=$(<$tmp/out) 497[[ $got == new ]] || err_exit "environment variable covering local variable not passed to script, expected 'new', got '$got'" 498[[ $VAR == old ]] || err_exit "previously set local variable changed after script, expected 'old', got '$VAR'" 499unset VAR 500export VAR=old 501VAR=new $tmp/script > $tmp/out 502got=$(<$tmp/out) 503[[ $got == new ]] || err_exit "environment variable covering environment variable not passed to script, expected 'new', got '$got'" 504[[ $VAR == old ]] || err_exit "previously set environment variable changed after script, expected 'old', got '$VAR'" 505 506( 507 unset dave 508 function dave.append 509 { 510 .sh.value+=$dave 511 dave= 512 } 513 dave=foo; dave+=bar 514 [[ $dave == barfoo ]] || exit 2 515) 2> /dev/null 516case $? in 5170) ;; 5181) err_exit 'append discipline not implemented';; 519*) err_exit 'append discipline not working';; 520esac 521.sh.foobar=hello 522{ 523 function .sh.foobar.get 524 { 525 .sh.value=world 526 } 527} 2> /dev/null || err_exit "cannot add get discipline to .sh.foobar" 528[[ ${.sh.foobar} == world ]] || err_exit 'get discipline for .sh.foobar not working' 529x='a|b' 530IFS='|' 531set -- $x 532[[ $2 == b ]] || err_exit '$2 should be b after set' 533exec 3>&2 2> /dev/null 534set -x 535( IFS= ) 2> /dev/null 536set +x 537exec 2>&3- 538set -- $x 539[[ $2 == b ]] || err_exit '$2 should be b after subshell' 540: & pid=$! 541( : & ) 542[[ $pid == $! ]] || err_exit '$! value not preserved across subshells' 543unset foo 544typeset -A foo 545function foo.set 546{ 547 case ${.sh.subscript} in 548 bar) if ((.sh.value > 1 )) 549 then .sh.value=5 550 foo[barrier_hit]=yes 551 fi 552 ;; 553 barrier_hit) 554 if [[ ${.sh.value} = yes ]] 555 then foo[barrier_not_hit]=no 556 else foo[barrier_not_hit]=yes 557 fi 558 ;; 559 esac 560} 561foo[barrier_hit]=no 562foo[bar]=1 563(( foo[bar] == 1 )) || err_exit 'foo[bar] should be 1' 564[[ ${foo[barrier_hit]} == no ]] || err_exit 'foo[barrier_hit] should be no' 565[[ ${foo[barrier_not_hit]} == yes ]] || err_exit 'foo[barrier_not_hit] should be yes' 566foo[barrier_hit]=no 567foo[bar]=2 568(( foo[bar] == 5 )) || err_exit 'foo[bar] should be 5' 569[[ ${foo[barrier_hit]} == yes ]] || err_exit 'foo[barrier_hit] should be yes' 570[[ ${foo[barrier_not_hit]} == no ]] || err_exit 'foo[barrier_not_hit] should be no' 571unset x 572typeset -i x 573function x.set 574{ 575 typeset sub=${.sh.subscript} 576 (( sub > 0 )) && (( x[sub-1]= x[sub-1] + .sh.value )) 577} 578x[0]=0 x[1]=1 x[2]=2 x[3]=3 579[[ ${x[@]} == '12 8 5 3' ]] || err_exit 'set discipline for indexed array not working correctly' 580float seconds 581((SECONDS=3*4)) 582seconds=SECONDS 583(( seconds < 12 || seconds > 12.1 )) && err_exit "SECONDS is $seconds and should be close to 12" 584unset a 585function a.set 586{ 587 print -r -- "${.sh.name}=${.sh.value}" 588} 589[[ $(a=1) == a=1 ]] || err_exit 'set discipline not working in subshell assignment' 590[[ $(a=1 :) == a=1 ]] || err_exit 'set discipline not working in subshell command' 591 592[[ ${.sh.subshell} == 0 ]] || err_exit '${.sh.subshell} should be 0' 593( 594 [[ ${.sh.subshell} == 1 ]] || err_exit '${.sh.subshell} should be 1' 595 ( 596 [[ ${.sh.subshell} == 2 ]] || err_exit '${.sh.subshell} should be 2' 597 ) 598) 599 600set -- {1..32768} 601(( $# == 32768 )) || err_exit "\$# failed -- expected 32768, got $#" 602set -- 603 604unset r v x 605path=$PATH 606x=foo 607for v in EDITOR VISUAL OPTIND CDPATH FPATH PATH ENV LINENO RANDOM SECONDS _ 608do nameref r=$v 609 unset $v 610 if ( $SHELL -c "unset $v; : \$$v" ) 2>/dev/null 611 then [[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'" 612 r=$x 613 [[ $r == $x ]] || err_exit "$v=$x failed -- expected '$x', got '$r'" 614 else err_exit "unset $v; : \$$v failed" 615 fi 616done 617 618x=x 619for v in LC_ALL LC_CTYPE LC_MESSAGES LC_COLLATE LC_NUMERIC 620do nameref r=$v 621 unset $v 622 [[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'" 623 d=$($SHELL -c "$v=$x" 2>&1) 624 [[ $d ]] || err_exit "$v=$x failed -- expected locale diagnostic" 625 { g=$( r=$x; print -- $r ); } 2>/dev/null 626 [[ $g == '' ]] || err_exit "$v=$x failed -- expected '', got '$g'" 627 { g=$( r=C; r=$x; print -- $r ); } 2>/dev/null 628 [[ $g == 'C' ]] || err_exit "$v=C; $v=$x failed -- expected 'C', got '$g'" 629done 630PATH=$path 631 632cd $tmp 633 634print print -n zzz > zzz 635chmod +x zzz 636exp='aaazzz' 637got=$($SHELL -c 'unset SHLVL; print -n aaa; ./zzz' 2>&1) >/dev/null 2>&1 638[[ $got == "$exp" ]] || err_exit "unset SHLVL causes script failure -- expected '$exp', got '$got'" 639 640mkdir glean 641for cmd in date ok 642do exp="$cmd ok" 643 rm -f $cmd 644 print print $exp > glean/$cmd 645 chmod +x glean/$cmd 646 got=$(CDPATH=:.. $SHELL -c "PATH=:/bin:/usr/bin; date > /dev/null; cd glean && ./$cmd" 2>&1) 647 [[ $got == "$exp" ]] || err_exit "cd with CDPATH after PATH change failed -- expected '$exp', got '$got'" 648done 649 650v=LC_CTYPE 651unset $v 652[[ -v $v ]] && err_exit "unset $v; [[ -v $v ]] failed" 653eval $v=C 654[[ -v $v ]] || err_exit "$v=C; [[ -v $v ]] failed" 655 656cmd='set --nounset; unset foo; : ${!foo*}' 657$SHELL -c "$cmd" 2>/dev/null || err_exit "'$cmd' exit status $?, expected 0" 658 659exit $((Errors)) 660