Home | History | Annotate | Line # | Download | only in sh
      1 # $NetBSD: t_fsplit.sh,v 1.10 2024/10/19 11:59:51 kre Exp $
      2 #
      3 # Copyright (c) 2007-2016 The NetBSD Foundation, Inc.
      4 # All rights reserved.
      5 #
      6 # Redistribution and use in source and binary forms, with or without
      7 # modification, are permitted provided that the following conditions
      8 # are met:
      9 # 1. Redistributions of source code must retain the above copyright
     10 #    notice, this list of conditions and the following disclaimer.
     11 # 2. Redistributions in binary form must reproduce the above copyright
     12 #    notice, this list of conditions and the following disclaimer in the
     13 #    documentation and/or other materials provided with the distribution.
     14 #
     15 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     16 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     17 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     19 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25 # POSSIBILITY OF SUCH DAMAGE.
     26 #
     27 
     28 # The standard
     29 # http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html
     30 # explains (section 2.6) that Field splitting should be performed on the
     31 # result of variable expansions.
     32 # In particular this means that in ${x-word}, 'word' must be expanded as if
     33 # the "${x-" and "}" were absent from the input line.
     34 #
     35 # So: sh -c 'set ${x-a b c}; echo $#' should give 3.
     36 # and: sh -c 'set -- ${x-}' echo $#' should give 0
     37 #
     38 
     39 # the implementation of "sh" to test
     40 : ${TEST_SH:="/bin/sh"}
     41 
     42 nl='
     43 '
     44 
     45 check()
     46 {
     47 	if [ "${TEST}" -eq 0 ]
     48 	then
     49 		FAILURES=
     50 	fi
     51 
     52 	TEST=$((${TEST} + 1))
     53 
     54 	case "$#" in
     55 	(2)	;;
     56 	(*)	atf_fail "Internal test error, $# args to check, test ${TEST}";;
     57 	esac
     58 
     59 	result=$( ${TEST_SH} -c "unset x a b d c e f g h; $1" )
     60 	STATUS="$?"
     61 
     62 	# Remove newlines
     63 	oifs="$IFS"
     64 	IFS="$nl"
     65 	result="$(echo $result)"
     66 	IFS="$oifs"
     67 
     68 	#  # trim the test text in case we use it in a message below
     69 	#  case "$1" in
     70 	#  ????????????????*)
     71 	#	  set -- "$(expr "$1" : '\(............\).*')..." "$2" ;;
     72 	#  esac
     73 
     74 	if [ "$2" != "${result}" ]
     75 	then
     76 		FAILURES="${FAILURES}${FAILURES:+ }${TEST}"
     77 		printf >&2 'Sub-test %d failed:\n      %s\n' \
     78 			"${TEST}" "$1"
     79 		printf >&2 ' Expected: [%s]\n' "$2"
     80 		printf >&2 ' Received: [%s]\n' "${result}"
     81 
     82 		if [ "${STATUS}" != 0 ]
     83 		then
     84 			printf >&2 ' Sub-test exit status: %d\n' "${STATUS}"
     85 		fi
     86 	elif [ "${STATUS}" != 0 ]
     87 	then
     88 		FAILURES="${FAILURES}${FAILURES:+ }${TEST}"
     89 		printf >&2 'Sub-test %d failed:\n\t%s\n' \
     90 			"${TEST}" "$1"
     91 		printf >&2 ' Sub-test exit status: %d (with correct output)\n' \
     92 			"${STATUS}"
     93 	fi
     94 
     95 	return 0
     96 }
     97 
     98 check_results()
     99 {
    100 	NAME=$1
    101 
    102 	set -- ${FAILURES}
    103 
    104 	if [ $# -eq 0 ]
    105 	then
    106 		return 0
    107 	fi
    108 
    109 	unset IFS
    110 	printf >&2 'Subtest %s: %d sub-tests (of %d) [%s] failed.\n' \
    111 		"${NAME}" "$#" "${TEST}" "$*"
    112 
    113 	atf_fail "$# of ${TEST} sub-tests (${FAILURES}), see stderr"
    114 	return 0
    115 }
    116 
    117 atf_test_case for
    118 for_head()
    119 {
    120 	atf_set "descr" "Checks field splitting in for loops"
    121 }
    122 for_body()
    123 {
    124 	unset x
    125 
    126 	TEST=0
    127 	# Since I managed to break this, leave the test in
    128 	check 'for f in $x; do echo x${f}y; done' ''
    129 
    130 	check_results for
    131 }
    132 
    133 atf_test_case default_val
    134 default_val_head()
    135 {
    136 	atf_set "descr" "Checks field splitting in variable default values"
    137 }
    138 default_val_body()
    139 {
    140 	TEST=0
    141 	# Check that IFS is applied to text from ${x-...} unless it is inside
    142 	# any set of "..."
    143 	check 'set -- ${x-a b c};   echo $#'   3
    144 
    145 	check 'set -- ${x-"a b" c}; echo $#'   2
    146 	check 'set -- ${x-a "b c"}; echo $#'   2
    147 	check 'set -- ${x-"a b c"}; echo $#'   1
    148 
    149 	check "set -- \${x-'a b' c}; echo \$#" 2
    150 	check "set -- \${x-a 'b c'}; echo \$#" 2
    151 	check "set -- \${x-'a b c'}; echo \$#" 1
    152 
    153 	check 'set -- ${x-a\ b c};  echo $#'   2
    154 	check 'set -- ${x-a b\ c};  echo $#'   2
    155 	check 'set -- ${x-a\ b\ c}; echo $#'   1
    156 
    157 	check 'set -- ${x};        echo $#' 0
    158 	check 'set -- ${x-};       echo $#' 0
    159 	check 'set -- ${x-""};     echo $#' 1
    160 	check 'set -- ""${x};      echo $#' 1
    161 	check 'set -- ""${x-};     echo $#' 1
    162 	check 'set -- ""${x-""};   echo $#' 1
    163 	check 'set -- ${x}"";      echo $#' 1
    164 	check 'set -- ${x-}"";     echo $#' 1
    165 	check 'set -- ${x-""}"";   echo $#' 1
    166 	check 'set -- ""${x}"";    echo $#' 1
    167 	check 'set -- ""${x-}"";   echo $#' 1
    168 	check 'set -- ""${x-""}""; echo $#' 1
    169 
    170 	check 'for i in ${x-a b c};            do echo "z${i}z"; done' \
    171 		'zaz zbz zcz'
    172 	check 'for i in ${x-"a b" c};          do echo "z${i}z"; done' \
    173 		'za bz zcz'
    174 	check 'for i in ${x-"a ${x-b c}" d};   do echo "z${i}z"; done' \
    175 		'za b cz zdz'
    176 	check 'for i in ${x-a ${x-b c} d};     do echo "z${i}z"; done' \
    177 		'zaz zbz zcz zdz'
    178 
    179 	# I am not sure the first of these two is correct, the rules on
    180 	# quoting word in ${var-word} are peculiar, and hard to fathom...
    181 	# It is what the NetBSD shell does, and bash, not the freebsd shell
    182 	# and not ksh93 (as of Mar 1, 2016, and still in June 2017)
    183 	# The likely correct interp of the next one is 'za bz zcz zdz'
    184 
    185 	# That and the "should be" below are correct as of POSIX 7 TC2
    186 	# But this is going to change to "unspecified" in POSIX 8
    187 	# (resolution of bug 221)  so instead of being incorrect (as now)
    188 	# the NetBSD shell will simply be implementing is version
    189 	# of unspecified behaviour.  Just beware that shells differ,
    190 	# a shell that fails this test is not incorrect because of it.
    191 
    192 	# should be:    uuuu qqqqqq uuu q uuu   (unquoted/quoted) no nesting.
    193 	check 'for i in ${x-"a ${x-"b c"}" d}; do echo "z${i}z"; done' \
    194 		'za b cz zdz'
    195 	check 'for i in ${x-a ${x-"b c"} d};   do echo "z${i}z"; done' \
    196 		'zaz zb cz zdz'
    197 
    198 	check_results default_val
    199 }
    200 
    201 atf_test_case replacement_val
    202 replacement_val_head()
    203 {
    204 	atf_set "descr" "Checks field splitting in variable replacement values"
    205 }
    206 replacement_val_body()
    207 {
    208 	TEST=0
    209 
    210 	# Check that IFS is applied to text from ${x+...} unless it is inside
    211 	# any set of "...", or whole expansion is quoted, or both...
    212 
    213 	check 'x=BOGUS; set -- ${x+a b c};   echo $#'   3
    214 
    215 	check 'x=BOGUS; set -- ${x+"a b" c}; echo $#'   2
    216 	check 'x=BOGUS; set -- ${x+a "b c"}; echo $#'   2
    217 	check 'x=BOGUS; set -- ${x+"a b c"}; echo $#'   1
    218 
    219 	check "x=BOGUS; set -- \${x+'a b' c}; echo \$#" 2
    220 	check "x=BOGUS; set -- \${x+a 'b c'}; echo \$#" 2
    221 	check "x=BOGUS; set -- \${x+'a b c'}; echo \$#" 1
    222 
    223 	check 'x=BOGUS; set -- ${x+a\ b c};  echo $#'   2
    224 	check 'x=BOGUS; set -- ${x+a b\ c};  echo $#'   2
    225 	check 'x=BOGUS; set -- ${x+a\ b\ c}; echo $#'   1
    226 
    227 	check 'x=BOGUS; set -- ${x+};       echo $#' 0
    228 	check 'x=BOGUS; set -- ${x+""};     echo $#' 1
    229 	check 'x=BOGUS; set -- ""${x+};     echo $#' 1
    230 	check 'x=BOGUS; set -- ""${x+""};   echo $#' 1
    231 	check 'x=BOGUS; set -- ${x+}"";     echo $#' 1
    232 	check 'x=BOGUS; set -- ${x+""}"";   echo $#' 1
    233 	check 'x=BOGUS; set -- ""${x+}"";   echo $#' 1
    234 	check 'x=BOGUS; set -- ""${x+""}""; echo $#' 1
    235 
    236 	# verify that the value of $x does not affecty the value of ${x+...}
    237 	check 'x=BOGUS; set -- ${x+};       echo X$1' X
    238 	check 'x=BOGUS; set -- ${x+""};     echo X$1' X
    239 	check 'x=BOGUS; set -- ""${x+};     echo X$1' X
    240 	check 'x=BOGUS; set -- ""${x+""};   echo X$1' X
    241 	check 'x=BOGUS; set -- ${x+}"";     echo X$1' X
    242 	check 'x=BOGUS; set -- ${x+""}"";   echo X$1' X
    243 	check 'x=BOGUS; set -- ""${x+}"";   echo X$1' X
    244 	check 'x=BOGUS; set -- ""${x+""}""; echo X$1' X
    245 
    246 	check 'x=BOGUS; set -- ${x+};       echo X${1-:}X' X:X
    247 	check 'x=BOGUS; set -- ${x+""};     echo X${1-:}X' XX
    248 	check 'x=BOGUS; set -- ""${x+};     echo X${1-:}X' XX
    249 	check 'x=BOGUS; set -- ""${x+""};   echo X${1-:}X' XX
    250 	check 'x=BOGUS; set -- ${x+}"";     echo X${1-:}X' XX
    251 	check 'x=BOGUS; set -- ${x+""}"";   echo X${1-:}X' XX
    252 	check 'x=BOGUS; set -- ""${x+}"";   echo X${1-:}X' XX
    253 	check 'x=BOGUS; set -- ""${x+""}""; echo X${1-:}X' XX
    254 
    255 	# and validate that the replacement can be used as expected
    256 	check 'x=BOGUS; for i in ${x+a b c};            do echo "z${i}z"; done'\
    257 		'zaz zbz zcz'
    258 	check 'x=BOGUS; for i in ${x+"a b" c};          do echo "z${i}z"; done'\
    259 		'za bz zcz'
    260 	check 'x=BOGUS; for i in ${x+"a ${x+b c}" d};   do echo "z${i}z"; done'\
    261 		'za b cz zdz'
    262 
    263 	# see the (extended) comment in the default_val test.  This will be
    264 	# unspecified, hence we are OK (will be) but expect differences.
    265 	# also incorrect:        uuuu qqqqqq uuu q uuu
    266 	check 'x=BOGUS; for i in ${x+"a ${x+"b c"}" d}; do echo "z${i}z"; done'\
    267 		'za b cz zdz'
    268 
    269 	check 'x=BOGUS; for i in ${x+a ${x+"b c"} d};   do echo "z${i}z"; done'\
    270 		'zaz zb cz zdz'
    271 	check 'x=BOGUS; for i in ${x+a ${x+b c} d};     do echo "z${i}z"; done'\
    272 		'zaz zbz zcz zdz'
    273 
    274 	check_results replacement_val
    275 }
    276 
    277 atf_test_case ifs_alpha
    278 ifs_alpha_head()
    279 {
    280 	atf_set "descr" "Checks that field splitting works with alphabetic" \
    281 	                "characters"
    282 }
    283 ifs_alpha_body()
    284 {
    285 	unset x
    286 
    287 	TEST=0
    288 	# repeat with an alphabetic in IFS
    289 	check 'IFS=q; set ${x-aqbqc}; echo $#' 3
    290 	check 'IFS=q; for i in ${x-aqbqc};            do echo "z${i}z"; done' \
    291 		'zaz zbz zcz'
    292 	check 'IFS=q; for i in ${x-"aqb"qc};          do echo "z${i}z"; done' \
    293 		'zaqbz zcz'
    294 	check 'IFS=q; for i in ${x-"aq${x-bqc}"qd};   do echo "z${i}z"; done' \
    295 		'zaqbqcz zdz'
    296 
    297 	# this is another almost certainly incorrect expectation
    298 	# (but again, see comment in default_val test - becoming unspecified.)
    299 	#                        uu qqqqqq uuu q uu	(quoted/unquoted)
    300 	check 'IFS=q; for i in ${x-"aq${x-"bqc"}"qd}; do echo "z${i}z"; done' \
    301 		'zaqbqcz zdz'
    302 
    303 	check 'IFS=q; for i in ${x-aq${x-"bqc"}qd};  do echo "z${i}z"; done' \
    304 		'zaz zbqcz zdz'
    305 
    306 	check_results ifs_alpha
    307 }
    308 
    309 atf_test_case quote
    310 quote_head()
    311 {
    312 	atf_set "descr" "Checks that field splitting works with multi-word" \
    313 	                "fields"
    314 }
    315 quote_body()
    316 {
    317 	unset x
    318 
    319 	TEST=0
    320 	# Some quote propagation checks
    321 	check 'set "${x-a b c}";   echo $#' 1
    322 
    323 	# this is another almost certainly incorrect expectation
    324 	# (but again, see comment in default_val test - becoming unspecified.)
    325 	#           qqqq uuu qqq  	(quoted/unquoted)  $1 is a $# is 2
    326 	check 'set "${x-"a b" c}"; echo $1' 'a b c'
    327 
    328 	check 'for i in "${x-a b c}"; do echo "z${i}z"; done' 'za b cz'
    329 
    330 	check_results quote
    331 }
    332 
    333 atf_test_case dollar_at
    334 dollar_at_head()
    335 {
    336 	atf_set "descr" "Checks that field splitting works when expanding" \
    337 	                "\$@"
    338 }
    339 dollar_at_body()
    340 {
    341 	unset x
    342 
    343 	TEST=0
    344 	# Check we get "$@" right
    345 
    346 	check 'set --;        for i in x"$@"x;  do echo "z${i}z"; done' 'zxxz'
    347 	check 'set a;         for i in x"$@"x;  do echo "z${i}z"; done' 'zxaxz'
    348 	check 'set a b;       for i in x"$@"x;  do echo "z${i}z"; done' \
    349 		'zxaz zbxz'
    350 
    351 	check 'set --;        for i;            do echo "z${i}z"; done' ''
    352 	check 'set --;        for i in $@;      do echo "z${i}z"; done' ''
    353 	check 'set --;        for i in "$@";    do echo "z${i}z"; done' ''
    354 	# atf_expect_fail "PR bin/50834"
    355 	check 'set --;        for i in ""$@;    do echo "z${i}z"; done' 'zz'
    356 	# atf_expect_pass
    357 	check 'set --;        for i in $@"";    do echo "z${i}z"; done' 'zz'
    358 	check 'set --;        for i in ""$@"";  do echo "z${i}z"; done' 'zz'
    359 	check 'set --;        for i in """$@";  do echo "z${i}z"; done' 'zz'
    360 	check 'set --;        for i in "$@""";  do echo "z${i}z"; done' 'zz'
    361 	check 'set --;        for i in """$@""";do echo "z${i}z"; done' 'zz'
    362 
    363 	check 'set "";        for i;            do echo "z${i}z"; done' 'zz'
    364 	check 'set "";        for i in "$@";    do echo "z${i}z"; done' 'zz'
    365 	check 'set "" "";     for i;            do echo "z${i}z"; done' 'zz zz'
    366 	check 'set "" "";     for i in "$@";    do echo "z${i}z"; done' 'zz zz'
    367 	check 'set "" "";     for i in $@;      do echo "z${i}z"; done' ''
    368 
    369 	check 'set "a b" c;   for i;            do echo "z${i}z"; done' \
    370 		'za bz zcz'
    371 	check 'set "a b" c;   for i in "$@";    do echo "z${i}z"; done' \
    372 		'za bz zcz'
    373 	check 'set "a b" c;   for i in $@;      do echo "z${i}z"; done' \
    374 		'zaz zbz zcz'
    375 	check 'set " a b " c; for i in "$@";    do echo "z${i}z"; done' \
    376 		'z a b z zcz'
    377 
    378 	check 'set a b c;     for i in "$@$@";  do echo "z${i}z"; done' \
    379 		'zaz zbz zcaz zbz zcz'
    380 	check 'set a b c;     for i in "$@""$@";do echo "z${i}z"; done' \
    381 		'zaz zbz zcaz zbz zcz'
    382 
    383 	check_results dollar_at
    384 }
    385 
    386 atf_test_case ifs
    387 ifs_head()
    388 {
    389 	atf_set "descr" "Checks that IFS correctly configures field" \
    390 	                "splitting behavior"
    391 }
    392 ifs_body()
    393 {
    394 	unset x
    395 
    396 	TEST=0
    397 	# Some IFS tests
    398 	check 't="-- "; IFS=" ";  set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '0'
    399 	check 't=" x";  IFS=" x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '1'
    400 	check 't=" x "; IFS=" x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' '1'
    401 	check 't=axb; IFS="x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r'  \
    402 		'2 a:b'
    403 	check 't="a x b"; IFS="x";  set $t; IFS=":"; r="$*"; IFS=; echo $# $r' \
    404 		'2 a : b'
    405 	check 't="a xx b"; IFS="x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' \
    406 		'3 a :: b'
    407 	check 't="a xx b"; IFS="x ";set $t; IFS=":"; r="$*"; IFS=; echo $# $r' \
    408 		'3 a::b'
    409 	# A recent 'clarification' means that a single trailing IFS
    410 	# non-whitespace doesn't generate an empty parameter
    411 	check 't="xax"; IFS="x"; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' \
    412 		'2 :a'
    413 	check 't="xax "; IFS="x "; set $t; IFS=":"; r="$*"; IFS=; echo $# $r' \
    414 		'2 :a'
    415 	# Verify that IFS isn't being applied where it shouldn't be.
    416 	check 'IFS="x"; set axb; IFS=":"; r="$*"; IFS=; echo $# $r' '1 axb'
    417 	check 'IFS=x; set axb; IFS=:; r=$*; IFS=; echo $# $r'       '1 axb'
    418 	check 'IFS=x; set axb; set -- "$*"; IFS=:; r=$*; IFS=; echo $# $r' \
    419 		'1 axb'
    420 	check 'IFS=x; set axb; set --  $*  ; IFS=:; r=$*; IFS=; echo $# $r' \
    421 		'2 a:b'
    422 
    423 	check_results ifs
    424 }
    425 
    426 atf_test_case var_length
    427 var_length_head()
    428 {
    429 	atf_set "descr" "Checks that field splitting works when expanding" \
    430 	                "a variable's length"
    431 }
    432 var_length_body()
    433 {
    434 	TEST=0
    435 
    436 	long=12345678123456781234567812345678
    437 	long=$long$long$long$long
    438 	export long
    439 	unset x
    440 
    441 	# first test that the test method works...
    442 	check 'set -u; : ${long}; echo ${#long}' '128'
    443 
    444 	# Check that we apply IFS to ${#var}
    445 	check 'echo ${#long}; IFS=2; echo ${#long}; set 1 ${#long};echo $#' \
    446 		'128 1 8 3'
    447 	check 'IFS=2; set ${x-${#long}};   IFS=" "; echo $* $#'     '1 8 2'
    448 	check 'IFS=2; set ${x-"${#long}"}; IFS=" "; echo $* $#'     '128 1'
    449 	check 'IFS=2; set "${x-${#long}}"; IFS=" "; echo $* $#'     '128 1'
    450 	check 'IFS=2; set ${x-${#long}};   :      ; echo $* $#'     '1 8 '
    451 	check 'IFS=2; set ${x-${#long}};   :      ; echo $* "$#"'   '1 8 2'
    452 	check 'IFS=2; set ${x-${#long}};   :      ; echo "$*" "$#"' '128 2'
    453 	check 'IFS=2; set ${x-${#long}};   :      ; echo "$@" "$#"' '1 8 2'
    454 
    455 	check_results var_length
    456 }
    457 
    458 atf_test_case split_arith
    459 split_arith_head()
    460 {
    461 	atf_set "descr" "Checks that field splitting works when expanding" \
    462 	                "the results from arithmetic"
    463 }
    464 split_arith_body()
    465 {
    466 	TEST=0
    467 
    468 	# Check that we apply IFS to $(( expr ))
    469 
    470 	# Note: we do not check the actual arithmetic operations here
    471 	# (there is a separate test just for that) so we just enter
    472 	# the "answer" inside $(( )) ... also makes it easier to visualise
    473 
    474 	check 'IFS=5; echo $(( 123456789 ))'	'1234 6789'
    475 	check 'IFS=5; echo "$(( 123456789 ))"'	'123456789'
    476 	check 'IFS=37; echo $(( 123456789 ))'	'12 456 89'
    477 	check 'IFS=37; echo "$(( 123456789 ))"'	'123456789'
    478 	check 'IFS=159; echo $(( 123456789 ))'	' 234 678'
    479 
    480 	check 'IFS=5; set -- $(( 123456789 )); echo $#: $1 $2 $3 $4' \
    481 		'2: 1234 6789'
    482 	check 'IFS=5; set -- "$(( 123456789 ))"; echo $#: $1 $2 $3 $4' \
    483 		'1: 1234 6789'		# go ahead: explain it!
    484 	check 'IFS=5; set -- "$(( 123456789 ))"; echo "$#: $1 $2 $3 $4"' \
    485 		'1: 123456789   '	# ah!
    486 
    487 	check 'IFS=37; set -- $(( 123456789 )); echo $#: $1 $2 $3 $4' \
    488 		' : 12 456 89'		# Tricky!
    489 	check 'IFS=5; set -- $(( 123456789 )); echo $#: $*' \
    490 		'2: 1234 6789'
    491 	check 'IFS=47; set -- $(( 123456789 )); echo $#: $*' \
    492 		'3: 123 56 89'
    493 	check 'IFS=5; set -- $(( 123456789 )); echo "$#: $*"' \
    494 		'2: 123456789'
    495 	check 'IFS=37; set -- $(( 123456789 )); echo "$#: $*"' \
    496 		'3: 123456389'	# [sic]
    497 	check 'IFS=5; set -- $(( 123456789 )); echo $#: $@' \
    498 		'2: 1234 6789'
    499 	check 'IFS=47; set -- $(( 123456789 )); echo $#: $@' \
    500 		'3: 123 56 89'
    501 	check 'IFS=5; set -- $(( 123456789 )); echo "$#: $@"' \
    502 		'2: 1234 6789'
    503 	check 'IFS=37; set -- $(( 123456789 )); echo "$#: $*"' \
    504 		'3: 123456389'	# [sic]
    505 
    506 	check 'IFS=1; set -- $(( 1111 )); echo "$#:" $*'	'4:   '
    507 	check 'IFS=" 1"; set -- $(( 1231231231 )); echo "$#: $*"' \
    508 		'4:  23 23 23'
    509 	check 'IFS="1 "; set -- $(( 1231231231 )); echo "$#: $*"' \
    510 		'4: 123123123'
    511 
    512 	check 'IFS=5; echo 5$(( 123456789 ))5'		'51234 67895'
    513 	check 'IFS=37; echo 73$(( 123456789 ))37'	'7312 456 8937'
    514 	check 'IFS=159; echo 11$(( 123456789 ))95'	'11 234 678 95'
    515 	check 'IFS="159 "; echo 11$(( 123456789 ))95'	'11 234 678 95'
    516 	check 'IFS="159 "; echo 11$(( 11234567899 ))95'	'11  234 678  95'
    517 
    518 	check_results split_arith
    519 }
    520 
    521 atf_test_case read_split
    522 read_split_head()
    523 {
    524 	atf_set "descr" "Checks that field splitting works for the read" \
    525 	                "built-in utility"
    526 }
    527 #
    528 # CAUTION: There are literal <tab> chars in the following test.
    529 # It is important that they be retained as is (the ones in the data
    530 # and results - those used for test formatting are immaterial).
    531 #
    532 read_split_body()
    533 {
    534 	DATA="  aaa bbb:ccc ddd+eee	fff:ggg+hhh	  "   # CAUTION: tabs!
    535 
    536 	TEST=0
    537 
    538 	check "unset IFS; printf '%s\n' '${DATA}' | {
    539 	  read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    540 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    541 	  '<aaa><bbb:ccc><ddd+eee><fff:ggg+hhh><><><><>'
    542 
    543 	check "unset IFS; printf '%s\n' '${DATA}' | {
    544 	  read x || printf 'FAIL:%d' \"\$?\" &&
    545 	  printf '<%s>' "'"$x"; }' \
    546 	  '<aaa bbb:ccc ddd+eee	fff:ggg+hhh>'
    547 
    548 	check "IFS=; printf '%s\n' '${DATA}' | {
    549 	  read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    550 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    551 	  "<${DATA}><><><><><><><>"
    552 
    553 	check "IFS=' 	'; printf '%s\n' '${DATA}' | {
    554 	  read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    555 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    556 	  '<aaa><bbb:ccc><ddd+eee><fff:ggg+hhh><><><><>'
    557 
    558 	check "IFS=':'; printf '%s\n' '${DATA}' | {
    559 	  read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    560 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    561 	  '<  aaa bbb><ccc ddd+eee	fff><ggg+hhh	  ><><><><><>'
    562 
    563 	check "IFS=': '; printf '%s\n' '${DATA}' | {
    564 	  read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    565 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    566 	  '<aaa><bbb><ccc><ddd+eee	fff><ggg+hhh	><><><>'
    567 
    568 	check "IFS=':	'; printf '%s\n' '${DATA}' | {
    569 	  read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    570 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    571 	  '<  aaa bbb><ccc ddd+eee><fff><ggg+hhh><  ><><><>'
    572 
    573 	check "IFS='+'; printf '%s\n' '${DATA}' | {
    574 	  read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    575 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    576 	  '<  aaa bbb:ccc ddd><eee	fff:ggg><hhh	  ><><><><><>'
    577 
    578 	check "IFS=' +'; printf '%s\n' '${DATA}' | {
    579 	  read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    580 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    581 	  '<aaa><bbb:ccc><ddd><eee	fff:ggg><hhh	><><><>'
    582 
    583 	check "IFS='+	'; printf '%s\n' '${DATA}' | {
    584 	  read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    585 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    586 	  '<  aaa bbb:ccc ddd><eee><fff:ggg><hhh><  ><><><>'
    587 
    588 	# This tests the bug from PR bin/57849 (which existed about 2 days)
    589 	# It also tests that a var-assign before read does not corrupt the
    590 	# value of the var in the executing shell environment
    591 	check "IFS='+'; printf '%s\n' '${DATA}' | {
    592 	  IFS=: read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    593 	  printf '<%s>' "'"$IFS" "$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    594 	  '<+><  aaa bbb><ccc ddd+eee	fff><ggg+hhh	  ><><><><><>'
    595 
    596 	check "IFS='+'; printf '%s\n' '${DATA}' | {
    597 	  IFS= read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    598 	  printf '<%s>' "'"$IFS" "$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }' \
    599 	  "<+><${DATA}><><><><><><><>"
    600 
    601 	# This doesn't really belong here, just tests that EOF works...
    602 	# (and that read sets unused vars to '', doesn't leave them unset)
    603 	check "unset IFS; set -u;
    604 	  read a b c d e f g h </dev/null || printf 'FAIL:%d' \"\$?\" &&
    605 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"'	\
    606 	  "FAIL:1<><><><><><><><>"
    607 
    608 	# And a similar one where EOF follows some data (which is read)
    609 	check "unset IFS; set -u; printf 'a b c' | {
    610 	  read a b c d e f g h || printf 'FAIL:%d' \"\$?\" &&
    611 	  printf '<%s>' "'"$a" "$b" "$c" "$d" "$e" "$f" "$g" "$h"; }'	\
    612 	  "FAIL:1<a><b><c><><><><><>"
    613 
    614 	check_results read_split
    615 }
    616 
    617 atf_init_test_cases()
    618 {
    619 	atf_add_test_case for
    620 	atf_add_test_case default_val
    621 	atf_add_test_case replacement_val
    622 	atf_add_test_case ifs_alpha
    623 	atf_add_test_case quote
    624 	atf_add_test_case dollar_at
    625 	atf_add_test_case ifs
    626 	atf_add_test_case var_length
    627 	atf_add_test_case split_arith
    628 	atf_add_test_case read_split
    629 }
    630