17c2fbfb3SApril Chin########################################################################
27c2fbfb3SApril Chin#                                                                      #
37c2fbfb3SApril Chin#               This software is part of the ast package               #
4*b30d1939SAndy Fiddaman#          Copyright (c) 1982-2012 AT&T Intellectual Property          #
57c2fbfb3SApril Chin#                      and is licensed under the                       #
6*b30d1939SAndy Fiddaman#                 Eclipse Public License, Version 1.0                  #
77c2fbfb3SApril Chin#                    by AT&T Intellectual Property                     #
87c2fbfb3SApril Chin#                                                                      #
97c2fbfb3SApril Chin#                A copy of the License is available at                 #
10*b30d1939SAndy Fiddaman#          http://www.eclipse.org/org/documents/epl-v10.html           #
11*b30d1939SAndy Fiddaman#         (with md5 checksum b35adb5213ca9657e911e9befb180842)         #
127c2fbfb3SApril Chin#                                                                      #
137c2fbfb3SApril Chin#              Information and Software Systems Research               #
147c2fbfb3SApril Chin#                            AT&T Research                             #
157c2fbfb3SApril Chin#                           Florham Park NJ                            #
167c2fbfb3SApril Chin#                                                                      #
177c2fbfb3SApril Chin#                  David Korn <dgk@research.att.com>                   #
187c2fbfb3SApril Chin#                                                                      #
197c2fbfb3SApril Chin########################################################################
207c2fbfb3SApril Chinfunction err_exit
217c2fbfb3SApril Chin{
227c2fbfb3SApril Chin	print -u$Error_fd -n "\t"
237c2fbfb3SApril Chin	print -u$Error_fd -r ${Command}[$1]: "${@:2}"
247c2fbfb3SApril Chin	(( Errors+=1 ))
257c2fbfb3SApril Chin}
267c2fbfb3SApril Chinalias err_exit='err_exit $LINENO'
2734f9b3eeSRoland Mainz
287c2fbfb3SApril ChinCommand=${0##*/}
297c2fbfb3SApril Chininteger Errors=0 Error_fd=2
307c2fbfb3SApril Chin
3134f9b3eeSRoland Mainztmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; }
3234f9b3eeSRoland Mainztrap "cd /; rm -rf $tmp" EXIT
3334f9b3eeSRoland Mainz
34*b30d1939SAndy Fiddamanbuiltin getconf
3534f9b3eeSRoland Mainzbincat=$(PATH=$(getconf PATH) whence -p cat)
3634f9b3eeSRoland Mainz
377c2fbfb3SApril Chinz=()
387c2fbfb3SApril Chinz.foo=( [one]=hello [two]=(x=3 y=4) [three]=hi)
397c2fbfb3SApril Chinz.bar[0]=hello
407c2fbfb3SApril Chinz.bar[2]=world
417c2fbfb3SApril Chinz.bar[1]=(x=4 y=5)
427c2fbfb3SApril Chinval='(
437c2fbfb3SApril Chin	typeset -a bar=(
447c2fbfb3SApril Chin		[0]=hello
457c2fbfb3SApril Chin		[2]=world
467c2fbfb3SApril Chin		[1]=(
477c2fbfb3SApril Chin			x=4
487c2fbfb3SApril Chin			y=5
497c2fbfb3SApril Chin		)
507c2fbfb3SApril Chin	)
517c2fbfb3SApril Chin	typeset -A foo=(
527c2fbfb3SApril Chin		[one]=hello
537c2fbfb3SApril Chin		[three]=hi
547c2fbfb3SApril Chin		[two]=(
557c2fbfb3SApril Chin			x=3
567c2fbfb3SApril Chin			y=4
577c2fbfb3SApril Chin		)
587c2fbfb3SApril Chin	)
597c2fbfb3SApril Chin)'
607c2fbfb3SApril Chin[[ $z == "$val" ]] || err_exit 'compound variable with mixed arrays not working'
617c2fbfb3SApril Chinz.bar[1]=yesyes
627c2fbfb3SApril Chin[[ ${z.bar[1]} == yesyes ]] || err_exit 'reassign of index array compound variable fails'
637c2fbfb3SApril Chinz.bar[1]=(x=12 y=5)
647c2fbfb3SApril Chin[[ ${z.bar[1]} == $'(\n\tx=12\n\ty=5\n)' ]] || err_exit 'reassign array simple to compound variable fails'
657c2fbfb3SApril Chineval val="$z"
667c2fbfb3SApril Chin(
677c2fbfb3SApril Chin	z.foo[three]=good
687c2fbfb3SApril Chin	[[ ${z.foo[three]} == good ]] || err_exit 'associative array assignment in subshell not working'
697c2fbfb3SApril Chin)
707c2fbfb3SApril Chin[[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment'
717c2fbfb3SApril Chineval val="$z"
727c2fbfb3SApril Chin(
737c2fbfb3SApril Chin	z.foo[two]=ok
747c2fbfb3SApril Chin	[[ ${z.foo[two]} == ok ]] || err_exit 'associative array assignment to compound variable in subshell not working'
757c2fbfb3SApril Chin	z.bar[1]=yes
767c2fbfb3SApril Chin	[[ ${z.bar[1]} == yes ]] || err_exit 'index array assignment to compound variable in subshell not working'
777c2fbfb3SApril Chin)
787c2fbfb3SApril Chin[[ $z == "$val" ]] || err_exit 'compound variable changes after associative array assignment'
7934f9b3eeSRoland Mainz
807c2fbfb3SApril Chinx=(
817c2fbfb3SApril Chin	foo=( qqq=abc rrr=def)
827c2fbfb3SApril Chin	bar=( zzz=no rst=fed)
837c2fbfb3SApril Chin)
847c2fbfb3SApril Chineval val="$x"
857c2fbfb3SApril Chin(
867c2fbfb3SApril Chin	unset x.foo
877c2fbfb3SApril Chin	[[ ${x.foo.qqq} ]] && err_exit 'x.foo.qqq should be unset'
887c2fbfb3SApril Chin	x.foo=good
897c2fbfb3SApril Chin	[[ ${x.foo} == good ]] || err_exit 'x.foo should be good'
907c2fbfb3SApril Chin)
917c2fbfb3SApril Chin[[ $x == "$val" ]] || err_exit 'compound variable changes after unset leaves'
927c2fbfb3SApril Chinunset l
937c2fbfb3SApril Chin(
947c2fbfb3SApril Chin	l=( a=1 b="BE" )
957c2fbfb3SApril Chin)
967c2fbfb3SApril Chin[[ ${l+foo} != foo ]] || err_exit 'l should be unset'
977c2fbfb3SApril Chin
987c2fbfb3SApril ChinError_fd=9
997c2fbfb3SApril Chineval "exec $Error_fd>&2 2>/dev/null"
1007c2fbfb3SApril Chin
1017c2fbfb3SApril ChinTEST_notfound=notfound
1027c2fbfb3SApril Chinwhile	whence $TEST_notfound >/dev/null 2>&1
1037c2fbfb3SApril Chindo	TEST_notfound=notfound-$RANDOM
1047c2fbfb3SApril Chindone
1057c2fbfb3SApril Chin
106*b30d1939SAndy Fiddaman
1077c2fbfb3SApril Chininteger BS=1024 nb=64 ss=60 bs no
1087c2fbfb3SApril Chinfor bs in $BS 1
1097c2fbfb3SApril Chindo	$SHELL -c '
1107c2fbfb3SApril Chin		{
1117c2fbfb3SApril Chin			sleep '$ss'
1127c2fbfb3SApril Chin			kill -KILL $$
1137c2fbfb3SApril Chin		} &
1147c2fbfb3SApril Chin		set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs')
1157c2fbfb3SApril Chin		print ${#1}
1167c2fbfb3SApril Chin		kill $!
11734f9b3eeSRoland Mainz	' > $tmp/sub 2>/dev/null
11834f9b3eeSRoland Mainz	no=$(<$tmp/sub)
1197c2fbfb3SApril Chin	(( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs -- expected $((BS*nb)), got ${no:-0}"
1207c2fbfb3SApril Chindone
1217c2fbfb3SApril Chin# this time with redirection on the trailing command
1227c2fbfb3SApril Chinfor bs in $BS 1
1237c2fbfb3SApril Chindo	$SHELL -c '
1247c2fbfb3SApril Chin		{
1257c2fbfb3SApril Chin			sleep 2
1267c2fbfb3SApril Chin			sleep '$ss'
1277c2fbfb3SApril Chin			kill -KILL $$
1287c2fbfb3SApril Chin		} &
1297c2fbfb3SApril Chin		set -- $(printf %.'$(($BS*$nb))'c x | dd bs='$bs' 2>/dev/null)
1307c2fbfb3SApril Chin		print ${#1}
1317c2fbfb3SApril Chin		kill $!
13234f9b3eeSRoland Mainz	' > $tmp/sub 2>/dev/null
13334f9b3eeSRoland Mainz	no=$(<$tmp/sub)
1347c2fbfb3SApril Chin	(( no == (BS * nb) )) || err_exit "shell hangs on command substitution output size >= $BS*$nb with write size $bs and trailing redirection -- expected $((BS*nb)), got ${no:-0}"
1357c2fbfb3SApril Chindone
1367c2fbfb3SApril Chin
1377c2fbfb3SApril Chin# exercise command substitutuion trailing newline logic w.r.t. pipe vs. tmp file io
1387c2fbfb3SApril Chin
1397c2fbfb3SApril Chinset -- \
1407c2fbfb3SApril Chin	'post-line print'								\
1417c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; print 1); print'					\
1427c2fbfb3SApril Chin	1										\
1437c2fbfb3SApril Chin	'pre-line print'								\
1447c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; print); print 1'					\
1457c2fbfb3SApril Chin	$'\n1'										\
1467c2fbfb3SApril Chin	'multiple pre-line print'							\
1477c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; print); print; ($TEST_fork; print 1); print'		\
1487c2fbfb3SApril Chin	$'\n\n1'									\
1497c2fbfb3SApril Chin	'multiple post-line print'							\
1507c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; print 1); print; ($TEST_fork; print); print'		\
1517c2fbfb3SApril Chin	1										\
1527c2fbfb3SApril Chin	'intermediate print'								\
1537c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; print 1); print; ($TEST_fork; print 2); print'	\
1547c2fbfb3SApril Chin	$'1\n\n2'									\
1557c2fbfb3SApril Chin	'simple variable'								\
1567c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; l=2; print "$l"); print $l'				\
1577c2fbfb3SApril Chin	2										\
1587c2fbfb3SApril Chin	'compound variable'								\
1597c2fbfb3SApril Chin	'$TEST_unset; ($TEST_fork; l=(a=2 b="BE"); print "$l"); print $l'		\
1607c2fbfb3SApril Chin	$'(\n\ta=2\n\tb=BE\n)'								\
1617c2fbfb3SApril Chin
1627c2fbfb3SApril Chinexport TEST_fork TEST_unset
1637c2fbfb3SApril Chin
1647c2fbfb3SApril Chinwhile	(( $# >= 3 ))
1657c2fbfb3SApril Chindo	txt=$1
1667c2fbfb3SApril Chin	cmd=$2
1677c2fbfb3SApril Chin	exp=$3
1687c2fbfb3SApril Chin	shift 3
1697c2fbfb3SApril Chin	for TEST_unset in '' 'unset var'
1707c2fbfb3SApril Chin	do	for TEST_fork in '' 'ulimit -c 0'
1717c2fbfb3SApril Chin		do	for TEST_shell in "eval" "$SHELL -c"
1727c2fbfb3SApril Chin			do	if	! got=$($TEST_shell "$cmd")
1737c2fbfb3SApril Chin				then	err_exit "${TEST_shell/*-c/\$SHELL -c} ${TEST_unset:+unset }${TEST_fork:+fork }$txt print failed"
1747c2fbfb3SApril Chin				elif	[[ "$got" != "$exp" ]]
1757c2fbfb3SApril Chin				then	EXP=$(printf %q "$exp")
1767c2fbfb3SApril Chin					GOT=$(printf %q "$got")
1777c2fbfb3SApril Chin					err_exit "${TEST_shell/*-c/\$SHELL -c} ${TEST_unset:+unset }${TEST_fork:+fork }$txt command substitution failed -- expected $EXP, got $GOT"
1787c2fbfb3SApril Chin				fi
1797c2fbfb3SApril Chin			done
1807c2fbfb3SApril Chin		done
1817c2fbfb3SApril Chin	done
1827c2fbfb3SApril Chindone
1837c2fbfb3SApril Chin
1847c2fbfb3SApril Chinr=$( ($SHELL -c '
1857c2fbfb3SApril Chin	{
1867c2fbfb3SApril Chin		sleep 32
1877c2fbfb3SApril Chin		kill -KILL $$
1887c2fbfb3SApril Chin	} &
1897c2fbfb3SApril Chin	for v in $(set | sed "s/=.*//")
1907c2fbfb3SApril Chin	do	command unset $v
1917c2fbfb3SApril Chin	done
1927c2fbfb3SApril Chin	typeset -Z5 I
1937c2fbfb3SApril Chin	for ((I = 0; I < 1024; I++))
1947c2fbfb3SApril Chin	do	eval A$I=1234567890
1957c2fbfb3SApril Chin	done
1967c2fbfb3SApril Chin	a=$(set 2>&1)
1977c2fbfb3SApril Chin	print ok
1987c2fbfb3SApril Chin	kill -KILL $!
1997c2fbfb3SApril Chin') 2>/dev/null)
2007c2fbfb3SApril Chin[[ $r == ok ]] || err_exit "large subshell command substitution hangs"
2017c2fbfb3SApril Chin
2027c2fbfb3SApril Chinfor TEST_command in '' $TEST_notfound
2037c2fbfb3SApril Chindo	for TEST_exec in '' 'exec'
2047c2fbfb3SApril Chin	do	for TEST_fork in '' 'ulimit -c 0;'
2057c2fbfb3SApril Chin		do	for TEST_redirect in '' '>/dev/null'
2067c2fbfb3SApril Chin			do	for TEST_substitute in '' ': $'
2077c2fbfb3SApril Chin				do
2087c2fbfb3SApril Chin
2097c2fbfb3SApril Chin	TEST_test="$TEST_substitute($TEST_fork $TEST_exec $TEST_command $TEST_redirect)"
2107c2fbfb3SApril Chin	[[ $TEST_test == '('*([[:space:]])')' ]] && continue
2117c2fbfb3SApril Chin	r=$($SHELL -c '
2127c2fbfb3SApril Chin		{
2137c2fbfb3SApril Chin			sleep 2
2147c2fbfb3SApril Chin			kill -KILL $$
2157c2fbfb3SApril Chin		} &
2167c2fbfb3SApril Chin		'"$TEST_test"'
2177c2fbfb3SApril Chin		kill $!
2187c2fbfb3SApril Chin		print ok
2197c2fbfb3SApril Chin		')
2207c2fbfb3SApril Chin	[[ $r == ok ]] || err_exit "shell hangs on $TEST_test"
2217c2fbfb3SApril Chin
2227c2fbfb3SApril Chin				done
2237c2fbfb3SApril Chin			done
2247c2fbfb3SApril Chin		done
2257c2fbfb3SApril Chin	done
2267c2fbfb3SApril Chindone
2277c2fbfb3SApril Chin
22834f9b3eeSRoland Mainz$SHELL -c '( autoload xxxxx);print -n' ||  err_exit 'autoloaded functions in subshells can cause failure'
22934f9b3eeSRoland Mainzfoo=$($SHELL  <<- ++EOF++
23034f9b3eeSRoland Mainz	(trap 'print bar' EXIT;print -n foo)
23134f9b3eeSRoland Mainz	++EOF++
23234f9b3eeSRoland Mainz)
23334f9b3eeSRoland Mainz[[ $foo == foobar ]] || err_exit 'trap on exit when last commands is subshell is not triggered'
23434f9b3eeSRoland Mainz
23534f9b3eeSRoland Mainzerr=$(
23634f9b3eeSRoland Mainz	$SHELL  2>&1  <<- \EOF
23734f9b3eeSRoland Mainz	        date=$(whence -p date)
23834f9b3eeSRoland Mainz	        function foo
23934f9b3eeSRoland Mainz	        {
24034f9b3eeSRoland Mainz	                x=$( $date > /dev/null 2>&1 ;:)
24134f9b3eeSRoland Mainz	        }
24234f9b3eeSRoland Mainz		# consume almost all fds to push the test to the fd limit #
24334f9b3eeSRoland Mainz		integer max=$(ulimit --nofile)
24434f9b3eeSRoland Mainz		(( max -= 6 ))
24534f9b3eeSRoland Mainz		for ((i=20; i < max; i++))
24634f9b3eeSRoland Mainz		do	exec {i}>&1
24734f9b3eeSRoland Mainz		done
24834f9b3eeSRoland Mainz	        for ((i=0; i < 20; i++))
24934f9b3eeSRoland Mainz	        do      y=$(foo)
25034f9b3eeSRoland Mainz	        done
25134f9b3eeSRoland Mainz	EOF
25234f9b3eeSRoland Mainz) || {
25334f9b3eeSRoland Mainz	err=${err%%$'\n'*}
25434f9b3eeSRoland Mainz	err=${err#*:}
25534f9b3eeSRoland Mainz	err=${err##[[:space:]]}
25634f9b3eeSRoland Mainz	err_exit "nested command substitution with redirections failed -- $err"
25734f9b3eeSRoland Mainz}
25834f9b3eeSRoland Mainz
25934f9b3eeSRoland Mainzexp=0
26034f9b3eeSRoland Mainz$SHELL -c $'
26134f9b3eeSRoland Mainz	function foobar
26234f9b3eeSRoland Mainz	{
26334f9b3eeSRoland Mainz		print "hello world"
26434f9b3eeSRoland Mainz	}
26534f9b3eeSRoland Mainz	[[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]]
26634f9b3eeSRoland Mainz	exit '$exp$'
26734f9b3eeSRoland Mainz'
26834f9b3eeSRoland Mainzgot=$?
26934f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'"
27034f9b3eeSRoland Mainzexp=ok
27134f9b3eeSRoland Mainzgot=$($SHELL -c $'
27234f9b3eeSRoland Mainz	function foobar
27334f9b3eeSRoland Mainz	{
27434f9b3eeSRoland Mainz		print "hello world"
27534f9b3eeSRoland Mainz	}
27634f9b3eeSRoland Mainz	[[ $(getopts \'[+?X\ffoobar\fX]\' v --man 2>&1) == *"Xhello worldX"* ]]
27734f9b3eeSRoland Mainz	print '$exp$'
27834f9b3eeSRoland Mainz')
27934f9b3eeSRoland Mainz[[ $got == $exp ]] || err_exit "getopts --man runtime callout with nonzero exit terminates shell -- expected '$exp', got '$got'"
28034f9b3eeSRoland Mainz
28134f9b3eeSRoland Mainz# command substitution variations #
28234f9b3eeSRoland Mainzset -- \
28334f9b3eeSRoland Mainz	'$('			')'		\
28434f9b3eeSRoland Mainz	'${ '			'; }'		\
28534f9b3eeSRoland Mainz	'$(ulimit -c 0; '	')'		\
28634f9b3eeSRoland Mainz	'$( ('			') )'		\
28734f9b3eeSRoland Mainz	'${ ('			'); }'		\
28834f9b3eeSRoland Mainz	'`'			'`'		\
28934f9b3eeSRoland Mainz	'`('			')`'		\
29034f9b3eeSRoland Mainz	'`ulimit -c 0; '	'`'		\
29134f9b3eeSRoland Mainz	# end of table #
29234f9b3eeSRoland Mainzexp=ok
29334f9b3eeSRoland Mainztestcase[1]='
29434f9b3eeSRoland Mainz	if	%sexpr "NOMATCH" : ".*Z" >/dev/null%s
29534f9b3eeSRoland Mainz	then	print error
29634f9b3eeSRoland Mainz	else	print ok
29734f9b3eeSRoland Mainz	fi
29834f9b3eeSRoland Mainz	exit %s
29934f9b3eeSRoland Mainz'
30034f9b3eeSRoland Mainztestcase[2]='
30134f9b3eeSRoland Mainz	function bar
30234f9b3eeSRoland Mainz	{
30334f9b3eeSRoland Mainz		pipeout=%1$sprintf Ok | tr O o%2$s
30434f9b3eeSRoland Mainz		print $pipeout
30534f9b3eeSRoland Mainz		return 0
30634f9b3eeSRoland Mainz	}
30734f9b3eeSRoland Mainz	foo=%1$sbar%2$s || foo="exit status $?"
30834f9b3eeSRoland Mainz	print $foo
30934f9b3eeSRoland Mainz	exit %3$s
31034f9b3eeSRoland Mainz'
31134f9b3eeSRoland Mainzwhile	(( $# >= 2 ))
31234f9b3eeSRoland Mainzdo	for ((TEST=1; TEST<=${#testcase[@]}; TEST++))
31334f9b3eeSRoland Mainz	do	body=${testcase[TEST]}
31434f9b3eeSRoland Mainz		for code in 0 2
31534f9b3eeSRoland Mainz		do	got=${ printf "$body" "$1" "$2" "$code" | $SHELL 2>&1 }
31634f9b3eeSRoland Mainz			status=$?
31734f9b3eeSRoland Mainz			if	(( status != code ))
31834f9b3eeSRoland Mainz			then	err_exit "test $TEST '$1...$2 exit $code' failed -- exit status $status, expected $code"
31934f9b3eeSRoland Mainz			elif	[[ $got != $exp ]]
32034f9b3eeSRoland Mainz			then	err_exit "test $TEST '$1...$2 exit $code' failed -- got '$got', expected '$exp'"
32134f9b3eeSRoland Mainz			fi
32234f9b3eeSRoland Mainz		done
32334f9b3eeSRoland Mainz	done
32434f9b3eeSRoland Mainz	shift 2
32534f9b3eeSRoland Mainzdone
32634f9b3eeSRoland Mainz
32734f9b3eeSRoland Mainz# the next tests loop on all combinations of
32834f9b3eeSRoland Mainz#	{ SUB CAT INS TST APP } X { file-sizes }
32934f9b3eeSRoland Mainz# where the file size starts at 1Ki and doubles up to and including 1Mi
33034f9b3eeSRoland Mainz#
33134f9b3eeSRoland Mainz# the tests and timeouts are done in async subshells to prevent
33234f9b3eeSRoland Mainz# the test harness from hanging
33334f9b3eeSRoland Mainz
33434f9b3eeSRoland MainzSUB=(
33534f9b3eeSRoland Mainz	( BEG='$( '	END=' )'	)
33634f9b3eeSRoland Mainz	( BEG='${ '	END='; }'	)
33734f9b3eeSRoland Mainz)
33834f9b3eeSRoland MainzCAT=(  cat  $bincat  )
33934f9b3eeSRoland MainzINS=(  ""  "builtin cat; "  "builtin -d cat $bincat; "  ": > /dev/null; "  )
34034f9b3eeSRoland MainzAPP=(  ""  "; :"  )
34134f9b3eeSRoland MainzTST=(
34234f9b3eeSRoland Mainz	( CMD='print foo | $cat'			EXP=3		)
34334f9b3eeSRoland Mainz	( CMD='$cat < $tmp/lin'						)
34434f9b3eeSRoland Mainz	( CMD='cat $tmp/lin | $cat'					)
34534f9b3eeSRoland Mainz	( CMD='read v < $tmp/buf; print $v'		LIM=4*1024	)
34634f9b3eeSRoland Mainz	( CMD='cat $tmp/buf | read v; print $v'		LIM=4*1024	)
34734f9b3eeSRoland Mainz)
34834f9b3eeSRoland Mainz
349*b30d1939SAndy Fiddamanif	cat /dev/fd/3 3</dev/null >/dev/null 2>&1 || whence mkfifo > /dev/null
35034f9b3eeSRoland Mainzthen	T=${#TST[@]}
35134f9b3eeSRoland Mainz	TST[T].CMD='$cat <(print foo)'
35234f9b3eeSRoland Mainz	TST[T].EXP=3
35334f9b3eeSRoland Mainzfi
35434f9b3eeSRoland Mainz
35534f9b3eeSRoland Mainz# prime the two data files to 512 bytes each
35634f9b3eeSRoland Mainz# $tmp/lin has newlines every 16 bytes and $tmp/buf has no newlines
35734f9b3eeSRoland Mainz# the outer loop doubles the file size at top
35834f9b3eeSRoland Mainz
35934f9b3eeSRoland Mainzbuf=$'1234567890abcdef'
36034f9b3eeSRoland Mainzlin=$'\n1234567890abcde'
36134f9b3eeSRoland Mainzfor ((i=0; i<5; i++))
36234f9b3eeSRoland Mainzdo	buf=$buf$buf
36334f9b3eeSRoland Mainz	lin=$lin$lin
36434f9b3eeSRoland Mainzdone
36534f9b3eeSRoland Mainzprint -n "$buf" > $tmp/buf
36634f9b3eeSRoland Mainzprint -n "$lin" > $tmp/lin
36734f9b3eeSRoland Mainz
36834f9b3eeSRoland Mainzunset SKIP
36934f9b3eeSRoland Mainzfor ((n=1024; n<=1024*1024; n*=2))
37034f9b3eeSRoland Mainzdo	cat $tmp/buf $tmp/buf > $tmp/tmp
37134f9b3eeSRoland Mainz	mv $tmp/tmp $tmp/buf
37234f9b3eeSRoland Mainz	cat $tmp/lin $tmp/lin > $tmp/tmp
37334f9b3eeSRoland Mainz	mv $tmp/tmp $tmp/lin
37434f9b3eeSRoland Mainz	for ((S=0; S<${#SUB[@]}; S++))
37534f9b3eeSRoland Mainz	do	for ((C=0; C<${#CAT[@]}; C++))
37634f9b3eeSRoland Mainz		do	cat=${CAT[C]}
37734f9b3eeSRoland Mainz			for ((I=0; I<${#INS[@]}; I++))
37834f9b3eeSRoland Mainz			do	for ((A=0; A<${#APP[@]}; A++))
37934f9b3eeSRoland Mainz				do	for ((T=0; T<${#TST[@]}; T++))
38034f9b3eeSRoland Mainz					do	#undent...#
38134f9b3eeSRoland Mainz
38234f9b3eeSRoland Mainz	if	[[ ! ${SKIP[S][C][I][A][T]} ]]
38334f9b3eeSRoland Mainz	then	eval "{ x=${SUB[S].BEG}${INS[I]}${TST[T].CMD}${APP[A]}${SUB[S].END}; print \${#x}; } >\$tmp/out &"
38434f9b3eeSRoland Mainz		m=$!
38534f9b3eeSRoland Mainz		{ sleep 4; kill -9 $m; } &
38634f9b3eeSRoland Mainz		k=$!
38734f9b3eeSRoland Mainz		wait $m
38834f9b3eeSRoland Mainz		h=$?
38934f9b3eeSRoland Mainz		kill -9 $k
39034f9b3eeSRoland Mainz		wait $k
39134f9b3eeSRoland Mainz		got=$(<$tmp/out)
39234f9b3eeSRoland Mainz		if	[[ ! $got ]] && (( h ))
39334f9b3eeSRoland Mainz		then	got=HUNG
39434f9b3eeSRoland Mainz		fi
39534f9b3eeSRoland Mainz		if	[[ ${TST[T].EXP} ]]
39634f9b3eeSRoland Mainz		then	exp=${TST[T].EXP}
39734f9b3eeSRoland Mainz		else	exp=$n
39834f9b3eeSRoland Mainz		fi
39934f9b3eeSRoland Mainz		if	[[ $got != $exp ]]
40034f9b3eeSRoland Mainz		then	# on failure skip similar tests on larger files sizes #
40134f9b3eeSRoland Mainz			SKIP[S][C][I][A][T]=1
40234f9b3eeSRoland Mainz			siz=$(printf $'%#i' $exp)
40334f9b3eeSRoland Mainz			cmd=${TST[T].CMD//\$cat/$cat}
40434f9b3eeSRoland Mainz			cmd=${cmd//\$tmp\/buf/$siz.buf}
40534f9b3eeSRoland Mainz			cmd=${cmd//\$tmp\/lin/$siz.lin}
40634f9b3eeSRoland Mainz			err_exit "'x=${SUB[S].BEG}${INS[I]}${cmd}${APP[A]}${SUB[S].END} && print \${#x}' failed -- expected '$exp', got '$got'"
40734f9b3eeSRoland Mainz		elif	[[ ${TST[T].EXP} ]] || (( TST[T].LIM >= n ))
40834f9b3eeSRoland Mainz		then	SKIP[S][C][I][A][T]=1
40934f9b3eeSRoland Mainz		fi
41034f9b3eeSRoland Mainz	fi
41134f9b3eeSRoland Mainz
41234f9b3eeSRoland Mainz						#...indent#
41334f9b3eeSRoland Mainz					done
41434f9b3eeSRoland Mainz				done
41534f9b3eeSRoland Mainz			done
41634f9b3eeSRoland Mainz		done
41734f9b3eeSRoland Mainz	done
41834f9b3eeSRoland Mainzdone
41934f9b3eeSRoland Mainz
42034f9b3eeSRoland Mainz# specifics -- there's more?
42134f9b3eeSRoland Mainz
42234f9b3eeSRoland Mainz{
42334f9b3eeSRoland Mainz	cmd='{ exec 5>/dev/null; print "$(eval ls -d . 2>&1 1>&5)"; } >$tmp/out &'
42434f9b3eeSRoland Mainz	eval $cmd
42534f9b3eeSRoland Mainz	m=$!
42634f9b3eeSRoland Mainz	{ sleep 4; kill -9 $m; } &
42734f9b3eeSRoland Mainz	k=$!
42834f9b3eeSRoland Mainz	wait $m
42934f9b3eeSRoland Mainz	h=$?
43034f9b3eeSRoland Mainz	kill -9 $k
43134f9b3eeSRoland Mainz	wait $k
43234f9b3eeSRoland Mainz	got=$(<$tmp/out)
43334f9b3eeSRoland Mainz} 2>/dev/null
43434f9b3eeSRoland Mainzexp=''
43534f9b3eeSRoland Mainzif	[[ ! $got ]] && (( h ))
43634f9b3eeSRoland Mainzthen	got=HUNG
43734f9b3eeSRoland Mainzfi
43834f9b3eeSRoland Mainzif	[[ $got != $exp ]]
43934f9b3eeSRoland Mainzthen	err_exit "eval '$cmd' failed -- expected '$exp', got '$got'"
44034f9b3eeSRoland Mainzfi
44134f9b3eeSRoland Mainz
44234f9b3eeSRoland Mainzfloat t1=$SECONDS
44334f9b3eeSRoland Mainzsleep=$(whence -p sleep)
44434f9b3eeSRoland Mainzif	[[ $sleep ]]
44534f9b3eeSRoland Mainzthen
44634f9b3eeSRoland Mainz	$SHELL -c "( $sleep 5 </dev/null >/dev/null 2>&1 & );exit 0" | cat
44734f9b3eeSRoland Mainz	(( (SECONDS-t1) > 4 )) && err_exit '/bin/sleep& in subshell hanging'
44834f9b3eeSRoland Mainz	((t1=SECONDS))
44934f9b3eeSRoland Mainzfi
45034f9b3eeSRoland Mainz$SHELL -c '( sleep 5 </dev/null >/dev/null 2>&1 & );exit 0' | cat
45134f9b3eeSRoland Mainz(( (SECONDS-t1) > 4 )) && err_exit 'sleep& in subshell hanging'
45234f9b3eeSRoland Mainz
4533e14f97fSRoger A. Faulknerexp=HOME=$HOME
4543e14f97fSRoger A. Faulkner( HOME=/bin/sh )
4553e14f97fSRoger A. Faulknergot=$(env | grep ^HOME=)
4563e14f97fSRoger A. Faulkner[[ $got == "$exp" ]] ||  err_exit "( HOME=/bin/sh ) cleanup failed -- expected '$exp', got '$got'"
4573e14f97fSRoger A. Faulkner
4583e14f97fSRoger A. Faulknercmd='echo $((case x in x)echo ok;esac);:)'
4593e14f97fSRoger A. Faulknerexp=ok
4603e14f97fSRoger A. Faulknergot=$($SHELL -c "$cmd" 2>&1)
4613e14f97fSRoger A. Faulkner[[ $got == "$exp" ]] ||  err_exit "'$cmd' failed -- expected '$exp', got '$got'"
4623e14f97fSRoger A. Faulkner
4633e14f97fSRoger A. Faulknercmd='eval "for i in 1 2; do eval /bin/echo x; done"'
4643e14f97fSRoger A. Faulknerexp=$'x\nx'
4653e14f97fSRoger A. Faulknergot=$($SHELL -c "$cmd")
4663e14f97fSRoger A. Faulknerif	[[ $got != "$exp" ]]
4673e14f97fSRoger A. Faulknerthen	EXP=$(printf %q "$exp")
4683e14f97fSRoger A. Faulkner	GOT=$(printf %q "$got")
4693e14f97fSRoger A. Faulkner	err_exit "'$cmd' failed -- expected $EXP, got $GOT"
4703e14f97fSRoger A. Faulknerfi
4713e14f97fSRoger A. Faulkner
472*b30d1939SAndy Fiddaman(
473*b30d1939SAndy Fiddaman$SHELL -c 'sleep 20 & pid=$!; { x=$( ( seq 60000 ) );kill -9 $pid;}&;wait $pid'
474*b30d1939SAndy Fiddaman) 2> /dev/null
475*b30d1939SAndy Fiddaman(( $? )) ||  err_exit 'nested command substitution with large output hangs'
476*b30d1939SAndy Fiddaman
477*b30d1939SAndy Fiddaman(.sh.foo=foobar)
478*b30d1939SAndy Fiddaman[[ ${.sh.foo} == foobar ]] && err_exit '.sh subvariables in subshells remain set'
479*b30d1939SAndy Fiddaman[[ $($SHELL -c 'print 1 | : "$(/bin/cat <(/bin/cat))"') ]] && err_exit 'process substitution not working correctly in subshells'
480*b30d1939SAndy Fiddaman
481*b30d1939SAndy Fiddaman# config hang bug
482*b30d1939SAndy Fiddamaninteger i
483*b30d1939SAndy Fiddamanfor ((i=1; i < 1000; i++))
484*b30d1939SAndy Fiddamando	typeset foo$i=$i
485*b30d1939SAndy Fiddamandone
486*b30d1939SAndy Fiddaman{
487*b30d1939SAndy Fiddaman    : $( (ac_space=' '; set | grep ac_space) 2>&1)
488*b30d1939SAndy Fiddaman} < /dev/null | cat > /dev/null &
489*b30d1939SAndy Fiddamansleep  1.5
490*b30d1939SAndy Fiddamanif	kill -KILL $! 2> /dev/null
491*b30d1939SAndy Fiddamanthen	err_exit 'process timed out with hung comsub'
492*b30d1939SAndy Fiddamanfi
493*b30d1939SAndy Fiddamanwait $! 2> /dev/null
494*b30d1939SAndy Fiddaman(( $? > 128 )) && err_exit 'incorrect exit status with comsub'
495*b30d1939SAndy Fiddaman
496*b30d1939SAndy Fiddaman$SHELL 2> /dev/null -c '[[ ${ print foo },${ print bar } == foo,bar ]]' || err_exit  '${ print foo },${ print bar } not working'
497*b30d1939SAndy Fiddaman$SHELL 2> /dev/null -c '[[ ${ print foo; },${ print bar } == foo,bar ]]' || err_exit  '${ print foo; },${ print bar } not working'
498*b30d1939SAndy Fiddaman
499*b30d1939SAndy Fiddamansrc=$'true 2>&1\n: $(true | true)\n: $(true | true)\n: $(true | true)\n'$(whence -p true)
500*b30d1939SAndy Fiddamanexp=ok
501*b30d1939SAndy Fiddamangot=$( $SHELL -c "(eval '$src'); echo $exp" )
502*b30d1939SAndy Fiddaman[[ $got == "$exp" ]] || err_exit 'subshell eval of pipeline clobbers stdout'
503*b30d1939SAndy Fiddaman
504*b30d1939SAndy Fiddamanx=$( { time $SHELL -c date >| /dev/null;} 2>&1)
505*b30d1939SAndy Fiddaman[[ $x == *real*user*sys* ]] || err_exit 'time { ...;} 2>&1 in $(...) fails'
506*b30d1939SAndy Fiddaman
507*b30d1939SAndy Fiddamanx=$($SHELL -c '( function fx { export X=123;  } ; fx; ); echo $X')
508*b30d1939SAndy Fiddaman[[ $x == 123 ]] && err_exit 'global variables set from with functions inside a
509*b30d1939SAndy Fiddamansubshell can leave side effects in parent shell'
510*b30d1939SAndy Fiddaman
511*b30d1939SAndy Fiddamandate=$(whence -p date)
512*b30d1939SAndy Fiddamanerr() { return $1; }
513*b30d1939SAndy Fiddaman( err 12 ) & pid=$!
514*b30d1939SAndy Fiddaman: $( $date)
515*b30d1939SAndy Fiddamanwait $pid
516*b30d1939SAndy Fiddaman[[ $? == 12 ]] || err_exit 'exit status from subshells not being preserved'
517*b30d1939SAndy Fiddaman
518*b30d1939SAndy Fiddamanif	cat /dev/fd/3 3</dev/null >/dev/null 2>&1 || whence mkfifo > /dev/null
519*b30d1939SAndy Fiddamanthen	x="$(sed 's/^/Hello /' <(print "Fred" | sort))"
520*b30d1939SAndy Fiddaman	[[ $x == 'Hello Fred' ]] || err_exit  "process substitution of pipeline in command substitution not working"
521*b30d1939SAndy Fiddamanfi
522*b30d1939SAndy Fiddaman
523*b30d1939SAndy Fiddaman{
524*b30d1939SAndy Fiddaman$SHELL <<- \EOF
525*b30d1939SAndy Fiddaman	function foo
526*b30d1939SAndy Fiddaman	{
527*b30d1939SAndy Fiddaman		integer i
528*b30d1939SAndy Fiddaman		print -u2 foobar
529*b30d1939SAndy Fiddaman		for	((i=0; i < 8000; i++))
530*b30d1939SAndy Fiddaman		do	print abcdefghijk
531*b30d1939SAndy Fiddaman		done
532*b30d1939SAndy Fiddaman		print -u2 done
533*b30d1939SAndy Fiddaman	}
534*b30d1939SAndy Fiddaman	out=$(eval "foo | cat" 2>&1)
535*b30d1939SAndy Fiddaman	(( ${#out} == 96011 )) || err_exit "\${#out} is ${#out} should be 96011"
536*b30d1939SAndy FiddamanEOF
537*b30d1939SAndy Fiddaman} & pid=$!
538*b30d1939SAndy Fiddaman$SHELL -c "{ sleep 4 && kill $pid ;}" 2> /dev/null
539*b30d1939SAndy Fiddaman(( $? == 0 )) &&  err_exit 'process has hung'
540*b30d1939SAndy Fiddaman
541*b30d1939SAndy Fiddaman{
542*b30d1939SAndy Fiddamanx=$( $SHELL  <<- \EOF
543*b30d1939SAndy Fiddaman	function func1 { typeset IFS; : $(func2); print END ;}
544*b30d1939SAndy Fiddaman	function func2 { IFS="BAR"; }
545*b30d1939SAndy Fiddaman	func1
546*b30d1939SAndy Fiddaman	func1
547*b30d1939SAndy FiddamanEOF
548*b30d1939SAndy Fiddaman)
549*b30d1939SAndy Fiddaman} 2> /dev/null
550*b30d1939SAndy Fiddaman[[ $x == $'END\nEND' ]] || err_exit 'bug in save/restore of IFS in subshell'
551*b30d1939SAndy Fiddaman
552*b30d1939SAndy Fiddamantrue=$(whence -p true)
553*b30d1939SAndy Fiddamandate=$(whence -p date)
554*b30d1939SAndy Fiddamantmpf=$tmp/foo
555*b30d1939SAndy Fiddamanfunction fun1
556*b30d1939SAndy Fiddaman{
557*b30d1939SAndy Fiddaman	$true
558*b30d1939SAndy Fiddaman	cd - >/dev/null 2>&1
559*b30d1939SAndy Fiddaman	print -u2 -- "$($date) SUCCESS"
560*b30d1939SAndy Fiddaman}
561*b30d1939SAndy Fiddaman
562*b30d1939SAndy Fiddamanprint -n $(fun1 2> $tmpf)
563*b30d1939SAndy Fiddaman[[  $(< $tmpf) == *SUCCESS ]] || err_exit 'standard error output lost with command substitution'
564*b30d1939SAndy Fiddaman
565*b30d1939SAndy Fiddaman
566*b30d1939SAndy Fiddamantmpfile=$tmp/foo
567*b30d1939SAndy Fiddamancat > $tmpfile <<-\EOF
568*b30d1939SAndy Fiddaman	$SHELL -c 'function g { IFS= ;};function f { typeset IFS;(g);: $V;};f;f'
569*b30d1939SAndy Fiddaman	EOF
570*b30d1939SAndy Fiddaman$SHELL 2> /dev/null "$tmpfile" || err_exit 'IFS in subshell causes core dump'
571*b30d1939SAndy Fiddaman
572*b30d1939SAndy Fiddamanunset i
573*b30d1939SAndy Fiddamanif      [[ -d /dev/fd ]]
574*b30d1939SAndy Fiddamanthen    integer i
575*b30d1939SAndy Fiddaman        for ((i=11; i < 29; i++))
576*b30d1939SAndy Fiddaman        do      if      ! [[ -r /dev/fd/$i  || -w /dev/fd/$i ]]
577*b30d1939SAndy Fiddaman                then    a=$($SHELL -c "[[ -r /dev/fd/$i || -w /dev/fd/$i ]]")
578*b30d1939SAndy Fiddaman                        (( $? )) || err_exit "file descriptor $i not close on exec"
579*b30d1939SAndy Fiddaman                fi
580*b30d1939SAndy Fiddaman        done
581*b30d1939SAndy Fiddamanfi
582*b30d1939SAndy Fiddaman
583*b30d1939SAndy Fiddamantrap USR1 USR1
584*b30d1939SAndy Fiddamantrap ERR ERR
585*b30d1939SAndy Fiddaman[[ $(trap -p USR1) == USR1 ]] || err_exit 'trap -p USR1 in subshell not working'
586*b30d1939SAndy Fiddaman[[ $(trap -p ERR) == ERR ]] || err_exit 'trap -p ERR in subshell not working'
587*b30d1939SAndy Fiddaman[[ $(trap -p) == *USR* ]] || err_exit 'trap -p in subshell does not contain USR'
588*b30d1939SAndy Fiddaman[[ $(trap -p) == *ERR* ]] || err_exit 'trap -p in subshell does not contain ERR'
589*b30d1939SAndy Fiddamantrap - USR1 ERR
590*b30d1939SAndy Fiddaman
591*b30d1939SAndy Fiddaman( PATH=/bin:/usr/bin
592*b30d1939SAndy Fiddamandot=$(cat <<-EOF
593*b30d1939SAndy Fiddaman		$(ls -d .)
594*b30d1939SAndy Fiddaman	EOF
595*b30d1939SAndy Fiddaman) ) & sleep 1
596*b30d1939SAndy Fiddamanif      kill -0 $! 2> /dev/null
597*b30d1939SAndy Fiddamanthen    err_exit  'command substitution containg here-doc with command substitution fails'
598*b30d1939SAndy Fiddamanfi
599*b30d1939SAndy Fiddaman
600*b30d1939SAndy Fiddamanprintf=$(whence -p printf)
601*b30d1939SAndy Fiddaman[[ $( { trap "echo foobar" EXIT; ( $printf ""); } & wait) == foobar ]] || err_exit  'exit trap not being invoked'
602*b30d1939SAndy Fiddaman
603*b30d1939SAndy Fiddaman$SHELL 2> /dev/null -c '( PATH=/bin; set -o restricted) ; exit 0'  || err_exit 'restoring PATH when a subshell enables restricted exits not working'
604*b30d1939SAndy Fiddaman
605*b30d1939SAndy Fiddaman$SHELL <<- \EOF
606*b30d1939SAndy Fiddaman	wc=$(whence wc) head=$(whence head)
607*b30d1939SAndy Fiddaman	print > /dev/null  $( ( $head -c 1 /dev/zero | ( $wc -c) 3>&1 ) 3>&1) &
608*b30d1939SAndy Fiddaman	pid=$!
609*b30d1939SAndy Fiddaman	sleep 2
610*b30d1939SAndy Fiddaman	kill -9 $! 2> /dev/null && err_exit '/dev/zero in command substitution hangs'
611*b30d1939SAndy Fiddaman	wait $!
612*b30d1939SAndy FiddamanEOF
613*b30d1939SAndy Fiddaman
614*b30d1939SAndy Fiddamanfor f in /dev/stdout /dev/fd/1
615*b30d1939SAndy Fiddamando	if	[[ -e $f ]]
616*b30d1939SAndy Fiddaman	then	$SHELL -c "x=\$(command -p tee $f </dev/null 2>/dev/null)" || err_exit "$f in command substitution fails"
617*b30d1939SAndy Fiddaman	fi
618*b30d1939SAndy Fiddamandone
619*b30d1939SAndy Fiddaman
620*b30d1939SAndy Fiddaman# ========================================
621*b30d1939SAndy Fiddaman# Test that closing file descriptors don't affect capturing the output of a
622*b30d1939SAndy Fiddaman# subshell. Regression test for issue #198.
623*b30d1939SAndy Fiddamantmpfile=$(mktemp)
624*b30d1939SAndy Fiddamanexpected='return value'
625*b30d1939SAndy Fiddaman
626*b30d1939SAndy Fiddamanfunction get_value {
627*b30d1939SAndy Fiddaman case=$1
628*b30d1939SAndy Fiddaman (( case >= 1 )) && exec 3< $tmpfile
629*b30d1939SAndy Fiddaman (( case >= 2 )) && exec 4< $tmpfile
630*b30d1939SAndy Fiddaman (( case >= 3 )) && exec 6< $tmpfile
631*b30d1939SAndy Fiddaman
632*b30d1939SAndy Fiddaman # To trigger the bug we have to spawn an external command. Why is a
633*b30d1939SAndy Fiddaman # mystery but not really relevant.
634*b30d1939SAndy Fiddaman $(whence -p true)
635*b30d1939SAndy Fiddaman
636*b30d1939SAndy Fiddaman (( case >= 1 )) && exec 3<&-
637*b30d1939SAndy Fiddaman (( case >= 2 )) && exec 4<&-
638*b30d1939SAndy Fiddaman (( case >= 3 )) && exec 6<&-
639*b30d1939SAndy Fiddaman
640*b30d1939SAndy Fiddaman print $expected
641*b30d1939SAndy Fiddaman}
642*b30d1939SAndy Fiddaman
643*b30d1939SAndy Fiddamanactual=$(get_value 0)
644*b30d1939SAndy Fiddamanif [[ $actual != $expected ]]
645*b30d1939SAndy Fiddamanthen
646*b30d1939SAndy Fiddaman err_exit -u2 "failed to capture subshell output when closing fd: case 0"
647*b30d1939SAndy Fiddamanfi
648*b30d1939SAndy Fiddaman
649*b30d1939SAndy Fiddamanactual=$(get_value 1)
650*b30d1939SAndy Fiddamanif [[ $actual != $expected ]]
651*b30d1939SAndy Fiddamanthen
652*b30d1939SAndy Fiddaman err_exit -u2 "failed to capture subshell output when closing fd: case 1"
653*b30d1939SAndy Fiddamanfi
654*b30d1939SAndy Fiddaman
655*b30d1939SAndy Fiddamanactual=$(get_value 2)
656*b30d1939SAndy Fiddamanif [[ $actual != $expected ]]
657*b30d1939SAndy Fiddamanthen
658*b30d1939SAndy Fiddaman err_exit -u2 "failed to capture subshell output when closing fd: case 2"
659*b30d1939SAndy Fiddamanfi
660*b30d1939SAndy Fiddaman
661*b30d1939SAndy Fiddamanactual=$(get_value 3)
662*b30d1939SAndy Fiddamanif [[ $actual != $expected ]]
663*b30d1939SAndy Fiddamanthen
664*b30d1939SAndy Fiddaman err_exit -u2 "failed to capture subshell output when closing fd: case 3"
665*b30d1939SAndy Fiddamanfi
666*b30d1939SAndy Fiddaman
667*b30d1939SAndy Fiddamanrm $tmpfile
668*b30d1939SAndy Fiddaman
669*b30d1939SAndy Fiddamanexit $((Errors<125?Errors:125))
670