1######################################################################## 2# # 3# This software is part of the ast package # 4# Copyright (c) 1982-2012 AT&T Intellectual Property # 5# and is licensed under the # 6# Eclipse Public License, Version 1.0 # 7# by AT&T Intellectual Property # 8# # 9# A copy of the License is available at # 10# http://www.eclipse.org/org/documents/epl-v10.html # 11# (with md5 checksum b35adb5213ca9657e911e9befb180842) # 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######################################################################## 20######################################################################## 21# # 22# This software is part of the ast package # 23# Copyright (c) 1982-2012 AT&T Intellectual Property # 24# and is licensed under the # 25# Eclipse Public License, Version 1.0 # 26# by AT&T Intellectual Property # 27# # 28# A copy of the License is available at # 29# http://www.eclipse.org/org/documents/epl-v10.html # 30# (with md5 checksum b35adb5213ca9657e911e9befb180842) # 31# # 32# Information and Software Systems Research # 33# AT&T Research # 34# Florham Park NJ # 35# # 36# Roland Mainz <roland.mainz@nrubsig.org> # 37# # 38######################################################################## 39 40# test setup 41function err_exit 42{ 43 print -u2 -n '\t' 44 print -u2 -r ${Command}[$1]: "${@:2}" 45 (( Errors++ )) 46} 47alias err_exit='err_exit $LINENO' 48 49# "nounset" disabled for now 50#set -o nounset 51Command=${0##*/} 52integer Errors=0 HAVE_signbit=0 53 54if typeset -f .sh.math.signbit >/dev/null && (( signbit(-NaN) )) 55then HAVE_signbit=1 56else print -u2 "$0: warning: -lm does not support signbit(-NaN)" 57fi 58 59compound bracketstat=( 60 integer bopen=0 61 integer bclose=0 62) 63 64function count_brackets 65{ 66 typeset x="$1" 67 typeset c 68 69 integer i 70 (( bracketstat.bopen=0 , bracketstat.bclose=0 )) 71 72 for (( i=0 ; i < ${#x} ; i++ )) ; do 73 c="${x:i:1}" 74 [[ "$c" == '(' ]] && (( bracketstat.bopen++ )) 75 [[ "$c" == ')' ]] && (( bracketstat.bclose++ )) 76 done 77 78 (( bracketstat.bopen != bracketstat.bclose )) && return 1 79 80 return 0 81} 82 83# compound variable "cat" nr.1, using $ print "%B\n" ... # 84function cpvcat1 85{ 86 set -o errexit 87 compound tmp 88 89 while read -C tmp ; do printf '%B\n' tmp ; done 90 return 0 91} 92 93# compound variable "cat" nr.2, using $ print "%#B\n" ... # 94function cpvcat2 95{ 96 set -o errexit 97 compound tmp 98 99 while read -C tmp ; do printf '%#B\n' tmp ; done 100 return 0 101} 102 103# compound variable "cat" nr.3, using $ print -C ... # 104function cpvcat3 105{ 106 set -o errexit 107 compound tmp 108 109 while read -C tmp ; do print -C tmp ; done 110 return 0 111} 112 113# compound variable "cat" nr.4, using $ print -v ... # 114function cpvcat4 115{ 116 set -o errexit 117 compound tmp 118 119 while read -C tmp ; do print -v tmp ; done 120 return 0 121} 122 123typeset s 124 125# Test 1: 126# Check whether "read -C" leaves the file pointer at the next line 127# (and does not read beyond that point). 128# Data layout is: 129# -- snip -- 130# <compound var> 131# hello 132# -- snip -- 133# (additionally we test some extra stuff like bracket count) 134s=${ 135 compound x=( 136 a=1 b=2 137 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) 138 typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) 139 typeset -A myarray3=( 140 [a]=( 141 float m1=0.5 142 float m2=0.6 143 foo="hello" 144 ) 145 [b]=( 146 foo="bar" 147 ) 148 ["c d"]=( 149 integer at=90 150 ) 151 [e]=( 152 compound nested_cpv=( 153 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) 154 typeset str=$'a \'string' 155 ) 156 ) 157 [f]=( 158 typeset g="f" 159 ) 160 [a_nan]=( 161 float my_nan=-nan 162 ) 163 [a_hexfloat]=( 164 typeset -X my_hexfloat=1.1 165 ) 166 ) 167 ) 168 169 { 170 printf "%B\n" x 171 print "hello" 172 } | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | { 173 read -C y 174 read s 175 } 176 print "x${s}x" 177} || err_exit "test returned exit code $?" 178 179[[ "${s}" == "xhellox" ]] || err_exit "Expected 'xhellox', got ${s}" 180count_brackets "$y" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 181count_brackets "$(print -v y)" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 182count_brackets "$(print -C y)" || err_exit "y: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 183 184# cleanup 185unset x y || err_exit "unset failed" 186[[ "$x" == '' ]] || err_exit "cleanup failed for x" 187[[ "$y" == '' ]] || err_exit "cleanup failed for y" 188 189 190# Test 2: 191# Same as test 1 except one more compound var following the "hello" 192# line. 193# Data layout is: 194# -- snip -- 195# <compound var> 196# hello 197# <compound var> 198# -- snip -- 199s=${ 200 compound x=( 201 a=1 b=2 202 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) 203 typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) 204 compound -A myarray3=( 205 [a]=( 206 float m1=0.5 207 float m2=0.6 208 foo="hello" 209 ) 210 [b]=( 211 foo="bar" 212 ) 213 ["c d"]=( 214 integer at=90 215 ) 216 [e]=( 217 compound nested_cpv=( 218 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) 219 typeset str=$'a \'string' 220 ) 221 ) 222 [f]=( 223 typeset g="f" 224 ) 225 [a_nan]=( 226 float my_nan=-nan 227 ) 228 [a_hexfloat]=( 229 typeset -X my_hexfloat=1.1 230 ) 231 ) 232 ) 233 234 { 235 printf "%B\n" x 236 print "hello" 237 printf "%B\n" x 238 } | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | { 239 read -C y1 240 read s 241 read -C y2 242 } 243 244 print "x${s}x" 245} || err_exit "test returned exit code $?" 246 247[[ "${s}" == "xhellox" ]] || err_exit "Expected 'xhellox', got ${s}." 248[[ "${y1.myarray3[b].foo}" == "bar" ]] || err_exit "y1.myarray3[b].foo != bar" 249[[ "${y2.myarray3[b].foo}" == "bar" ]] || err_exit "y2.myarray3[b].foo != bar" 250[[ "$y1" != "" ]] || err_exit "y1 is empty" 251[[ "$y2" != "" ]] || err_exit "y2 is empty" 252(( ${#y1.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in y1.myarray3[e].nested_cpv, got ${#y1.myarray3[e].nested_cpv[@]}" 253(( ${#y2.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in y2.myarray3[e].nested_cpv, got ${#y2.myarray3[e].nested_cpv[@]}" 254(( isnan(y1.myarray3[a_nan].my_nan) )) || err_exit "y1.myarray3[a_nan].my_nan not a NaN" 255(( isnan(y2.myarray3[a_nan].my_nan) )) || err_exit "y2.myarray3[a_nan].my_nan not a NaN" 256if (( HAVE_signbit )) 257then (( signbit(y1.myarray3[a_nan].my_nan) )) || err_exit "y1.myarray3[a_nan].my_nan not negative" 258 (( signbit(y2.myarray3[a_nan].my_nan) )) || err_exit "y2.myarray3[a_nan].my_nan not negative" 259fi 260count_brackets "$y1" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 261count_brackets "$(print -v y1)" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 262count_brackets "$(print -C y1)" || err_exit "y1: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 263count_brackets "$y2" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 264count_brackets "$(print -v y2)" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 265count_brackets "$(print -C y2)" || err_exit "y2: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 266[[ "$y1" == "$y2" ]] || err_exit "Expected $(printf "%q\n" "${y1}") == $(printf "%q\n" "${y2}")." 267[[ "$x" == "$y1" ]] || err_exit "Expected $(printf "%q\n" "${x}") == $(printf "%q\n" "${y1}")." 268 269# cleanup 270unset x y1 y2 || err_exit "unset failed" 271[[ "$x" == '' ]] || err_exit "cleanup failed for x" 272[[ "$y1" == '' ]] || err_exit "cleanup failed for y1" 273[[ "$y2" == '' ]] || err_exit "cleanup failed for y2" 274 275 276# Test 3: Test compound variable copy operator vs. "read -C" 277compound x=( 278 a=1 b=2 279 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) 280 typeset -A myarray2=( [a]=1 [b]=2 ["c d"]=3 [e]=4 ["f"]=5 [g]=6 [h]=7 [i]=8 [j]=9 [k]=10 ) 281 compound -A myarray3=( 282 [a]=( 283 float m1=0.5 284 float m2=0.6 285 foo="hello" 286 ) 287 [b]=( 288 foo="bar" 289 ) 290 ["c d"]=( 291 integer at=90 292 ) 293 [e]=( 294 compound nested_cpv=( 295 typeset -a myarray=( 1 2 3 4 5 6 7 8 9 10 ) 296 typeset str=$'a \'string' 297 ) 298 ) 299 [f]=( 300 typeset g="f" 301 ) 302 [a_nan]=( 303 float my_nan=-nan 304 ) 305 [a_hexfloat]=( 306 typeset -X my_hexfloat=1.1 307 ) 308 ) 309) 310 311compound x_copy=x || err_exit "x_copy copy failed" 312[[ "${x_copy}" != "" ]] || err_exit "x_copy should not be empty" 313count_brackets "${x_copy}" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 314count_brackets "$(print -v x_copy)" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 315count_brackets "$(print -C x_copy)" || err_exit "x_copy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 316 317compound nested_cpv_copy 318 319nested_cpv_copy=x.myarray3[e].nested_cpv || err_exit "x.myarray3[e].nested_cpv copy failed" 320(( ${#nested_cpv_copy.myarray[@]} == 10 )) || err_exit "Expected 10 elements in nested_cpv_copy.myarray, got ${#nested_cpv_copy.myarray[@]}" 321 322# unset branch "x.myarray3[e].nested_cpv" of the variable tree "x" ... 323unset x.myarray3[e].nested_cpv || err_exit "unset x.myarray3[e].nested_cpv failed" 324[[ "${x.myarray3[e].nested_cpv}" == "" ]] || err_exit "x.myarray3[e].nested_cpv still has a value" 325 326# ... and restore it from the saved copy 327printf "%B\n" nested_cpv_copy | cpvcat1 | cpvcat2 | cpvcat3 | cpvcat4 | read -C x.myarray3[e].nested_cpv || err_exit "read failed" 328 329# compare copy of the original tree and the modified one 330[[ "${x}" == "${x_copy}" ]] || err_exit "x != x_copy" 331count_brackets "${x}" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 332count_brackets "$(print -v x)" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 333count_brackets "$(print -C x)" || err_exit "x: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" 334(( ${#x.myarray3[e].nested_cpv.myarray[@]} == 10 )) || err_exit "Expected 10 elements in x.myarray3[e].nested_cpv, got ${#x.myarray3[e].nested_cpv[@]}" 335(( isnan(x.myarray3[a_nan].my_nan) )) || err_exit "x.myarray3[a_nan].my_nan not a NaN" 336if (( HAVE_signbit )) 337then (( signbit(x.myarray3[a_nan].my_nan) )) || err_exit "x.myarray3[a_nan].my_nan not negative" 338fi 339 340# cleanup 341unset x x_copy nested_cpv_copy || err_exit "unset failed" 342 343 344# Test 4: Test "read -C" failure for missing bracket at the end 345typeset s 346s=$($SHELL -c 'compound myvar ; print "( unfinished=1" | read -C myvar 2>'/dev/null' || print "error $?"') || err_exit 'shell failed' 347[[ "$s" == 'error 3' ]] || err_exit "compound_read: expected error 3, got ${s}" 348 349 350# Test 5: Test "read -C" failure for missing bracket at the beginning 351typeset s 352s=$($SHELL -c 'compound myvar ; print " unfinished=1 )" | read -C myvar 2>'/dev/null' || print "error $?"') || err_exit 'shell failed' 353[[ "$s" == 'error 3' ]] || err_exit "compound_read: expected error 3, got ${s}" 354 355 356# test6: Derived from the test2 for CR #6944386 357# ("compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -C v prints trash") 358# which caused compound variables to be corrupted like this: 359# -- snip -- 360# ksh93 -c 'compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -v v' 361# ( 362# typeset -A -l -i ar=( 363# [aa]=$'\004' 364# [bb]=$'\t' 365# ) 366# ) 367# -- snip -- 368 369function test6 370{ 371 compound out=( typeset stdout stderr ; integer res ) 372 compound val 373 integer testid 374 375 compound -r -a tests=( 376 # subtests1: 377 ( cmd='compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -C v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='ar' ) 378 ( cmd='compound v=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -C v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='ar' ) 379 ( cmd='compound v=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -C v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='ar' ) 380 ( cmd='compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -v v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='ar' ) 381 ( cmd='compound v=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -v v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='ar' ) 382 ( cmd='compound v=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; print -v v' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='ar' ) 383 384 # subtests2: Same as subtests1 but variable "v" is inside "vx" 385 ( cmd='compound vx=( compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='v.ar' ) 386 ( cmd='compound vx=( compound v=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='v.ar' ) 387 ( cmd='compound vx=( compound v=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -C vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='v.ar' ) 388 ( cmd='compound vx=( compound v=( integer -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='v.ar' ) 389 ( cmd='compound vx=( compound v=( float -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=9.*)&(.*\\[aa\\]=4.*)' arrefname='v.ar' ) 390 ( cmd='compound vx=( compound v=( typeset -A ar=( [aa]=4 [bb]=9 ) ; ) ; ) ; print -v vx' stdoutpattern=$'~(Alr)(.*\\[bb\\]=["\']*9.*)&(.*\\[aa\\]=["\']*4.*)' arrefname='v.ar' ) 391 392 # subtests3: Same as subtests1 but variable "va" is an indexed array 393 ( 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' ) 394 ( 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' ) 395 ( 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' ) 396 ( 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' ) 397 ( 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' ) 398 ( 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' ) 399 400 # subtests4: Same as subtests1 but variable "va" is an 2d indexed array 401 ( 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' ) 402 ( 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' ) 403 ( 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' ) 404 ( 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' ) 405 ( 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' ) 406 ( 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' ) 407 408 # subtests5: Same as subtests1 but variable "va" is an associative array 409 ( 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' ) 410 ( 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' ) 411 ( 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' ) 412 ( 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' ) 413 ( 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' ) 414 ( 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' ) 415 ) 416 417 for testid in "${!tests[@]}" ; do 418 nameref test=tests[testid] 419 typeset testname="test2/${testid}" 420 421 out.stderr="${ { out.stdout="${ ${SHELL} -c "${test.cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" 422 423 (( out.res == 0 )) || err_exit "${testname}: Test shell returned with exit code ${out.res}" 424 [[ "${out.stdout}" == ${test.stdoutpattern} ]] || err_exit "${testname}: Expected match for ${test.stdoutpattern}, got $(printf "%q\n" "${out.stdout}")" 425 [[ "${out.stderr}" == "" ]] || err_exit "${testname}: Expected empty stderr, got $(printf "%q\n" "${out.stderr}")" 426 427 read -C val <<<"${out.stdout}" || err_exit "${testname}: read -C val failed with exit code $?" 428 nameref ar="val.${test.arrefname}" 429 (( ar[aa] == 4 )) || err_exit "${testname}: Expected ar[aa] == 4, got ${ar[aa]}" 430 (( ar[bb] == 9 )) || err_exit "${testname}: Expected ar[bb] == 9, got ${ar[bb]}" 431 done 432 433 return 0 434} 435 436test6 437 438function test_3D_array_read_C 439{ 440 compound out=( typeset stdout stderr ; integer res ) 441 integer i 442 typeset -r -a tests=( 443 # ast-ksh.2010-03-09 will print "ksh93[1]: read: line 4: 0[0]: invalid variable name" for 3D arrays passed to read -C 444 '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' 445 446 # same test, 4D, fails with 'ksh[1]: read: line 4: 0: invalid variable name' 447 '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' 448 ) 449 450 for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do 451 out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${tests[i]}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" 452 453 [[ "${out.stdout}" == '' ]] || err_exit "$0/${i}: Expected empty stdout, got $(printf '%q\n' "${out.stdout}")" 454 [[ "${out.stderr}" == '' ]] || err_exit "$0/${i}: Expected empty stderr, got $(printf '%q\n' "${out.stderr}")" 455 done 456 457 return 0 458} 459 460 461function test_access_2Darray_in_type_in_compound 462{ 463 compound out=( typeset stdout stderr ; integer res ) 464 integer i 465 typeset -r -a tests=( 466 # ast-ksh.2010-03-09 will print 'ksh: line 1: l.c.x[i][j]=: no parent' 467 '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' 468 ) 469 470 for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do 471 out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${tests[i]}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" 472 473 [[ "${out.stdout}" == '' ]] || err_exit "$0/${i}: Expected empty stdout, got $(printf '%q\n' "${out.stdout}")" 474 [[ "${out.stderr}" == '' ]] || err_exit "$0/${i}: Expected empty stderr, got $(printf '%q\n' "${out.stderr}")" 475 done 476 477 return 0 478} 479 480function test_read_type_crash 481{ 482 compound out=( typeset stdout stderr ; integer res ) 483 typeset -r test=' 484typeset -T field_t=( 485 typeset -a f 486 487 function reset 488 { 489 integer i j 490 491 for (( i=0 ; i < 3 ; i++ )) ; do 492 for (( j=0 ; j < 3 ; j++ )) ; do 493 _.f[i][j]="" 494 done 495 done 496 return 0 497 } 498 499 function enumerate_empty_fields 500 { 501 integer i j 502 503 for (( i=0 ; i < 3 ; i++ )) ; do 504 for (( j=0 ; j < 3 ; j++ )) ; do 505 [[ "${_.f[i][j]}" == "" ]] && printf "[%d][%d]\n" i j 506 done 507 done 508 return 0 509 } 510 511 function setf 512 { 513 _.f[$1][$2]="$3" 514 } 515) 516 517set -o nounset 518 519compound c1=( field_t x ) 520 521c1.x.reset 522 523print -v c1 | read -C c2 524print -v c2 525' 526 527 out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -c "${test}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" 528 529 [[ "${out.stdout}" != '' ]] || err_exit "$0: Expected nonempty stdout." 530 [[ "${out.stderr}" == '' ]] || err_exit "$0: Expected empty stderr, got $(printf '%q\n' "${out.stderr}")" 531 532 if [[ -f 'core' && -x '/usr/bin/pstack' ]] ; then 533 pstack 'core' 534 rm 'core' 535 fi 536 537 return 0 538} 539 540 541function test_read_C_into_array 542{ 543 compound out=( typeset stdout stderr ; integer res ) 544 # fixme: 545 # - The tests should cover 3D and 5D indexed arrays and namerefs to sub-dimensions of a 5D indexed array 546 compound -r -a tests=( 547 ( 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\].+)' ) ) 548 ( 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\].+)' ) ) 549 550 ( 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\].+)' ) ) 551 ( 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\].+)' ) ) 552 553 ( 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\].+)' ) ) 554 ( 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\].+)' ) ) 555 556 ( 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\].+)' ) ) 557 ( 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\].+)' ) ) 558 ( 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\].+)' ) ) 559 ( 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\].+)' ) ) 560 561 ( 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\].+)' ) ) 562 ( 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\].+)' ) ) 563 564 ( 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\].+)' ) ) 565 ( 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\].+)' ) ) 566 567 ( 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\].+)' ) ) 568 ( 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\].+)' ) ) 569 ) 570 typeset cmd 571 typeset pat 572 integer i 573 574 compound -a test_variants 575 576 # build list of variations of the tests above 577 for (( i=0 ; i < ${#tests[@]} ; i++ )) ; do 578 nameref tst=tests[i] 579 580 # plain test 581 cmd="${tst.cmd}" 582 test_variants+=( testname="${0}/${i}/plain" cmd="$cmd" typeset -a stdoutpattern=( "${tst.stdoutpattern[@]}" ) ) 583 584 # test with "read -C" in a function 585 cmd="${tst.cmd/~(E)read[[:space:]]+-C[[:space:]]+([[:alnum:]]+)[[:space:]]+\;/{ function rf { nameref val=\$1 \; read -C val \; } \; rf \1 \; } \; }" 586 test_variants+=( testname="${0}/${i}/read_in_function" cmd="$cmd" typeset -a stdoutpattern=( "${tst.stdoutpattern[@]}" ) ) 587 588 # test with "read -C" in a nested function 589 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 \; } \; }" 590 test_variants+=( testname="${0}/${i}/read_in_nested_function" cmd="$cmd" typeset -a stdoutpattern=( "${tst.stdoutpattern[@]}" ) ) 591 592 # test with "read -C" in a nested function with target variable 593 # being a function-local variable of function "main" 594 cmd='function rf2 { nameref val=$1 ; read -C val ; } ; function rf { nameref val=$1 ; rf2 val ; } ; function main { ' 595 cmd+="${tst.cmd/~(E)read[[:space:]]+-C[[:space:]]+([[:alnum:]]+)[[:space:]]+\;/rf \1 \; }" 596 cmd+=' ; } ; main' 597 test_variants+=( testname="${0}/${i}/read_into_localvar_in_nested_function" cmd="$cmd" typeset -a stdoutpattern=( "${tst.stdoutpattern[@]}" ) ) 598 done 599 600 # run test variants 601 for (( i=0 ; i < ${#test_variants[@]} ; i++ )) ; do 602 nameref tv=test_variants[i] 603 604 out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -o errexit -c "${tv.cmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" 605 606 for pat in "${tv.stdoutpattern[@]}" ; do 607 [[ "${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}")" 608 done 609 [[ "${out.stderr}" == '' ]] || err_exit "${tv.testname}: Expected empty stderr for $(printf '%q\n' "${tv.cmd}"), got $(printf '%q\n' "${out.stderr}")" 610 (( out.res == 0 )) || err_exit "${tv.testname}: Unexpected exit code ${out.res} for $(printf '%q\n' "${tv.cmd}")" 611 done 612 613 return 0 614} 615 616 617# This test checks whether reading a compound variable value with 618# "read -C var" which contains special shell keywords or aliases 619# like "functions", "alias", "!" etc. in a string array causes the 620# shell to produce errors like this: 621# -- snip -- 622# $ ksh93 -c 'print "( compound -A a1=( [4]=( typeset -a x=( alias ) ) ) ; 623# compound -A a2=( [4]=( typeset -a x=( ! ! ! alias ) ) ) )" | read -C c ; print -v c' 1>/dev/null 624# ksh93[1]: alias: c.a1[4].x: compound assignment requires sub-variable name 625# -- snip -- 626# A 2nd issue indirectly tested here was that simple indexed string array 627# declarations in a function with the same special keywords did not work 628# either. 629# This happened in ast-ksh.2010-11-12 or older. 630function test_read_C_special_shell_keywords 631{ 632 typeset -r -a testcmdpatterns=( 633 # this was the original testcase 634 '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"' 635 # same as above but uses indexed arrays instead of associative arrays 636 '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"' 637 # same as first testcase but uses a blank in the array index value 638 $'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"' 639 ) 640 typeset -r -a shell_special_words=( 641 'alias' 642 'compound' 643 'function' 644 'functions' 645 'integer' 646 'local' 647 'namespace' 648 'typeset' 649 'SECONDS' 650 '.sh.version' 651 '!' 652 ) 653 integer spwi # shell_special_words index 654 integer tcpi # testcmdpatterns index 655 typeset testcmd 656 typeset testname 657 typeset shkeyword 658 compound out=( typeset stdout stderr ; integer res ) 659 660 for (( tcpi=0 ; tcpi < ${#testcmdpatterns[@]} ; tcpi++ )) ; do 661 for (( spwi=0 ; spwi < ${#shell_special_words[@]} ; spwi++ )) ; do 662 shkeyword=${shell_special_words[spwi]} 663 testcmd="${testcmdpatterns[tcpi]//%keyword%/${shkeyword}}" 664 testname="${0}/${tcpi}/${spwi}/" 665 666 out.stderr="${ { out.stdout="${ ${SHELL} -o nounset -o errexit -c "${testcmd}" ; (( out.res=$? )) ; }" ; } 2>&1 ; }" 667 668 [[ "${out.stdout}" == "X${shkeyword}X" ]] || err_exit "${testname}: Expected stdout to match $(printf '%q\n' "X${shkeyword}X"), got $(printf '%q\n' "${out.stdout}")" 669 [[ "${out.stderr}" == '' ]] || err_exit "${testname}: Expected empty stderr, got $(printf '%q\n' "${out.stderr}")" 670 (( out.res == 0 )) || err_exit "${testname}: Unexpected exit code ${out.res}" 671 done 672 done 673 674 return 0 675} 676 677 678test_3D_array_read_C 679test_access_2Darray_in_type_in_compound 680test_read_type_crash 681test_read_C_into_array 682test_read_C_special_shell_keywords 683 684 685# tests done 686exit $((Errors<125?Errors:125)) 687