#### ksh93 test suite ## Introduction The directory /opt/ksh93-tests/ contains the ksh93 test suite which is used to verify the correct behaviour of ksh93. The test suite is split into modules with the ending *.sh and a frontend called "shtests" which is used to run the tests. ## Basic description: /opt/ksh93-tests/shtests By default, with no , each test is run three times: o In the posix/C locale; o In the C.UTF-8 locale; o As a compiled script using $SHCOMP. may be: -c execute test module as compiled shell script only -p execute test module as normal shell script in posix/C only -u execute test module as normal shell script in c.UTF-8 only -t do not print timing information -v use VMDEBUG Sets one or more environment variables to value "value". file name of test module ## Basic usage in illumos: The tests can be executed like this: $ export SHELL= $ export SHCOMP=/usr/bin/shcomp for t in /opt/ksh93-tests/tests/*.sh; do $SHELL /opt/ksh93-tests/shtests "$t" done Note that you MUST NOT use "/usr/bin/ksh93" as value for SHELL since /usr/bin/ksh93 on illumos is a wrapper which selects a suitable executable in /usr/bin//ksh93 based on the hardware capabilities defined via /usr/bin/isalist Valid values for SHELL are: - SHELL=/usr/bin/i86/ksh93 # 32-bit i386 - SHELL=/usr/bin/amd64/ksh93 # 64-bit AMD64 - SHELL=/usr/bin/sparcv7/ksh93 # 32-bit SPARC - SHELL=/usr/bin/sparcv9/ksh93 # 64-bit SPARC # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # # Copyright 2021 OmniOS Community Edition (OmniOSce) Association. # # # Test whether ksh mishandles a heredoc that spans a 8K chunk and has # a backslash as the last character of the first chunk. # See https://www.illumos.org/issues/13434 # # test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" (( Errors++ )) } alias err_exit='err_exit $LINENO' set -o nounset Command=${0##*/} integer Errors=0 # ......................................................................... # This comment introduces the correct number of padding characters to that # the \ in the second heredoc below occurs at byte position 8192 of the # script. # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................................... # ......................................................... t1=`mktemp` t2=`mktemp` if [[ ! -f "$t1" || ! -f "$t2" ]]; then # Don't use the global err _ exit function as the test harness uses # calls to that to compute the number of tests present in this file. echo "Could not create temporary files" exit 1 fi cat > "$t1" << EOF \$ EOF cat > "$t2" << EOF \$ EOF if ! cmp -s "$t1" "$t2"; then err_exit "Shell truncates heredoc over chunk boundary" #/bin/od -t x1 "$t1" #/bin/od -t x1 "$t2" fi rm -f "$t1" "$t2" # tests done exit $Errors # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # # Copyright 2021 OmniOS Community Edition (OmniOSce) Association. # # # Test whether the builtin head command properly handles files which do # not have a trailing newline. # # test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" (( Errors++ )) } alias err_exit='err_exit $LINENO' set -o nounset Command=${0##*/} integer Errors=0 builtin head tail t1=`mktemp` t2=`mktemp` t3=`mktemp` if [[ ! -f "$t1" || ! -f "$t2" || ! -f "$t3" ]]; then # Don't use the global err _ exit function as the test harness uses # calls to that to compute the number of tests present in this file. echo "Could not create temporary files" rm -f "$t1" "$t2" "$t3" exit 1 fi for f in test{0..4%02d}; do echo $f done | tee $t1 > $t2 printf "nonewline" >> $t2 printf "nonewline" >> $t3 # Standard file, five lines, with trailing newline [[ $(head -1 $t1) == 'test00' ]] || \ err_exit "Shell head -1 standard file" [[ $(head -2 $t1) == $'test00\ntest01' ]] || \ err_exit "Shell head -2 standard file" [[ $(head -s 2 -n2 $t1) == $'test02\ntest03' ]] || \ err_exit "Shell head -s 2 -n 2 standard file" [[ $(head -5 $t1) == $'test00\ntest01\ntest02\ntest03\ntest04' ]] || \ err_exit "Shell head -5 standard file" [[ $(head -10 $t1) == $'test00\ntest01\ntest02\ntest03\ntest04' ]] || \ err_exit "Shell head -10 standard file" [[ $(tail -1 $t1) == 'test04' ]] || \ err_exit "Shell tail -1 standard file" [[ $(tail -2 $t1) == $'test03\ntest04' ]] || \ err_exit "Shell tail -2 standard file" [[ $(tail -10 $t1) == $'test00\ntest01\ntest02\ntest03\ntest04' ]] || \ err_exit "Shell tail -10 standard file" # File with a single line, no trailing newline [[ $(head -1 $t3) == 'nonewline' ]] || \ err_exit "Shell head -1 one-line file" [[ $(head -2 $t3) == 'nonewline' ]] || \ err_exit "Shell head -2 one-line file" [[ $(tail -1 $t3) == 'nonewline' ]] || \ err_exit "Shell tail -1 one-line file" [[ $(tail -2 $t3) == 'nonewline' ]] || \ err_exit "Shell tail -2 one-line file" # File with six lines, no trailing newline [[ $(head -1 $t2) == "test00" ]] || \ err_exit "Shell head -1 six-line file" [[ $(head -2 $t2) == $'test00\ntest01' ]] || \ err_exit "Shell head -2 six-line file" [[ $(head -s 2 -n2 $t2) == $'test02\ntest03' ]] || \ err_exit "Shell head -s 2 -n 2 six-line file" [[ $(head -5 $t2) == $'test00\ntest01\ntest02\ntest03\ntest04' ]] || \ err_exit "Shell head -5 six-line file" [[ $(head -6 $t2) == $'test00\ntest01\ntest02\ntest03\ntest04\nnonewline' ]] \ || err_exit "Shell head -6 six-line file" [[ $(head -10 $t2) == $'test00\ntest01\ntest02\ntest03\ntest04\nnonewline' ]] \ || err_exit "Shell head -10 six-line file" [[ $(tail -1 $t2) == 'nonewline' ]] || \ err_exit "Shell tail -1 six-line file" [[ $(tail -2 $t2) == $'test04\nnonewline' ]] || \ err_exit "Shell tail -2 six-line file" [[ $(tail -10 $t2) == $'test00\ntest01\ntest02\ntest03\ntest04\nnonewline' ]] \ || err_exit "Shell tail -10 six-line file" rm -f "$t1" "$t2" "$t3" # tests done exit $Errors # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test module checks whether indexed+associative arrays # set the default datatype correctly if someone uses the "+=" # operator to add a value to an array element which does not # exist yet. # # test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" (( Errors < 127 && Errors++ )) } alias err_exit='err_exit $LINENO' # the test cannot use "nounset" Command=${0##*/} integer Errors=0 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 } # function to add the floating-point value 1.1 to array element "34" # floating-point datatypes should increment by 1.1, integers by 1 function add_float { nameref arr=$1 arr[34]+=1.1 return 0 } # function to add a compound variable called "val" to array element arr[34] function add_compound { nameref arr=$1 arr[34]+=( float val=1.1 ) return 0 } # We run the tests in multiple cyles: # First cycle uses a normal compound variable as basis # Second cycle uses a nameref to a compound variable as basis # Third cycle uses a nameref to a nameref to a compound variable as basis for cycle in \ c1 c2 c3 c4 \ c2_sub c3_sub c4_sub \ c2_indexed_array c3_indexed_array c4_indexed_array \ c2_associative_array c3_associative_array c4_associative_array; do case ${cycle} in c1) compound mycpv ;; c2) compound rootcpv nameref mycpv=rootcpv ;; c3) compound rootcpv nameref namereftoroot=rootcpv nameref mycpv=namereftoroot ;; c4) compound rootcpv nameref namereftoroot0=rootcpv nameref namereftoroot1=namereftoroot0 nameref mycpv=namereftoroot1 ;; # same as cX but uses a subvariable of rootcpv c2_sub) compound rootcpv compound rootcpv.sub nameref mycpv=rootcpv.sub ;; c3_sub) compound rootcpv compound rootcpv.sub nameref namereftoroot=rootcpv.sub nameref mycpv=namereftoroot ;; c4_sub) compound rootcpv compound rootcpv.sub nameref namereftoroot0=rootcpv.sub nameref namereftoroot1=namereftoroot0 nameref mycpv=namereftoroot1 ;; # same as cX but uses a subvariable of an indexed array c2_indexed_array) compound -a rootcpv nameref mycpv=rootcpv[4] ;; c3_indexed_array) compound -a rootcpv nameref namereftoroot=rootcpv[4] nameref mycpv=namereftoroot ;; c4_indexed_array) compound -a rootcpv nameref namereftoroot0=rootcpv[4] nameref namereftoroot1=namereftoroot0 nameref mycpv=namereftoroot1 ;; # same as cX but uses a subvariable of an indexed array c2_associative_array) compound -A rootcpv nameref mycpv=rootcpv["hello world"] ;; c3_associative_array) compound -A rootcpv nameref namereftoroot=rootcpv["hello world"] nameref mycpv=namereftoroot ;; c4_associative_array) compound -A rootcpv nameref namereftoroot0=rootcpv["hello world"] nameref namereftoroot1=namereftoroot0 nameref mycpv=namereftoroot1 ;; *) err_exit "${cycle}: Should not happen." ;; esac # Test 001: Test indexed floating-point array float -a mycpv.myindexedfloatarray add_float mycpv.myindexedfloatarray (( mycpv.myindexedfloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 1.1" add_float mycpv.myindexedfloatarray (( mycpv.myindexedfloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 2.2" unset mycpv.myindexedfloatarray[34] (( mycpv.myindexedfloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 0.0" # 2nd try (we do this to check whether "unset" works properly) add_float mycpv.myindexedfloatarray (( mycpv.myindexedfloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 1.1" add_float mycpv.myindexedfloatarray (( mycpv.myindexedfloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 2.2" unset mycpv.myindexedfloatarray[34] (( mycpv.myindexedfloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myindexedfloatarray[34] == ${mycpv.myindexedfloatarray[34]}, expected 0.0" # Test 002: Test associative floating-point array float -A mycpv.myassociativefloatarray add_float mycpv.myassociativefloatarray (( mycpv.myassociativefloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 1.1" add_float mycpv.myassociativefloatarray (( mycpv.myassociativefloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 2.2" unset mycpv.myassociativefloatarray[34] (( mycpv.myassociativefloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 0.0" # 2nd try (we do this to check whether "unset" works properly) add_float mycpv.myassociativefloatarray (( mycpv.myassociativefloatarray[34] == 1.1 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 1.1" add_float mycpv.myassociativefloatarray (( mycpv.myassociativefloatarray[34] == 2.2 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 2.2" unset mycpv.myassociativefloatarray[34] (( mycpv.myassociativefloatarray[34] == 0.0 )) || err_exit "${cycle}: mycpv.myassociativefloatarray[34] == ${mycpv.myassociativefloatarray[34]}, expected 0.0" # Test 003: Test indexed integer array integer -a mycpv.myindexedintegerarray add_float mycpv.myindexedintegerarray (( mycpv.myindexedintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 1" add_float mycpv.myindexedintegerarray (( mycpv.myindexedintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 2" unset mycpv.myindexedintegerarray[34] (( mycpv.myindexedintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 0" # 2nd try (we do this to check whether "unset" works properly) add_float mycpv.myindexedintegerarray (( mycpv.myindexedintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 1" add_float mycpv.myindexedintegerarray (( mycpv.myindexedintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 2" unset mycpv.myindexedintegerarray[34] (( mycpv.myindexedintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myindexedintegerarray[34] == ${mycpv.myindexedintegerarray[34]}, expected 0" # Test 004: Test associative integer array integer -A mycpv.myassociativeintegerarray add_float mycpv.myassociativeintegerarray (( mycpv.myassociativeintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 1" add_float mycpv.myassociativeintegerarray (( mycpv.myassociativeintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 2" unset mycpv.myassociativeintegerarray[34] (( mycpv.myassociativeintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 0" # 2nd try (we do this to check whether "unset" works properly) add_float mycpv.myassociativeintegerarray (( mycpv.myassociativeintegerarray[34] == 1 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 1" add_float mycpv.myassociativeintegerarray (( mycpv.myassociativeintegerarray[34] == 2 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 2" unset mycpv.myassociativeintegerarray[34] (( mycpv.myassociativeintegerarray[34] == 0 )) || err_exit "${cycle}: mycpv.myassociativeintegerarray[34] == ${mycpv.myassociativeintegerarray[34]}, expected 0" # Test 005: Tested indexed compound variable array compound -a mycpv.myindexedcompoundarray add_compound mycpv.myindexedcompoundarray (( mycpv.myindexedcompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myindexedcompoundarray[34].val == ${mycpv.myindexedcompoundarray[34].val}, expected 1.1" # try to add it a 2nd time - since the new element will replace the old # one the value will _not_ be incremented (or better: The compound # variable value "val" will be added, not the value of the "val" # variable) add_compound mycpv.myindexedcompoundarray (( mycpv.myindexedcompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myindexedcompoundarray[34].val == ${mycpv.myindexedcompoundarray[34].val}, expected 1.1" unset mycpv.myindexedcompoundarray[34] [[ ! -v mycpv.myindexedcompoundarray[34].val ]] || err_exit "${cycle}: [[ ! -v mycpv.myindexedcompoundarray[34].val ]] should return failure, got $?" (( mycpv.myindexedcompoundarray[34].val == 0.0 )) || err_exit "${cycle}: mycpv.myindexedcompoundarray[34].val == ${mycpv.myindexedcompoundarray[34].val}, expected 0.0" [[ "${mycpv.myindexedcompoundarray[34]}" == "" ]] || err_exit "${cycle}: mycpv.myindexedcompoundarray[34] expected to be equal to an empty string but contains |${mycpv.myindexedcompoundarray[34]}|" # Test 006: Tested associative compound variable array compound -A mycpv.myassociativecompoundarray add_compound mycpv.myassociativecompoundarray (( mycpv.myassociativecompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myassociativecompoundarray[34].val == ${mycpv.myassociativecompoundarray[34].val}, expected 1.1" # try to add it a 2nd time - since the new element will replace the old # one the value will _not_ be incremented (or better: The compound # variable value "val" will be added, not the value of the "val" # variable) add_compound mycpv.myassociativecompoundarray (( mycpv.myassociativecompoundarray[34].val == 1.1 )) || err_exit "${cycle}: mycpv.myassociativecompoundarray[34].val == ${mycpv.myassociativecompoundarray[34].val}, expected 1.1" unset mycpv.myassociativecompoundarray[34] [[ ! -v mycpv.myassociativecompoundarray[34].val ]] || err_exit "${cycle}: [[ ! -v mycpv.myassociativecompoundarray[34].val ]] should return failure, got $?" (( mycpv.myassociativecompoundarray[34].val == 0.0 )) || err_exit "${cycle}: mycpv.myassociativecompoundarray[34].val == ${mycpv.myassociativecompoundarray[34].val}, expected 0.0" [[ "${mycpv.myassociativecompoundarray[34]}" == "" ]] || err_exit "${cycle}: mycpv.myassociativecompoundarray[34] expected to be equal to an empty string but contains |${mycpv.myassociativecompoundarray[34]}|" # check whether the compound variable output is still Ok count_brackets "${mycpv}" || err_exit "${cycle}: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" count_brackets "$(print -v mycpv)" || err_exit "${cycle}: print -v mycpy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" count_brackets "$(print -C mycpv)" || err_exit "${cycle}: print -C mycpy: bracket open ${bracketstat.bopen} != bracket close ${bracketstat.bclose}" # reset unset mycpv [[ ! -v mycpv ]] || err_exit "${cycle}: mycpy should not exist" [[ "${mycpv}" == "" ]] || err_exit "${cycle}: mycpv expected to be empty" done # tests done exit $((Errors)) # # 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 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # Test whether the ksh93/poll builtin works as expected # # test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" (( Errors++ )) } alias err_exit='err_exit $LINENO' set -o nounset Command=${0##*/} integer Errors=0 builtin -f libshell.so.1 poll || err_exit "poll builtin not found." compound d1=( compound -A u=( [y]=( fd=5 events="POLLIN" revents="" ) [x]=( fd=5 events="POLLIN" revents="" ) ) ) # test 1: cat /dev/zero | { redirect 5<&0 ; poll -e d1.res -t 5. d1.u ; } || err_exit "poll returned non-zero exit code $?" [[ "${d1.u[x].revents}" == "POLLIN" ]] || err_exit "d1.u[x].revents contains '${d1.u[x].revents}', not POLLIN" [[ "${d1.u[y].revents}" == "POLLIN" ]] || err_exit "d1.u[y].revents contains '${d1.u[y].revents}', not POLLIN" [[ "${d1.res[*]}" == "x y" ]] || err_exit "d1.res contains '${d1.res[*]}', not 'x y'" # test 2: unset d1.res d1.u[z]=( fd=5 events="POLLOUT" revents="" ) { poll -e d1.res -t 5. d1.u ; } 5/dev/null || err_exit "poll returned non-zero exit code $?" [[ "${d1.u[x].revents}" == "POLLIN" ]] || err_exit "d1.u[x].revents contains '${d1.u[x].revents}', not 'POLLIN'" [[ "${d1.u[y].revents}" == "POLLIN" ]] || err_exit "d1.u[y].revents contains '${d1.u[y].revents}', not 'POLLIN'" [[ "${d1.u[z].revents}" == "POLLOUT|POLLWRNORM" ]] || err_exit "d1.u[z].revents contains '${d1.u[z].revents}', not 'POLLOUT|POLLWRNORM,'" [[ "${d1.res[*]}" == "x y z" ]] || err_exit "d1.res contains '${d1.res[*]}', not 'x y z'" # tests done exit $((Errors)) # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # Test whether the ksh93/libcmd sum builtin is compatible to # Solaris/SystemV /usr/bin/sum # # test setup 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 x builtin sum || err_exit "sum builtin not found" # Basic tests x="$(print 'hello' | /usr/bin/sum)" || err_exit "/usr/bin/sum pipe failed." [[ "$x" == "542 1" ]] || err_exit "print 'hello' | /usr/bin/sum did not return 542 1, got $x" x="$(print 'hello' | sum)" || err_exit "sum builtin pipe failed." [[ "$x" == "542 1" ]] || err_exit "print 'hello' | sum builtin did not return 542 1, got $x" x="$(print 'hello' | sum -x md5)" || err_exit "sum md5 builtin pipe failed." [[ "$x" == "b1946ac92492d2347c6235b4d2611184" ]] || err_exit "print 'hello' | sum md5 builtin did not return b1946ac92492d2347c6235b4d2611184, got $x" x="$(print 'hello' | sum -x sha1)" || err_exit "sum sha1 builtin pipe failed." [[ "$x" == "f572d396fae9206628714fb2ce00f72e94f2258f" ]] || err_exit "print 'hello' | sum sha1 builtin did not return f572d396fae9206628714fb2ce00f72e94f2258f, got $x" x="$(print 'hello' | sum -x sha256)" || err_exit "sum sha256 builtin pipe failed." [[ "$x" == "5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03" ]] || err_exit "print 'hello' | sum sha256 builtin did not return 5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03, got $x" x="$(print 'hello' | sum -x sha512)" || err_exit "sum sha512 builtin pipe failed." [[ "$x" == "e7c22b994c59d9cf2b48e549b1e24666636045930d3da7c1acb299d1c3b7f931f94aae41edda2c2b207a36e10f8bcb8d45223e54878f5b316e7ce3b6bc019629" ]] || err_exit "print 'hello' | sum sha512 builtin did not return e7c22b994c59d9cf2b48e549b1e24666636045930d3da7c1acb299d1c3b7f931f94aae41edda2c2b207a36e10f8bcb8d45223e54878f5b316e7ce3b6bc019629, got $x" # note that Solaris /usr/bin/cksum outputs $'3015617425\t6' (which may be a bug in Solaris /usr/bin/cksum) x="$(print 'hello' | sum -x cksum)" || err_exit "sum cksum builtin pipe failed." [[ "$x" == $'3015617425 6' ]] || err_exit "print 'hello' | sum cksum builtin did not return \$'3015617425 6', got $(printf "%q\n" "$x")" [[ "$(print 'hello' | /usr/bin/sum)" == "$(print 'hello' | sum)" ]] || err_exit "sum hello != /usr/bin/sum hello" [[ "$(print 'fish' | /usr/bin/sum)" == "$(print 'fish' | sum)" ]] || err_exit "sum fish != /usr/bin/sum fish" [[ "$(print '12345' | /usr/bin/sum)" == "$(print '12345' | sum)" ]] || err_exit "sum 12345 != /usr/bin/sum 12345" [[ "$(print '\n\r\n \v' | /usr/bin/sum)" == "$(print '\n\r\n \v' | sum)" ]] || err_exit "sum spaces != /usr/bin/sum spaces" # Test some binary files... x="/bin/ls" [[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" [[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" x="/bin/chmod" [[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" [[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" x="/usr/bin/tee" [[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" [[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" x="/bin/grep" [[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" [[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" x="/bin/egrep" [[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" [[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" x="/bin/awk" [[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" [[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" x="/bin/nawk" [[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" [[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" x="/usr/bin/ksh" [[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" [[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" x="/usr/bin/sh" [[ "$(cat "$x" | /usr/bin/sum)" == "$(cat "$x" | sum)" ]] || err_exit "pipe: /usr/bin/sum $x != sum $x" [[ "$(/usr/bin/sum "$x")" == "$(sum "$x")" ]] || err_exit "file: /usr/bin/sum $x != sum $x" # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # Test whether the ksh93/libcmd tail builtin is compatible to # Solaris/SystemV { /bin/tail, /usr/xpg4/bin/tail } and # POSIX "tail" # # test setup 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 # common functions function isvalidpid { kill -0 ${1} 2>/dev/null && return 0 return 1 } function waitpidtimeout { integer pid=$1 float timeout=$2 float i float -r STEP=0.5 # const (( timeout=timeout/STEP )) for (( i=0 ; i < timeout ; i+=STEP )) ; do isvalidpid ${pid} || break sleep ${STEP} done return 0 } function myintseq { integer i case $# in 1) for (( i=1 ; i <= $1 ; i++ )) ; do printf "%d\n" i done ;; 2) for (( i=$1 ; i <= $2 ; i++ )) ; do printf "%d\n" i done ;; 3) for (( i=$1 ; i <= $3 ; i+=$2 )) ; do printf "%d\n" i done ;; *) print -u2 -f "%s: Illegal number of arguments %d\n" "$0" $# return 1 ;; esac return 0 } # quote input string but use single-backslash that "err_exit" prints # the strings correctly function singlebackslashquote { typeset s s="$(printf "%q\n" "$1")" print -r "$s" return 0 } # quote input string but use double-backslash that "err_exit" prints # the strings correctly function doublebackslashquote { typeset s s="$(printf "%q\n" "$1")" s="${s//\\/\\\\}" print -r "$s" return 0 } # main builtin mktemp || err_exit "mktemp builtin not found" builtin rm || err_exit "rm builtin not found" builtin tail || err_exit "tail builtin not found" typeset ocwd typeset tmpdir # create temporary test directory ocwd="$PWD" tmpdir="$(mktemp -t -d "test_sun_solaris_builtin_tail.XXXXXXXX")" || err_exit "Cannot create temporary directory" cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } # run tests: # test1: basic tests compound -a testcases=( ( name="reverse_n" input=$'hello\nworld' compound -A tail_args=( [legacy]=( argv=( "-r" ) ) ) expected_output=$'world\nhello' ) ( name="revlist0n" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "-0" ) ) [std_like]=( argv=( "-n" "0" ) ) ) expected_output=$'' ) ( name="revlist0nr" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "-0r" ) ) [std_like]=( argv=( "-n" "0" "-r" ) ) [long_options]=( argv=( "--lines" "0" "--reverse" ) ) ) expected_output=$'' ) ( name="revlist1n" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "-1" ) ) [std_like]=( argv=( "-n" "1" ) ) [long_options]=( argv=( "--lines" "1" ) ) ) expected_output=$'4' ) ( name="revlist1nr" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "-1r" ) ) [std_like]=( argv=( "-n" "1" "-r" ) ) [long_options]=( argv=( "--lines" "1" "--reverse" ) ) ) expected_output=$'4' ) ( name="revlist2n" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "-2" ) ) [std_like]=( argv=( "-n" "2" ) ) ) expected_output=$'3\n4' ) ( name="revlist2nr" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "-2r" ) ) [std_like]=( argv=( "-n" "2" "-r" ) ) ) expected_output=$'4\n3' ) ( name="revlist3nr" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "-3r" ) ) [std_like]=( argv=( "-n" "3" "-r" ) ) ) expected_output=$'4\n3\n2' ) ( name="revlist2p" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "+2" ) ) [std_like]=( argv=( "-n" "+2" ) ) ) expected_output=$'2\n3\n4' ) ( name="revlist2pr" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "+2r" ) ) [std_like]=( argv=( "-n" "+2" "-r" ) ) ) expected_output=$'4\n3\n2' ) ( name="revlist3p" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "+3" ) ) [std_like]=( argv=( "-n" "+3" ) ) ) expected_output=$'3\n4' ) ( name="revlist3pr" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "+3r" ) ) [std_like]=( argv=( "-n" "+3" "-r" ) ) ) expected_output=$'4\n3' ) ( name="revlist4p" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "+4" ) ) [std_like]=( argv=( "-n" "+4" ) ) ) expected_output=$'4' ) ( name="revlist4pr" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "+4r" ) ) [std_like]=( argv=( "-n" "+4" "-r" ) ) ) expected_output=$'4' ) ( name="revlist5p" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "+5" ) ) [std_like]=( argv=( "-n" "+5" ) ) ) expected_output=$'' ) ( name="revlist5pr" input=$'1\n2\n3\n4' compound -A tail_args=( [legacy]=( argv=( "+5r" ) ) [std_like]=( argv=( "-n" "+5" "-r" ) ) ) expected_output=$'' ) ) for testid in "${!testcases[@]}" ; do nameref tc=testcases[${testid}] for argv_variants in "${!tc.tail_args[@]}" ; do nameref argv=tc.tail_args[${argv_variants}].argv output=$( set -o pipefail (trap "" PIPE ; print -r -- "${tc.input}") | tail "${argv[@]}" ) || err_exit "test ${tc.name}/${argv_variants}: command failed with exit code $?" [[ "${output}" == "${tc.expected_output}" ]] || err_exit "test ${tc.name}/${argv_variants}: Expected $(doublebackslashquote "${tc.expected_output}"), got $(doublebackslashquote "${output}")" done done # test2: test "tail -r /dev/null 2>&1 (( $? == 2 )) || err_exit "expected exit code 2 for unsupported long option, got $?" # test 4: FIFO tests # FIFO test functions # (we use functions here to do propper garbage collection) function test_tail_fifo_1 { typeset tail_cmd="$1" integer i integer tail_pid=-1 # cleanup trap trap "rm -f tailtestfifo tailout" EXIT # create test FIFO mkfifo tailtestfifo ${tail_cmd} -f tailout & tail_pid=$! myintseq 20 >tailtestfifo waitpidtimeout ${tail_pid} 5 if isvalidpid ${tail_pid} ; then err_exit "test_tail_fifo_1: # tail hung (not expected)" kill -KILL ${tail_pid} fi wait || err_exit "tail child returned non-zero exit code=$?" [[ "$(cat tailout)" == $'11\n12\n13\n14\n15\n16\n17\n18\n19\n20' ]] || err_exit "test_tail_fifo_1: Expected $(doublebackslashquote '11\n12\n13\n14\n15\n16\n17\n18\n19\n20'), got $(doublebackslashquote "$(cat tailout)")" return 0 } function test_tail_fifo_2 { typeset tail_cmd="$1" integer i integer tail_pid=-1 # cleanup trap trap "rm -f tailtestfifo tailout" EXIT # create test FIFO mkfifo tailtestfifo ${tail_cmd} -f tailtestfifo >tailout & tail_pid=$! myintseq 14 >tailtestfifo waitpidtimeout ${tail_pid} 5 if isvalidpid ${tail_pid} ; then [[ "$(cat tailout)" == $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14' ]] || err_exit "test_tail_fifo_2: Expected $(doublebackslashquote $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14'), got $(doublebackslashquote "$(cat tailout)")" myintseq 15 >>tailtestfifo waitpidtimeout ${tail_pid} 5 if isvalidpid ${tail_pid} ; then kill -KILL ${tail_pid} else err_exit "test_tail_fifo_2: # tail exit with return code $? (not expected)" fi fi wait || err_exit "tail child returned non-zero exit code=$?" [[ "$(cat tailout)" == $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15' ]] || err_exit "test_tail_fifo_2: Expected $(doublebackslashquote $'5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15'), got $(doublebackslashquote "$(cat tailout)")" return 0 } # fixme: This should test /bin/tail and /usr/xpg4/bin/tail in Solaris test_tail_fifo_1 "tail" test_tail_fifo_2 "tail" # test 5: "tail -f" tests function followtest1 { typeset -r FOLLOWFILE="followfile.txt" typeset -r OUTFILE="outfile.txt" typeset title="$1" typeset testcmd="$2" typeset usenewline=$3 typeset followstr="" typeset newline="" integer i integer tailchild=-1 if ${usenewline} ; then newline=$'\n' fi rm -f "${FOLLOWFILE}" "${OUTFILE}" print -n "${newline}" > "${FOLLOWFILE}" ${testcmd} -f "${FOLLOWFILE}" >"${OUTFILE}" & (( tailchild=$! )) for (( i=0 ; i < 10 ; i++)) ; do followstr+="${newline}${i}" print -n "${i}${newline}" >>"${FOLLOWFILE}" sleep 2 [[ "$( < "${OUTFILE}")" == "${followstr}" ]] || err_exit "${title}: Expected $(doublebackslashquote "${followstr}"), got "$(doublebackslashquote "$( < "${OUTFILE}")")"" done kill -KILL ${tailchild} 2>/dev/null #kill -TERM ${tailchild} 2>/dev/null waitpidtimeout ${tailchild} 5 if isvalidpid ${tailchild} ; then err_exit "${title}: tail pid=${tailchild} hung." kill -KILL ${tailchild} 2>/dev/null fi wait ${tailchild} 2>/dev/null rm -f "${FOLLOWFILE}" "${OUTFILE}" return 0 } followtest1 "test5a" "tail" true # fixme: later we should test this, too: #followtest1 "test5b" "tail" false #followtest1 "test5c" "/usr/xpg4/bin/tail" true #followtest1 "test5d" "/usr/xpg4/bin/tail" false #followtest1 "test5e" "/bin/tail" true #followtest1 "test5f" "/bin/tail" false # test 6: "tail -f" tests function followtest2 { typeset -r FOLLOWFILE="followfile.txt" typeset -r OUTFILE="outfile.txt" typeset title="$1" typeset testcmd="$2" integer tailchild=-1 rm -f "${FOLLOWFILE}" "${OUTFILE}" myintseq 50000 >"${FOLLOWFILE}" ${testcmd} -n 60000 -f "${FOLLOWFILE}" >"${OUTFILE}" & (( tailchild=$! )) sleep 10 kill -KILL ${tailchild} 2>/dev/null #kill -TERM ${tailchild} 2>/dev/null waitpidtimeout ${tailchild} 5 if isvalidpid ${tailchild} ; then err_exit "${title}: tail pid=${tailchild} hung." kill -KILL ${tailchild} 2>/dev/null fi wait ${tailchild} 2>/dev/null # this tail should be an external process outstr=$(/bin/tail "${OUTFILE}") || err_exit "tail returned non-zero exit code $?" [[ "${outstr}" == 49991*50000 ]] || err_exit "${title}: Expected match for 49991*50000, got "$(singlebackslashquote "${outstr}")"" rm -f "${FOLLOWFILE}" "${OUTFILE}" return 0 } followtest2 "test6a" "tail" followtest2 "test6b" "/usr/xpg4/bin/tail" # fixme: later we should test this, too: #followtest2 "test6c" "/bin/tail" # cleanup cd "${ocwd}" rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". # tests done exit $((Errors)) # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # Written by Roland Mainz # # test setup 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 function isvalidpid { kill -0 ${1} 2>/dev/null && return 0 return 1 } integer testfilesize i maxwait typeset tmpfile integer testid ######################################################################## #### test set 001: # run loop and check various temp filesizes # (Please keep this test syncted with sun_solaris_cr_6800929_large_command_substitution_hang.sh) # test 1: run loop and check various temp filesizes tmpfile="$(mktemp -t "ksh93_tests_command_substitution.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file." compound test1=( compound -a testcases=( # test 1a: Run test child for $(...) # (note the pipe chain has to end in a builtin command, an external command may not trigger the bug) ( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) # test 1b: Same as test1a but uses ${... ; } instead if $(...) ( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) # test 1c: Same as test1a but does not use a pipe ( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) # test 1d: Same as test1a but does not use a pipe ( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) # test 1e: Same as test1a but uses an external "cat" command ( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) # test 1f: Same as test1a but uses an external "cat" command ( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) # test 1g: Same as test1a but uses an external "cat" command ( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) # test 1h: Same as test1a but uses an external "cat" command ( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) ) ) for (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do # Create temp file { for (( i=0 ; i < testfilesize ; i+=64 )) ; do print "0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE" done } >"${tmpfile}" # wait up to log2(i) seconds for the child to terminate # (this is 10 seconds for 1KB and 19 seconds for 512KB) (( maxwait=log2(testfilesize) )) for testid in "${!test1.testcases[@]}" ; do nameref currtst=test1.testcases[testid] ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" & (( childpid=$! )) for (( i=0 ; i < maxwait ; i++ )) ; do isvalidpid ${childpid} || break sleep 0.25 done if isvalidpid ${childpid} ; then err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}." kill -KILL ${childpid} 2>/dev/null fi wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) # compare input/output cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}." rm "${tmpfile}.out" done # Cleanup rm "${tmpfile}" done ######################################################################## #### test set 002: # If a command substitution calls a function and that function contains # a command substitution which contains a piped command, the original # command substitution calling the function will return 127 instead of 0. # This is causing problems in several VSC tests. # If we remove the piped command from the simple # case in the attached script, it returns 0. typeset str typeset testbody typeset testout testbody=$( # means command substitution start, means command substitution end cat < printf "hi" | tr "h" "H" echo \$pipedcmd return 0 } foo=myfunc retval=\$? if [ "\$foo"X != "HiX" ]; then echo "myfunc returned '\${foo}'; expected 'Hi'" fi if [ \$retval -ne 0 ]; then echo "command substitution calling myfunc returned \"\${retval}\"; expected 0" else echo "command substitution calling myfunc successfully returned 0" fi EOF ) # Test 002/a: Plain test testout=${ printf "%B\n" testbody | sed 's//$(/g;s//)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } [[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" # Test 002/b: Same as test002/a but replaces "$(" with "${" testout=${ printf "%B\n" testbody | sed 's//${ /g;s// ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } [[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" # Test 002/c: Same as test002/a but forces |fork()| for a subshell via "ulimit -c 0" testout=${ printf "%B\n" testbody | sed 's//$( ulimit -c 0 ; /g;s//)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } [[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" # Test 002/d: Same as test002/a but uses extra subshell testout=${ printf "%B\n" testbody | sed 's//$( ( /g;s//) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } [[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" # Test 002/e: Same as test002/b but uses extra subshell after "${ " testout=${ printf "%B\n" testbody | sed 's//${ ( /g;s//) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } [[ "${testout}" == "command substitution calling myfunc successfully returned 0" ]] || err_exit "Expected 'command substitution calling myfunc successfully returned 0', got ${testout}" ######################################################################## #### test set 003: # An expression within backticks which should return false, instead # returns true (0). typeset str typeset testbody typeset testout testbody=$( # means command substitution start, means command substitution end cat <expr "NOMATCH" : ".*Z" > /dev/null ; then echo "xerror" else echo "xok" fi EOF ) # Test 003/a: Plain test testout=${ printf "%B\n" testbody | sed 's//$(/g;s//)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } [[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" # Test 003/b: Same as test003/a but replaces "$(" with "${" testout=${ printf "%B\n" testbody | sed 's//${ /g;s// ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } [[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" # Test 003/c: Same as test003/a but forces |fork()| for a subshell via "ulimit -c 0" testout=${ printf "%B\n" testbody | sed 's//$( ulimit -c 0 ; /g;s//)/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } [[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" # Test 003/d: Same as test003/a but uses extra subshell testout=${ printf "%B\n" testbody | sed 's//$( ( /g;s//) )/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } [[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" # Test 003/e: Same as test003/b but uses extra subshell after "${ " testout=${ printf "%B\n" testbody | sed 's//${ ( /g;s//) ; }/g' | ${SHELL} 2>&1 || err_exit "command returned exit code $?" } [[ "${testout}" == "xok" ]] || err_exit "Expected 'xok', got ${testout}" ######################################################################## #### test set 004: # test pipe within ${... ; } command subtitution ending in a # non-builtin command (therefore we use "/bin/cat" instead of "cat" below # to force the use of the external "cat" command). ast-ksh.2009-01-20 # had a bug which caused this test to fail. testout=$( ${SHELL} -c 'pipedcmd=${ printf "hi" | /bin/cat ; } ; print $pipedcmd' ) [[ "${testout}" == "hi" ]] || err_exit "test004: Expected 'hi', got '${testout}'" ######################################################################## #### test set 005: # Test whether the shell may hang in a # 'exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)' # Originally discovered with ast-ksh.2009-05-05 which hung in # the "configure" script of postgresql-8.3.7.tar.gz (e.g. # configure --enable-thread-safety --without-readline) compound test5=( compound -a testcases=( # gsf's reduced testcase ( name="test5_a" cmd='exec 5>/dev/null; print $(eval ls -d . 2>&1 1>&5)done' ) # gisburn's reduced testcase ( name="test5_b" cmd='exec 5>/dev/null; print $(eval "/bin/printf hello\n" 2>&1 1>&5)done' ) ## The following tests do not trigger the problem but are included here for completeness ## and to make sure we don't get other incarnations of the same problem later... # same as test5_a but uses ${ ... ; } instead of $(...) ( name="test5_c" cmd='exec 5>/dev/null; print "${ eval ls -d . 2>&1 1>&5 ;}done"' ) # same as test5_b but uses ${ ... ; } instead of $(...) ( name="test5_d" cmd='exec 5>/dev/null; print "${ eval "/bin/printf hello\n" 2>&1 1>&5 ;}done"' ) # same as test5_a but uses "ulimit -c 0" to force the shell to use a seperare process for $(...) ( name="test5_e" cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval ls -d . 2>&1 1>&5)done' ) # same as test5_b but uses "ulimit -c 0" to force the shell to use a seperare process for $(...) ( name="test5_f" cmd='exec 5>/dev/null; print $(ulimit -c 0 ; eval "/bin/printf hello\n" 2>&1 1>&5)done' ) ) ) maxwait=5 for testid in "${!test5.testcases[@]}" ; do nameref currtst=test5.testcases[testid] ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" & (( childpid=$! )) for (( i=0 ; i < maxwait ; i++ )) ; do isvalidpid ${childpid} || break sleep 0.25 done if isvalidpid ${childpid} ; then err_exit "${currtst.name}: child (pid=${childpid}) still busy." kill -KILL ${childpid} 2>/dev/null fi wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) testout="$( < "${tmpfile}.out")" rm "${tmpfile}.out" || err_exit "File '${tmpfile}.out' could not be removed." [[ "${testout}" == "done" ]] || err_exit "test '${currtst.name}' failed, expected 'done', got '${testout}'" done # tests done exit $((Errors)) # # 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 (c) 2010, Oracle and/or its affiliates. All rights reserved. # # # This test module contains misc compound tests which do not have # their own module yet. # # # test setup 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 # global utility functions 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 } typeset ocwd typeset tmpdir # create temporary test directory ocwd="$PWD" tmpdir="$(mktemp -t -d "test_sun_solaris_compound_misc.XXXXXXXX")" || err_exit "Cannot create temporary directory" cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } # ksh93 <= ast-ksh.2010-03-09 prints garbage for compound x=( compound -a nodes=( [4]=( ) ) );typeset -p x function test_compound_indexed_array_init_1 { compound vx=( compound -a nodes=( [4]=( ) ) ) compound vy compound -a vy.nodes=( [4]=( ) ) compound vz compound -a vz.nodes vz.nodes[4]=( ) cx="$(typeset -p vx)" ; cx="${cx//vx/tt}" cy="$(typeset -p vy)" ; cy="${cy//vy/tt}" cz="$(typeset -p vz)" ; cz="${cz//vz/tt}" [[ "$cx" == "$cy" ]] || err_exit "'$cx' != '$cy'" [[ "$cx" == "$cz" ]] || err_exit "'$cx' != '$cz'" [[ "$cy" == "$cz" ]] || err_exit "'$cy' != '$cz'" count_brackets "$cx" || err_exit "Brackets not balanced for '$cx'" count_brackets "$cy" || err_exit "Brackets not balanced for '$cy'" count_brackets "$cz" || err_exit "Brackets not balanced for '$cz'" count_brackets "$(print -v vx)" || err_exit "Brackets not balanced for '$(print -v vx)'" count_brackets "$(print -v vy)" || err_exit "Brackets not balanced for '$(print -v vy)'" count_brackets "$(print -v vz)" || err_exit "Brackets not balanced for '$(print -v vz)'" count_brackets "$(print -C vx)" || err_exit "Brackets not balanced for '$(print -C vx)'" count_brackets "$(print -C vy)" || err_exit "Brackets not balanced for '$(print -C vy)'" count_brackets "$(print -C vz)" || err_exit "Brackets not balanced for '$(print -C vz)'" cx="$(typeset +p vx.nodes)" ; [[ "$cx" == *-C* && "$cx" == *-a* ]] || err_exit "'$cx' lacks -C/-a attribute" cy="$(typeset +p vy.nodes)" ; [[ "$cy" == *-C* && "$cy" == *-a* ]] || err_exit "'$cy' lacks -C/-a attribute" cz="$(typeset +p vz.nodes)" ; [[ "$cz" == *-C* && "$cz" == *-a* ]] || err_exit "'$cz' lacks -C/-a attribute" cx="$(typeset +p vx.nodes[4])" ; [[ "$cx" == *-C* ]] || err_exit "'$cx' lacks -C attribute" cy="$(typeset +p vy.nodes[4])" ; [[ "$cy" == *-C* ]] || err_exit "'$cy' lacks -C attribute" cz="$(typeset +p vz.nodes[4])" ; [[ "$cz" == *-C* ]] || err_exit "'$cz' lacks -C attribute" return 0 } # ksh93 <= ast-ksh.2010-03-09 prints garbage for compound x=( compound -a nodes=( [4]=( ) ) );typeset -p x # this test is the same as test_compound_indexed_array_init_1 but "-a" was replaced with "-A" function test_compound_associative_array_init_1 { compound vx=( compound -A nodes=( [4]=( ) ) ) compound vy compound -A vy.nodes=( [4]=( ) ) compound vz compound -A vz.nodes vz.nodes[4]=( ) cx="$(typeset -p vx)" ; cx="${cx//vx/tt}" cy="$(typeset -p vy)" ; cy="${cy//vy/tt}" cz="$(typeset -p vz)" ; cz="${cz//vz/tt}" [[ "$cx" == "$cy" ]] || err_exit "'$cx' != '$cy'" [[ "$cx" == "$cz" ]] || err_exit "'$cx' != '$cz'" [[ "$cy" == "$cz" ]] || err_exit "'$cy' != '$cz'" count_brackets "$cx" || err_exit "Brackets not balanced for '$cx'" count_brackets "$cy" || err_exit "Brackets not balanced for '$cy'" count_brackets "$cz" || err_exit "Brackets not balanced for '$cz'" count_brackets "$(print -v vx)" || err_exit "Brackets not balanced for '$(print -v vx)'" count_brackets "$(print -v vy)" || err_exit "Brackets not balanced for '$(print -v vy)'" count_brackets "$(print -v vz)" || err_exit "Brackets not balanced for '$(print -v vz)'" count_brackets "$(print -C vx)" || err_exit "Brackets not balanced for '$(print -C vx)'" count_brackets "$(print -C vy)" || err_exit "Brackets not balanced for '$(print -C vy)'" count_brackets "$(print -C vz)" || err_exit "Brackets not balanced for '$(print -C vz)'" cx="$(typeset +p vx.nodes)" ; [[ "$cx" == *-C* && "$cx" == *-A* ]] || err_exit "'$cx' lacks -C/-A attribute" cy="$(typeset +p vy.nodes)" ; [[ "$cy" == *-C* && "$cy" == *-A* ]] || err_exit "'$cy' lacks -C/-A attribute" cz="$(typeset +p vz.nodes)" ; [[ "$cz" == *-C* && "$cz" == *-A* ]] || err_exit "'$cz' lacks -C/-A attribute" cx="$(typeset +p vx.nodes[4])" ; [[ "$cx" == *-C* ]] || err_exit "'$cx' lacks -C attribute" cy="$(typeset +p vy.nodes[4])" ; [[ "$cy" == *-C* ]] || err_exit "'$cy' lacks -C attribute" cz="$(typeset +p vz.nodes[4])" ; [[ "$cz" == *-C* ]] || err_exit "'$cz' lacks -C attribute" return 0 } # run tests test_compound_indexed_array_init_1 test_compound_associative_array_init_1 cd "${ocwd}" rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". # tests done exit $((Errors)) # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # test setup 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 # # name reference test #001 # Note we run this test in a seperate shell to make sure the memory # corruption originally reported can be reproduced (which precisely # depends on ordering in the testcase) ( cat < # 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 -- # # hello # # -- 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" (( 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" 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" (( signbit(x.myarray3[a_nan].my_nan) )) || err_exit "x.myarray3[a_nan].my_nan not negative" # 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}" # tests done exit $((Errors)) # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether the issue described in CR #6687139 # ("command substitution, exec, and stdout redirection cause # allocation loop") has been fixed: # -- snip -- # The following one-liner (including back ticks) causes ksh93 to spin # out of control consuming all memory at a *very* rapid pace: # # `exec program > file` # # If "file" is a real file (as opposed to /dev/null), the file will # also grow without bound. "program" need not exist, i.e. # # `exec > file` # # has the same result. Using $() instead of `` also has the same # effect. # # This works fine under all other bourne-compatible shells. # -- snip -- # # test setup 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 function isvalidpid { kill -0 ${1} 2>/dev/null && return 0 return 1 } integer childpid typeset testdir integer childretval testdir="/tmp/sun_solaris_cr_6687139_pid$$_${PPID}" mkdir -p "${testdir}" || err_exit "Cannot create test dirctory" cd "${testdir}" || { err_exit "Cannot cd to test dirctory" ; exit $Errors ; } ############################################################################## ## ## test variant 1a: Use command substitution $( ... ) ## # Run testcase with "nice" to make sure a "runaway" process can # still be caught&&terminated by the current shell nice -n 10 ${SHELL} -c 'touch z ; $(exec nosuchprogram_for_cr_6687139 > z) ; rm z' 2>/dev/null & childpid=$! sleep 5 if isvalidpid ${childpid} ; then # First _stop_, then log error since the child may eat up memory # VERY VERY quickly kill -STOP ${childpid} err_exit "Child still active after 5 seconds (hang ?)" # Get sample stack trace pstack ${childpid} kill -KILL ${childpid} fi # collect child's return status wait ${childpid} childretval=$? (( childretval == 0 )) || err_exit "Child returned non-zero exit code ${childretval}." [[ ! -f "z" ]] || { rm "z" ; err_exit "Child did not remove test file" ; } ############################################################################## ## ## test variant 1b: Same as test 1a but forces the shell to |fork()| for the ## subshell ## # Run testcase with "nice" to make sure a "runaway" process can # still be caught&&terminated by the current shell nice -n 10 ${SHELL} -c 'touch z ; $(ulimit -c 0 ; exec nosuchprogram_for_cr_6687139 > z) ; rm z' 2>/dev/null & childpid=$! sleep 5 if isvalidpid ${childpid} ; then # First _stop_, then log error since the child may eat up memory # VERY VERY quickly kill -STOP ${childpid} err_exit "Child still active after 5 seconds (hang ?)" # Get sample stack trace pstack ${childpid} kill -KILL ${childpid} fi # collect child's return status wait ${childpid} childretval=$? (( childretval == 0 )) || err_exit "Child returned non-zero exit code ${childretval}." [[ ! -f "z" ]] || { rm "z" ; err_exit "Child did not remove test file" ; } ############################################################################## ## ## test variant 2a: Use plain subshell ( ... ) ## # Run testcase with "nice" to make sure a "runaway" process can # still be caught&&terminated by the current shell nice -n 10 ${SHELL} -c 'touch z ; (exec nosuchprogram_for_cr_6687139 > z) ; rm z' 2>/dev/null & childpid=$! sleep 5 if isvalidpid ${childpid} ; then # First _stop_, then log error since the child may eat up memory # VERY VERY quickly kill -STOP ${childpid} err_exit "Child still active after 5 seconds (hang ?)" # Get sample stack trace pstack ${childpid} kill -KILL ${childpid} fi # collect child's return status wait ${childpid} childretval=$? (( childretval == 0 )) || err_exit "Child returned non-zero exit code ${childretval}." [[ ! -f "z" ]] || { rm "z" ; err_exit "Child did not remove test file" ; } ############################################################################## ## ## test variant 2b: Same as test 2a but forces the shell to |fork()| for the ## subshell ## # Run testcase with "nice" to make sure a "runaway" process can # still be caught&&terminated by the current shell nice -n 10 ${SHELL} -c 'touch z ; (ulimit -c 0 ; exec nosuchprogram_for_cr_6687139 > z) ; rm z' 2>/dev/null & childpid=$! sleep 5 if isvalidpid ${childpid} ; then # First _stop_, then log error since the child may eat up memory # VERY VERY quickly kill -STOP ${childpid} err_exit "Child still active after 5 seconds (hang ?)" # Get sample stack trace pstack ${childpid} kill -KILL ${childpid} fi # collect child's return status wait ${childpid} childretval=$? (( childretval == 0 )) || err_exit "Child returned non-zero exit code ${childretval}." [[ ! -f "z" ]] || { rm "z" ; err_exit "Child did not remove test file" ; } # tests done, remove temporary test subdir cd /tmp rmdir "${testdir}" || err_exit "Could not remove temporary test directory ${testdir}" # tests done exit $((Errors)) # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # Test whether CR #6713682 has been fixed. # # Creating a compound variable in s subshell "bleeds through" to the calling subshell in some conditions. # Example: # -- snip -- # $ ksh93 -c 'unset l ; ( l=( a=1 b="BE" ) ; print "$l" ) ; print $l' # ( # a=1 # b=BE # ) # ( ) # -- snip -- # The first bracket pair is Ok since it's coming from $ print "$l" # , however the 2nd pair comes from the print $l _outside_ the subshell where the variable "l" should no longer exist. # # Workaround: # Force ksh93 to call |fork()| for the matching subshell using $ ulimit -c #, e.g. ... # -- snip -- # $ ksh93 -c 'unset l ; ( ulimit -c 0 ; l=( a=1 b="BE" ) ; print "$l" ) ; print $l' # ( # a=1 # b=BE # ) # -- snip -- # ... provides the correct output. # # test setup 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 var1 var2 # use unset, l=() compound syntax and print var1="$(${SHELL} -c 'unset l ; ( l=( a=1 b="BE" ) ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; l=( a=1 b="BE" ) ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # do not use unset, l=() compound syntax and print var1="$(${SHELL} -c '( l=( a=1 b="BE" ) ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." var2="$(${SHELL} -c '( ulimit -c 0 ; l=( a=1 b="BE" ) ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (without unset)." # use unset, typeset -C compound syntax and print var1="$(${SHELL} -c 'unset l ; ( compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # do not use unset, typeset -C compound syntax and print var1="$(${SHELL} -c '( compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." var2="$(${SHELL} -c '( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; print "$l" ) ; print $l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # use unset, l=() compound syntax and printf "%B\n" var1="$(${SHELL} -c 'unset l ; ( l=( a=1 b="BE" ) ; printf "%B\n" l ) ; printf "%B\n" l')" || err_exit "Non-zero exit code." var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; l=( a=1 b="BE" ) ; printf "%B\n" l ) ; printf "%B\n" l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # do not use unset, l=() compound syntax and printf "%B\n" var1="$(${SHELL} -c '( l=( a=1 b="BE" ) ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." var2="$(${SHELL} -c '( ulimit -c 0 ; l=( a=1 b="BE" ) ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (without unset)." # use unset, typeset -C compound syntax and printf "%B\n" var1="$(${SHELL} -c 'unset l ; ( compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." var2="$(${SHELL} -c 'unset l ; ( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # do not use unset, typeset -C compound syntax and printf "%B\n" var1="$(${SHELL} -c '( compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." var2="$(${SHELL} -c '( ulimit -c 0 ; compound l ; l.a=1 ; l.b="BE" ; printf "%B\n" l) ; printf "%B\n" l')" || err_exit "Non-zero exit code." [[ "${var1}" == "${var2}" ]] || err_exit "Non-fork()'ed subshell output differes from fork()'ed subshell output (with unset)." # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether ksh93 (like ksh88) generates calls a # CHLD/SIGCHLD trap for background jobs and _not_ for foreground jobs. # # This was reported as CR #6722134 ("*ksh93* (20080624_snapshot) # doesn't execute CHLD trap"): # -- snip -- # With "set -o monitor" on and "set -o notify" off, ksh88 executes the CHLD # trap while waiting for interactive input when a background job completes. # ksh93 appears not to execute the CHLD trap when a background job terminates. # Probably related: I noticed that with no CHLD trap set, but -o monitor and # -o notify set, there should be a similar asynchronous job completion notice. # It works in ksh88 but not in this ksh93 build. # -- snip -- # # test setup 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 ## ## test one: ## s="$($SHELL -c ' set -o errexit integer i trap "print got_child" SIGCHLD sleep 5 & sleep 7 & for ((i=0 ; i < 15 ; i++)) ; do print $i sleep 1 # external, non-background command for which a SIGCHLD should # _not_ be fired /bin/true >/dev/null done print "loop finished" wait print "done" ' 2>&1 )" || err_exit "test loop failed." [[ "$s" == ~(Er)$'14\nloop finished\ndone' ]] || err_exit "Expected '14\nloop finished\ndone' at the end of the output, got ${s}." [[ "$s" == ~(El)$'0\n1\n2' ]] || err_exit "Expected '0\n1\n2' as at the beginning of the output, got ${s}." integer count (( count=$(fgrep "got_child" <<< "$s" | wc -l) )) || err_exit "counting failed." (( count == 2 )) || err_exit "Expected count==2, got count==${count}." ## ## test two: ## (same as test "one" except that this test has one more "sleep" child) ## s="$($SHELL -c ' set -o errexit integer i trap "print got_child" SIGCHLD sleep 5 & sleep 7 & sleep 9 & for ((i=0 ; i < 15 ; i++)) ; do print $i sleep 1 # external, non-background command for which a SIGCHLD should # _not_ be fired /bin/true >/dev/null done print "loop finished" wait print "done" ' 2>&1 )" || err_exit "test loop failed." [[ "$s" == ~(Er)$'14\nloop finished\ndone' ]] || err_exit "Expected '14\nloop finished\ndone' at the end of the output, got ${s}." [[ "$s" == ~(El)$'0\n1\n2' ]] || err_exit "Expected '0\n1\n2' as at the beginning of the output, got ${s}." (( count=$(fgrep "got_child" <<< "$s" | wc -l) )) || err_exit "counting failed." (( count == 3 )) || err_exit "Expected count==3, got count==${count}." # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # Test whether CR #6753538 ("umask modification leaks out of a ksh93 # subshell") has been fixed. # # Quote from CR #6753538: # -- snip -- # I discovered that Solaris 11's /bin/sh exhibits the following # surprising behavior: # # $ /bin/sh -c 'umask 22; (umask 0); umask' # 0000 # # All other shells I tried print 22. # -- snip -- # test setup 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 # # test set 1: Simple umask in subshell # x=$(${SHELL} -c 'umask 22; (umask 0); umask') [[ "$x" == "0022" ]] || err_exit "expected umask 0022, got $x" x=$(${SHELL} -c 'umask 20; (umask 0); umask') [[ "$x" == "0020" ]] || err_exit "expected umask 0020, got $x" x=$(${SHELL} -c 'umask 0; (umask 22); umask') [[ "$x" == "0000" ]] || err_exit "expected umask 0000, got $x" # # test set 2: Simple umask in two subshells # x=$(${SHELL} -c 'umask 22; ( (umask 10); umask 0); umask') [[ "$x" == "0022" ]] || err_exit "expected umask 0022, got $x" x=$(${SHELL} -c 'umask 20; ( (umask 10); umask 0); umask') [[ "$x" == "0020" ]] || err_exit "expected umas k 0020, got $x" x=$(${SHELL} -c 'umask 0; ( (umask 10); umask 22); umask') [[ "$x" == "0000" ]] || err_exit "expected umask 0000, got $x" # # test set 3: Compare normal subshell vs. subshell in seperate process # ($ ulimit -c 0 # forced the subshell to |fork()| # x=$(${SHELL} -c 'umask 22; ( umask 0); umask') || err_exit "shell failed." y=$(${SHELL} -c 'umask 22; (ulimit -c 0 ; umask 0); umask') || err_exit "shell failed." [[ "$x" == "$y" ]] || err_exit "$x != $y" x=$(${SHELL} -c 'umask 20; ( umask 0); umask') || err_exit "shell failed." y=$(${SHELL} -c 'umask 20; (ulimit -c 0 ; umask 0); umask') || err_exit "shell failed." [[ "$x" == "$y" ]] || err_exit "$x != $y" x=$(${SHELL} -c 'umask 0; ( umask 20); umask') || err_exit "shell failed." y=$(${SHELL} -c 'umask 0; (ulimit -c 0 ; umask 20); umask') || err_exit "shell failed." [[ "$x" == "$y" ]] || err_exit "$x != $y" # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # Test whether CR #6754020 ("ksh93 does weird '[' expansion") has # been fixed. # # Quote from CR #6754020: # ---- snip ---- # The problem is that subprocess uses /bin/sh as the shell when it # spins off the process. As Brad demonstrated: # /bin/sh -c 'echo F[[O]' # F[[O][ # # In short, this bug only appears when run through the test suite, # or by people running /bin/sh who don't understand how their shell # treats special characters. # -- snip -- # # In this case ksh93 has a bug which causes "F[[O]" to be expanded # in a wrong way. # ---- snip ---- # test setup 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 s # test using "echo" s="$(${SHELL} -c 'echo F[[O]')" [[ "$s" == 'F[[O]' ]] || err_exit "Expected 'F[[O]', got $s" s="$(${SHELL} -c 'echo F[[[O]]')" [[ "$s" == 'F[[[O]]' ]] || err_exit "Expected 'F[[[O]]', got $s" # test using "print" s="$(${SHELL} -c 'print F[[O]')" [[ "$s" == 'F[[O]' ]] || err_exit "Expected 'F[[O]', got $s" s="$(${SHELL} -c 'print F[[[O]]')" [[ "$s" == 'F[[[O]]' ]] || err_exit "Expected 'F[[[O]]', got $s" # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # Test whether CR #6763594 ('ksh93 executes command after "command" # builtin twice on failure') has been fixed. # # Quote from CR #6763594: # ---- snip ---- # ksh93 has a bug which causes shell to execute the command after the # "command" builtin to be executed twice if "command" fails: # -- snip -- # $ ksh93 -x -c 'print "true" >myfoo ; chmod a+x,a-r myfoo ; command ./myfoo ; # print $?' # + print true # + 1> myfoo # + chmod a+x,a-r myfoo # + command ./myfoo # ksh93[1]: ./myfoo: ./myfoo: cannot open [Permission denied] # + print 1 # 1 # + print 0 # 0 # -- snip -- # The "print" command at the end is executed twice in this case since # the shell jumps to the wrong position in the execution sequence. # # The correct output should be: # -- snip -- # $ ksh93 -x -c 'print "true" >myfoo ; chmod a+x,a-r myfoo ; command ./myfoo ; # print $?' # + print true # + 1> myfoo # + chmod a+x,a-r myfoo # + command ./myfoo # ksh93[1]: ./myfoo: ./myfoo: cannot open [Permission denied] # + print 1 # 1 # -- snip -- # ---- snip ---- # test setup 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 testtmpdir=/tmp/ksh93_test_cr_6763594_${PPID}_$$ mkdir "${testtmpdir}" || { err_exit "Could not create temporary directory ${testtmpdir}." ; exit ${Errors} ; } cd "${testtmpdir}" || { err_exit "Cannot cd to temporary directory ${testtmpdir}." ; exit ${Errors} ; } typeset s ${SHELL} -c 'print "true" >myfoo ; chmod a+x,a-r myfoo ; command ./myfoo ; print $?' 1>out_stdout 2>out_stderr (( $? == 0 )) || err_exit "Return code $?, expected 0" s=$( < out_stdout ) ; [[ "$s" == '126' ]] || err_exit "Expected '126', got $(printf "%q\n" "$s")." s=$( < out_stderr ) ; [[ "$s" == ~(Elr)(.*:\ \./myfoo:\ \./myfoo:\ .*\[.*\]) ]] || err_exit "Output $(printf "%q\n" "$s") does not match pattern '~(Elr)(.*:\ \./myfoo:\ \./myfoo:\ .*\[.*\])'." rm "myfoo" "out_stdout" "out_stderr" || err_exit "rm failed." cd .. rmdir "${testtmpdir}" || err_exit "Failed to remove temporary directory ${testtmpdir}." # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # Test whether CR #6766246 ("bug in pattern matching") has been fixed. # # Quote from CR #6766246: # ---- snip ---- # The bootstrap script of pkgsrc contains this code # checkarg_sane_absolute_path() { # case "$1" in # "") ;; # the default value will be used. # *[!-A-Za-z0-9_./]*) # die "ERROR: Invalid characters in path $1 (from $2)." ;; # /*) ;; # *) die "ERROR: The argument to $2 must be an absolute path." ;; # esac # } # It turns out, the leading "!" in the pattern is not interpreted # as negation, and the first "-" not as a literal. Instead the # character range "! to A" is constructed. Paths containing "%" # or "@" are accepted, but paths containing "-" are rejected. # Note that this interpretation makes the whole pattern # syntactically wrong, which isn't noticed either. # # Test case: # -- snip -- # !/bin/sh # case "$1" in # *[!-A-Za-z0-9_./]*) # echo invalid characters used in $1 # ;; # *) # echo only valid characters used in $1 # ;; # esac # -- snip -- # Expected Result: # strings containing a "-" should be accepted, strings containing # a "@" should be rejected # Actual Result: # strings containing a "-" are rejected, strings containing a # "@" are accepted # Workaround # The pattern "*[!A-Za-z0-9_./-]*" (i.e. shifting the dash to # the end) works as expected. # ---- snip ---- # test setup 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 ## test 1 (based on the bug report): function do_match { case "$1" in *[!-A-Za-z0-9_./]*) print "match" ;; *) print "nomatch" ;; esac return 0 } typeset pat pat="foo-bar" ; [[ "$(do_match "${pat}")" == "nomatch" ]] || err_exit "${pat} matched." pat="foo+bar" ; [[ "$(do_match "${pat}")" == "match" ]] || err_exit "${pat} not matched." pat="foo/bar" ; [[ "$(do_match "${pat}")" == "nomatch" ]] || err_exit "${pat} matched." pat="foo_bar" ; [[ "$(do_match "${pat}")" == "nomatch" ]] || err_exit "${pat} matched." pat="foo@bar" ; [[ "$(do_match "${pat}")" == "match" ]] || err_exit "${pat} not matched." pat="foobar-" ; [[ "$(do_match "${pat}")" == "nomatch" ]] || err_exit "${pat} matched." pat="foobar+" ; [[ "$(do_match "${pat}")" == "match" ]] || err_exit "${pat} not matched." pat="foobar/" ; [[ "$(do_match "${pat}")" == "nomatch" ]] || err_exit "${pat} matched." pat="foobar_" ; [[ "$(do_match "${pat}")" == "nomatch" ]] || err_exit "${pat} matched." pat="foobar@" ; [[ "$(do_match "${pat}")" == "match" ]] || err_exit "${pat} not matched." pat="-foobar" ; [[ "$(do_match "${pat}")" == "nomatch" ]] || err_exit "${pat} matched." pat="+foobar" ; [[ "$(do_match "${pat}")" == "match" ]] || err_exit "${pat} not matched." pat="/foobar" ; [[ "$(do_match "${pat}")" == "nomatch" ]] || err_exit "${pat} matched." pat="_foobar" ; [[ "$(do_match "${pat}")" == "nomatch" ]] || err_exit "${pat} matched." pat="@foobar" ; [[ "$(do_match "${pat}")" == "match" ]] || err_exit "${pat} not matched." ## test 2 (gsf's test chain): # Make sure LC_COLLATE has a value if [[ ! -v LC_COLLATE ]] ; then if [[ -v LANG && ! -v LC_ALL ]]; then LC_COLLATE="${LANG}" fi fi if [[ -v LC_ALL ]] ; then LC_COLLATE="${LC_ALL}" fi [[ -v LC_COLLATE ]] || LC_COLLATE=C 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 # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether ksh93 supports more than 256 recursive # function+command substitution calls. # # This was reported as CR #6769332 ('Recursive function+command # substitutions terminate shell after 257 iterations'): # ------------ snip ------------ # Recursive function+command substitutions # (e.g. func1() { x=$( func2 ) ; } ; x=$( func1 ) ) terminate the # ksh93 shell after 257 iterations with a exit code of "0" (it # seems the shell just "quits" after the last "return 0" statement # in the function). # Running the attached testcase terminates the shell after 257 # iterations (g=257 in the script) while 256 iterations (replace # "257" with "256" in the script) just works fine. # The same testcase works Ok in ksh88 (=/usr/bin/ksh in # Solaris 10U5) # # Expected Result # The script should output "done" and return the exit code 0. # # Actual Result # No messsge. Exit code "0". # # Error Message(s) # None (exit code is "0"). # # Test Case # f1() # { # h=$1 # (( h=h-1 )) # (( h <= 0 )) && return 0 # x=$(f1 "$h" "$l" "$g" d e "$l") || print -u2 "$g/$h: fail" # return 0 # } # l="" # g=257 # i=0 # while (( i < $g )) ; do # l="${l}x" # (( i=i+1 )) # done # f1 "$g" "$l" "$g" d e "$l" || print -u2 "$g: fail0" # print "done" # exit 0 # # Workaround # - # ------------ snip ------------ # # test setup 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 # # test1: Testcase from CR #6769332 # ( cat <&1 )" || err_exit "test $i: returned non-zero exit code $?" [[ "${str}" == "OK" ]] || err_exit "test $i: expected 'OK', got '${str}'" done # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether ksh93 supports traps for the SIGTHAW # signal. # # This was reported as CR #6778077 ("*ksh93* does not understand "THAW" # as a signal for use with trap"): # -- snip -- # While ksh93 understand THAW in the list of signals for kill it does # not understand it for "trap' # # : pod5.eu TS 6 $; kill -l | egrep '(THAW|FREEZE)' # FREEZE # THAW # : pod5.eu TS 7 $; trap "echo THAW" THAW # ksh93: trap: THAW: bad trap # : pod5.eu TS 8 $; # # Using the signal number (35) works around this. # -- snip -- # # test setup 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 ## test one: Check whether the shell supports SIGTHAW as trap ${SHELL} -o errexit -c 'trap "true" SIGTHAW ; true' || err_exit "SIGTHAW not supported." ${SHELL} -o errexit -c 'trap "true" THAW ; true' || err_exit "THAW not supported." ${SHELL} -o errexit -c 'trap "true" 35 ; true' || err_exit "signal 35 not supported." ## test two: Check whether the shell supports SIGFREEZE as trap ## (we check this since it is SIGTHAW's counterpart) ${SHELL} -o errexit -c 'trap "true" SIGFREEZE ; true' || err_exit "SIGFREEZE not supported." ${SHELL} -o errexit -c 'trap "true" FREEZE ; true' || err_exit "FREEZE not supported." ${SHELL} -o errexit -c 'trap "true" 34 ; true' || err_exit "signal 34 not supported." ## test three: Check all other signals listed by "kill -l" kill -l | while read i ; do str="$( ${SHELL} -c "trap true $i ; print 'ok'" 2>&1 )" || err_exit "shell returned code $? for trap $i" [[ "${str}" == "ok" ]] || err_exit "expected 'ok', got $str" done # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether arithmetric math correctly supports # negative zero values # # This was reported as CR #6789247 ("libast/ksh93 1-digit hexfloat base conversion rounds incorrectly"): # ---- snip ---- # Description # [The same issue was described in http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2008-December/006737.html] # This is basically a spin-off of http://bugs.opensolaris.org/view_bug.do?bug_id=6773712 ("1-digit hex fp # base conversion of long double rounds incorrectly"). # The bug description for Solaris libc says this: # > The first line of output from this program is correct. The second line # > is not. # > # > leviathan% cat a.c # > #include # > # > int main() # > { # > printf("%.0a\n", 1.5); # > printf("%.0La\n", 1.5L); # > return 0; # > } # > leviathan% cc -o a a.c # > leviathan% a # > 0x1p+1 # > 0x1p+0 # > leviathan% # If I compile the testcase with libast on Solaris 11/B84 SPARC (which # matches ast-open.2008-11-04) I get this: # -- snip -- # $ cc -xc99=%all -I/usr/include/ast -last a.c -o a && # ./a # 0x1p+00 # 0x1p+00 # -- snip -- # ... which seems to be incorrect per the bugs comment above and should # be: # -- snip -- # 0x1p+1 # 0x1p+1 # -- snip -- # ksh93 has the same problem: # $ ksh93 -c 'float r=1.5 ; printf "%.0a\n" r' # 0x1p+00 # Steps to Reproduce # Compile and run testcase like this: # -- snip -- # $ cc -xc99=%all -I/usr/include/ast -last a.c -o a && # ./a # -- snip -- # Expected Result # 0x1p+1 # 0x1p+1 # Actual Result # 0x1p+00 # 0x1p+00 # ---- snip ---- # # test setup 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 float r float result typeset str # Test #001/a - check whether the result of a rounded 1.5 is 2.0 r=1.5 result=$(printf "%.0a\n" r) || err_exit "printf returned non-zero exit code" (( result == 2.0 )) || err_exit "result expected to be 2.0, got ${result}" # Test #001/b - same as test #001/a but uses "%.0A\n" instead of "%.0a\n" r=1.5 result=$(printf "%.0A\n" r) || err_exit "printf returned non-zero exit code" (( result == 2.0 )) || err_exit "result expected to be 2.0, got ${result}" # Test #002/a - check whether the hexfloat string value matches the expected pattern r=1.5 str=$(printf "%.0a\n" r) || err_exit "printf returned non-zero exit code" [[ "${str}" == ~(Glri)0x0*1p\+0*1 ]] || err_exit "str expected to match ~(Glri)0x0*1p\+0*1, got |${str}|" # Test #002/b - same as test #002/a but uses "%.0A\n" instead of "%.0a\n" r=1.5 str=$(printf "%.0A\n" r) || err_exit "printf returned non-zero exit code" [[ "${str}" == ~(Glri)0x0*1p\+0*1 ]] || err_exit "str expected to match ~(Glri)0x0*1p\+0*1, got |${str}|" # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # Test whether CR #6800929 ("snv_106 ksh93 update breaks Install(1M)") has been fixed. # # Quote from CR #6800929: # ---- snip ---- # so i just upgraded this morning from snv_105 to snv_106. now # Install(1M) is hanging whenever i run it. i'm running it as follows: # Install -o debug -k i86xpv -T domu-219:/tmp # # and here's where it's hung: # ---8<--- # Edward Pilatowicz # $ pstack 204600 # 204600: /bin/ksh /opt/onbld/bin/Install -o debug -k i86xpv -T domu-219:/tmp # fffffd7fff2e3d1a write (1, 4154c0, 64) # fffffd7ffefdafc8 sfwr () + 2d0 # fffffd7ffefc0f6f _sfflsbuf () + 217 # fffffd7ffefcb9f7 sfsync () + 17f # fffffd7ffefc5c58 _sfphead () + 188 # fffffd7ffefc5ef5 _sfpmove () + 55 # fffffd7ffefc2595 _sfmode () + 22d # fffffd7ffefc5fb1 sfpool () + 99 # fffffd7fff15eb8e sh_exec () + 2f56 # fffffd7fff15f78c sh_exec () + 3b54 # fffffd7fff15d9c8 sh_exec () + 1d90 # fffffd7fff15788e sh_subshell () + 646 # fffffd7fff134562 comsubst () + 8a2 # fffffd7fff12f61f copyto () + bcf # fffffd7fff12df79 sh_macexpand () + 1f1 # fffffd7fff1129f5 arg_expand () + a5 # fffffd7fff112812 sh_argbuild () + 9a # fffffd7fff15dbe2 sh_exec () + 1faa # fffffd7fff15d854 sh_exec () + 1c1c # fffffd7fff0f22ef b_dot_cmd () + 507 # fffffd7fff161559 sh_funct () + 199 # fffffd7fff15ef35 sh_exec () + 32fd # fffffd7fff136e86 exfile () + 786 # fffffd7fff136676 sh_main () + 7fe # 0000000000400e72 main () + 52 # 0000000000400ccc ???? # ---8<--- # # there is only one place where Install(1M) invokes "uniq": # set -- `grep "^CONF" $modlist | sort | uniq`; # # as it turns out, i can easily reproduce this problem as follows: # ---8<--- # $ ksh93 # $ set -- `cat /etc/termcap | sort | uniq` # # ---8<--- # ---- snip ---- # test setup 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 # common functions/variables function isvalidpid { kill -0 ${1} 2>/dev/null && return 0 return 1 } integer testfilesize i maxwait typeset tmpfile integer testid # test 1: run loop and check various temp filesizes tmpfile="$(mktemp -t "sun_solaris_cr_6800929_large_command_substitution_hang.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file." compound -a testcases=( # test 1a: Run test child for $(...) # (note the pipe chain has to end in a builtin command, an external command may not trigger the bug) ( name="test1a" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) # test 1b: Same as test1a but uses ${... ; } instead if $(...) ( name="test1b" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) # test 1c: Same as test1a but does not use a pipe ( name="test1c" cmd="builtin cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) # test 1d: Same as test1a but does not use a pipe ( name="test1d" cmd="builtin cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) # test 1e: Same as test1a but uses an external "cat" command ( name="test1e" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" | cat)\" ; true" ) # test 1f: Same as test1a but uses an external "cat" command ( name="test1f" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" | cat ; }\" ; true" ) # test 1g: Same as test1a but uses an external "cat" command ( name="test1g" cmd="builtin -d cat /bin/cat ; print -- \"\$(cat \"${tmpfile}\" ; true)\" ; true" ) # test 1h: Same as test1a but uses an external "cat" command ( name="test1h" cmd="builtin -d cat /bin/cat ; print -- \"\${ cat \"${tmpfile}\" ; true ; }\" ; true" ) ) for (( testfilesize=1*1024 ; testfilesize <= 1024*1024 ; testfilesize*=2 )) ; do # Create temp file { for (( i=0 ; i < testfilesize ; i+=64 )) ; do print "0123456789abcdef01234567890ABCDEF0123456789abcdef01234567890ABCDE" done } >"${tmpfile}" # wait up to log2(i) seconds for the child to terminate # (this is 10 seconds for 1KB and 19 seconds for 512KB) (( maxwait=log2(testfilesize) )) for testid in "${!testcases[@]}" ; do nameref currtst=testcases[testid] ${SHELL} -o errexit -c "${currtst.cmd}" >"${tmpfile}.out" & (( childpid=$! )) for (( i=0 ; i < maxwait ; i++ )) ; do isvalidpid ${childpid} || break sleep 0.25 done if isvalidpid ${childpid} ; then err_exit "${currtst.name}: child (pid=${childpid}) still busy, filesize=${testfilesize}." kill -KILL ${childpid} 2>/dev/null fi wait || err_exit "${currtst.name}: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) # compare input/output cmp -s "${tmpfile}" "${tmpfile}.out" || err_exit "${currtst.name}: ${tmpfile} and ${tmpfile}.out differ, filesize=${testfilesize}." rm "${tmpfile}.out" done # Cleanup rm "${tmpfile}" done # test 2a: Edward Pilatowicz 's Solaris-specific testcase ${SHELL} -o errexit -c 'builtin uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null & (( childpid=$! )) sleep 5 if isvalidpid ${childpid} ; then err_exit "test2a: child (pid=${childpid}) still busy." kill -KILL ${childpid} 2>/dev/null fi wait || err_exit "test2a: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) # test 2b: Same as test 2a but uses ${... ; } instead of $(...) ${SHELL} -o errexit -c 'builtin uniq ; set -- ${ cat /etc/termcap | sort | uniq ; } ; true' >/dev/null & (( childpid=$! )) sleep 5 if isvalidpid ${childpid} ; then err_exit "test2b: child (pid=${childpid}) still busy." kill -KILL ${childpid} 2>/dev/null fi wait || err_exit "test2b: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) # test 2c: Same as test 2a but makes sure that "uniq" is not a builtin ${SHELL} -o errexit -c 'builtin -d uniq /bin/uniq ; set -- `cat /etc/termcap | sort | uniq` ; true' >/dev/null & (( childpid=$! )) sleep 5 if isvalidpid ${childpid} ; then err_exit "test2c: child (pid=${childpid}) still busy." kill -KILL ${childpid} 2>/dev/null fi wait || err_exit "test2c: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) # test 2d: Same as test 2c but uses ${... ; } instead of $(...) ${SHELL} -o errexit -c 'builtin -d uniq /bin/uniq ; set -- ${ cat /etc/termcap | sort | uniq ; } ; true' >/dev/null & (( childpid=$! )) sleep 5 if isvalidpid ${childpid} ; then err_exit "test2d: child (pid=${childpid}) still busy." kill -KILL ${childpid} 2>/dev/null fi wait || err_exit "test2d: Child returned non-zero exit code." # wait for child (and/or avoid zombies/slime) # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether "typeset -m" correctly moves local variables # into a global variable tree. # # This was reported as CR #6805792 ("XXXX"): # -------- snip -------- # The following attempt to move a local node into an associative array # fails like this: # -- snip -- # 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 # # return 0 # } # f1 tree # printf "%B\n" tree # print "ok" # exit 0 # -- snip -- # The output looks like this: # -- snip -- # $ ksh93 # varmovetest1.sh # ( # ( # ) # ok # -- snip -- # ... but AFAIK it should print: # -- snip -- # ( # typeset -A subtree=( # [a_node]=( # one=hello # two=world # ) # ) # ) # ok # -- snip -- # -------- snip -------- # # test setup 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 ## test start compound 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 compound node node.one="dummy1" node.two="dummy2" # We use the nameref's here since ast-ksh,2008-12-12 crashes # when this function returns because "nodeone" and "nodetwo" # still reference "node" which was renamed. # (note that "f1" must be first function and the first being # called, otherwise the crash will not occur) nameref nodeone=node.one nameref nodetwo=node.two nodeone="hello" nodetwo="world" # move local note into the array 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'"$(diff -u <( printf '%B\n' tree1 ) <( printf '%B\n' tree2 ) )" # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether arithmetric operator ' # is working # # This was reported as CR #6805794 ('[ku1] printf returns "invalid character constant" for $ printf "%d\n" "'"'): # ------------ snip ------------ # There seems be a bug in how ast-ksh.2008-11-04's "printf" builtin # handles multibyte characters. For example if I try this in the # en_US.UTF-8 locale ("" needs to be replace with the EURO symbol): # -- snip -- # $ printf "%d\n" "'" # -ksh93: printf: warning: ': invalid character constant # 226 # -- snip -- # AFAIK the correct behaviour was to return the numeric value of the # symbol in this case (hexadecimal "20ac", decimal 8364), e.g. # -- snip -- # $ printf "%d\n" # "'" # 8364 # -- snip -- # Frequency # Always # Regression # No # Steps to Reproduce # Enter this in an interractive shell: # $ printf "%d\n" "'" # Expected Result # -- snip -- # $ printf "%d\n" # "'" # 8364 # -- snip -- # Actual Result # -- snip -- # $ printf "%d\n" "'" # -ksh93: printf: warning: ': invalid character constant # 226 # -- snip -- # Error Message(s) # printf: warning: ': invalid character constant # Test Case # printf "%d\n" "'" # Workaround # None. # ------------ snip ------------ # # test setup 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 # declare variables typeset str # test whether the locale uses an UTF-8 (-like) encoding and override it on demand [[ "$(printf "\u[20ac]")" == $'\342\202\254' ]] || LC_ALL=en_US.UTF-8 if [[ "$(printf "\u[20ac]")" != $'\342\202\254' ]] ; then err_exit "Local overrride failed." exit $((Errors)) fi # run test str=$(print $'printf "%d\\\\n" "\'\342\202\254"' | source /dev/stdin) [[ "${str}" == "8364" ]] || err_exit "expected 8364, got ${str}" # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether arithmetric math correctly supports # negative zero values # # This was reported as CR #6805795 ("[ku1] ksh93 does not differ between -0 and +0"): # ------------ snip ------------ # Original bug report was: # ------ snip ------ # Is there a reason why ksh93 does not display the negative sign for the # value zero ? For example if I have use the C99 function "copysign" # (copies absolute value of operant a and sign of operant b) I get this # for { a=5, b=-0 }: # -- snip -- # $ ksh93 -c 'float x; (( x=copysign(5, -0) )) ; printf "%f\n" # x' # -5.000000 # -- snip -- # Now if I swap operands a and b I get this result: # -- snip -- # $ ksh93 -c 'float x; (( x=copysign(0, -5) )) ; printf "%f\n" x' # 0.000000 # -- snip -- # AFAIK this result should be "-0.000000" ... or not ? # BTW: Parsing of "-0" doesn't seem to work either, e.g. # -- snip -- # $ ksh93 -c 'float x a=-1 b=-0; (( x=copysign(a, b) )) ; printf "%f\n" # x' # 1.000000 # -- snip -- # ... while AFAIK it should be "-1.000000" since the 2nd operand of # "copysign" defines the sign of the result. # ------ snip ------ # ------------ snip ------------ # # test setup 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 str # test 1: test "copysign()" using constant values str=$( set -o errexit print -- $(( copysign(0, -5) )) ) || err_exit "test failed." [[ "${str}" == "-0" ]] || err_exit "Expected copysign(0, -5) == -0, got ${str}" # test 2: Same as test 1 but using variables for the values str=$( set -o errexit float a float b float c a=0. b=-5. (( c=copysign(a, b) )) print -- "$c" ) || err_exit "test failed." [[ "${str}" == "-0" ]] || err_exit "Expected c == -0, got ${str}" # test 3: test "signbit()" str=$( set -o errexit float a a=-0. print -- $(( signbit(a) )) ) || err_exit "test failed." [[ "${str}" == "1" ]] || err_exit "Expected signbit(a, b) == 1, got ${str}" # test 4: test "signbit()" str=$( set -o errexit float a float c a=-0. (( c=signbit(a) )) print -- "$c" ) || err_exit "test failed." [[ "${str}" == "1" ]] || err_exit "Expected c == 1, got ${str}" # test 5: test whether "typeset -X" (C99 "hexfloat") correctly recognizes # negative zero assigned from a "float" str=$( set -o errexit float a # float typeset -X c # hexfloat a=-0. # copy value from "float" to "hexfloat" (( c=a )) print -- "$c" ) || err_exit "test failed." [[ "${str}" == -0x* ]] || err_exit "Expected c == -0x*, got ${str}" # test 6: Reverse of test 5: Test whether "float" correctly recognizes # a C99 "hexfloat" value str=$( set -o errexit typeset -X a # hexfloat float c # float a=-0x0.0000000000000000000000000000p+00 # copy value from "hexfloat" to "float" (( c=a )) print -- "$c" ) || err_exit "test failed." [[ "${str}" == "-0" ]] || err_exit "Expected c == -0, got ${str}" # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether ksh93 does unneccesaty |libc::getpwnam()| # calls for "~(modifer)pattern"-style shell patterns # # This was reported as CR #6807179 ("ksh93 does unneccesary |libc::getpwnam()| lookups for ~(modifier) pattern patterns"): # ------------ snip ------------ # ksh93 does unneccesary |libc::getpwnam()| lookups for # ~(modifer)pattern patterns, e.g. [[ $foo == ~(E)hello.*world ]]. # The problem is that the shell ~(modifer)pattern is an extended # pattern syntax which allows to specify a "modifer" to change # the behaviour for "pattern". However the '~' at the beginning # of this string is causing a tilde expansion (or better: It's # filling an internal buffer as preparation for tilde expansion # and this code calls |libc::getpwnam()|) which shouldn't be # done in this case. # [1]=For example the "modifer" allows to specifcy "perl", # "fgrep", "grep", "egrep", "POSIX shell", "korn shell" and # other types of pattern matching systems (or select stuff # like archors, case-insensitive matching etc. etc.). # ------------ snip ------------ # # test setup 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 tmpfile tmpfile="$(mktemp -t "sun_solaris_cr_6807179_shellpattern_uses_getpwnam.${PPID}.$$.XXXXXX")" || err_exit "Cannot create temporary file." rm -f "${tmpfile}" # test 1: Check if the shell uses |libc::getpwnam()| for pattern "~(Elr)wo.*ld" truss -u :: -o "${tmpfile}" ${SHELL} -c '[[ ${hello} == ~(Elr)wo.*ld ]] ; true' || err_exit "truss returned failure=$?" [[ "$( < "${tmpfile}")" != *getpwnam* ]] || err_exit "truss log reports the use of getpwnam() for pattern ~(Elr)wo.*ld" rm "${tmpfile}" || err_exit "rm ${tmpfile} failed." # test 2: Check if the shell uses |libc::getpwnam()| for pattern "~(Si)wo*ld" truss -u :: -o "${tmpfile}" ${SHELL} -c '[[ ${hello} == ~(Si)wo*ld ]] ; true' || err_exit "truss returned failure=$?" [[ "$( < "${tmpfile}")" != *getpwnam* ]] || err_exit "truss log reports the use of getpwnam() for pattern ~(Si)wo*ld" rm "${tmpfile}" || err_exit "rm ${tmpfile} failed." # test 3: Same as test 1 but uses ~root/ as pattern which will force the use of |libc::getpwnam()| getent passwd root >/dev/null || err_exit "getent passwd root failed" # safeguard to make sure we get a warning if user root is missing truss -u :: -o "${tmpfile}" ${SHELL} -c '[[ ${hello} == ~root/ ]] ; true' || err_exit "truss returned failure=$?" [[ "$( < "${tmpfile}" )" == *getpwnam* ]] || err_exit "truss log reports the use of getpwnam() for pattern ~root/" rm "${tmpfile}" || err_exit "rm ${tmpfile} failed." # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether ksh93's builtin "cat" command properly # supports the "-n" option. # # This was reported as CR #6835835 ('ksh93 "cat" builtin does not handle "-n" correctly'): # ------------ snip ------------ # [Originally reported in # http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2009-February/007050.html # by Casper Dik] # -- snip -- # I just noticed this in ksh93: # ksh93 -c 'yes "" | head -5|cat -n' # 1 # 2 # 3 # 4 # (I used this for older shells when I want to a list of all integers from 1 # to a particular number) # -- snip -- # Frequency # Always # Regression # No # Steps to Reproduce # Execute $ ksh93 -c 'yes "" | head -5|cat -n' # # Expected Result # 1 # 2 # 3 # 4 # 5 # Actual Result # # # 1 # 2 # # 3 # # 4 # Error Message(s) # None. # Test Case # See description. # Workaround # Disable ksh93's builtin "cat" command either via using an absolute path # to the "cat" command (POSIX-style workaround) or using ksh93's # "builtin" command to remove "cat" from the list of builtin # commands (e.g. $ builtin -d /bin/cat /bin/cat #). # ------------ snip ------------ # # test setup 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 # # test 1: Compare output of various "cat -n" combinations # integer i typeset expected_output typeset out expected_output=$( ${SHELL} -c 'for ((i=1 ; i <= 12 ; i++ )) ; do printf "%6d\t\n" i ; done' ) compound -a testcases=( # note: we have to add an extra /bin/cat at the end of the pipe to make # sure the "cat" builtin uses the correct buffering mode to trigger # the error and a "true" to make sure the "cat" command isn't the last command # of the shell ( name="test1a" cmd='integer i ; builtin cat ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | cat -n | /bin/cat ; true' ) # same as "test1a" but uses external "cat" command ( name="test1b" cmd='integer i ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | /bin/cat -n | /bin/cat ; true' ) # same as "test1a" but without the last /bin/cat in the pipe ( name="test1c" cmd='integer i ; builtin cat ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | cat -n ; true' ) # same as "test1b" but without the last /bin/cat in the pipe ( name="test1d" cmd='integer i ; for ((i=1 ; i <= 12 ; i++ )) ; do print ; done | /bin/cat -n ; true' ) ) for testid in "${!testcases[@]}" ; do nameref tc=testcases[${testid}] out="$( ${SHELL} -o errexit -c "${tc.cmd}" )" || err_exit "${tc.name}: Shell failed" [[ "${expected_output}" == "${out}" ]] || err_exit "${tc.name}: Builtin output does not match expected output" out="$( ${SHELL} +o errexit -c "${tc.cmd}" )" || err_exit "${tc.name}: Shell failed" [[ "${expected_output}" == "${out}" ]] || err_exit "${tc.name}: Builtin output does not match expected output" done # # test 2: Casper Dik's original testcase # from http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2009-February/007050.html # cmp -s \ <( ${SHELL} -c 'yes "" | head -5 | cat -n' ) \ <( for ((i=1 ; i <= 5 ; i++ )) ; do printf "%6d\t\n" i ; done ) \ || err_exit 'yes "" | head -5 | cat -n does not match expected output.' # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether ksh93 does not execute builtin command # "foo" when referencing variable "foo" when the variable is not # set (this applies to all builtin commands not bound to a # specific PATH element, e.g. "test", "sleep", "print" etc.). # # This was reported as CR #6848486 ('"echo ${test}" with test # undefined crashes the shell') # ------------ snip ------------ # This is an odd one: # # $ ksh93 --version # version sh (AT&T Research) 93t 2008-11-04 # $ ksh93 # jl138328@gir:~$ echo $test # # jl138328@gir:~$ echo ${test} # Segmentation Fault (core dumped) # ------------ snip ------------ # # The bug originates from the ksh93 "type system" which allows # an application to define it's own types in ksh93. In such cases # the output of function "mytype.len" is used when type "mytype" # has no member variable "len" (note it requires the use of # ${foo} since the use of $foo does not allow "foo" to contain # a dot in the variable name). # The implementation in ast-ksh.2009-11-04 however does this # for _all_ types of variables and not only for those which # are a member of an application-defined type, therefore # causing this bug. # # test setup 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 # Test 1: Test whether the shell crashes when looking for an empty # "shell" variable. # (note: return code 78 was just picked randomly) $SHELL -c 'unset test ; print ${test} ; exit 78' >/dev/null 2>&1 (( $? == 78 )) || err_exit "expected return code is 78, got $?" # Test 2: Test whether the shell can reach a point (which prints # "#mark") after the use of ${test} in the script. out=$($SHELL -o errexit -c 'unset test ; print ${test} ; print "#mark"' 2>&1 ) || err_exit "Shell returned error code $?, expected 0." [[ "$out" == $'\n#mark' ]] || err_exit "Expected output \$'\n#mark', got '${out}'" # Test 3: Check whether the use of ${sleep} returns nothing # (ast-ksh.2008-11-04 will return the usage string of the sleep # builtin) out=$($SHELL -o errexit -c 'print ${sleep} ; print "#mark"' 2>&1 ) || err_exit "Shell returned error code $?, expected 0." [[ "$out" == $'\n#mark' ]] || err_exit "Expected output \$'\n#mark', got '${out}'" # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether arithmetric math correctly # converts a IEEE 754-2008 floating-point value to the C99 hexfloat format # and back _without_ using digits. # # This was reported as CR #6855875 ("typeset -X x ; print $x # does not # print sufficient digits to restore value"): # ------------ snip ------------ # $ typeset -X varname # was added to ksh93 to get a reliable way # (using the C99 "hexfloat" format (see printf(3c)'s "%a" format)) to # serialise a IEEE754-2008 floating-point value to a string and later feed # it back into a application _without_ loosing any precision (normal # base10 floating-point values (e.g. used by $ typeset -E/-F-G #) cause # rounding errors since IEEE754-2008 |long double| uses base2). # However $ typeset -l -X x ; ... ; print $x # currently does not print # sufficient number of digits to restore the full |long double| value as # expected, instead some digits are missing, resulting in an unwanted # rounding. # Example: # -- snip -- # $ ksh93 -c 'typeset -l -X y y_ascii; (( y=sin(90) )) ; y_ascii=$y ; (( y # == y_ascii )) || print "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf # "%a\n" y_ascii)"' # no match, # 0x1.c9b9ee41cb8665c7890a136ace6bp-01 # != # 0x1.c9b9ee41cc000000000000000000p-01 # -- snip -- # Frequency # Always # Regression # No # Steps to Reproduce # [See description] # Expected Result # [See description] # Actual Result # [See description] # Error Message(s) # - # Test Case # typeset -l -X y y_ascii # (( y=sin(90) )) # y_ascii=$y # convert y to string and store it in "y_ascii" # if (( y == y_ascii )) ; then # print "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf "%a\n" # y_ascii)" # fi # Workaround # 1. Manually increase the number of digits via typeset # -X # OR # 2. Use $ printf "%a" varname # # ------------ snip ------------ # # test setup 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 # declare variables typeset str integer i float x float -a test_values typeset -l -X y # hexfloat typeset -l -E y_restored1 typeset -l -F y_restored2 typeset -l -X y_restored3 # create array of test values for (( x=-181. ; x < 361. ; x+=.1 )) ; do test_values+=( x ) done test_values+=( 0 -0 +0 ) # (nan -nan inf -inf) are excluded since nan!=nan is always "true" # run the tests for (( i=0 ; i < ${#test_values[@]} ; i++ )) ; do (( y=sin(test_values[i]) )) # convert floating-point value to string (using the hexfloat format) and store it in "str" str="${y}" # convert it back (via string assignment) y_restored1="${str}" y_restored2="${str}" y_restored3="${str}" (( y == y_restored1 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored1)" (( y == y_restored2 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored2)" (( y == y_restored3 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored3)" # convert it back (using arithmetric expression) (( y_restored1=str )) (( y_restored2=str )) (( y_restored3=str )) (( y == y_restored1 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored1)" (( y == y_restored2 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored2)" (( y == y_restored3 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored3)" # we exit if we get more than 8 errors (126 would be the maximum) (( Errors > 8 )) && exit $((Errors)) done # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether the Solaris kernel can directly execute compiled # shell code. # # This was reported as CR #6862121 ("shbinexec kernel module defunct"): # ------------ snip ------------ # [Originally reported by Sun Japan] # The new shbinexec kernel module added in B106 is defunct, originally # caused by my mismerge of the original development tree and later # because the matching test module didn't test it correctly (April # quickly discovered the problem but the issue drowned in the cleanup # putbacks ). # Frequency # Always # Regression # No # Steps to Reproduce # $ cat test1.sh # print hello # printf "args=%s\n" "$@" # $ shcomp test1.sh test1 # # note: this MUST be bash since ksh93 has special support for compiled shell # # scripts which causes the kernel module to be bypassed (that's why the tes # # never worked) # $ bash -c './test1 "a b" "c" "d"' # Expected Result # hello # args=a a1 # args=b # args=c # Actual Result # ./test1: line 1: a: not found # Error Message(s) # ./test1: line 1: a: not found # Test Case # See above. # ------------ snip ------------ # # test setup 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 ocwd typeset tmpdir typeset out # create temporary test directory ocwd="$PWD" tmpdir="$(mktemp -t -d "test_sun_solaris_cr_6862121_shbinexec_kernel_module_defunct.XXXXXXXX")" || err_exit "Cannot create temporary directory" cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } # run tests { cat <script1.sh # Compile script (note we use the platform's /usr/bin/shcomp, _not_ ${SHCOMP}) /usr/bin/shcomp "script1.sh" "script1" || err_exit "shcomp failed with error=$?" [[ -x "./script1" ]] || err_exit "Script script1 not executable" out="$(/usr/bin/bash -c './script1 a b "c d"' 2>&1 )" || err_exit "Compiled script failed to execute, error=$?" [[ "${out}" == $'hello\nargs=a\nargs=b\nargs=c d' ]] || err_exit "Expected xxx, got $(printf "%q\n" "$out")" # cleanup rm "script1" "script1.sh" cd "${ocwd}" rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether a background process called in a subshell can # cause it to wait for the child process instead of exiting. # # This was reported as CR #6881017 ("Subshell doesn't exit, holds pipe # open preventing callers from exiting"): # ------------ snip ------------ # The following scenario hangs with snv_122, 100% reproducible: # # Create a script hangit: # ----- # #!/bin/ksh # ( sleep 100000 /dev/null 2>&1 & ) # exit 0 # ----- # # Run the following command: # hangit | tee -a /tmp/log # # The hang can be eliminated either by removing the "exit 0" line (?!?), or by # redirecting the subshell output to /dev/null. # # This is pretty nasty. I've whittled it down to this simple case but am seeing # it in a much more subtle and complex environment where there are several # intermediate calling scripts which have exited and eventually the parent pipes # the output and hangs on the open pipe. It was hard to track down. # ------------ snip ------------ # # test setup 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 float tstart tstop tdiff # run test with 10 second timeout (( tstart=SECONDS )) $SHELL -c '( sleep 10 /dev/null 2>&1 & ) ; exit 0' | cat >/dev/null (( tstop=SECONDS )) # we remove two seconds below to make sure we don't run into issues # with smaller xntpd adjustments (( tdiff=tstop-tstart )) (( tdiff < (10.-2.) )) || err_exit "test run needed ${tdiff} seconds to complete (instead of < 8.)" # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether the return code of a child process # is reported properly. # # This was reported as CR #6887363 ("Korn shell 93 sometimes # mishandles return value of its child process"): # ------------ snip ------------ # Following construction sometimes ends with wrong return value. # # 56 echo $op | grep rand 2>&1 >/dev/null # 57 if [ $? = 0 ]; then # 58 randseq="rand${SEED}" # 59 else # 60 randseq="seq" # 61 fi # # Sometimes, the given result is "rand..." even when there is # no "rand" word in $op. This can be demonstrated with # TSufs/SnapShots/Func test case which excercises shown code # quite often. # # As it happens only sometimes, I suppose there is an # race-condition in handling return value from a child process. # ------------ snip ------------ # # test setup 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 ocwd typeset tmpdir typeset out # create temporary test directory ocwd="$PWD" tmpdir="$(mktemp -t -d "test_sun_solaris_cr_6887363_shell_sometimes_mishandles_return_value_of_its_child_process.XXXXXXXX")" || err_exit "Cannot create temporary directory" cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } # run tests # print test case from bug that ksh93 can read this script via stdin function cat_test { cat <&1 >/dev/null status=\$? if [ \$status = 0 ]; then randseq="rand" phrase="read-rand" else randseq="seq" phrase="read-seq" fi retcode=\$status echo \$op | /bin/grep sync 2>&1 >/dev/null status=\$? if [ \$status = 0 ]; then syncasync="sync" phrase="sync\$phrase" else syncasync="async" fi retcode=\${status}-\${retcode} if [ "\$op" != "\$phrase" ]; then echo "Bad mode: \$op != \$phrase (\$retcode)" exit 2 fi for sz in 1 2 3 4; do for type in 1 2 3 4; do PASS "Something" doblockstamper & done wait # Let a few finish done done wait # Make sure everyone got done PASS "lotsafiles \$1 \$fill" } cycle=0 while [ cycle -lt 24 ]; do cycle=\`/bin/expr \$cycle + 1\` lotsaFiles write lotsaFiles write lotsaFiles write lotsaFiles read lotsaFiles read lotsaFiles read PASS "Cycle" done exit 0 EOF } # FIXME: we reset the VMALLOC_OPTIONS (and the depreciated VMDEBUG (for now)) variable for the run to avoid # that the test may run for hours. This may require re-investigation why this happens. out="$(unset VMALLOC_OPTIONS VMDEBUG ; cat_test | ${SHELL} 2>&1)" || err_exit "Unexpected exit code $?" [[ "${out}" != "" ]] || err_exit "No output from test" # filter output and check it out2="$(/bin/egrep -v '^((read-seq|read-rand|syncread-seq|syncread-seq)[[:space:][:blank:]]*)*$' <<<"${out}")" [[ "${out2}" == "" ]] || err_exit "Unexpected output '${out2}'" cd "${ocwd}" rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether "wc" builtin counts the number of bytes # and multibyte characters in different locales correctly. # # This was reported as CR #6904557 ("wc no longer counts number of # bytes correctly"): # ------------ snip ------------ # wc no longer count bytes. # # $ echo $LANG # en_US.UTF-8 # $ ls -l mb.utf8 # -rw-r--r-- 1 nakanon staff 7 Nov 2 14:06 mb.utf8 # $ wc mb.utf8 # 1 1 4 mb.utf8 # $ # # mb.utf8 is attached. # # Man page says: # # If no option is specified, the default is -lwc (counts # lines, words, and bytes.) # # SUS says: # http://www.opengroup.org/onlinepubs/000095399/utilities/wc.html # # By default, the standard output shall contain an entry for each # input file of the form: # # "%d %d %d %s\n", , , , # # If the -m option is specified, the number of characters shall # replace the field in this format. # ------------ snip ------------ # # test setup 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 ocwd typeset tmpdir typeset out # create temporary test directory ocwd="$PWD" tmpdir="$(mktemp -t -d "test_sun_solaris_cr_6904557_wc_no_longer_counts_number_of_bytes_correctly.XXXXXXXX")" || err_exit "Cannot create temporary directory" cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } # run tests function test1 { typeset wc_cmd="$1" typeset testid typeset out typeset testname compound saved_locale # save locale information [[ -v LC_ALL ]] && saved_locale.LC_ALL="${LC_ALL}" [[ -v LC_CTYPE ]] && saved_locale.LC_CTYPE="${LC_CTYPE}" [[ -v LANG ]] && saved_locale.LANG="${LANG}" compound -r -a testcases=( ( typeset name="unicode_plain" typeset locale="" typeset input_format='\xc3\xa1\xc3\xa2\xc3\xa3\x0a' typeset output_pattern='~(Elr)[[:space:][:blank:]]*1[[:space:][:blank:]]*1[[:space:][:blank:]]*7' typeset -a wc_args=( ) ) ( typeset name="unicode_clw" typeset locale="" typeset input_format='\xc3\xa1\xc3\xa2\xc3\xa3\x0a' typeset output_pattern='~(Elr)[[:space:][:blank:]]*1[[:space:][:blank:]]*1[[:space:][:blank:]]*7' typeset -a wc_args=( "-c" "-l" "-w" ) ) ( typeset name="unicode_widechars_lines_words" typeset locale="" typeset input_format='\xc3\xa1\xc3\xa2\xc3\xa3\x0a' typeset output_pattern='~(Elr)[[:space:][:blank:]]*1[[:space:][:blank:]]*1[[:space:][:blank:]]*4' typeset -a wc_args=( "-C" "-l" "-w" ) ) ( typeset name="ja_JP.eucJP_plain" typeset locale="ja_JP.eucJP" typeset input_format='\x74\x32\xa1\xf7\x66\x31\x0a' typeset output_pattern='~(Elr)[[:space:][:blank:]]*1[[:space:][:blank:]]*1[[:space:][:blank:]]*7' typeset -a wc_args=( ) ) ( typeset name="ja_JP.eucJP_widechars_lines_words" typeset locale="ja_JP.eucJP" typeset input_format='\x74\x32\xa1\xf7\x66\x31\x0a' typeset output_pattern='~(Elr)[[:space:][:blank:]]*1[[:space:][:blank:]]*1[[:space:][:blank:]]*6' typeset -a wc_args=( "-C" "-l" "-w" ) ) ) for testid in "${!testcases[@]}" ; do nameref tc=testcases[${testid}] testname="${wc_cmd}/${tc.name}" if [[ "${tc.locale}" == "" ]] ; then if [[ "$LC_ALL" != *.UTF-8 ]] ; then export LC_ALL='en_US.UTF-8' fi else export LC_ALL="${tc.locale}" fi out="$(printf "${tc.input_format}" | ${SHELL} -c "${wc_cmd} \"\$@\"" dummy "${tc.wc_args[@]}" 2>&1)" || err_exit "${testname}: Command returned exit code $?" [[ "${out}" == ${tc.output_pattern} ]] || err_exit "${testname}: Expected match for $(printf "%q\n" "${tc.output_pattern}"), got $(printf "%q\n" "${out}")" # restore locale settings [[ -v saved_locale.LC_ALL ]] && LC_ALL="${saved_locale.LC_ALL}" || unset LC_ALL [[ -v saved_locale.LC_CTYPE ]] && LC_CTYPE="${saved_locale.LC_CTYPE}" || unset LC_CTYPE [[ -v saved_locale.LANG ]] && LANG="${saved_locale.LANG}" || unset LANG done return 0 } #for cmd in "wc" "/usr/bin/wc" ; do for cmd in "wc" ; do test1 "${cmd}" done cd "${ocwd}" rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether the AST "cut" utility's "-d" option # works with multibyte characters # # This was reported as CR #6904575 ("cut -d with multibyte character no longer works"): # ------------ snip ------------ # cut -d with multibyte char no longer work correctly. # # $ echo $LANG # ja # $ od -tx1 mb.eucjp # 0000000 a4 a2 a4 a4 a4 a4 a4 a6 a4 a8 0a # 0000013 # $ od -tx1 delim # 0000000 a4 a4 0a # 0000003 # $ wc -m mb.eucjp # 6 mb.eucjp # # It has 5 characters (2byte each). # # $ /usr/bin/cut -d `cat delim` -f1 mb.eucjp | od -tx1 # 0000000 0a # 0000001 # # correct output is # # 0000000 a4 a2 0a # 0000003 # # files are attached. # ------------ snip ------------ # # test setup 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 ocwd typeset tmpdir typeset out # create temporary test directory ocwd="$PWD" tmpdir="$(mktemp -t -d "test_sun_solaris_cr_6904575_cut_-d_with_multibyte_character_no_longer_works.XXXXXXXX")" || err_exit "Cannot create temporary directory" cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } # run tests function test1 { typeset cut_cmd="$1" typeset testid typeset out typeset testname compound saved_locale # save locale information [[ -v LC_ALL ]] && saved_locale.LC_ALL="${LC_ALL}" [[ -v LC_CTYPE ]] && saved_locale.LC_CTYPE="${LC_CTYPE}" [[ -v LANG ]] && saved_locale.LANG="${LANG}" compound -r -a testcases=( ( typeset name="ascii_plain" typeset locale="C" typeset input_format='abcdefg' typeset -a cut_args_format=( "-f1" "-d" "e" ) typeset output_format='abcd' ) ( typeset name="unicode_plain" typeset locale="" typeset input_format='abcd\u[20ac]fg' typeset -a cut_args_format=( '-f1' '-d' '\u[20ac]' ) typeset output_format='abcd' ) ( typeset name="unicode_plain2" typeset locale="" typeset input_format='abcd\u[20ac]fg' typeset -a cut_args_format=( '-f1' '-d' 'f' ) typeset output_format='abcd\u[20ac]' ) ) for testid in "${!testcases[@]}" ; do nameref tc=testcases[${testid}] testname="${cut_cmd}/${tc.name}" if [[ "${tc.locale}" == "" ]] ; then if [[ ! -v LC_ALL || $LC_ALL != .*.UTF-8 ]]; then export LC_ALL='en_US.UTF-8' fi else export LC_ALL="${tc.locale}" fi # build "cut_args" array with multibyte characters in the current locale typeset -a cut_args integer arg_index for arg_index in "${!tc.cut_args_format[@]}" ; do cut_args+=( "$( printf -- "${tc.cut_args_format[arg_index]}" )" ) done typeset output_format="$( printf -- "${tc.output_format}" )" #printf "args=|%q|\n" "${cut_args[@]}" out="$(printf "${tc.input_format}" | ${SHELL} -c "${cut_cmd} \"\$@\"" dummy "${cut_args[@]}" 2>&1)" || err_exit "${testname}: Command returned exit code $?" [[ "${out}" == ${output_format} ]] || err_exit "${testname}: Expected match for $(printf "%q\n" "${output_format}"), got $(printf "%q\n" "${out}")" # cleanup and restore locale settings unset cut_args arg_index [[ -v saved_locale.LC_ALL ]] && LC_ALL="${saved_locale.LC_ALL}" || unset LC_ALL [[ -v saved_locale.LC_CTYPE ]] && LC_CTYPE="${saved_locale.LC_CTYPE}" || unset LC_CTYPE [[ -v saved_locale.LANG ]] && LANG="${saved_locale.LANG}" || unset LANG done return 0 } function test2 { typeset cutcmd=$1 typeset testname="${cutcmd}" typeset out # create files printf "\xa4\xa2\xa4\xa4\xa4\xa4\xa4\xa6\xa4\xa8\x0a" >"mb.eucjp" printf "\xa4\xa4\x0a" >"delim" # run test out=$( LC_ALL=ja_JP.eucJP ${SHELL} -o pipefail -o errexit -c '$1 -d $(cat delim) -f1 "mb.eucjp" | od -tx1' dummy "${cutcmd}" 2>&1 ) || err_exit "${testname}: Test failed with exit code $?" [[ "${out}" == $'0000000 a4 a2 0a\n0000003' ]] || err_exit "${testname}: Expected \$'0000000 a4 a2 0a\n0000003', got $(printf "%q\n" "${out}")" # cleanup rm "mb.eucjp" "delim" return 0 } #for cmd in "/usr/bin/cut" "cut" ; do for cmd in "cut" ; do test1 "${cmd}" test2 "${cmd}" done cd "${ocwd}" rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether the AST "join" utility works with # multibyte characters as seperator. # # This was reported as CR #6904878 ("join -t no longer works with multibyte char separator"): # ------------ snip ------------ # join doesn't handle multibyte separator correctly. # # $ echo $LANG # ja # $ od -tx1 input1 # 0000000 66 31 a1 f7 66 32 0a # 0000007 # $ od -tx1 input2 # 0000000 74 32 a1 f7 66 31 0a # 0000007 # # 0xa1 0xf7 in the file is multibyte character. # $ od -tx1 delim # 0000000 a1 f7 0a # 0000003 # # $ /usr/bin/join -j1 1 -j2 2 -o 1.1 -t `cat delim` input1 input2 # $ # # It should output "f1". # # files are attached. # ------------ snip ------------ # # test setup 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 ocwd typeset tmpdir typeset out # create temporary test directory ocwd="$PWD" tmpdir="$(mktemp -t -d "test_sun_solaris_cr_6904878_join_-t_no_longer_works_with_multibyte_char_separator.XXXXXXXX")" || err_exit "Cannot create temporary directory" cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } # run tests function test1 { typeset join_cmd="$1" typeset testid typeset out typeset testname compound saved_locale # save locale information [[ -v LC_ALL ]] && saved_locale.LC_ALL="${LC_ALL}" [[ -v LC_CTYPE ]] && saved_locale.LC_CTYPE="${LC_CTYPE}" [[ -v LANG ]] && saved_locale.LANG="${LANG}" compound -r -a testcases=( ( typeset name="ascii_simple" typeset locale="C" typeset input1_format="fish 81 91\n" typeset input2_format="fish B A\n" typeset -a join_args_format=( "input1" "input2" ) typeset output_format="fish 81 91 B A" ) ( typeset name="ja_JP.eucJP_multibyte_delimiter" typeset locale="ja_JP.eucJP" typeset input1_format="\x66\x31\xa1\xf7\x66\x32\x0a" typeset input2_format="\x74\x32\xa1\xf7\x66\x31\x0a" typeset -a join_args_format=( "-j1" "1" "-j2" "2" "-o" "1.1" "-t" "\xa1\xf7" "input1" "input2" ) typeset output_format="f1" ) ) for testid in "${!testcases[@]}" ; do nameref tc=testcases[${testid}] testname="${join_cmd}/${tc.name}" if [[ "${tc.locale}" == "" ]] ; then if [[ "$LC_ALL" != *.UTF-8 ]] ; then export LC_ALL='en_US.UTF-8' fi else export LC_ALL="${tc.locale}" fi # build "join_args" array with multibyte characters in the current locale typeset -a join_args integer arg_index for arg_index in "${!tc.join_args_format[@]}" ; do join_args+=( "$( printf -- "${tc.join_args_format[arg_index]}" )" ) done typeset output_format="$( printf -- "${tc.output_format}" )" #printf "args=|%q|\n" "${join_args[@]}" printf "${tc.input1_format}" >"input1" printf "${tc.input2_format}" >"input2" out="$(${SHELL} -c "${join_cmd} \"\$@\"" dummy "${join_args[@]}" 2>&1)" || err_exit "${testname}: Command returned exit code $?" [[ "${out}" == ${output_format} ]] || err_exit "${testname}: Expected match for $(printf "%q\n" "${output_format}"), got $(printf "%q\n" "${out}")" rm "input1" "input2" # cleanup and restore locale settings unset join_args arg_index [[ -v saved_locale.LC_ALL ]] && LC_ALL="${saved_locale.LC_ALL}" || unset LC_ALL [[ -v saved_locale.LC_CTYPE ]] && LC_CTYPE="${saved_locale.LC_CTYPE}" || unset LC_CTYPE [[ -v saved_locale.LANG ]] && LANG="${saved_locale.LANG}" || unset LANG done return 0 } function test2 { typeset joincmd=$1 typeset testname="${joincmd}" typeset out # create files printf "\x66\x31\xa1\xf7\x66\x32\x0a" >"input1" printf "\x74\x32\xa1\xf7\x66\x31\x0a" >"input2" printf "\xa1\xf7\x0a" >"delim" # run test out=$( LC_ALL=ja_JP.eucJP ${SHELL} -o pipefail -o errexit -c '$1 -j1 1 -j2 2 -o 1.1 -t $(cat delim) input1 input2' dummy "${joincmd}" 2>&1 ) || err_exit "${testname}: Test failed with exit code $?" [[ "${out}" == 'f1' ]] || err_exit "${testname}: Expected 'f1', got $(printf "%q\n" "${out}")" # cleanup rm "input1" "input2" "delim" return 0 } #for cmd in "/usr/bin/join" "join" ; do for cmd in "join" ; do test1 "${cmd}" test2 "${cmd}" done cd "${ocwd}" rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". # tests done exit $((Errors)) # # 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # # # This test checks whether the EXIT trap is called correctly in subshells # # This was reported as CR #6907460 ("EXIT trap handlers are sometimes executed twice"): # ------------ snip ------------ # During SST testing of snv_128(RE) we found out that ksh93 executes EXIT # trap handlers twice under some circumstances. # # Here is a test script: # --- # #!/bin/ksh93 -x # # function A # { # set -x # trap "print TRAP A >>log" EXIT # print >&2 # } # # function B # { # set -x # trap "print TRAP B >>log" EXIT # A # } # # rm -f log # x=$(B) # --- # # It produces the following output on snv_128: # --- # + rm -f log # + B # + trap 'print TRAP B >>log' EXIT # + A # + trap 'print TRAP A >>log' EXIT # + print # + + print TRAP A # 1>& 2 # + 1>> log # + print TRAP B # # + 1>> log # + print TRAP A # + 1>> log # + print TRAP B # + 1>> log # + x='' # --- # # The log file then contains: # TRAP A # TRAP B # TRAP A # TRAP B # # However, the expected log would be: # TRAP A # TRAP B # # When the "x=$(B)" line is changed to "B", the log is correct: # TRAP A # TRAP B # ------------ snip ------------ # # test setup 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 ocwd typeset tmpdir typeset out # create temporary test directory ocwd="$PWD" tmpdir="$(mktemp -t -d "test_sun_solaris_cr_6907460_EXIT_trap_handlers_are_sometimes_executed_twice.XXXXXXXX")" || err_exit "Cannot create temporary directory" cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } # run tests # test 1: Run test with some variations compound vari typeset testname for vari.shell_options in \ "" \ "-o xtrace" \ "-o errexit" \ "-o errexit -o xtrace" ; do for vari.xtrace1 in \ "" \ "set -x" ; do for vari.xtrace2 in \ "" \ "set -x" ; do for vari.func_A_end in \ "" \ "print >&2" \ "return 0" \ "print >&2 ; return 0" ; do for vari.subshell in \ $'x=$(B)' \ $'x=$( ( B ) )' \ $'x=${ B ; }' \ $'x=${ ( B ) ; }' \ $'( x=$(B) )' \ $'( x=$( ( B ) ) )' \ $'( x=${ B ; } )' \ $'( x=${ ( B ) ; } )' ; do testname="$( printf "test |%#B|\n" vari )" cat >"testscript.sh" <>log" EXIT ${vari.func_A_end} } function B { ${vari.xtrace2} trap "print TRAP B >>log" EXIT A } rm -f log ${vari.subshell} EOF ${SHELL} ${vari.shell_options} "testscript.sh" >/dev/null 2>&1 || err_exit "${testname}: Unexpected error code $?" rm "testscript.sh" if [[ -f "log" ]] ; then out="$( < log )" rm "log" else err_exit "${testname}: File 'log' not found." fi [[ "${out}" == $'TRAP A\nTRAP B' ]] || err_exit "${testname}: Expected \$'TRAP A\nTRAP B', got $(printf "%q\n" "${out}")" done done done done done # test 2: This is the unmodified test from the bugster bug report ( cat <>log" EXIT print >&2 } function B { set -x trap "print TRAP B >>log" EXIT A } rm -f log x=\$(B) EOF ) | ${SHELL} >/dev/null 2>&1 || err_exit "Unexpected error code $?" if [[ -f "log" ]] ; then out="$( < log )" rm "log" else err_exit "File 'log' not found." fi [[ "${out}" == $'TRAP A\nTRAP B' ]] || err_exit "Expected \$'TRAP A\nTRAP B', got $(printf "%q\n" "${out}")" cd "${ocwd}" rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". # tests done exit $((Errors)) # # 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 (c) 2010, Oracle and/or its affiliates. All rights reserved. # # # # # This was reported as CR #xxxxxxxx (""): # ------------ snip ------------ # <description> # ------------ snip ------------ # # test setup 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 ocwd typeset tmpdir typeset out # create temporary test directory ocwd="$PWD" tmpdir="$(mktemp -t -d "test_<description>.XXXXXXXX")" || err_exit "Cannot create temporary directory" cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } # run tests cd "${ocwd}" rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". # tests done exit $((Errors)) # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # sun_solaris_getconf.sh - test the ksh93 getconf builtin for compatibility # with /usr/bin/getconf # # test setup 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 # setup integer mismatch # counts mismatches between builtin and external command integer getconf_keys # counts tests (paranoid check to make sure the test loop works) export PATH=/usr/bin:/bin # prechecks [[ ! -f "/bin/getconf" ]] && err_exit '/bin/getconf not found.' [[ ! -x "/bin/getconf" ]] && err_exit '/bin/getconf not executable.' # Define test functions and store them in a string for repeated usagae # (we can't use "functions" (alias "typeset -f") since this does not # work in compiled shell scripts) typeset -r getconf_test_functions="$( cat <<EOF 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 # compare builtin getconf output with /usr/bin/getconf function compare_normal { mismach=0 getconf_keys=0 /usr/bin/getconf -a | while read i ; do (( getconf_keys++ )) t="\${i%:*}" a="\$(getconf "\$t" 2>/dev/null)" b="\$(/usr/bin/getconf "\$t" 2>/dev/null)" if [[ "\$a" != "\$b" ]] ; then print -u2 "getconf/normal built mismatch: |\$t|:|\$a| != |\$b|" (( mismatch++ )) fi done } # compare builtin getconf output with /usr/bin/getconf while passing a path argument function compare_path { mismach=0 getconf_keys=0 /usr/bin/getconf -a | while read i ; do (( getconf_keys++ )) t="\${i%:*}" a="\$(getconf "\$t" "/tmp" 2>/dev/null)" b="\$(/usr/bin/getconf "\$t" "/tmp" 2>/dev/null)" if [[ "\$a" != "\$b" ]] ; then print -u2 "getconf/path built mismatch: |\$t|:|\$a| != |\$b|" (( mismatch++ )) fi done } EOF )" print -r -- "$getconf_test_functions" | source /dev/stdin # future versions of this test should test the following ${PATH}s, too: # "/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin" \ #"/usr/xpg4/bin:/bin:/usr/bin" \ for i in \ "/usr/bin:/bin" \ "/bin:/usr/bin" do export PATH="${i}" ## test whether the getconf builtin is available if [[ "$(builtin | fgrep "/bin/getconf")" == "" ]] ; then err_exit '/bin/getconf not found in the list of builtins.' fi ## compare "getconf -a" output if [[ "$(getconf -a)" != "$(/usr/bin/getconf -a)" ]] ; then err_exit 'getconf -a output mismatch.' fi ## check for a key which is only supported by the AST builtin version of getconf: if [[ "$(getconf LIBPREFIX)" != "lib" ]] ; then err_exit 'getconf LIBPREFIX did not return "lib".' fi ## run normal test compare_normal (( getconf_keys == 0 )) && err_exit "getconf/normal not working (PATH=${PATH})." (( mismatch > 0 )) && err_exit "getconf/normal test found ${mismatch} differences (PATH=${PATH})." # run the same test in a seperate shell # (we explicitly test this because ast-ksh.2007-01-11 picks up /usr/xpg6/bin/getconf # if /usr/xpg6/bin/ comes in ${PATH} before /usr/bin (this happens only of ${PATH} # contains /usr/xpg6/bin before ksh93 is started)). ${SHELL} -c "integer mismatch ; \ integer getconf_keys ; \ ${getconf_test_functions} ; \ compare_normal ; (( getconf_keys == 0 )) && err_exit \"getconf/normal not working (PATH=\${PATH}).\" ; \ (( mismatch > 0 )) && err_exit \"getconf/normal test found \${mismatch} differences (PATH=\${PATH}).\" ; \ exit $((Errors))" (( Errors+=$? )) ## run test with path argument compare_path (( getconf_keys == 0 )) && err_exit "getconf/path not working." (( mismatch > 0 )) && err_exit "getconf/path test found ${mismatch} differences." # run the same test in a seperate shell # (see comment above) ${SHELL} -c "integer mismatch ; \ integer getconf_keys ; \ ${getconf_test_functions} ; \ compare_path ; (( getconf_keys == 0 )) && err_exit \"getconf/normal not working (PATH=\${PATH}).\" ; \ (( mismatch > 0 )) && err_exit \"getconf/normal test found \${mismatch} differences (PATH=\${PATH}).\" ; \ exit $((Errors))" (( Errors+=$? )) done # tests done exit $((Errors)) # # 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. # # # name reference test #001 # # test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" (( Errors++ )) } alias err_exit='err_exit $LINENO' set -o nounset Command=${0##*/} integer Errors=0 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}'" # tests done exit $((Errors)) # # 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 (c) 2010, Oracle and/or its affiliates. All rights reserved. # # # This test module contains misc l10n tests # # # test setup 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 ocwd typeset tmpdir # create temporary test directory ocwd="$PWD" tmpdir="$(mktemp -t -d "test_sun_solaris_locale_misc.XXXXXXXX")" || err_exit "Cannot create temporary directory" cd "${tmpdir}" || { err_exit "cd ${tmpdir} failed." ; exit $((Errors)) ; } # # utility functions # function string_has_multibyte_characters { typeset str="$1" integer bytecount integer mbcharactercount (( mbcharactercount=$(LC_ALL="en_US.UTF-8" wc -C <<<"${str}") )) (( bytecount=$(wc -c <<<"${str}") )) (( bytecount != mbcharactercount )) && return 0 return 1 } # # test functions # # test whether LC_ALL correctly overrides LC_MESSAGES in the choice of the system message # catalog # 1. This test assumes that the machine has ko_KR.UTF-8 + matching message catalogs installed # 2. We run this test in a |fork()|'ed subshell to isolate it from the other tests function test_lc_all_override1 { typeset out ( ulimit -c 0 # force ksh93 to |fork()| for this subshell unset ${!LC_*} LANG #export LANG=en_US.UTF-8 export LC_ALL="en_US.UTF-8" integer ch_val integer korean_count=0 ${SHELL} -c 'LC_MESSAGES=C ${SHELL} -c "cd no_dir_llkk ; export LC_ALL="ko_KR.UTF-8" ; cd "no_dir_ooo" ; true"' >"out" 2>&1 || err_exit "Test shell failed with non-zero exit code $?" while read -N1 c ; do (( ch_val='${c} )) (( ch_val >= 0xac00 && ch_val <= 0xdfff )) && (( korean_count++ )) done <"out" # Solaris 11/B110 returns 13 characters for this test (( korean_count >= 10 )) || err_exit "Expected at least 10 korean characters, got ${korean_count}" rm "out" exit $((Errors)) ) (( Errors += $? )) return 0 } # test whether the shell internally selects the correct message catalogs # when the value of LC_* or LANG is restored to a "previous" value (e.g. # subshell, function) or gets "reset" (e.g. unset) function test_lc_l10n_scope1 { compound -r -a testgroups=( ( name="subshell" typeset -a tests=( 'LC_ALL="C" ; cd "nosuchdir2" ; (LC_ALL="ja_JP.UTF-8" ; cd "nosuchdir2") ; cd "nosuchdir2" ; true' 'LC_MESSAGES="C" ; cd "nosuchdir2" ; (LC_MESSAGES="ja_JP.UTF-8" ; cd "nosuchdir2") ; cd "nosuchdir2" ; true' 'LANG="C" ; cd "nosuchdir2" ; (LANG="ja_JP.UTF-8" ; cd "nosuchdir2") ; cd "nosuchdir2" ; true' ) ) ( name="unset" typeset -a tests=( 'LC_ALL="C" ; cd "nosuchdir2" ; LC_ALL="ja_JP.UTF-8" ; cd "nosuchdir2" ; unset LC_ALL ; cd "nosuchdir2" ; true' 'LC_MESSAGES="C" ; cd "nosuchdir2" ; LC_MESSAGES="ja_JP.UTF-8" ; cd "nosuchdir2" ; unset LC_MESSAGES ; cd "nosuchdir2" ; true' 'LANG="C" ; cd "nosuchdir2" ; LANG="ja_JP.UTF-8" ; cd "nosuchdir2" ; unset LANG ; cd "nosuchdir2" ; true' ) ) ( name="empty LC_xxx" typeset -a tests=( 'LC_ALL="C" ; cd "nosuchdir2" ; LC_ALL="ja_JP.UTF-8" ; cd "nosuchdir2" ; LC_ALL="" ; cd "nosuchdir2" ; true' 'LC_MESSAGES="C" ; cd "nosuchdir2" ; LC_MESSAGES="ja_JP.UTF-8" ; cd "nosuchdir2" ; LC_MESSAGES="" ; cd "nosuchdir2" ; true' 'LANG="C" ; cd "nosuchdir2" ; LANG="ja_JP.UTF-8" ; cd "nosuchdir2" ; LANG="" ; cd "nosuchdir2" ; true' ) ) ( name="function" typeset -a tests=( 'LC_ALL="C" ; cd "nosuchdir2" ; function x { typeset LC_ALL="ja_JP.UTF-8" ; cd "nosuchdir2" ; } ; x ; cd "nosuchdir2" ; true' 'LC_MESSAGES="C" ; cd "nosuchdir2" ; function x { typeset LC_MESSAGES="ja_JP.UTF-8" ; cd "nosuchdir2" ; } ; x ; cd "nosuchdir2" ; true' 'LANG="C" ; cd "nosuchdir2" ; function x { typeset LANG="ja_JP.UTF-8" ; cd "nosuchdir2" ; } ; x ; cd "nosuchdir2" ; true' ) ) ) typeset tgi ti out2 for tgi in "${!testgroups[@]}" ; do nameref tg=testgroups[${tgi}] for ti in "${!tg.tests[@]}" ; do nameref ts=tg.tests[${ti}] ${SHELL} -c "unset LANG \${!LC_*} ; ${SHELL} -c \"${ts}\"" >out 2>&1 || err_exit "test returned non-zero exit code $?" out2="${ while read -r line ; do string_has_multibyte_characters "${line}" && print -n "A" || print -n "_" done <"out" print "" }" if [[ "${out2}" != '_A_' ]] ; then err_exit "test '${tg.name}'/'$ts' failed: Expected '_A_', got '${out2}'" #cat out fi done done rm "out" return 0 } # run tests test_lc_all_override1 test_lc_l10n_scope1 cd "${ocwd}" rmdir "${tmpdir}" || err_exit "Cannot remove temporary directory ${tmpdir}". # tests done exit $((Errors)) # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # function err_exit2 { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" (( Errors < 127 && Errors++ )) } 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_exit2 ${line_number} "${output} != ${expected_output}" } alias testfunc='testfunc $LINENO' alias err_exit='err_exit2 $LINENO' set -o nounset Command=${0##*/} integer Errors=0 # string testfunc '(function l { typeset -S x ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true)' "###" testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; l false ; l true' ">###" testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false ; (l false) ; l true' ">##" testfunc 'function l { typeset -S x=">" ; x+="#" ; $1 && print "$x" ; } ; l false; ( ulimit -c 0 ; l false) ; l true' ">##" # integer testfunc '(function l { typeset -S -i x ; x+=1 ; $1 && print "$x" ; } ; l false ; l false ; l true )' "3" testfunc '(function l { typeset -S -i x ; x+=1 ; $1 && print "$x" ; } ; l false ; (l false) ; l true )' "2" # float testfunc '(function l { float -S x=0.5 ; (( x+=.5 )) ; $1 && print "$x" ; } ; l false ; l false ; l true )' "2" testfunc '(function l { float -S x=0.5 ; (( x+=.5 )) ; $1 && print "$x" ; } ; l false ; (l false) ; l true )' "1.5" # compound variable [[ "${ function l { typeset -S s=( a=0 b=0 ) (( s.a++, s.b++ )) $1 && printf 'a=%d, b=%d\n' s.a s.b } l false ; l false ; l true }" != "a=3, b=3" ]] && err_exit "static compound var failed" # array variable [[ "$( function ar { typeset -a -S s=( "hello" ) s+=( "an element" ) $1 && { printf '%s' "${s[@]}" ; printf '\n' ; } } ar false ; ar false ; ar true )" != "helloan elementan elementan element" ]] && err_exit "static array var failed" # 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" # tests done exit $((Errors)) # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # variable tree test #001 # Propose of this test is whether ksh93 crashes or not - ast-ksh.2008-05-14 # crashes like this when running this test: # # program terminated by signal ILL (illegal opcode) # 0xffffffffffffffff: <bad address 0xffffffffffffffff> # Current function is nv_diropen # 123 dp->hp = (Namval_t*)dtprev(dp->root,&fake); # (dbx) where # [1] 0x100381e80(0x100381e80, 0xffffffff7fffe690, 0x10, 0x61, 0x0, 0x100381ec9), at 0x100381e80 # =>[2] nv_diropen(np = (nil), name = 0x100381ebc "mysrcdata"), line 123 in "nvtree.c" # [3] walk_tree(np = 0x1003809e0, dlete = 524289), line 743 in "nvtree.c" # [4] put_tree(np = 0x1003809e0, val = (nil), flags = 524289, fp = 0x100381db0), line 814 in "nvtree.c" # [5] nv_putv(np = 0x1003809e0, value = (nil), flags = 524289, nfp = 0x100381db0), line 141 in "nvdisc.c" # [6] _nv_unset(np = 0x1003809e0, flags = 524289), line 1976 in "name.c" # [7] table_unset(shp = 0x10033e900, root = 0x100380900, flags = 524289, oroot = 0x100360980), line 1902 in "name.c" # [8] sh_unscope(shp = 0x10033e900), line 2711 in "name.c" # [9] sh_funscope(argn = 1, argv = 0x10035e680, fun = (nil), arg = 0xffffffff7ffff118, execflg = 4), line 2470 in "xec.c" # [10] sh_funct(np = 0x100380860, argn = 1, argv = 0x10035e680, envlist = (nil), execflg = 4), line 2528 in "xec.c" # [11] sh_exec(t = 0x10035e620, flags = 4), line 1032 in "xec.c" # [12] exfile(shp = 0x10033e900, iop = 0x100379a20, fno = 10), line 589 in "main.c" # [13] sh_main(ac = 2, av = 0xffffffff7ffffa08, userinit = (nil)), line 364 in "main.c" # [14] main(argc = 2, argv = 0xffffffff7ffffa08), line 46 in "pmain.c" # # test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" (( Errors < 127 && Errors++ )) } alias err_exit='err_exit $LINENO' # the test cannot use "nounset" Command=${0##*/} integer Errors=0 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 } function main { typeset mysrcdata=( 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=() build_tree mytree mysrcdata leaf_compound # (( $(print -r -- "$mytree" | wc -l) > 10 )) || err_exit "Compound tree too small." } main # tests done exit $((Errors)) # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # 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. # # test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" (( Errors < 127 && Errors++ )) } alias err_exit='err_exit $LINENO' # the test cannot use "nounset" Command=${0##*/} integer Errors=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 "! ([[ -v varname ]] ; res=$? ; unset varname ; exit $res)", 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 "! ([[ -v varname ]] ; res=$? ; unset varname ; exit $res)", 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 ! ([[ -v dest_tree.l1["$a"] ]] ; res=$? ; unset dest_tree.l1["$a"] ; exit $res) ; then typeset -A dest_tree.l1["$a"].l2 fi #if [[ "${dest_tree.l1["$a"].l2["$b"]}" == "" ]] ; then if ! ([[ -v dest_tree.l1["$a"].l2["$b"] ]] ; res=$? ; unset dest_tree.l1["$a"].l2["$b"] ; exit $res) ; 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" diff -u <( printf "%s\n" "${mytree_global1}" ) <( printf "%s\n" "${mytree_local1}" ) fi if [[ "${mytree_global1}" != "${mytree_global2}" ]] ; then err_exit "Compound trees 'mytree_global1' and 'mytree_global2' not identical" diff -u <( printf "%s\n" "${mytree_global1}" ) <( printf "%s\n" "${mytree_global2}" ) fi if [[ "${mytree_local1}" != "${mytree_local2}" ]] ; then err_exit "Compound trees 'mytree_local1' and 'mytree_local2' not identical" diff -u <( printf "%s\n" "${mytree_local1}" ) <( printf "%s\n" "${mytree_local2}" ) fi #### test "unset" in a subshell ( [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ]] ; res=$? ; unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ; exit $res ) || \ err_exit "Try 1: Variable 'mytree_global1.l1[urw].l2[itc zapfdingbats]' not found." ( [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ]] ; res=$? ; unset 'mytree_global1.l1[urw].l2[itc zapfdingbats]' ; exit $res ) || \ 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: ( set -o errexit 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" ( set -o errexit 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: ( set -o errexit 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" ( set -o errexit 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 [[ -v 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ; res=$? unset 'mytree_global1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' (( res == 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" [[ -v 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' ]] ; res=$? unset 'mytree_local1.l1[urw].l2[itc zapfdingbats].l3[medium].entries[abcd].filenames[0]' (( res == 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" diff -u <( printf "%s\n" "${mytree_global1}" ) <( printf "%s\n" "${mytree_local1}" ) fi } main # tests done exit $((Errors)) # # 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # variable tree test #003 # Propose of this test is whether ksh93 handles global variable trees # and function-local variable trees the same way, including "nameref" # and "unset" handling. # # test setup function err_exit { print -u2 -n "\t" print -u2 -r ${Command}[$1]: "${@:2}" (( Errors < 127 && Errors++ )) } alias err_exit='err_exit $LINENO' # the test cannot use "nounset" Command=${0##*/} integer Errors=0 function example_tree { cat <<EOF ( typeset -A l1=( [adobe]=( typeset -A l2=( [avantgarde]=( typeset -A l3=( [demi]=( typeset -A entries=( [182c069a485316b1bc7ae001c04c7835]=( typeset -a comments=( FONT -adobe-avantgarde-demi-r-normal--199-120-1200-1200-p-1130-iso8859-1 COPYRIGHT 'Copyright Notice not available' RAW_PIXELSIZE RAW_POINTSIZE -- section diaeresis copyright ordfeminine guillemotleft ) typeset -a filenames=( X11Rx/R6.4/xc/programs/Xserver/XpConfig/C/print/models/SPSPARC2/fonts/AvantGarde-Demi.pmf ) md5sum=182c069a485316b1bc7ae001c04c7835 typeset -a xlfd=( -adobe-avantgarde-demi-r-normal--199-120-1200-1200-p-1130-iso8859-1 ) ) [7db15b51965d8fe1f1c55fcb101d7616]=( typeset -a comments=( FONT -adobe-avantgarde-demi-i-normal--199-120-1200-1200-p-1130-iso8859-1 COPYRIGHT 'Copyright Notice not available' RAW_PIXELSIZE RAW_POINTSIZE -- section diaeresis copyright ordfeminine guillemotleft ) typeset -a filenames=( X11Rx/R6.4/xc/programs/Xserver/XpConfig/C/print/models/SPSPARC2/fonts/AvantGarde-DemiOblique.pmf ) md5sum=7db15b51965d8fe1f1c55fcb101d7616 typeset -a xlfd=( -adobe-avantgarde-demi-i-normal--199-120-1200-1200-p-1130-iso8859-1 ) ) [a37e4a4a5035abf6f294d830fbd9e775]=( typeset -a comments=( FONT -adobe-avantgarde-demi-r-normal--422-120-2540-2540-p-2395-iso8859-1 COPYRIGHT 'Copyright (c) 1985, 1987, 1989, 1990, 1991 Adobe Systems Incorporated. All Rights Reserved.ITC Avant Garde Gothic is a registered trademark of International Typeface Corporation.' RAW_PIXELSIZE RAW_POINTSIZE -- section diaeresis copyright ordfeminine guillemotleft ) typeset -a filenames=( fox-gate/XW_NV/open-src/tarballs/xorg-server-1.3.0.0/hw/xprint/config/C/print/models/PSdefault/fonts/AvantGarde-Demi.pmf ) md5sum=a37e4a4a5035abf6f294d830fbd9e775 typeset -a xlfd=( -adobe-avantgarde-demi-r-normal--422-120-2540-2540-p-2395-iso8859-1 ) ) [da3d6d94fcf759b95c7f829ce5619374]=( typeset -a comments=( FONT -adobe-avantgarde-demi-i-normal--422-120-2540-2540-p-2395-iso8859-1 COPYRIGHT 'Copyright (c) 1985, 1987, 1989, 1990, 1991 Adobe Systems Incorporated. All Rights Reserved.ITC Avant Garde Gothic is a registered trademark of International Typeface Corporation.' RAW_PIXELSIZE RAW_POINTSIZE -- section diaeresis copyright ordfeminine guillemotleft ) typeset -a filenames=( fox-gate/XW_NV/open-src/tarballs/xorg-server-1.3.0.0/hw/xprint/config/C/print/models/PSdefault/fonts/AvantGarde-DemiOblique.pmf ) md5sum=da3d6d94fcf759b95c7f829ce5619374 typeset -a xlfd=( -adobe-avantgarde-demi-i-normal--422-120-2540-2540-p-2395-iso8859-1 ) ) ) ) ) ) ) ) ) ) EOF } function main { set -o errexit typeset xlfd_tree=() typeset -A xlfd_tree.l1 eval "xlfd_tree=$( example_tree )" typeset i j k l fn # filter chain begin for i in "${!xlfd_tree.l1[@]}" ; do for j in "${!xlfd_tree.l1["$i"].l2[@]}" ; do for k in "${!xlfd_tree.l1["$i"].l2["$j"].l3[@]}" ; do nameref vndnode=xlfd_tree.l1["$i"].l2["$j"].l3["$k"] for l in "${!vndnode.entries[@]}" ; do nameref node=vndnode.entries["$l"] for fn in "${node.filenames[@]}" ; do if [[ "${fn}" != ~(E)x-re_gate_XW_NV_MWS ]] ; then unset "${!node}" break fi done done done done done # filter chain end return 0 } main || ((Errors++)) # tests done exit $((Errors))