# $MirOS: src/bin/mksh/check.t,v 1.853 2020/10/31 03:53:03 tg Exp $
# -*- mode: sh -*-
#-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
#	      2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
#	      2019, 2020
#	mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
# is granted to deal in this work without restriction, including un‐
# limited rights to use, publicly perform, distribute, sell, modify,
# merge, give away, or sublicence.
#
# This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
# the utmost extent permitted by applicable law, neither express nor
# implied; without malicious intent or gross negligence. In no event
# may a licensor, author or contributor be held liable for indirect,
# direct, other damage, loss, or other issues arising in any way out
# of dealing in the work, even if advised of the possibility of such
# damage or existence of a defect, except proven that it results out
# of said person’s immediate fault when using the work as intended.
#-
# You may also want to test IFS with the script at
# http://www.research.att.com/~gsf/public/ifs.sh
#
# More testsuites at:
# http://svnweb.freebsd.org/base/head/bin/test/tests/legacy_test.sh?view=co&content-type=text%2Fplain
#
# Integrated testsuites from:
# (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date

expected-stdout:
	KSH R59 2020/10/31
description:
	Check base version of full shell
stdin:
	vsn=${KSH_VERSION%%' +'*}
	echo "${vsn#* }"
name: KSH_VERSION
---
expected-stdout:
	@(#)MIRBSD
description:
	Check this identifies as legacy shell
stdin:
	echo "${KSH_VERSION%% *}"
name: KSH_VERSION-modern
category: !shell:legacy-yes
---
expected-stdout:
	@(#)LEGACY
description:
	Check this identifies as legacy shell
stdin:
	echo "${KSH_VERSION%% *}"
name: KSH_VERSION-legacy
category: !shell:legacy-no
---
name: KSH_VERSION-ascii
description:
	Check that the shell version tag does not include EBCDIC
category: !shell:ebcdic-yes
stdin:
	set -o noglob
	for x in $KSH_VERSION; do
		[[ $x = '+EBCDIC' ]] && exit 1
	done
	exit 0
---
name: KSH_VERSION-ebcdic
description:
	Check that the shell version tag includes EBCDIC
category: !shell:ebcdic-no
stdin:
	set -o noglob
	for x in $KSH_VERSION; do
		[[ $x = '+EBCDIC' ]] && exit 0
	done
	exit 1
---
name: KSH_VERSION-binmode
description:
	Check that the shell version tag does not include TEXTMODE
category: !shell:textmode-yes
stdin:
	set -o noglob
	for x in $KSH_VERSION; do
		[[ $x = '+TEXTMODE' ]] && exit 1
	done
	exit 0
---
name: KSH_VERSION-textmode
description:
	Check that the shell version tag includes TEXTMODE
category: !shell:textmode-no
stdin:
	set -o noglob
	for x in $KSH_VERSION; do
		[[ $x = '+TEXTMODE' ]] && exit 0
	done
	exit 1
---
name: selftest-1
description:
	Regression test self-testing
stdin:
	echo ${foo:-baz}
expected-stdout:
	baz
---
name: selftest-2
description:
	Regression test self-testing
env-setup: !foo=bar!
stdin:
	echo ${foo:-baz}
expected-stdout:
	bar
---
name: selftest-3
description:
	Regression test self-testing
env-setup: !ENV=fnord!
stdin:
	echo "<$ENV>"
expected-stdout:
	<fnord>
---
name: selftest-exec
description:
	Ensure that the test run directory (default /tmp but can be changed
	with check.pl flag -T or test.sh $TMPDIR) is not mounted noexec, as
	we execute scripts from the scratch directory during several tests.
stdin:
	print '#!'"$__progname"'\necho tf' >lq
	chmod +x lq
	./lq
expected-stdout:
	tf
---
name: selftest-env
description:
	Just output the environment variables set (always fails)
category: disabled
stdin:
	set
---
name: selftest-direct-builtin-call
description:
	Check that direct builtin calls work
stdin:
	ln -s "$__progname" cat || cp "$__progname" cat
	ln -s "$__progname" echo || cp "$__progname" echo
	./echo -c 'echo  foo' | ./cat -u
expected-stdout:
	-c echo  foo
---
name: selftest-pathsep-unix
description:
	Check that $PATHSEP is set correctly.
category: !os:os2
stdin:
	PATHSEP=.; export PATHSEP
	"$__progname" -c 'print -r -- $PATHSEP'
expected-stdout:
	:
---
name: selftest-pathsep-dospath
description:
	Check that $PATHSEP is set correctly.
category: os:os2
stdin:
	PATHSEP=.; export PATHSEP
	"$__progname" -c 'print -r -- $PATHSEP'
expected-stdout:
	;
---
name: selftest-tty-absent
description:
	Check that a controlling tty is not present as regress:no-ctty was used
	(if this test fails for you DO NOT PASS regress:no-ctty and fix every
	other test that fails: why u use it if u haz ctty?)
category: regress:no-ctty
env-setup: !ENV=./envf!
file-setup: file 644 "envf"
	PS1=X
arguments: !-i!
stdin:
	echo ok
expected-stdout:
	ok
expected-stderr-pattern:
	/ksh: warning: won't have full job control\nXX/
---
name: selftest-tty-present
description:
	Check that a controlling tty is present as regress:no-ctty was not used
need-ctty: yes
env-setup: !ENV=./envf!
file-setup: file 644 "envf"
	PS1=X
arguments: !-i!
stdin:
	echo ok
expected-stdout:
	ok
expected-stderr: !
	XX
---
name: alias-1
description:
	Check that recursion is detected/avoided in aliases.
stdin:
	alias fooBar=fooBar
	fooBar
	exit 0
expected-stderr-pattern:
	/fooBar.*not found.*/
---
name: alias-2
description:
	Check that recursion is detected/avoided in aliases.
stdin:
	alias fooBar=barFoo
	alias barFoo=fooBar
	fooBar
	barFoo
	exit 0
expected-stderr-pattern:
	/fooBar.*not found.*\n.*barFoo.*not found/
---
name: alias-3
description:
	Check that recursion is detected/avoided in aliases.
stdin:
	alias Echo='echo '
	alias fooBar=barFoo
	alias barFoo=fooBar
	Echo fooBar
	unalias barFoo
	Echo fooBar
expected-stdout:
	fooBar
	barFoo
---
name: alias-4
description:
	Check that alias expansion isn't done on keywords (in keyword
	postitions).
stdin:
	alias Echo='echo '
	alias while=While
	while false; do echo hi ; done
	Echo while
expected-stdout:
	While
---
name: alias-5
description:
	Check that alias expansion done after alias with trailing space.
stdin:
	alias Echo='echo '
	alias foo='bar stuff '
	alias bar='Bar1 Bar2 '
	alias stuff='Stuff'
	alias blah='Blah'
	Echo foo blah
expected-stdout:
	Bar1 Bar2 Stuff Blah
---
name: alias-6
description:
	Check that alias expansion done after alias with trailing space.
stdin:
	alias Echo='echo '
	alias foo='bar bar'
	alias bar='Bar '
	alias blah=Blah
	Echo foo blah
expected-stdout:
	Bar Bar Blah
---
name: alias-7
description:
	Check that alias expansion done after alias with trailing space
	after a keyword.
stdin:
	alias X='case '
	alias Y=Z
	X Y in 'Y') echo is y ;; Z) echo is z ;; esac
expected-stdout:
	is z
---
name: alias-8
description:
	Check that newlines in an alias don't cause the command to be lost.
stdin:
	alias foo='
	
	
	echo hi
	
	
	
	echo there
	
	
	'
	foo
expected-stdout:
	hi
	there
---
name: alias-9
description:
	Check that recursion is detected/avoided in aliases.
	This check fails for slow machines or Cygwin, raise
	the time-limit clause (e.g. to 7) if this occurs.
time-limit: 3
stdin:
	print '#!'"$__progname"'\necho tf' >lq
	chmod +x lq
	PATH=$PWD$PATHSEP$PATH
	alias lq=lq
	lq
	echo = now
	i=`lq`
	print -r -- $i
	echo = out
	exit 0
expected-stdout:
	tf
	= now
	tf
	= out
---
name: alias-10
description:
	Check that recursion is detected/avoided in aliases.
	Regression, introduced during an old bugfix.
stdin:
	alias foo='print hello '
	alias bar='foo world'
	echo $(bar)
expected-stdout:
	hello world
---
name: alias-11
description:
	Check that special argument handling still applies with escaped aliases
stdin:
	alias local1='\typeset'
	alias local2='\\builtin typeset'
	function fooa {
		local1 x=$1 y=z
		print -r -- "$x,$y"
	}
	function foob {
		local2 x=$1 y=z
		print -r -- "$x,$y"
	}
	x=1 y=2; fooa 'bar - baz'
	x=1 y=2; foob 'bar - baz'
expected-stdout:
	bar - baz,z
	bar - baz,z
---
name: alias-12
description:
	Something weird from Martijn Dekker
stdin:
	alias echo=print
	x() { echo a; (echo b); x=$(echo c); }
	typeset -f x
	alias OPEN='{' CLOSE='};'
	{ OPEN echo hi1; CLOSE }
	var=`{ OPEN echo hi2; CLOSE }` && echo "$var"
	var=$({ OPEN echo hi3; CLOSE }) && echo "$var"
expected-stdout:
	x() {
		\print a 
		( \print b ) 
		x=$(\print c ) 
	} 
	hi1
	hi2
	hi3
---
name: arith-compound
description:
	Check that arithmetic expressions are compound constructs
stdin:
	{ ! (( 0$(cat >&2) )) <<<1; } <<<2
expected-stderr:
	1
---
name: arith-lazy-1
description:
	Check that only one side of ternary operator is evaluated
stdin:
	x=i+=2
	y=j+=2
	typeset -i i=1 j=1
	echo $((1 ? 20 : (x+=2)))
	echo $i,$x
	echo $((0 ? (y+=2) : 30))
	echo $j,$y
expected-stdout:
	20
	1,i+=2
	30
	1,j+=2
---
name: arith-lazy-2
description:
	Check that assignments not done on non-evaluated side of ternary
	operator
stdin:
	x=i+=2
	y=j+=2
	typeset -i i=1 j=1
	echo $((1 ? 20 : (x+=2)))
	echo $i,$x
	echo $((0 ? (y+=2) : 30))
	echo $i,$y
expected-stdout:
	20
	1,i+=2
	30
	1,j+=2
---
name: arith-lazy-3
description:
	Check that assignments not done on non-evaluated side of ternary
	operator and this construct is parsed correctly (Debian #445651)
stdin:
	x=4
	y=$((0 ? x=1 : 2))
	echo = $x $y =
expected-stdout:
	= 4 2 =
---
name: arith-lazy-4
description:
	Check that preun/postun not done on non-evaluated side of ternary
	operator
stdin:
	(( m = n = 0, 1 ? n++ : m++ ? 2 : 3 ))
	echo "($n, $m)"
	m=0; echo $(( 0 ? ++m : 2 )); echo $m
	m=0; echo $(( 0 ? m++ : 2 )); echo $m
expected-stdout:
	(1, 0)
	2
	0
	2
	0
---
name: arith-lazy-5-arr-n
description: Check lazy evaluation with side effects
stdin:
	a=0; echo "$((0&&b[a++],a))"
expected-stdout:
	0
---
name: arith-lazy-5-arr-p
description: Check lazy evaluation with side effects
stdin:
	a=0; echo "$((0&&(b[a++]),a))"
expected-stdout:
	0
---
name: arith-lazy-5-str-n
description: Check lazy evaluation with side effects
stdin:
	a=0 b=a++; ((0&&b)); echo $a
expected-stdout:
	0
---
name: arith-lazy-5-str-p
description: Check lazy evaluation with side effects
stdin:
	a=0 b=a++; ((0&&(b))); echo $a
expected-stdout:
	0
---
name: arith-lazy-5-tern-l-n
description: Check lazy evaluation with side effects
stdin:
	a=0; echo "$((0?b[a++]:999,a))"
expected-stdout:
	0
---
name: arith-lazy-5-tern-l-p
description: Check lazy evaluation with side effects
stdin:
	a=0; echo "$((0?(b[a++]):999,a))"
expected-stdout:
	0
---
name: arith-lazy-5-tern-r-n
description: Check lazy evaluation with side effects
stdin:
	a=0; echo "$((1?999:b[a++],a))"
expected-stdout:
	0
---
name: arith-lazy-5-tern-r-p
description: Check lazy evaluation with side effects
stdin:
	a=0; echo "$((1?999:(b[a++]),a))"
expected-stdout:
	0
---
name: arith-ternary-prec-1
description:
	Check precedence of ternary operator vs assignment
stdin:
	typeset -i x=2
	y=$((1 ? 20 : x+=2))
expected-exit: e != 0
expected-stderr-pattern:
	/.*:.*1 \? 20 : x\+=2.*lvalue.*\n$/
---
name: arith-ternary-prec-2
description:
	Check precedence of ternary operator vs assignment
stdin:
	typeset -i x=2
	echo $((0 ? x+=2 : 20))
expected-stdout:
	20
---
name: arith-prec-1
description:
	Prove arithmetic expressions with embedded parameter
	substitutions cannot be parsed ahead of time
stdin:
	a='3 + 4'
	print 1 $((2 * a)) .
	print 2 $((2 * $a)) .
expected-stdout:
	1 14 .
	2 10 .
---
name: arith-div-assoc-1
description:
	Check associativity of division operator
stdin:
	echo $((20 / 2 / 2))
expected-stdout:
	5
---
name: arith-div-byzero
description:
	Check division by zero errors out
stdin:
	x=$(echo $((1 / 0)))
	echo =$?:$x.
expected-stdout:
	=1:.
expected-stderr-pattern:
	/.*divisor/
---
name: arith-div-intmin-by-minusone
description:
	Check division overflow wraps around silently
category: int:32
stdin:
	echo signed:$((-2147483648 / -1))r$((-2147483648 % -1)).
	echo unsigned:$((# -2147483648 / -1))r$((# -2147483648 % -1)).
expected-stdout:
	signed:-2147483648r0.
	unsigned:0r2147483648.
---
name: arith-div-intmin-by-minusone-64
description:
	Check division overflow wraps around silently
category: int:64
stdin:
	echo signed:$((-9223372036854775808 / -1))r$((-9223372036854775808 % -1)).
	echo unsigned:$((# -9223372036854775808 / -1))r$((# -9223372036854775808 % -1)).
expected-stdout:
	signed:-9223372036854775808r0.
	unsigned:0r9223372036854775808.
---
name: arith-assop-assoc-1
description:
	Check associativity of assignment-operator operator
stdin:
	typeset -i i=1 j=2 k=3
	echo $((i += j += k))
	echo $i,$j,$k
expected-stdout:
	6
	6,5,3
---
name: arith-mandatory
description:
	Passing of this test is *mandatory* for a valid mksh executable!
category: shell:legacy-no
stdin:
	typeset -i sari=0
	typeset -Ui uari=0
	typeset -i x=0
	print -r -- $((x++)):$sari=$uari. #0
	let --sari --uari
	print -r -- $((x++)):$sari=$uari. #1
	sari=2147483647 uari=2147483647
	print -r -- $((x++)):$sari=$uari. #2
	let ++sari ++uari
	print -r -- $((x++)):$sari=$uari. #3
	let --sari --uari
	let 'sari *= 2' 'uari *= 2'
	let ++sari ++uari
	print -r -- $((x++)):$sari=$uari. #4
	let ++sari ++uari
	print -r -- $((x++)):$sari=$uari. #5
	sari=-2147483648 uari=-2147483648
	print -r -- $((x++)):$sari=$uari. #6
	let --sari --uari
	print -r -- $((x++)):$sari=$uari. #7
	(( sari = -5 >> 1 ))
	((# uari = -5 >> 1 ))
	print -r -- $((x++)):$sari=$uari. #8
	(( sari = -2 ))
	((# uari = sari ))
	print -r -- $((x++)):$sari=$uari. #9
expected-stdout:
	0:0=0.
	1:-1=4294967295.
	2:2147483647=2147483647.
	3:-2147483648=2147483648.
	4:-1=4294967295.
	5:0=0.
	6:-2147483648=2147483648.
	7:2147483647=2147483647.
	8:-3=2147483645.
	9:-2=4294967294.
---
name: arith-unsigned-1
description:
	Check if unsigned arithmetics work
category: int:32
stdin:
	# signed vs unsigned
	echo x1 $((-1)) $((#-1))
	# calculating
	typeset -i vs
	typeset -Ui vu
	vs=4123456789; vu=4123456789
	echo x2 $vs $vu
	(( vs %= 2147483647 ))
	(( vu %= 2147483647 ))
	echo x3 $vs $vu
	vs=4123456789; vu=4123456789
	(( # vs %= 2147483647 ))
	(( # vu %= 2147483647 ))
	echo x4 $vs $vu
	# make sure the calculation does not change unsigned flag
	vs=4123456789; vu=4123456789
	echo x5 $vs $vu
	# short form
	echo x6 $((# vs % 2147483647)) $((# vu % 2147483647))
	# array refs
	set -A va
	va[1975973142]=right
	va[4123456789]=wrong
	echo x7 ${va[#4123456789%2147483647]}
	# make sure multiple calculations don't interfere with each other
	let '# mca = -4 % -2' ' mcb = -4 % -2'
	echo x8 $mca $mcb
expected-stdout:
	x1 -1 4294967295
	x2 -171510507 4123456789
	x3 -171510507 4123456789
	x4 1975973142 1975973142
	x5 -171510507 4123456789
	x6 1975973142 1975973142
	x7 right
	x8 -4 0
---
name: arith-limit32-1
description:
	Check if arithmetics are 32 bit
category: int:32
stdin:
	# signed vs unsigned
	echo x1 $((-1)) $((#-1))
	# calculating
	typeset -i vs
	typeset -Ui vu
	vs=2147483647; vu=2147483647
	echo x2 $vs $vu
	let vs++ vu++
	echo x3 $vs $vu
	vs=4294967295; vu=4294967295
	echo x4 $vs $vu
	let vs++ vu++
	echo x5 $vs $vu
	let vs++ vu++
	echo x6 $vs $vu
expected-stdout:
	x1 -1 4294967295
	x2 2147483647 2147483647
	x3 -2147483648 2147483648
	x4 -1 4294967295
	x5 0 0
	x6 1 1
---
name: arith-limit64-1
description:
	Check if arithmetics are 64 bit
category: int:64
stdin:
	# signed vs unsigned
	echo x1 $((-1)) $((#-1))
	# calculating
	typeset -i vs
	typeset -Ui vu
	vs=9223372036854775807; vu=9223372036854775807
	echo x2 $vs $vu
	let vs++ vu++
	echo x3 $vs $vu
	vs=18446744073709551615; vu=18446744073709551615
	echo x4 $vs $vu
	let vs++ vu++
	echo x5 $vs $vu
	let vs++ vu++
	echo x6 $vs $vu
expected-stdout:
	x1 -1 18446744073709551615
	x2 9223372036854775807 9223372036854775807
	x3 -9223372036854775808 9223372036854775808
	x4 -1 18446744073709551615
	x5 0 0
	x6 1 1
---
name: bksl-nl-ign-1
description:
	Check that \newline is not collapsed after #
stdin:
	echo hi #there \
	echo folks
expected-stdout:
	hi
	folks
---
name: bksl-nl-ign-2
description:
	Check that \newline is not collapsed inside single quotes
stdin:
	echo 'hi \
	there'
	echo folks
expected-stdout:
	hi \
	there
	folks
---
name: bksl-nl-ign-3
description:
	Check that \newline is not collapsed inside single quotes
stdin:
	cat << \EOF
	hi \
	there
	EOF
expected-stdout:
	hi \
	there
---
name: bksl-nl-ign-4
description:
	Check interaction of aliases, single quotes and here-documents
	with backslash-newline
	(don't know what POSIX has to say about this)
stdin:
	a=2
	alias x='echo hi
	cat << "EOF"
	foo\
	bar
	some'
	x
	more\
	stuff$a
	EOF
expected-stdout:
	hi
	foo\
	bar
	some
	more\
	stuff$a
---
name: bksl-nl-ign-5
description:
	Check what happens with backslash at end of input
	(the old Bourne shell trashes them; so do we)
stdin: !
	echo `echo foo\\`bar
	echo hi\
expected-stdout:
	foobar
	hi
---
#
# Places \newline should be collapsed
#
name: bksl-nl-1
description:
	Check that \newline is collapsed before, in the middle of, and
	after words
stdin:
	 	 	\
			 echo hi\
	There, \
	folks
expected-stdout:
	hiThere, folks
---
name: bksl-nl-2
description:
	Check that \newline is collapsed in $ sequences
	(ksh93 fails this)
stdin:
	a=12
	ab=19
	echo $\
	a
	echo $a\
	b
	echo $\
	{a}
	echo ${a\
	b}
	echo ${ab\
	}
expected-stdout:
	12
	19
	12
	19
	19
---
name: bksl-nl-3
description:
	Check that \newline is collapsed in $(..) and `...` sequences
	(ksh93 fails this)
stdin:
	echo $\
	(echo foobar1)
	echo $(\
	echo foobar2)
	echo $(echo foo\
	bar3)
	echo $(echo foobar4\
	)
	echo `
	echo stuff1`
	echo `echo st\
	uff2`
expected-stdout:
	foobar1
	foobar2
	foobar3
	foobar4
	stuff1
	stuff2
---
name: bksl-nl-4
description:
	Check that \newline is collapsed in $((..)) sequences
	(ksh93 fails this)
stdin:
	echo $\
	((1+2))
	echo $(\
	(1+2+3))
	echo $((\
	1+2+3+4))
	echo $((1+\
	2+3+4+5))
	echo $((1+2+3+4+5+6)\
	)
expected-stdout:
	3
	6
	10
	15
	21
---
name: bksl-nl-5
description:
	Check that \newline is collapsed in double quoted strings
stdin:
	echo "\
	hi"
	echo "foo\
	bar"
	echo "folks\
	"
expected-stdout:
	hi
	foobar
	folks
---
name: bksl-nl-6
description:
	Check that \newline is collapsed in here document delimiters
	(ksh93 fails second part of this)
stdin:
	a=12
	cat << EO\
	F
	a=$a
	foo\
	bar
	EOF
	cat << E_O_F
	foo
	E_O_\
	F
	echo done
expected-stdout:
	a=12
	foobar
	foo
	done
---
name: bksl-nl-7
description:
	Check that \newline is collapsed in double-quoted here-document
	delimiter.
stdin:
	a=12
	cat << "EO\
	F"
	a=$a
	foo\
	bar
	EOF
	echo done
expected-stdout:
	a=$a
	foo\
	bar
	done
---
name: bksl-nl-8
description:
	Check that \newline is collapsed in various 2+ character tokens
	delimiter.
	(ksh93 fails this)
stdin:
	echo hi &\
	& echo there
	echo foo |\
	| echo bar
	cat <\
	< EOF
	stuff
	EOF
	cat <\
	<\
	- EOF
		more stuff
	EOF
	cat <<\
	EOF
	abcdef
	EOF
	echo hi >\
	> /dev/null
	echo $?
	i=1
	case $i in
	(\
	x|\
	1\
	) echo hi;\
	;
	(*) echo oops
	esac
expected-stdout:
	hi
	there
	foo
	stuff
	more stuff
	abcdef
	0
	hi
---
name: bksl-nl-9
description:
	Check that \ at the end of an alias is collapsed when followed
	by a newline
	(don't know what POSIX has to say about this)
stdin:
	alias x='echo hi\'
	x
	echo there
expected-stdout:
	hiecho there
---
name: bksl-nl-10
description:
	Check that \newline in a keyword is collapsed
stdin:
	i\
	f true; then\
	 echo pass; el\
	se echo fail; fi
expected-stdout:
	pass
---
#
# Places \newline should be collapsed (ksh extensions)
#
name: bksl-nl-ksh-1
description:
	Check that \newline is collapsed in extended globbing
	(ksh93 fails this)
stdin:
	xxx=foo
	case $xxx in
	(f*\
	(\
	o\
	)\
	) echo ok ;;
	*) echo bad
	esac
expected-stdout:
	ok
---
name: bksl-nl-ksh-2
description:
	Check that \newline is collapsed in ((...)) expressions
	(ksh93 fails this)
stdin:
	i=1
	(\
	(\
	i=i+2\
	)\
	)
	echo $i
expected-stdout:
	3
---
name: break-1
description:
	See if break breaks out of loops
stdin:
	for i in a b c; do echo $i; break; echo bad-$i; done
	echo end-1
	for i in a b c; do echo $i; break 1; echo bad-$i; done
	echo end-2
	for i in a b c; do
	    for j in x y z; do
		echo $i:$j
		break
		echo bad-$i
	    done
	    echo end-$i
	done
	echo end-3
	for i in a b c; do echo $i; eval break; echo bad-$i; done
	echo end-4
expected-stdout:
	a
	end-1
	a
	end-2
	a:x
	end-a
	b:x
	end-b
	c:x
	end-c
	end-3
	a
	end-4
---
name: break-2
description:
	See if break breaks out of nested loops
stdin:
	for i in a b c; do
	    for j in x y z; do
		echo $i:$j
		break 2
		echo bad-$i
	    done
	    echo end-$i
	done
	echo end
expected-stdout:
	a:x
	end
---
name: break-3
description:
	What if break used outside of any loops
	(ksh88,ksh93 don't print error messages here)
stdin:
	break
expected-stderr-pattern:
	/.*break.*/
---
name: break-4
description:
	What if break N used when only N-1 loops
	(ksh88,ksh93 don't print error messages here)
stdin:
	for i in a b c; do echo $i; break 2; echo bad-$i; done
	echo end
expected-stdout:
	a
	end
expected-stderr-pattern:
	/.*break.*/
---
name: break-5
description:
	Error if break argument isn't a number
stdin:
	for i in a b c; do echo $i; break abc; echo more-$i; done
	echo end
expected-stdout:
	a
expected-exit: e != 0
expected-stderr-pattern:
	/.*break.*/
---
name: continue-1
description:
	See if continue continues loops
stdin:
	for i in a b c; do echo $i; continue; echo bad-$i ; done
	echo end-1
	for i in a b c; do echo $i; continue 1; echo bad-$i; done
	echo end-2
	for i in a b c; do
	    for j in x y z; do
		echo $i:$j
		continue
		echo bad-$i-$j
	    done
	    echo end-$i
	done
	echo end-3
	for i in a b c; do echo $i; eval continue; echo bad-$i ; done
	echo end-4
expected-stdout:
	a
	b
	c
	end-1
	a
	b
	c
	end-2
	a:x
	a:y
	a:z
	end-a
	b:x
	b:y
	b:z
	end-b
	c:x
	c:y
	c:z
	end-c
	end-3
	a
	b
	c
	end-4
---
name: continue-2
description:
	See if continue breaks out of nested loops
stdin:
	for i in a b c; do
	    for j in x y z; do
		echo $i:$j
		continue 2
		echo bad-$i-$j
	    done
	    echo end-$i
	done
	echo end
expected-stdout:
	a:x
	b:x
	c:x
	end
---
name: continue-3
description:
	What if continue used outside of any loops
	(ksh88,ksh93 don't print error messages here)
stdin:
	continue
expected-stderr-pattern:
	/.*continue.*/
---
name: continue-4
description:
	What if continue N used when only N-1 loops
	(ksh88,ksh93 don't print error messages here)
stdin:
	for i in a b c; do echo $i; continue 2; echo bad-$i; done
	echo end
expected-stdout:
	a
	b
	c
	end
expected-stderr-pattern:
	/.*continue.*/
---
name: continue-5
description:
	Error if continue argument isn't a number
stdin:
	for i in a b c; do echo $i; continue abc; echo more-$i; done
	echo end
expected-stdout:
	a
expected-exit: e != 0
expected-stderr-pattern:
	/.*continue.*/
---
name: cd-history
description:
	Test someone's CD history package (uses arrays)
stdin:
	# go to known place before doing anything
	cd /
	
	alias cd=_cd
	function _cd
	{
		typeset -i cdlen i
		typeset t
	
		if [ $# -eq 0 ]
		then
			set -- $HOME
		fi
	
		if [ "$CDHISTFILE" -a -r "$CDHISTFILE" ] # if directory history exists
		then
			typeset CDHIST
			i=-1
			while read -r t			# read directory history file
			do
				CDHIST[i=i+1]=$t
			done <$CDHISTFILE
		fi
	
		if [ "${CDHIST[0]}" != "$PWD" -a "$PWD" != "" ]
		then
			_cdins				# insert $PWD into cd history
		fi
	
		cdlen=${#CDHIST[*]}			# number of elements in history
	
		case "$@" in
		-)					# cd to new dir
			if [ "$OLDPWD" = "" ] && ((cdlen>1))
			then
				'print' ${CDHIST[1]}
				'cd' ${CDHIST[1]}
				_pwd
			else
				'cd' $@
				_pwd
			fi
			;;
		-l)					# print directory list
			typeset -R3 num
			((i=cdlen))
			while (((i=i-1)>=0))
			do
				num=$i
				'print' "$num ${CDHIST[i]}"
			done
			return
			;;
		-[0-9]|-[0-9][0-9])			# cd to dir in list
			if (((i=${1#-})<cdlen))
			then
				'print' ${CDHIST[i]}
				'cd' ${CDHIST[i]}
				_pwd
			else
				'cd' $@
				_pwd
			fi
			;;
		-*)					# cd to matched dir in list
			t=${1#-}
			i=1
			while ((i<cdlen))
			do
				case ${CDHIST[i]} in
				*$t*)
					'print' ${CDHIST[i]}
					'cd' ${CDHIST[i]}
					_pwd
					break
					;;
				esac
				((i=i+1))
			done
			if ((i>=cdlen))
			then
				'cd' $@
				_pwd
			fi
			;;
		*)					# cd to new dir
			'cd' $@
			_pwd
			;;
		esac
	
		_cdins					# insert $PWD into cd history
	
		if [ "$CDHISTFILE" ]
		then
			cdlen=${#CDHIST[*]}		# number of elements in history
	
			i=0
			while ((i<cdlen))
			do
				'print' -r ${CDHIST[i]}	# update directory history
				((i=i+1))
			done >$CDHISTFILE
		fi
	}
	
	function _cdins					# insert $PWD into cd history
	{						# meant to be called only by _cd
		typeset -i i
	
		((i=0))
		while ((i<${#CDHIST[*]}))		# see if dir is already in list
		do
			if [ "${CDHIST[$i]}" = "$PWD" ]
			then
				break
			fi
			((i=i+1))
		done
	
		if ((i>22))				# limit max size of list
		then
			i=22
		fi
	
		while (((i=i-1)>=0))			# bump old dirs in list
		do
			CDHIST[i+1]=${CDHIST[i]}
		done
	
		CDHIST[0]=$PWD				# insert new directory in list
	}
	
	
	function _pwd
	{
		if [ -n "$ECD" ]
		then
			pwd 1>&6
		fi
	}
	# Start of test
	cd /tmp
	cd /bin
	cd /etc
	cd -
	cd -2
	cd -l
expected-stdout:
	/bin
	/tmp
	  3 /
	  2 /etc
	  1 /bin
	  0 /tmp
---
name: cd-pe
description:
	Check package for cd -Pe
need-pass: no
# the mv command fails on Cygwin and z/OS
# Hurd aborts the testsuite (permission denied)
# QNX does not find subdir to cd into
category: !os:cygwin,!os:gnu,!os:midipix,!os:msys,!os:nto,!os:os390,!nosymlink
file-setup: file 644 "x"
	mkdir noread noread/target noread/target/subdir
	ln -s noread link
	chmod 311 noread
	cd -P$1 .
	echo 0=$?
	bwd=$PWD
	cd -P$1 link/target
	echo 1=$?,${PWD#$bwd/}
	epwd=$($TSHELL -c pwd 2>/dev/null)
	# This unexpectedly succeeds on GNU/Linux and MidnightBSD
	#echo pwd=$?,$epwd
	# expect:	pwd=1,
	mv ../../noread ../../renamed
	cd -P$1 subdir
	echo 2=$?,${PWD#$bwd/}
	cd $bwd
	chmod 755 noread renamed 2>/dev/null
	rm -rf noread link renamed
stdin:
	export TSHELL="$__progname"
	"$__progname" x
	echo "now with -e:"
	"$__progname" x e
expected-stdout:
	0=0
	1=0,noread/target
	2=0,noread/target/subdir
	now with -e:
	0=0
	1=0,noread/target
	2=1,noread/target/subdir
---
name: env-prompt
description:
	Check that prompt not printed when processing ENV
env-setup: !ENV=./foo!
file-setup: file 644 "foo"
	XXX=_
	PS1=X
	false && echo hmmm
need-ctty: yes
arguments: !-i!
stdin:
	echo hi${XXX}there
expected-stdout:
	hi_there
expected-stderr: !
	XX
---
name: expand-ugly
description:
	Check that weird ${foo+bar} constructs are parsed correctly
stdin:
	print '#!'"$__progname"'\nfor x in "$@"; do print -r -- "$x"; done' >pfn
	print '#!'"$__progname"'\nfor x in "$@"; do print -nr -- "<$x> "; done' >pfs
	chmod +x pfn pfs
	(echo 1 ${IFS+'}'z}) 2>/dev/null || echo failed in 1
	(echo 2 "${IFS+'}'z}") 2>/dev/null || echo failed in 2
	(echo 3 "foo ${IFS+'bar} baz") 2>/dev/null || echo failed in 3
	(echo -n '4 '; ./pfn "foo ${IFS+"b   c"} baz") 2>/dev/null || echo failed in 4
	(echo -n '5 '; ./pfn "foo ${IFS+b   c} baz") 2>/dev/null || echo failed in 5
	(echo 6 ${IFS+"}"z}) 2>/dev/null || echo failed in 6
	(echo 7 "${IFS+"}"z}") 2>/dev/null || echo failed in 7
	(echo 8 "${IFS+\"}\"z}") 2>/dev/null || echo failed in 8
	(echo 9 "${IFS+\"\}\"z}") 2>/dev/null || echo failed in 9
	(echo 10 foo ${IFS+'bar} baz'}) 2>/dev/null || echo failed in 10
	(echo 11 "$(echo "${IFS+'}'z}")") 2>/dev/null || echo failed in 11
	(echo 12 "$(echo ${IFS+'}'z})") 2>/dev/null || echo failed in 12
	(echo 13 ${IFS+\}z}) 2>/dev/null || echo failed in 13
	(echo 14 "${IFS+\}z}") 2>/dev/null || echo failed in 14
	u=x; (echo -n '15 '; ./pfs "foo ${IFS+a"b$u{ {"{{\}b} c ${IFS+d{}} bar" ${IFS-e{}} baz; echo .) 2>/dev/null || echo failed in 15
	l=t; (echo 16 ${IFS+h`echo -n i ${IFS+$l}h`ere}) 2>/dev/null || echo failed in 16
	l=t; (echo 17 ${IFS+h$(echo -n i ${IFS+$l}h)ere}) 2>/dev/null || echo failed in 17
	l=t; (echo 18 "${IFS+h`echo -n i ${IFS+$l}h`ere}") 2>/dev/null || echo failed in 18
	l=t; (echo 19 "${IFS+h$(echo -n i ${IFS+$l}h)ere}") 2>/dev/null || echo failed in 19
	l=t; (echo 20 ${IFS+h`echo -n i "${IFS+$l}"h`ere}) 2>/dev/null || echo failed in 20
	l=t; (echo 21 ${IFS+h$(echo -n i "${IFS+$l}"h)ere}) 2>/dev/null || echo failed in 21
	l=t; (echo 22 "${IFS+h`echo -n i "${IFS+$l}"h`ere}") 2>/dev/null || echo failed in 22
	l=t; (echo 23 "${IFS+h$(echo -n i "${IFS+$l}"h)ere}") 2>/dev/null || echo failed in 23
	key=value; (echo -n '24 '; ./pfn "${IFS+'$key'}") 2>/dev/null || echo failed in 24
	key=value; (echo -n '25 '; ./pfn "${IFS+"'$key'"}") 2>/dev/null || echo failed in 25	# ksh93: “'$key'”
	key=value; (echo -n '26 '; ./pfn ${IFS+'$key'}) 2>/dev/null || echo failed in 26
	key=value; (echo -n '27 '; ./pfn ${IFS+"'$key'"}) 2>/dev/null || echo failed in 27
	(echo -n '28 '; ./pfn "${IFS+"'"x ~ x'}'x"'}"x}" #') 2>/dev/null || echo failed in 28
	u=x; (echo -n '29 '; ./pfs foo ${IFS+a"b$u{ {"{ {\}b} c ${IFS+d{}} bar ${IFS-e{}} baz; echo .) 2>/dev/null || echo failed in 29
	(echo -n '30 '; ./pfs ${IFS+foo 'b\
	ar' baz}; echo .) 2>/dev/null || (echo failed in 30; echo failed in 31)
	(echo -n '32 '; ./pfs ${IFS+foo "b\
	ar" baz}; echo .) 2>/dev/null || echo failed in 32
	(echo -n '33 '; ./pfs "${IFS+foo 'b\
	ar' baz}"; echo .) 2>/dev/null || echo failed in 33
	(echo -n '34 '; ./pfs "${IFS+foo "b\
	ar" baz}"; echo .) 2>/dev/null || echo failed in 34
	(echo -n '35 '; ./pfs ${v=a\ b} x ${v=c\ d}; echo .) 2>/dev/null || echo failed in 35
	(echo -n '36 '; ./pfs "${v=a\ b}" x "${v=c\ d}"; echo .) 2>/dev/null || echo failed in 36
	(echo -n '37 '; ./pfs ${v-a\ b} x ${v-c\ d}; echo .) 2>/dev/null || echo failed in 37
	(echo 38 ${IFS+x'a'y} / "${IFS+x'a'y}" .) 2>/dev/null || echo failed in 38
	foo="x'a'y"; (echo 39 ${foo%*'a'*} / "${foo%*'a'*}" .) 2>/dev/null || echo failed in 39
	foo="a b c"; (echo -n '40 '; ./pfs "${foo#a}"; echo .) 2>/dev/null || echo failed in 40
	(foo() { return 100; }; foo; echo 41 ${#+${#:+${#?}}\ \}\}\}}) 2>/dev/null || echo failed in 41
expected-stdout:
	1 }z
	2 ''z}
	3 foo 'bar baz
	4 foo b   c baz
	5 foo b   c baz
	6 }z
	7 }z
	8 ""z}
	9 "}"z
	10 foo bar} baz
	11 ''z}
	12 }z
	13 }z
	14 }z
	15 <foo abx{ {{{}b c d{} bar> <}> <baz> .
	16 hi there
	17 hi there
	18 hi there
	19 hi there
	20 hi there
	21 hi there
	22 hi there
	23 hi there
	24 'value'
	25 'value'
	26 $key
	27 'value'
	28 'x ~ x''x}"x}" #
	29 <foo> <abx{ {{> <{}b> <c> <d{}> <bar> <}> <baz> .
	30 <foo> <b\
	ar> <baz> .
	32 <foo> <bar> <baz> .
	33 <foo 'bar' baz> .
	34 <foo bar baz> .
	35 <a> <b> <x> <a> <b> .
	36 <a\ b> <x> <a\ b> .
	37 <a b> <x> <c d> .
	38 xay / x'a'y .
	39 x' / x' .
	40 < b c> .
	41 3 }}}
---
name: expand-unglob-dblq
description:
	Check that regular "${foo+bar}" constructs are parsed correctly
stdin:
	u=x
	tl_norm() {
		v=$2
		test x"$v" = x"-" && unset v
		(echo "$1 plus norm foo ${v+'bar'} baz")
		(echo "$1 dash norm foo ${v-'bar'} baz")
		(echo "$1 eqal norm foo ${v='bar'} baz")
		(echo "$1 qstn norm foo ${v?'bar'} baz") 2>/dev/null || \
		    echo "$1 qstn norm -> error"
		(echo "$1 PLUS norm foo ${v:+'bar'} baz")
		(echo "$1 DASH norm foo ${v:-'bar'} baz")
		(echo "$1 EQAL norm foo ${v:='bar'} baz")
		(echo "$1 QSTN norm foo ${v:?'bar'} baz") 2>/dev/null || \
		    echo "$1 QSTN norm -> error"
	}
	tl_paren() {
		v=$2
		test x"$v" = x"-" && unset v
		(echo "$1 plus parn foo ${v+(bar)} baz")
		(echo "$1 dash parn foo ${v-(bar)} baz")
		(echo "$1 eqal parn foo ${v=(bar)} baz")
		(echo "$1 qstn parn foo ${v?(bar)} baz") 2>/dev/null || \
		    echo "$1 qstn parn -> error"
		(echo "$1 PLUS parn foo ${v:+(bar)} baz")
		(echo "$1 DASH parn foo ${v:-(bar)} baz")
		(echo "$1 EQAL parn foo ${v:=(bar)} baz")
		(echo "$1 QSTN parn foo ${v:?(bar)} baz") 2>/dev/null || \
		    echo "$1 QSTN parn -> error"
	}
	tl_brace() {
		v=$2
		test x"$v" = x"-" && unset v
		(echo "$1 plus brac foo ${v+a$u{{{\}b} c ${v+d{}} baz")
		(echo "$1 dash brac foo ${v-a$u{{{\}b} c ${v-d{}} baz")
		(echo "$1 eqal brac foo ${v=a$u{{{\}b} c ${v=d{}} baz")
		(echo "$1 qstn brac foo ${v?a$u{{{\}b} c ${v?d{}} baz") 2>/dev/null || \
		    echo "$1 qstn brac -> error"
		(echo "$1 PLUS brac foo ${v:+a$u{{{\}b} c ${v:+d{}} baz")
		(echo "$1 DASH brac foo ${v:-a$u{{{\}b} c ${v:-d{}} baz")
		(echo "$1 EQAL brac foo ${v:=a$u{{{\}b} c ${v:=d{}} baz")
		(echo "$1 QSTN brac foo ${v:?a$u{{{\}b} c ${v:?d{}} baz") 2>/dev/null || \
		    echo "$1 QSTN brac -> error"
	}
	: '}}}' '}}}' '}}}' '}}}' '}}}' '}}}' '}}}' '}}}'
	tl_norm 1 -
	tl_norm 2 ''
	tl_norm 3 x
	tl_paren 4 -
	tl_paren 5 ''
	tl_paren 6 x
	tl_brace 7 -
	tl_brace 8 ''
	tl_brace 9 x
expected-stdout:
	1 plus norm foo  baz
	1 dash norm foo 'bar' baz
	1 eqal norm foo 'bar' baz
	1 qstn norm -> error
	1 PLUS norm foo  baz
	1 DASH norm foo 'bar' baz
	1 EQAL norm foo 'bar' baz
	1 QSTN norm -> error
	2 plus norm foo 'bar' baz
	2 dash norm foo  baz
	2 eqal norm foo  baz
	2 qstn norm foo  baz
	2 PLUS norm foo  baz
	2 DASH norm foo 'bar' baz
	2 EQAL norm foo 'bar' baz
	2 QSTN norm -> error
	3 plus norm foo 'bar' baz
	3 dash norm foo x baz
	3 eqal norm foo x baz
	3 qstn norm foo x baz
	3 PLUS norm foo 'bar' baz
	3 DASH norm foo x baz
	3 EQAL norm foo x baz
	3 QSTN norm foo x baz
	4 plus parn foo  baz
	4 dash parn foo (bar) baz
	4 eqal parn foo (bar) baz
	4 qstn parn -> error
	4 PLUS parn foo  baz
	4 DASH parn foo (bar) baz
	4 EQAL parn foo (bar) baz
	4 QSTN parn -> error
	5 plus parn foo (bar) baz
	5 dash parn foo  baz
	5 eqal parn foo  baz
	5 qstn parn foo  baz
	5 PLUS parn foo  baz
	5 DASH parn foo (bar) baz
	5 EQAL parn foo (bar) baz
	5 QSTN parn -> error
	6 plus parn foo (bar) baz
	6 dash parn foo x baz
	6 eqal parn foo x baz
	6 qstn parn foo x baz
	6 PLUS parn foo (bar) baz
	6 DASH parn foo x baz
	6 EQAL parn foo x baz
	6 QSTN parn foo x baz
	7 plus brac foo  c } baz
	7 dash brac foo ax{{{}b c d{} baz
	7 eqal brac foo ax{{{}b c ax{{{}b} baz
	7 qstn brac -> error
	7 PLUS brac foo  c } baz
	7 DASH brac foo ax{{{}b c d{} baz
	7 EQAL brac foo ax{{{}b c ax{{{}b} baz
	7 QSTN brac -> error
	8 plus brac foo ax{{{}b c d{} baz
	8 dash brac foo  c } baz
	8 eqal brac foo  c } baz
	8 qstn brac foo  c } baz
	8 PLUS brac foo  c } baz
	8 DASH brac foo ax{{{}b c d{} baz
	8 EQAL brac foo ax{{{}b c ax{{{}b} baz
	8 QSTN brac -> error
	9 plus brac foo ax{{{}b c d{} baz
	9 dash brac foo x c x} baz
	9 eqal brac foo x c x} baz
	9 qstn brac foo x c x} baz
	9 PLUS brac foo ax{{{}b c d{} baz
	9 DASH brac foo x c x} baz
	9 EQAL brac foo x c x} baz
	9 QSTN brac foo x c x} baz
---
name: expand-unglob-unq
description:
	Check that regular ${foo+bar} constructs are parsed correctly
stdin:
	u=x
	tl_norm() {
		v=$2
		test x"$v" = x"-" && unset v
		(echo $1 plus norm foo ${v+'bar'} baz)
		(echo $1 dash norm foo ${v-'bar'} baz)
		(echo $1 eqal norm foo ${v='bar'} baz)
		(echo $1 qstn norm foo ${v?'bar'} baz) 2>/dev/null || \
		    echo "$1 qstn norm -> error"
		(echo $1 PLUS norm foo ${v:+'bar'} baz)
		(echo $1 DASH norm foo ${v:-'bar'} baz)
		(echo $1 EQAL norm foo ${v:='bar'} baz)
		(echo $1 QSTN norm foo ${v:?'bar'} baz) 2>/dev/null || \
		    echo "$1 QSTN norm -> error"
	}
	tl_paren() {
		v=$2
		test x"$v" = x"-" && unset v
		(echo $1 plus parn foo ${v+\(bar')'} baz)
		(echo $1 dash parn foo ${v-\(bar')'} baz)
		(echo $1 eqal parn foo ${v=\(bar')'} baz)
		(echo $1 qstn parn foo ${v?\(bar')'} baz) 2>/dev/null || \
		    echo "$1 qstn parn -> error"
		(echo $1 PLUS parn foo ${v:+\(bar')'} baz)
		(echo $1 DASH parn foo ${v:-\(bar')'} baz)
		(echo $1 EQAL parn foo ${v:=\(bar')'} baz)
		(echo $1 QSTN parn foo ${v:?\(bar')'} baz) 2>/dev/null || \
		    echo "$1 QSTN parn -> error"
	}
	tl_brace() {
		v=$2
		test x"$v" = x"-" && unset v
		(echo $1 plus brac foo ${v+a$u{{{\}b} c ${v+d{}} baz)
		(echo $1 dash brac foo ${v-a$u{{{\}b} c ${v-d{}} baz)
		(echo $1 eqal brac foo ${v=a$u{{{\}b} c ${v=d{}} baz)
		(echo $1 qstn brac foo ${v?a$u{{{\}b} c ${v?d{}} baz) 2>/dev/null || \
		    echo "$1 qstn brac -> error"
		(echo $1 PLUS brac foo ${v:+a$u{{{\}b} c ${v:+d{}} baz)
		(echo $1 DASH brac foo ${v:-a$u{{{\}b} c ${v:-d{}} baz)
		(echo $1 EQAL brac foo ${v:=a$u{{{\}b} c ${v:=d{}} baz)
		(echo $1 QSTN brac foo ${v:?a$u{{{\}b} c ${v:?d{}} baz) 2>/dev/null || \
		    echo "$1 QSTN brac -> error"
	}
	: '}}}' '}}}' '}}}' '}}}' '}}}' '}}}' '}}}' '}}}'
	tl_norm 1 -
	tl_norm 2 ''
	tl_norm 3 x
	tl_paren 4 -
	tl_paren 5 ''
	tl_paren 6 x
	tl_brace 7 -
	tl_brace 8 ''
	tl_brace 9 x
expected-stdout:
	1 plus norm foo baz
	1 dash norm foo bar baz
	1 eqal norm foo bar baz
	1 qstn norm -> error
	1 PLUS norm foo baz
	1 DASH norm foo bar baz
	1 EQAL norm foo bar baz
	1 QSTN norm -> error
	2 plus norm foo bar baz
	2 dash norm foo baz
	2 eqal norm foo baz
	2 qstn norm foo baz
	2 PLUS norm foo baz
	2 DASH norm foo bar baz
	2 EQAL norm foo bar baz
	2 QSTN norm -> error
	3 plus norm foo bar baz
	3 dash norm foo x baz
	3 eqal norm foo x baz
	3 qstn norm foo x baz
	3 PLUS norm foo bar baz
	3 DASH norm foo x baz
	3 EQAL norm foo x baz
	3 QSTN norm foo x baz
	4 plus parn foo baz
	4 dash parn foo (bar) baz
	4 eqal parn foo (bar) baz
	4 qstn parn -> error
	4 PLUS parn foo baz
	4 DASH parn foo (bar) baz
	4 EQAL parn foo (bar) baz
	4 QSTN parn -> error
	5 plus parn foo (bar) baz
	5 dash parn foo baz
	5 eqal parn foo baz
	5 qstn parn foo baz
	5 PLUS parn foo baz
	5 DASH parn foo (bar) baz
	5 EQAL parn foo (bar) baz
	5 QSTN parn -> error
	6 plus parn foo (bar) baz
	6 dash parn foo x baz
	6 eqal parn foo x baz
	6 qstn parn foo x baz
	6 PLUS parn foo (bar) baz
	6 DASH parn foo x baz
	6 EQAL parn foo x baz
	6 QSTN parn foo x baz
	7 plus brac foo c } baz
	7 dash brac foo ax{{{}b c d{} baz
	7 eqal brac foo ax{{{}b c ax{{{}b} baz
	7 qstn brac -> error
	7 PLUS brac foo c } baz
	7 DASH brac foo ax{{{}b c d{} baz
	7 EQAL brac foo ax{{{}b c ax{{{}b} baz
	7 QSTN brac -> error
	8 plus brac foo ax{{{}b c d{} baz
	8 dash brac foo c } baz
	8 eqal brac foo c } baz
	8 qstn brac foo c } baz
	8 PLUS brac foo c } baz
	8 DASH brac foo ax{{{}b c d{} baz
	8 EQAL brac foo ax{{{}b c ax{{{}b} baz
	8 QSTN brac -> error
	9 plus brac foo ax{{{}b c d{} baz
	9 dash brac foo x c x} baz
	9 eqal brac foo x c x} baz
	9 qstn brac foo x c x} baz
	9 PLUS brac foo ax{{{}b c d{} baz
	9 DASH brac foo x c x} baz
	9 EQAL brac foo x c x} baz
	9 QSTN brac foo x c x} baz
---
name: expand-threecolons-dblq
description:
	Check for a particular thing that used to segfault
stdin:
	TEST=1234
	echo "${TEST:1:2:3}"
	echo $? but still living
expected-stderr-pattern:
	/bad substitution/
expected-exit: 1
---
name: expand-threecolons-unq
description:
	Check for a particular thing that used to not error out
stdin:
	TEST=1234
	echo ${TEST:1:2:3}
	echo $? but still living
expected-stderr-pattern:
	/bad substitution/
expected-exit: 1
---
name: expand-weird-1
description:
	Check corner cases of trim expansion vs. $# vs. ${#var} vs. ${var?}
stdin:
	set 1 2 3 4 5 6 7 8 9 10 11
	echo ${#}	# value of $#
	echo ${##}	# length of $#
	echo ${##1}	# $# trimmed 1
	set 1 2 3 4 5 6 7 8 9 10 11 12
	echo ${##1}
	(exit 0)
	echo $? = ${#?} .
	(exit 111)
	echo $? = ${#?} .
expected-stdout:
	11
	2
	1
	2
	0 = 1 .
	111 = 3 .
---
name: expand-weird-2
description:
	Check more substitution and extension corner cases
stdin:
	:& set -C; pid=$$; sub=$!; flg=$-; set -- i; exec 3>x.tmp
	#echo "D: !=$! #=$# \$=$$ -=$- ?=$?"
	echo >&3 3 = s^${!-word} , ${#-word} , p^${$-word} , f^${--word} , ${?-word} .
	echo >&3 4 = ${!+word} , ${#+word} , ${$+word} , ${-+word} , ${?+word} .
	echo >&3 5 = s^${!=word} , ${#=word} , p^${$=word} , f^${-=word} , ${?=word} .
	echo >&3 6 = s^${!?word} , ${#?word} , p^${$?word} , f^${-?word} , ${??word} .
	echo >&3 7 = sl^${#!} , ${##} , pl^${#$} , fl^${#-} , ${#?} .
	echo >&3 8 = sw^${%!} , ${%#} , pw^${%$} , fw^${%-} , ${%?} .
	echo >&3 9 = ${!!} , s^${!#} , ${!$} , s^${!-} , s^${!?} .
	echo >&3 10 = s^${!#pattern} , ${##pattern} , p^${$#pattern} , f^${-#pattern} , ${?#pattern} .
	echo >&3 11 = s^${!%pattern} , ${#%pattern} , p^${$%pattern} , f^${-%pattern} , ${?%pattern} .
	echo >&3 12 = $# : ${##} , ${##1} .
	set --
	echo >&3 14 = $# : ${##} , ${##1} .
	set -- 1 2 3 4 5
	echo >&3 16 = $# : ${##} , ${##1} .
	set -- 1 2 3 4 5 6 7 8 9 a b c d e
	echo >&3 18 = $# : ${##} , ${##1} .
	exec 3>&-
	<x.tmp sed \
	    -e "s/ pl^${#pid} / PID /g" -e "s/ sl^${#sub} / SUB /g" -e "s/ fl^${#flg} / FLG /g" \
	    -e "s/ pw^${%pid} / PID /g" -e "s/ sw^${%sub} / SUB /g" -e "s/ fw^${%flg} / FLG /g" \
	    -e "s/ p^$pid / PID /g" -e "s/ s^$sub / SUB /g" -e "s/ f^$flg / FLG /g"
expected-stdout:
	3 = SUB , 1 , PID , FLG , 0 .
	4 = word , word , word , word , word .
	5 = SUB , 1 , PID , FLG , 0 .
	6 = SUB , 1 , PID , FLG , 0 .
	7 = SUB , 1 , PID , FLG , 1 .
	8 = SUB , 1 , PID , FLG , 1 .
	9 = ! , SUB , $ , SUB , SUB .
	10 = SUB , 1 , PID , FLG , 0 .
	11 = SUB , 1 , PID , FLG , 0 .
	12 = 1 : 1 , .
	14 = 0 : 1 , 0 .
	16 = 5 : 1 , 5 .
	18 = 14 : 2 , 4 .
---
name: expand-weird-3
description:
	Check that trimming works with positional parameters (Debian #48453)
stdin:
	A=9999-02
	B=9999
	echo 1=${A#$B?}.
	set -- $A $B
	echo 2=${1#$2?}.
expected-stdout:
	1=02.
	2=02.
---
name: expand-weird-4
description:
	Check that tilde expansion is enabled in ${x#~}
	and cases that are modelled after it (${x/~/~})
stdin:
	HOME=/etc
	a="~/x"
	echo "<${a#~}> <${a#\~}> <${b:-~}> <${b:-\~}> <${c:=~}><$c> <${a/~}> <${a/x/~}> <${a/x/\~}>"
expected-stdout:
	<~/x> </x> <~> <\~> <~><~> <~/x> <~//etc> <~/~>
---
name: expand-bang-1
description:
	Check corner case of ${!?} with ! being var vs. op
stdin:
	echo ${!?}
expected-exit: 1
expected-stderr-pattern: /not set/
---
name: expand-bang-2
description:
	Check corner case of ${!var} vs. ${var op} with var=!
stdin:
	echo 1 $! .
	echo 2 ${!#} .
	echo 3 ${!#[0-9]} .
	echo 4 ${!-foo} .
	# get an at least three-digit bg pid
	while :; do
		:&
		x=$!
		if [[ $x != +([0-9]) ]]; then
			echo >&2 "cannot test, pid '$x' not numeric"
			echo >&2 report this with as many details as possible
			exit 1
		fi
		[[ $x = [0-9][0-9][0-9]* ]] && break
	done
	y=${x#?}
	t=$!; [[ $t = $x ]]; echo 5 $? .
	t=${!#}; [[ $t = $x ]]; echo 6 $? .
	t=${!#[0-9]}; [[ $t = $y ]]; echo 7 $? .
	t=${!-foo}; [[ $t = $x ]]; echo 8 $? .
	t=${!?bar}; [[ $t = $x ]]; echo 9 $? .
expected-stdout:
	1 .
	2 .
	3 .
	4 foo .
	5 0 .
	6 0 .
	7 0 .
	8 0 .
	9 0 .
---
name: expand-number-1
description:
	Check that positional arguments do not overflow
stdin:
	echo "1 ${12345678901234567890} ."
expected-stdout:
	1  .
---
name: expand-slashes-1
description:
	Check that side effects in substring replacement are handled correctly
stdin:
	foo=n1n1n1n2n3
	i=2
	n=1
	echo 1 ${foo//n$((n++))/[$((++i))]} .
	echo 2 $n , $i .
expected-stdout:
	1 [3][3][3]n2n3 .
	2 2 , 3 .
---
name: expand-slashes-2
description:
	Check that side effects in substring replacement are handled correctly
stdin:
	foo=n1n1n1n2n3
	i=2
	n=1
	echo 1 ${foo@/n$((n++))/[$((++i))]} .
	echo 2 $n , $i .
expected-stdout:
	1 [3]n1n1[4][5] .
	2 5 , 5 .
---
name: expand-slashes-3
description:
	Check that we can access the replaced string
stdin:
	foo=n1n1n1n2n3
	echo 1 ${foo@/n[12]/[$KSH_MATCH]} .
expected-stdout:
	1 [n1][n1][n1][n2]n3 .
---
name: eglob-bad-1
description:
	Check that globbing isn't done when glob has syntax error
category: !os:cygwin,!os:midipix,!os:msys,!os:os2
file-setup: file 644 "@(a[b|)c]foo"
stdin:
	echo @(a[b|)c]*
expected-stdout:
	@(a[b|)c]*
---
name: eglob-bad-2
description:
	Check that globbing isn't done when glob has syntax error
	(AT&T ksh fails this test)
file-setup: file 644 "abcx"
file-setup: file 644 "abcz"
file-setup: file 644 "bbc"
stdin:
	echo [a*(]*)z
expected-stdout:
	[a*(]*)z
---
name: eglob-infinite-plus
description:
	Check that shell doesn't go into infinite loop expanding +(...)
	expressions.
file-setup: file 644 "abc"
time-limit: 3
stdin:
	echo +()c
	echo +()x
	echo +(*)c
	echo +(*)x
expected-stdout:
	+()c
	+()x
	abc
	+(*)x
---
name: eglob-subst-1
description:
	Check that eglobbing isn't done on substitution results
file-setup: file 644 "abc"
stdin:
	x='@(*)'
	echo $x
expected-stdout:
	@(*)
---
name: eglob-nomatch-1
description:
	Check that the pattern doesn't match
stdin:
	echo 1: no-file+(a|b)stuff
	echo 2: no-file+(a*(c)|b)stuff
	echo 3: no-file+((((c)))|b)stuff
expected-stdout:
	1: no-file+(a|b)stuff
	2: no-file+(a*(c)|b)stuff
	3: no-file+((((c)))|b)stuff
---
name: eglob-match-1
description:
	Check that the pattern matches correctly
file-setup: file 644 "abd"
file-setup: file 644 "acd"
file-setup: file 644 "abac"
stdin:
	echo 1: a+(b|c)d
	echo 2: a!(@(b|B))d
	echo 3: *(a(b|c))		# (...|...) can be used within X(..)
	echo 4: a[b*(foo|bar)]d		# patterns not special inside [...]
expected-stdout:
	1: abd acd
	2: acd
	3: abac
	4: abd
---
name: eglob-case-1
description:
	Simple negation tests
stdin:
	case foo in !(foo|bar)) echo yes;; *) echo no;; esac
	case bar in !(foo|bar)) echo yes;; *) echo no;; esac
expected-stdout:
	no
	no
---
name: eglob-case-2
description:
	Simple kleene tests
stdin:
	case foo in *(a|b[)) echo yes;; *) echo no;; esac
	case foo in *(a|b[)|f*) echo yes;; *) echo no;; esac
	case '*(a|b[)' in *(a|b[)) echo yes;; *) echo no;; esac
	case 'aab[b[ab[a' in *(a|b[)) echo yes;; *) echo no;; esac
expected-stdout:
	no
	yes
	no
	yes
---
name: eglob-trim-1
description:
	Eglobbing in trim expressions...
	(AT&T ksh fails this - docs say # matches shortest string, ## matches
	longest...)
stdin:
	x=abcdef
	echo 1: ${x#a|abc}
	echo 2: ${x##a|abc}
	echo 3: ${x%def|f}
	echo 4: ${x%%f|def}
expected-stdout:
	1: bcdef
	2: def
	3: abcde
	4: abc
---
name: eglob-trim-2
description:
	Check eglobbing works in trims...
stdin:
	x=abcdef
	echo 1: ${x#*(a|b)cd}
	echo 2: "${x#*(a|b)cd}"
	echo 3: ${x#"*(a|b)cd"}
	echo 4: ${x#a(b|c)}
expected-stdout:
	1: ef
	2: ef
	3: abcdef
	4: cdef
---
name: eglob-trim-3
description:
	Check eglobbing works in trims, for Korn Shell
	Ensure eglobbing does not work for reduced-feature /bin/sh
stdin:
	set +o sh
	x=foobar
	y=foobaz
	z=fooba\?
	echo "<${x%bar|baz},${y%bar|baz},${z%\?}>"
	echo "<${x%ba(r|z)},${y%ba(r|z)}>"
	set -o sh
	echo "<${x%bar|baz},${y%bar|baz},${z%\?}>"
	z='foo(bar'
	echo "<${z%(*}>"
expected-stdout:
	<foo,foo,fooba>
	<foo,foo>
	<foobar,foobaz,fooba>
	<foo>
---
name: eglob-substrpl-1
description:
	Check eglobbing works in substs... and they work at all
stdin:
	[[ -n $BASH_VERSION ]] && shopt -s extglob
	x=1222321_ab/cde_b/c_1221
	y=xyz
	echo 1: ${x/2} . ${x/}
	echo 2: ${x//2}
	echo 3: ${x/+(2)}
	echo 4: ${x//+(2)}
	echo 5: ${x/2/4}
	echo 6: ${x//2/4}
	echo 7: ${x/+(2)/4}
	echo 8: ${x//+(2)/4}
	echo 9: ${x/b/c/e/f}
	echo 10: ${x/b\/c/e/f}
	echo 11: ${x/b\/c/e\/f}
	echo 12: ${x/b\/c/e\\/f}
	echo 13: ${x/b\\/c/e\\/f}
	echo 14: ${x//b/c/e/f}
	echo 15: ${x//b\/c/e/f}
	echo 16: ${x//b\/c/e\/f}
	echo 17: ${x//b\/c/e\\/f}
	echo 18: ${x//b\\/c/e\\/f}
	echo 19: ${x/b\/*\/c/x}
	echo 20: ${x/\//.}
	echo 21: ${x//\//.}
	echo 22: ${x///.}
	echo 23: ${x/#1/9}
	echo 24: ${x//#1/9}
	echo 25: ${x/%1/9}
	echo 26: ${x//%1/9}
	echo 27: ${x//\%1/9}
	echo 28: ${x//\\%1/9}
	echo 29: ${x//\a/9}
	echo 30: ${x//\\a/9}
	echo 31: ${x/2/$y}
expected-stdout:
	1: 122321_ab/cde_b/c_1221 . 1222321_ab/cde_b/c_1221
	2: 131_ab/cde_b/c_11
	3: 1321_ab/cde_b/c_1221
	4: 131_ab/cde_b/c_11
	5: 1422321_ab/cde_b/c_1221
	6: 1444341_ab/cde_b/c_1441
	7: 14321_ab/cde_b/c_1221
	8: 14341_ab/cde_b/c_141
	9: 1222321_ac/e/f/cde_b/c_1221
	10: 1222321_ae/fde_b/c_1221
	11: 1222321_ae/fde_b/c_1221
	12: 1222321_ae\/fde_b/c_1221
	13: 1222321_ab/cde_b/c_1221
	14: 1222321_ac/e/f/cde_c/e/f/c_1221
	15: 1222321_ae/fde_e/f_1221
	16: 1222321_ae/fde_e/f_1221
	17: 1222321_ae\/fde_e\/f_1221
	18: 1222321_ab/cde_b/c_1221
	19: 1222321_ax_1221
	20: 1222321_ab.cde_b/c_1221
	21: 1222321_ab.cde_b.c_1221
	22: 1222321_ab/cde_b/c_1221
	23: 9222321_ab/cde_b/c_1221
	24: 1222321_ab/cde_b/c_1221
	25: 1222321_ab/cde_b/c_1229
	26: 1222321_ab/cde_b/c_1221
	27: 1222321_ab/cde_b/c_1221
	28: 1222321_ab/cde_b/c_1221
	29: 1222321_9b/cde_b/c_1221
	30: 1222321_ab/cde_b/c_1221
	31: 1xyz22321_ab/cde_b/c_1221
---
name: eglob-substrpl-2
description:
	Check anchored substring replacement works, corner cases
stdin:
	foo=123
	echo 1: ${foo/#/x}
	echo 2: ${foo/%/x}
	echo 3: ${foo/#/}
	echo 4: ${foo/#}
	echo 5: ${foo/%/}
	echo 6: ${foo/%}
expected-stdout:
	1: x123
	2: 123x
	3: 123
	4: 123
	5: 123
	6: 123
---
name: eglob-substrpl-3a
description:
	Check substring replacement works with variables and slashes, too
stdin:
	HOME=/etc
	pfx=/home/user
	wd=/home/user/tmp
	echo "${wd/#$pfx/~}"
	echo "${wd/#\$pfx/~}"
	echo "${wd/#"$pfx"/~}"
	echo "${wd/#'$pfx'/~}"
	echo "${wd/#"\$pfx"/~}"
	echo "${wd/#'\$pfx'/~}"
expected-stdout:
	/etc/tmp
	/home/user/tmp
	/etc/tmp
	/home/user/tmp
	/home/user/tmp
	/home/user/tmp
---
name: eglob-substrpl-3b
description:
	More of this, bash fails it (bash4 passes)
stdin:
	HOME=/etc
	pfx=/home/user
	wd=/home/user/tmp
	echo "${wd/#$(echo /home/user)/~}"
	echo "${wd/#"$(echo /home/user)"/~}"
	echo "${wd/#'$(echo /home/user)'/~}"
expected-stdout:
	/etc/tmp
	/etc/tmp
	/home/user/tmp
---
name: eglob-substrpl-3c
description:
	Even more weird cases
stdin:
	HOME=/etc
	pfx=/home/user
	wd='$pfx/tmp'
	echo 1: ${wd/#$pfx/~}
	echo 2: ${wd/#\$pfx/~}
	echo 3: ${wd/#"$pfx"/~}
	echo 4: ${wd/#'$pfx'/~}
	echo 5: ${wd/#"\$pfx"/~}
	echo 6: ${wd/#'\$pfx'/~}
	ts='a/ba/b$tp$tp_a/b$tp_*(a/b)_*($tp)'
	tp=a/b
	tr=c/d
	[[ -n $BASH_VERSION ]] && shopt -s extglob
	echo 7: ${ts/a\/b/$tr}
	echo 8: ${ts/a\/b/\$tr}
	echo 9: ${ts/$tp/$tr}
	echo 10: ${ts/\$tp/$tr}
	echo 11: ${ts/\\$tp/$tr}
	echo 12: ${ts/$tp/c/d}
	echo 13: ${ts/$tp/c\/d}
	echo 14: ${ts/$tp/c\\/d}
	echo 15: ${ts/+(a\/b)/$tr}
	echo 16: ${ts/+(a\/b)/\$tr}
	echo 17: ${ts/+($tp)/$tr}
	echo 18: ${ts/+($tp)/c/d}
	echo 19: ${ts/+($tp)/c\/d}
	echo 20: ${ts//a\/b/$tr}
	echo 21: ${ts//a\/b/\$tr}
	echo 22: ${ts//$tp/$tr}
	echo 23: ${ts//$tp/c/d}
	echo 24: ${ts//$tp/c\/d}
	echo 25: ${ts//+(a\/b)/$tr}
	echo 26: ${ts//+(a\/b)/\$tr}
	echo 27: ${ts//+($tp)/$tr}
	echo 28: ${ts//+($tp)/c/d}
	echo 29: ${ts//+($tp)/c\/d}
	tp="+($tp)"
	echo 30: ${ts/$tp/$tr}
	echo 31: ${ts//$tp/$tr}
expected-stdout:
	1: $pfx/tmp
	2: /etc/tmp
	3: $pfx/tmp
	4: /etc/tmp
	5: /etc/tmp
	6: $pfx/tmp
	7: c/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
	8: $tra/b$tp$tp_a/b$tp_*(a/b)_*($tp)
	9: c/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
	10: a/ba/bc/d$tp_a/b$tp_*(a/b)_*($tp)
	11: a/ba/b$tp$tp_a/b$tp_*(a/b)_*($tp)
	12: c/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
	13: c/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
	14: c\/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
	15: c/d$tp$tp_a/b$tp_*(a/b)_*($tp)
	16: $tr$tp$tp_a/b$tp_*(a/b)_*($tp)
	17: c/d$tp$tp_a/b$tp_*(a/b)_*($tp)
	18: c/d$tp$tp_a/b$tp_*(a/b)_*($tp)
	19: c/d$tp$tp_a/b$tp_*(a/b)_*($tp)
	20: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
	21: $tr$tr$tp$tp_$tr$tp_*($tr)_*($tp)
	22: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
	23: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
	24: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
	25: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
	26: $tr$tp$tp_$tr$tp_*($tr)_*($tp)
	27: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
	28: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
	29: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
	30: a/ba/b$tp$tp_a/b$tp_*(a/b)_*($tp)
	31: a/ba/b$tp$tp_a/b$tp_*(a/b)_*($tp)
#	This is what GNU bash does:
#	30: c/d$tp$tp_a/b$tp_*(a/b)_*($tp)
#	31: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
---
name: eglob-utf8-1
description:
	UTF-8 mode differences for eglobbing
category: !shell:ebcdic-yes
stdin:
	s=blöd
	set +U
	print 1: ${s%???} .
	print 2: ${s/b???d/x} .
	set -U
	print 3: ${s%???} .
	print 4: ${s/b??d/x} .
	x=nö
	print 5: ${x%?} ${x%%?} .
	x=äh
	print 6: ${x#?} ${x##?} .
	x=
	print 7: ${x%?} ${x%%?} .
	x=mä
	print 8: ${x%?} ${x%%?} .
	x=何
	print 9: ${x%?} ${x%%?} .
expected-stdout:
	1: bl .
	2: x .
	3: b .
	4: x .
	5: n n .
	6: h h .
	7:   .
	8: mä mä .
	9: .
---
name: glob-bad-1
description:
	Check that [ matches itself if it's not a valid bracket expr
	but does not prevent globbing, while backslash-escaping does
file-setup: dir 755 "[x"
file-setup: file 644 "[x/foo"
stdin:
	echo [*
	echo *[x
	echo [x/*
	:>'ab[x'
	:>'a[a-z][x'
	echo a[a-z][*
	echo a[a-z]*
	echo a[a\-z]*
expected-stdout:
	[x
	[x
	[x/foo
	ab[x
	ab[x
	a[a-z]*
---
name: glob-bad-2
description:
	Check that symbolic links aren't stat()'d
# breaks on Dell UNIX 4.0 R2.2 (SVR4) where unlink also fails
# breaks on FreeMiNT (cannot unlink dangling symlinks)
# breaks on MSYS, OS/2 (do not support symlinks)
category: !os:mint,!os:msys,!os:svr4.0,!nosymlink
file-setup: dir 755 "dir"
file-setup: symlink 644 "dir/abc"
	non-existent-file
stdin:
	echo d*/*
	echo d*/abc
expected-stdout:
	dir/abc
	dir/abc
---
name: glob-bad-3
description:
	Check that the slash is parsed before the glob
stdin:
	mkdir a 'a[b'
	(cd 'a[b'; echo ok >'c]d')
	echo nok >abd
	echo fail >a/d
	cat a[b/c]d
expected-stdout:
	ok
---
name: glob-range-1
description:
	Test range matching
file-setup: file 644 ".bc"
file-setup: file 644 "abc"
file-setup: file 644 "bbc"
file-setup: file 644 "cbc"
file-setup: file 644 "-bc"
file-setup: file 644 "!bc"
file-setup: file 644 "^bc"
file-setup: file 644 "+bc"
file-setup: file 644 ",bc"
file-setup: file 644 "0bc"
file-setup: file 644 "1bc"
stdin:
	echo [ab-]*
	echo [-ab]*
	echo [!-ab]*
	echo [!ab]*
	echo []ab]*
	echo [^ab]*
	echo [+--]*
	echo [--1]*

expected-stdout:
	-bc abc bbc
	-bc abc bbc
	!bc +bc ,bc 0bc 1bc ^bc cbc
	!bc +bc ,bc -bc 0bc 1bc ^bc cbc
	abc bbc
	^bc abc bbc
	+bc ,bc -bc
	-bc 0bc 1bc
---
name: glob-range-2
description:
	Test range matching
	(AT&T ksh fails this; POSIX says invalid)
file-setup: file 644 "abc"
stdin:
	echo [a--]*
expected-stdout:
	[a--]*
---
name: glob-range-3
description:
	Check that globbing matches the right things...
# breaks on Mac OSX (HFS+ non-standard UTF-8 canonical decomposition)
# breaks on Cygwin 1.7 (files are now UTF-16 or something)
# breaks on QNX 6.4.1 (says RT)
category: !os:cygwin,!os:midipix,!os:darwin,!os:msys,!os:nto,!os:os2,!os:os390
need-pass: no
file-setup: file 644 "ac"
stdin:
	echo a[-]*
expected-stdout:
	ac
---
name: glob-range-4
description:
	Results unspecified according to POSIX
file-setup: file 644 ".bc"
stdin:
	echo [a.]*
expected-stdout:
	[a.]*
---
name: glob-range-5
description:
	Results unspecified according to POSIX
	(AT&T ksh treats this like [a-cc-e]*)
file-setup: file 644 "abc"
file-setup: file 644 "bbc"
file-setup: file 644 "cbc"
file-setup: file 644 "dbc"
file-setup: file 644 "ebc"
file-setup: file 644 "-bc"
file-setup: file 644 "@bc"
stdin:
	echo [a-c-e]*
	echo [a--@]*
expected-stdout:
	-bc abc bbc cbc ebc
	@bc
---
name: glob-range-6
description:
	ksh93 fails this but POSIX probably demands it
file-setup: file 644 "abc"
file-setup: file 644 "cbc"
stdin:
	echo *b*
	[ '*b*' = *b* ] && echo yep; echo $?
expected-stdout:
	abc cbc
	2
expected-stderr-pattern: /.*/
---
name: glob-word-1
description:
	Check BSD word boundary matches
stdin:
	t() { [[ $1 = *[[:\<:]]bar[[:\>:]]* ]]; echo =$?; }
	t 'foo bar baz'
	t 'foobar baz'
	t 'foo barbaz'
	t 'bar'
	t '_bar'
	t 'bar_'
expected-stdout:
	=0
	=1
	=1
	=0
	=1
	=1
---
name: glob-trim-1
description:
	Check against a regression from fixing IFS-subst-2
stdin:
	x='#foo'
	print -r "before='$x'"
	x=${x%%#*}
	print -r "after ='$x'"
expected-stdout:
	before='#foo'
	after =''
---
name: heredoc-1
description:
	Check ordering/content of redundent here documents.
stdin:
	cat << EOF1 << EOF2
	hi
	EOF1
	there
	EOF2
expected-stdout:
	there
---
name: heredoc-2
description:
	Check quoted here-doc is protected.
stdin:
	a=foo
	cat << 'EOF'
	hi\
	there$a
	stuff
	EO\
	F
	EOF
expected-stdout:
	hi\
	there$a
	stuff
	EO\
	F
---
name: heredoc-3
description:
	Check that newline isn't needed after heredoc-delimiter marker.
stdin: !
	cat << EOF
	hi
	there
	EOF
expected-stdout:
	hi
	there
---
name: heredoc-4a
description:
	Check that an error occurs if the heredoc-delimiter is missing.
stdin: !
	cat << EOF
	hi
	there
expected-exit: e > 0
expected-stderr-pattern: /.*/
---
name: heredoc-4an
description:
	Check that an error occurs if the heredoc-delimiter is missing.
arguments: !-n!
stdin: !
	cat << EOF
	hi
	there
expected-exit: e > 0
expected-stderr-pattern: /.*/
---
name: heredoc-4b
description:
	Check that an error occurs if the heredoc is missing.
stdin: !
	cat << EOF
expected-exit: e > 0
expected-stderr-pattern: /.*/
---
name: heredoc-4bn
description:
	Check that an error occurs if the heredoc is missing.
arguments: !-n!
stdin: !
	cat << EOF
expected-exit: e > 0
expected-stderr-pattern: /.*/
---
name: heredoc-5
description:
	Check that backslash quotes a $, ` and \ and kills a \newline
stdin:
	a=BAD
	b=ok
	cat << EOF
	h\${a}i
	h\\${b}i
	th\`echo not-run\`ere
	th\\`echo is-run`ere
	fol\\ks
	more\\
	last \
	line
	EOF
expected-stdout:
	h${a}i
	h\oki
	th`echo not-run`ere
	th\is-runere
	fol\ks
	more\
	last line
---
name: heredoc-6
description:
	Check that \newline in initial here-delim word doesn't imply
	a quoted here-doc.
stdin:
	a=i
	cat << EO\
	F
	h$a
	there
	EOF
expected-stdout:
	hi
	there
---
name: heredoc-7
description:
	Check that double quoted $ expressions in here delimiters are
	not expanded and match the delimiter.
	POSIX says only quote removal is applied to the delimiter.
stdin:
	a=b
	cat << "E$a"
	hi
	h$a
	hb
	E$a
	echo done
expected-stdout:
	hi
	h$a
	hb
	done
---
name: heredoc-8
description:
	Check that double quoted escaped $ expressions in here
	delimiters are not expanded and match the delimiter.
	POSIX says only quote removal is applied to the delimiter
	(\ counts as a quote).
stdin:
	a=b
	cat << "E\$a"
	hi
	h$a
	h\$a
	hb
	h\b
	E$a
	echo done
expected-stdout:
	hi
	h$a
	h\$a
	hb
	h\b
	done
---
name: heredoc-9
description:
	Check that here strings work.
stdin:
	bar="bar
		baz"
	tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<foo
	"$__progname" -c "tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<foo"
	tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<"$bar"
	tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<'$bar'
	tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<\$bar
	tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<-foo
	tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<"$(echo "foo bar")"
	tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<"A $(echo "foo bar") B"
	tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<\$b\$b$bar
	fnord=42
	bar="bar
		 \$fnord baz"
	tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<$bar
	tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<< bar
	echo $(tr r z <<<'bar' 2>/dev/null)
	cat <<< "$(  :                                                             )aa"
	IFS=$'\n'
	x=(a "b c")
	tr ac 12 <<< ${x[*]}
	tr ac 34 <<< "${x[*]}"
	tr ac 56 <<< ${x[@]}
	tr ac 78 <<< "${x[@]}"
expected-stdout:
	sbb
	sbb
	one
		onm
	$one
	$one
	-sbb
	sbb one
	A sbb one B
	$o$oone
		onm
	one
		 $sabeq onm
	one
	baz
	aa
	1
	b 2
	3
	b 4
	5 b 6
	7 b 8
---
name: heredoc-10
description:
	Check direct here document assignment
category: !shell:ebcdic-yes
stdin:
	x=u
	va=<<EOF
	=a $x \x40=
	EOF
	vb=<<'EOF'
	=b $x \x40=
	EOF
	function foo {
		vc=<<-EOF
			=c $x \x40=
		EOF
	}
	fnd=$(typeset -f foo)
	print -r -- "$fnd"
	function foo {
		echo blub
	}
	foo
	eval "$fnd"
	foo
	# rather nonsensical, but…
	vd=<<<"=d $x \x40="
	ve=<<<'=e $x \x40='
	vf=<<<$'=f $x \x40='
	# now check
	print -r -- "| va={$va} vb={$vb} vc={$vc} vd={$vd} ve={$ve} vf={$vf} |"
	# check append
	v=<<-EOF
		vapp1
	EOF
	v+=<<-EOF
		vapp2
	EOF
	print -r -- "| ${v//$'\n'/^} |"
expected-stdout:
	function foo {
		vc=<<-EOF 
	=c $x \x40=
	EOF
	
	} 
	blub
	| va={=a u \x40=
	} vb={=b $x \x40=
	} vc={=c u \x40=
	} vd={=d u \x40=
	} ve={=e $x \x40=
	} vf={=f $x @=
	} |
	| vapp1^vapp2^ |
---
name: heredoc-10-ebcdic
description:
	Check direct here document assignment
category: !shell:ebcdic-no
stdin:
	x=u
	va=<<EOF
	=a $x \x7C=
	EOF
	vb=<<'EOF'
	=b $x \x7C=
	EOF
	function foo {
		vc=<<-EOF
			=c $x \x7C=
		EOF
	}
	fnd=$(typeset -f foo)
	print -r -- "$fnd"
	function foo {
		echo blub
	}
	foo
	eval "$fnd"
	foo
	# rather nonsensical, but…
	vd=<<<"=d $x \x7C="
	ve=<<<'=e $x \x7C='
	vf=<<<$'=f $x \x7C='
	# now check
	print -r -- "| va={$va} vb={$vb} vc={$vc} vd={$vd} ve={$ve} vf={$vf} |"
	# check append
	v=<<-EOF
		vapp1
	EOF
	v+=<<-EOF
		vapp2
	EOF
	print -r -- "| ${v//$'\n'/^} |"
expected-stdout:
	function foo {
		vc=<<-EOF 
	=c $x \x7C=
	EOF
	
	} 
	blub
	| va={=a u \x7C=
	} vb={=b $x \x7C=
	} vc={=c u \x7C=
	} vd={=d u \x7C=
	} ve={=e $x \x7C=
	} vf={=f $x @=
	} |
	| vapp1^vapp2^ |
---
name: heredoc-11
description:
	Check here documents with no or empty delimiter
stdin:
	x=u
	va=<<
	=a $x \x40=
	<<
	vb=<<''
	=b $x \x40=
	
	function foo {
		vc=<<-
			=c $x \x40=
		<<
		vd=<<-''
			=d $x \x40=
	
	}
	fnd=$(typeset -f foo)
	print -r -- "$fnd"
	function foo {
		echo blub
	}
	foo
	eval "$fnd"
	foo
	print -r -- "| va={$va} vb={$vb} vc={$vc} vd={$vd} |"
	x=y
	foo
	typeset -f foo
	print -r -- "| vc={$vc} vd={$vd} |"
	# check append
	v=<<-
		vapp1
	<<
	v+=<<-''
		vapp2
	
	print -r -- "| ${v//$'\n'/^} |"
expected-stdout:
	function foo {
		vc=<<- 
	=c $x \x40=
	<<
	
		vd=<<-"" 
	=d $x \x40=
	
	
	} 
	blub
	| va={=a u \x40=
	} vb={=b $x \x40=
	} vc={=c u \x40=
	} vd={=d $x \x40=
	} |
	function foo {
		vc=<<- 
	=c $x \x40=
	<<
	
		vd=<<-"" 
	=d $x \x40=
	
	
	} 
	| vc={=c y \x40=
	} vd={=d $x \x40=
	} |
	| vapp1^vapp2^ |
---
name: heredoc-12
description:
	Check here documents can use $* and $@; note shells vary:
	• pdksh 5.2.14 acts the same
	• dash has 1 and 2 the same but 3 lacks the space
	• ksh93, bash4 differ in 2 by using space ipv colon
stdin:
	set -- a b
	nl='
	'
	IFS=" 	$nl"; n=1
	cat <<EOF
	$n foo $* foo
	$n bar "$*" bar
	$n baz $@ baz
	$n bla "$@" bla
	EOF
	IFS=":"; n=2
	cat <<EOF
	$n foo $* foo
	$n bar "$*" bar
	$n baz $@ baz
	$n bla "$@" bla
	EOF
	IFS=; n=3
	cat <<EOF
	$n foo $* foo
	$n bar "$*" bar
	$n baz $@ baz
	$n bla "$@" bla
	EOF
expected-stdout:
	1 foo a b foo
	1 bar "a b" bar
	1 baz a b baz
	1 bla "a b" bla
	2 foo a:b foo
	2 bar "a:b" bar
	2 baz a:b baz
	2 bla "a:b" bla
	3 foo a b foo
	3 bar "a b" bar
	3 baz a b baz
	3 bla "a b" bla
---
name: heredoc-14
description:
	Check that using multiple here documents works
stdin:
	foo() {
		echo "got $(cat) on stdin"
		echo "got $(cat <&4) on fd#4"
		echo "got $(cat <&5) on fd#5"
	}
	bar() {
		foo 4<<-a <<-b 5<<-c
		four
		a
		zero
		b
		five
		c
	}
	x=$(typeset -f bar)
	eval "$x"
	y=$(typeset -f bar)
	[[ $x = "$y" ]]; echo $?
	typeset -f bar
	bar
expected-stdout:
	0
	bar() {
		\foo 4<<-a <<-b 5<<-c 
	four
	a
	zero
	b
	five
	c
	
	} 
	got zero on stdin
	got four on fd#4
	got five on fd#5
---
name: heredoc-15
description:
	Check high-bit7 separators work
stdin:
	u=ä
	tr a-z A-Z <<-…
		m${u}h
	…
	echo ok
expected-stdout:
	MäH
	ok
---
name: heredoc-comsub-1
description:
	Tests for here documents in COMSUB, taken from Austin ML
stdin:
	text=$(cat <<EOF
	here is the text
	EOF)
	echo = $text =
expected-stdout:
	= here is the text =
---
name: heredoc-comsub-2
description:
	Tests for here documents in COMSUB, taken from Austin ML
stdin:
	unbalanced=$(cat <<EOF
	this paren ) is a problem
	EOF)
	echo = $unbalanced =
expected-stdout:
	= this paren ) is a problem =
---
name: heredoc-comsub-3
description:
	Tests for here documents in COMSUB, taken from Austin ML
stdin:
	balanced=$(cat <<EOF
	these parens ( ) are not a problem
	EOF)
	echo = $balanced =
expected-stdout:
	= these parens ( ) are not a problem =
---
name: heredoc-comsub-4
description:
	Tests for here documents in COMSUB, taken from Austin ML
stdin:
	balanced=$(cat <<EOF
	these parens \( ) are a problem
	EOF)
	echo = $balanced =
expected-stdout:
	= these parens \( ) are a problem =
---
name: heredoc-comsub-5
description:
	Check heredoc and COMSUB mixture in input
stdin:
	prefix() { sed -e "s/^/$1:/"; }
	XXX() { echo x-en; }
	YYY() { echo y-es; }
	
	prefix A <<XXX && echo "$(prefix B <<XXX
	echo line 1
	XXX
	echo line 2)" && prefix C <<YYY
	echo line 3
	XXX
	echo line 4)"
	echo line 5
	YYY
	XXX
expected-stdout:
	A:echo line 3
	B:echo line 1
	line 2
	C:echo line 4)"
	C:echo line 5
	x-en
---
name: heredoc-comsub-6
description:
	Check here documents and here strings can be used
	without a specific command, like $(<…) (extension)
stdin:
	foo=bar
	x=$(<<<EO${foo}F)
	echo "3<$x>"
		y=$(<<-EOF
			hi!
	
			$foo) is not a problem
	
	
		EOF)
	echo "7<$y>"
expected-stdout:
	3<EObarF>
	7<hi!
	
	bar) is not a problem>
---
name: heredoc-subshell-1
description:
	Tests for here documents in subshells, taken from Austin ML
stdin:
	(cat <<EOF
	some text
	EOF)
	echo end
expected-stdout:
	some text
	end
---
name: heredoc-subshell-2
description:
	Tests for here documents in subshells, taken from Austin ML
stdin:
	(cat <<EOF
	some text
	EOF
	)
	echo end
expected-stdout:
	some text
	end
---
name: heredoc-subshell-3
description:
	Tests for here documents in subshells, taken from Austin ML
stdin:
	(cat <<EOF; )
	some text
	EOF
	echo end
expected-stdout:
	some text
	end
---
name: heredoc-weird-1
description:
	Tests for here documents, taken from Austin ML
	Documents current state in mksh, *NOT* necessarily correct!
stdin:
	cat <<END
	hello
	END\
	END
	END
	echo end
expected-stdout:
	hello
	ENDEND
	end
---
name: heredoc-weird-2
description:
	Tests for here documents, taken from Austin ML
stdin:
	cat <<'    END    '
	hello
	    END    
	echo end
expected-stdout:
	hello
	end
---
name: heredoc-weird-4
description:
	Tests for here documents, taken from Austin ML
	Documents current state in mksh, *NOT* necessarily correct!
stdin:
	cat <<END
	hello\
	END
	END
	echo end
expected-stdout:
	helloEND
	end
---
name: heredoc-weird-5
description:
	Tests for here documents, taken from Austin ML
	Documents current state in mksh, *NOT* necessarily correct!
stdin:
	cat <<END
	hello
	\END
	END
	echo end
expected-stdout:
	hello
	\END
	end
---
name: heredoc-tmpfile-1
description:
	Check that heredoc temp files aren't removed too soon or too late.
	Heredoc in simple command.
stdin:
	TMPDIR=$PWD
	eval '
		cat <<- EOF
		hi
		EOF
		for i in a b ; do
			cat <<- EOF
			more
			EOF
		done
	    ' &
	sleep 1
	echo Left overs: *
expected-stdout:
	hi
	more
	more
	Left overs: *
---
name: heredoc-tmpfile-2
description:
	Check that heredoc temp files aren't removed too soon or too late.
	Heredoc in function, multiple calls to function.
stdin:
	TMPDIR=$PWD
	eval '
		foo() {
			cat <<- EOF
			hi
			EOF
		}
		foo
		foo
	    ' &
	sleep 1
	echo Left overs: *
expected-stdout:
	hi
	hi
	Left overs: *
---
name: heredoc-tmpfile-3
description:
	Check that heredoc temp files aren't removed too soon or too late.
	Heredoc in function in loop, multiple calls to function.
stdin:
	TMPDIR=$PWD
	eval '
		foo() {
			cat <<- EOF
			hi
			EOF
		}
		for i in a b; do
			foo
			foo() {
				cat <<- EOF
				folks $i
				EOF
			}
		done
		foo
	    ' &
	sleep 1
	echo Left overs: *
expected-stdout:
	hi
	folks b
	folks b
	Left overs: *
---
name: heredoc-tmpfile-4
description:
	Check that heredoc temp files aren't removed too soon or too late.
	Backgrounded simple command with here doc
stdin:
	TMPDIR=$PWD
	eval '
		cat <<- EOF &
		hi
		EOF
	    ' &
	sleep 1
	echo Left overs: *
expected-stdout:
	hi
	Left overs: *
---
name: heredoc-tmpfile-5
description:
	Check that heredoc temp files aren't removed too soon or too late.
	Backgrounded subshell command with here doc
stdin:
	TMPDIR=$PWD
	eval '
	      (
		sleep 1	# so parent exits
		echo A
		cat <<- EOF
		hi
		EOF
		echo B
	      ) &
	    ' &
	sleep 5
	echo Left overs: *
expected-stdout:
	A
	hi
	B
	Left overs: *
---
name: heredoc-tmpfile-6
description:
	Check that heredoc temp files aren't removed too soon or too late.
	Heredoc in pipeline.
stdin:
	TMPDIR=$PWD
	eval '
		cat <<- EOF | sed "s/hi/HI/"
		hi
		EOF
	    ' &
	sleep 1
	echo Left overs: *
expected-stdout:
	HI
	Left overs: *
---
name: heredoc-tmpfile-7
description:
	Check that heredoc temp files aren't removed too soon or too late.
	Heredoc in backgrounded pipeline.
stdin:
	TMPDIR=$PWD
	eval '
		cat <<- EOF | sed 's/hi/HI/' &
		hi
		EOF
	    ' &
	sleep 1
	echo Left overs: *
expected-stdout:
	HI
	Left overs: *
---
name: heredoc-tmpfile-8
description:
	Check that heredoc temp files aren't removed too soon or too
	late. Heredoc in function, backgrounded call to function.
	This check can fail on slow machines (<100 MHz), or Cygwin,
	that's normal.
need-pass: no
stdin:
	TMPDIR=$PWD
	# Background eval so main shell doesn't do parsing
	eval '
		foo() {
			cat <<- EOF
			hi
			EOF
		}
		foo
		# sleep so eval can die
		(sleep 1; foo) &
		(sleep 1; foo) &
		foo
	    ' &
	sleep 5
	echo Left overs: *
expected-stdout:
	hi
	hi
	hi
	hi
	Left overs: *
---
name: heredoc-quoting-unsubst
description:
	Check for correct handling of quoted characters in
	here documents without substitution (marker is quoted).
stdin:
	foo=bar
	cat <<-'EOF'
		x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
	EOF
expected-stdout:
	x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
---
name: heredoc-quoting-subst
description:
	Check for correct handling of quoted characters in
	here documents with substitution (marker is not quoted).
stdin:
	foo=bar
	cat <<-EOF
		x " \" \ \\ $ \$ `echo baz` \`echo baz\` $foo \$foo x
	EOF
expected-stdout:
	x " \" \ \ $ $ baz `echo baz` bar $foo x
---
name: single-quotes-in-braces
description:
	Check that single quotes inside unquoted {} are treated as quotes
stdin:
	foo=1
	echo ${foo:+'blah  $foo'}
expected-stdout:
	blah  $foo
---
name: single-quotes-in-quoted-braces
description:
	Check that single quotes inside quoted {} are treated as
	normal char
stdin:
	foo=1
	echo "${foo:+'blah  $foo'}"
expected-stdout:
	'blah  1'
---
name: single-quotes-in-braces-nested
description:
	Check that single quotes inside unquoted {} are treated as quotes,
	even if that's inside a double-quoted command expansion
stdin:
	foo=1
	echo "$( echo ${foo:+'blah  $foo'})"
expected-stdout:
	blah  $foo
---
name: single-quotes-in-brace-pattern
description:
	Check that single quotes inside {} pattern are treated as quotes
stdin:
	foo=1234
	echo ${foo%'2'*} "${foo%'2'*}" ${foo%2'*'} "${foo%2'*'}"
expected-stdout:
	1 1 1234 1234
---
name: single-quotes-in-heredoc-braces
description:
	Check that single quotes inside {} in heredoc are treated
	as normal char
stdin:
	foo=1
	cat <<EOM
	${foo:+'blah  $foo'}
	EOM
expected-stdout:
	'blah  1'
---
name: single-quotes-in-nested-braces
description:
	Check that single quotes inside nested unquoted {} are
	treated as quotes
stdin:
	foo=1
	echo ${foo:+${foo:+'blah  $foo'}}
expected-stdout:
	blah  $foo
---
name: single-quotes-in-nested-quoted-braces
description:
	Check that single quotes inside nested quoted {} are treated
	as normal char
stdin:
	foo=1
	echo "${foo:+${foo:+'blah  $foo'}}"
expected-stdout:
	'blah  1'
---
name: single-quotes-in-nested-braces-nested
description:
	Check that single quotes inside nested unquoted {} are treated
	as quotes, even if that's inside a double-quoted command expansion
stdin:
	foo=1
	echo "$( echo ${foo:+${foo:+'blah  $foo'}})"
expected-stdout:
	blah  $foo
---
name: single-quotes-in-nested-brace-pattern
description:
	Check that single quotes inside nested {} pattern are treated as quotes
stdin:
	foo=1234
	echo ${foo:+${foo%'2'*}} "${foo:+${foo%'2'*}}" ${foo:+${foo%2'*'}} "${foo:+${foo%2'*'}}"
expected-stdout:
	1 1 1234 1234
---
name: single-quotes-in-heredoc-nested-braces
description:
	Check that single quotes inside nested {} in heredoc are treated
	as normal char
stdin:
	foo=1
	cat <<EOM
	${foo:+${foo:+'blah  $foo'}}
	EOM
expected-stdout:
	'blah  1'
---
name: single-quotes-in-heredoc-trim
description:
	In some cases, single quotes inside {} in heredoc are not normal
stdin:
	x=notOK
	cat <<EOF
	1: ${x#not} ${x:+${x#not}}
	2: ${x#\n\o\t} ${x:+${x#\n\o\t}}
	3: ${x#"not"} ${x:+${x#"not"}}
	4: ${x#'not'} ${x:+${x#'not'}}
	5: ${x#$'not'} ${x:+${x#$'not'}}
	EOF
expected-stdout:
	1: OK OK
	2: OK OK
	3: OK OK
	4: OK OK
	5: OK OK
---
name: history-basic
description:
	See if we can test history at all
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo hi
	fc -l
expected-stdout:
	hi
	1	echo hi
expected-stderr-pattern:
	/^X*$/
---
name: history-dups
description:
	Verify duplicates and spaces are not entered
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo hi
	 echo yo
	echo hi
	fc -l
expected-stdout:
	hi
	yo
	hi
	1	echo hi
expected-stderr-pattern:
	/^X*$/
---
name: history-unlink
description:
	Check if broken HISTFILEs do not cause trouble
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=foo/hist.file!
file-setup: file 644 "Env"
	PS1=X
file-setup: dir 755 "foo"
file-setup: file 644 "foo/hist.file"
	sometext
time-limit: 5
perl-setup: chmod(0555, "foo");
stdin:
	echo hi
	fc -l
	chmod 0755 foo
expected-stdout:
	hi
	1	echo hi
expected-stderr-pattern:
	/(.*can't unlink HISTFILE.*\n)?X*$/
---
name: history-multiline
description:
	Check correct multiline history, Debian #783978
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!
file-setup: file 644 "Env"
	PS1=X
	PS2=Y
stdin:
	for i in A B C
	do
	   print $i
	   print $i
	done
	fc -l
expected-stdout:
	A
	A
	B
	B
	C
	C
	1	for i in A B C
		do
		   print $i
		   print $i
		done
expected-stderr-pattern:
	/^XYYYYXX$/
---
name: history-e-minus-1
description:
	Check if more recent command is executed
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo hi
	echo there
	fc -e -
expected-stdout:
	hi
	there
	there
expected-stderr-pattern:
	/^X*echo there\nX*$/
---
name: history-e-minus-2
description:
	Check that repeated command is printed before command
	is re-executed.
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	exec 2>&1
	echo hi
	echo there
	fc -e -
expected-stdout-pattern:
	/X*hi\nX*there\nX*echo there\nthere\nX*/
expected-stderr-pattern:
	/^X*$/
---
name: history-e-minus-3
description:
	fc -e - fails when there is no history
	(ksh93 has a bug that causes this to fail)
	(ksh88 loops on this)
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	fc -e -
	echo ok
expected-stdout:
	ok
expected-stderr-pattern:
	/^X*.*:.*history.*\nX*$/
---
name: history-e-minus-4
description:
	Check if "fc -e -" command output goes to stdout.
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc
	fc -e - | (read x; echo "A $x")
	echo ok
expected-stdout:
	abc
	A abc
	ok
expected-stderr-pattern:
	/^X*echo abc\nX*/
---
name: history-e-minus-5
description:
	fc is replaced in history by new command.
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc def
	echo ghi jkl
	:
	fc -e - echo
	fc -l 2 5
expected-stdout:
	abc def
	ghi jkl
	ghi jkl
	2	echo ghi jkl
	3	:
	4	echo ghi jkl
	5	fc -l 2 5
expected-stderr-pattern:
	/^X*echo ghi jkl\nX*$/
---
name: history-list-1
description:
	List lists correct range
	(ksh88 fails 'cause it lists the fc command)
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2
	echo line 3
	fc -l -- -2
expected-stdout:
	line 1
	line 2
	line 3
	2	echo line 2
	3	echo line 3
expected-stderr-pattern:
	/^X*$/
---
name: history-list-2
description:
	Lists oldest history if given pre-historic number
	(ksh93 has a bug that causes this to fail)
	(ksh88 fails 'cause it lists the fc command)
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2
	echo line 3
	fc -l -- -40
expected-stdout:
	line 1
	line 2
	line 3
	1	echo line 1
	2	echo line 2
	3	echo line 3
expected-stderr-pattern:
	/^X*$/
---
name: history-list-3
description:
	Can give number 'options' to fc
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2
	echo line 3
	echo line 4
	fc -l -3 -2
expected-stdout:
	line 1
	line 2
	line 3
	line 4
	2	echo line 2
	3	echo line 3
expected-stderr-pattern:
	/^X*$/
---
name: history-list-4
description:
	-1 refers to previous command
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2
	echo line 3
	echo line 4
	fc -l -1 -1
expected-stdout:
	line 1
	line 2
	line 3
	line 4
	4	echo line 4
expected-stderr-pattern:
	/^X*$/
---
name: history-list-5
description:
	List command stays in history
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2
	echo line 3
	echo line 4
	fc -l -1 -1
	fc -l -2 -1
expected-stdout:
	line 1
	line 2
	line 3
	line 4
	4	echo line 4
	4	echo line 4
	5	fc -l -1 -1
expected-stderr-pattern:
	/^X*$/
---
name: history-list-6
description:
	HISTSIZE limits about of history kept.
	(ksh88 fails 'cause it lists the fc command)
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!HISTSIZE=3!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2
	echo line 3
	echo line 4
	echo line 5
	fc -l
expected-stdout:
	line 1
	line 2
	line 3
	line 4
	line 5
	4	echo line 4
	5	echo line 5
expected-stderr-pattern:
	/^X*$/
---
name: history-list-7
description:
	fc allows too old/new errors in range specification
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!HISTSIZE=3!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2
	echo line 3
	echo line 4
	echo line 5
	fc -l 1 30
expected-stdout:
	line 1
	line 2
	line 3
	line 4
	line 5
	4	echo line 4
	5	echo line 5
	6	fc -l 1 30
expected-stderr-pattern:
	/^X*$/
---
name: history-list-r-1
description:
	test -r flag in history
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2
	echo line 3
	echo line 4
	echo line 5
	fc -l -r 2 4
expected-stdout:
	line 1
	line 2
	line 3
	line 4
	line 5
	4	echo line 4
	3	echo line 3
	2	echo line 2
expected-stderr-pattern:
	/^X*$/
---
name: history-list-r-2
description:
	If first is newer than last, -r is implied.
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2
	echo line 3
	echo line 4
	echo line 5
	fc -l 4 2
expected-stdout:
	line 1
	line 2
	line 3
	line 4
	line 5
	4	echo line 4
	3	echo line 3
	2	echo line 2
expected-stderr-pattern:
	/^X*$/
---
name: history-list-r-3
description:
	If first is newer than last, -r is cancelled.
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2
	echo line 3
	echo line 4
	echo line 5
	fc -l -r 4 2
expected-stdout:
	line 1
	line 2
	line 3
	line 4
	line 5
	2	echo line 2
	3	echo line 3
	4	echo line 4
expected-stderr-pattern:
	/^X*$/
---
name: history-subst-1
description:
	Basic substitution
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc def
	echo ghi jkl
	fc -e - abc=AB 'echo a'
expected-stdout:
	abc def
	ghi jkl
	AB def
expected-stderr-pattern:
	/^X*echo AB def\nX*$/
---
name: history-subst-2
description:
	Does subst find previous command?
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc def
	echo ghi jkl
	fc -e - jkl=XYZQRT 'echo g'
expected-stdout:
	abc def
	ghi jkl
	ghi XYZQRT
expected-stderr-pattern:
	/^X*echo ghi XYZQRT\nX*$/
---
name: history-subst-3
description:
	Does subst find previous command when no arguments given
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc def
	echo ghi jkl
	fc -e - jkl=XYZQRT
expected-stdout:
	abc def
	ghi jkl
	ghi XYZQRT
expected-stderr-pattern:
	/^X*echo ghi XYZQRT\nX*$/
---
name: history-subst-4
description:
	Global substitutions work
	(ksh88 and ksh93 do not have -g option)
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc def asjj sadjhasdjh asdjhasd
	fc -e - -g a=FooBAR
expected-stdout:
	abc def asjj sadjhasdjh asdjhasd
	FooBARbc def FooBARsjj sFooBARdjhFooBARsdjh FooBARsdjhFooBARsd
expected-stderr-pattern:
	/^X*echo FooBARbc def FooBARsjj sFooBARdjhFooBARsdjh FooBARsdjhFooBARsd\nX*$/
---
name: history-subst-5
description:
	Make sure searches don't find current (fc) command
	(ksh88/ksh93 don't have the ? prefix thing so they fail this test)
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc def
	echo ghi jkl
	fc -e - abc=AB \?abc
expected-stdout:
	abc def
	ghi jkl
	AB def
expected-stderr-pattern:
	/^X*echo AB def\nX*$/
---
name: history-ed-1-old
description:
	Basic (ed) editing works (assumes you have generic ed editor
	that prints no prompts). This is for oldish ed(1) which write
	the character count to stdout.
category: stdout-ed
need-ctty: yes
need-pass: no
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc def
	fc echo
	s/abc/FOOBAR/
	w
	q
expected-stdout:
	abc def
	13
	16
	FOOBAR def
expected-stderr-pattern:
	/^X*echo FOOBAR def\nX*$/
---
name: history-ed-2-old
description:
	Correct command is edited when number given
category: stdout-ed
need-ctty: yes
need-pass: no
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2 is here
	echo line 3
	echo line 4
	fc 2
	s/is here/is changed/
	w
	q
expected-stdout:
	line 1
	line 2 is here
	line 3
	line 4
	20
	23
	line 2 is changed
expected-stderr-pattern:
	/^X*echo line 2 is changed\nX*$/
---
name: history-ed-3-old
description:
	Newly created multi line commands show up as single command
	in history.
	(ksh88 fails 'cause it lists the fc command)
category: stdout-ed
need-ctty: yes
need-pass: no
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc def
	fc echo
	s/abc/FOOBAR/
	$a
	echo a new line
	.
	w
	q
	fc -l
expected-stdout:
	abc def
	13
	32
	FOOBAR def
	a new line
	1	echo abc def
	2	echo FOOBAR def
		echo a new line
expected-stderr-pattern:
	/^X*echo FOOBAR def\necho a new line\nX*$/
---
name: history-ed-1
description:
	Basic (ed) editing works (assumes you have generic ed editor
	that prints no prompts). This is for newish ed(1) and stderr.
category: !no-stderr-ed
need-ctty: yes
need-pass: no
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc def
	fc echo
	s/abc/FOOBAR/
	w
	q
expected-stdout:
	abc def
	FOOBAR def
expected-stderr-pattern:
	/^X*13\n16\necho FOOBAR def\nX*$/
---
name: history-ed-2
description:
	Correct command is edited when number given
category: !no-stderr-ed
need-ctty: yes
need-pass: no
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo line 1
	echo line 2 is here
	echo line 3
	echo line 4
	fc 2
	s/is here/is changed/
	w
	q
expected-stdout:
	line 1
	line 2 is here
	line 3
	line 4
	line 2 is changed
expected-stderr-pattern:
	/^X*20\n23\necho line 2 is changed\nX*$/
---
name: history-ed-3
description:
	Newly created multi line commands show up as single command
	in history.
category: !no-stderr-ed
need-ctty: yes
need-pass: no
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	echo abc def
	fc echo
	s/abc/FOOBAR/
	$a
	echo a new line
	.
	w
	q
	fc -l
expected-stdout:
	abc def
	FOOBAR def
	a new line
	1	echo abc def
	2	echo FOOBAR def
		echo a new line
expected-stderr-pattern:
	/^X*13\n32\necho FOOBAR def\necho a new line\nX*$/
---
name: IFS-space-1
description:
	Simple test, default IFS
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	set -- A B C
	showargs 1 $*
	showargs 2 "$*"
	showargs 3 $@
	showargs 4 "$@"
expected-stdout:
	<1> <A> <B> <C> .
	<2> <A B C> .
	<3> <A> <B> <C> .
	<4> <A> <B> <C> .
---
name: IFS-colon-1
description:
	Simple test, IFS=:
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	IFS=:
	set -- A B C
	showargs 1 $*
	showargs 2 "$*"
	showargs 3 $@
	showargs 4 "$@"
expected-stdout:
	<1> <A> <B> <C> .
	<2> <A:B:C> .
	<3> <A> <B> <C> .
	<4> <A> <B> <C> .
---
name: IFS-null-1
description:
	Simple test, IFS=""
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	IFS=""
	set -- A B C
	showargs 1 $*
	showargs 2 "$*"
	showargs 3 $@
	showargs 4 "$@"
expected-stdout:
	<1> <A> <B> <C> .
	<2> <ABC> .
	<3> <A> <B> <C> .
	<4> <A> <B> <C> .
---
name: IFS-space-colon-1
description:
	Simple test, IFS=<white-space>:
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	IFS="$IFS:"
	set --
	showargs 1 $*
	showargs 2 "$*"
	showargs 3 $@
	showargs 4 "$@"
	showargs 5 : "$@"
expected-stdout:
	<1> .
	<2> <> .
	<3> .
	<4> .
	<5> <:> .
---
name: IFS-space-colon-2
description:
	Simple test, IFS=<white-space>:
	AT&T ksh fails this, POSIX says the test is correct.
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	IFS="$IFS:"
	set --
	showargs :"$@"
expected-stdout:
	<:> .
---
name: IFS-space-colon-4
description:
	Simple test, IFS=<white-space>:
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	IFS="$IFS:"
	set --
	showargs "$@$@"
expected-stdout:
	.
---
name: IFS-space-colon-5
description:
	Simple test, IFS=<white-space>:
	Don't know what POSIX thinks of this.  AT&T ksh does not do this.
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	IFS="$IFS:"
	set --
	showargs "${@:-}"
expected-stdout:
	<> .
---
name: IFS-subst-1
description:
	Simple test, IFS=<white-space>:
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	IFS="$IFS:"
	x=":b: :"
	echo -n '1:'; for i in $x ; do echo -n " [$i]" ; done ; echo
	echo -n '2:'; for i in :b:: ; do echo -n " [$i]" ; done ; echo
	showargs 3 $x
	showargs 4 :b::
	x="a:b:"
	echo -n '5:'; for i in $x ; do echo -n " [$i]" ; done ; echo
	showargs 6 $x
	x="a::c"
	echo -n '7:'; for i in $x ; do echo -n " [$i]" ; done ; echo
	showargs 8 $x
	echo -n '9:'; for i in ${FOO-`echo -n h:i`th:ere} ; do echo -n " [$i]" ; done ; echo
	showargs 10 ${FOO-`echo -n h:i`th:ere}
	showargs 11 "${FOO-`echo -n h:i`th:ere}"
	x=" A :  B::D"
	echo -n '12:'; for i in $x ; do echo -n " [$i]" ; done ; echo
	showargs 13 $x
expected-stdout:
	1: [] [b] []
	2: [:b::]
	<3> <> <b> <> .
	<4> <:b::> .
	5: [a] [b]
	<6> <a> <b> .
	7: [a] [] [c]
	<8> <a> <> <c> .
	9: [h] [ith] [ere]
	<10> <h> <ith> <ere> .
	<11> <h:ith:ere> .
	12: [A] [B] [] [D]
	<13> <A> <B> <> <D> .
---
name: IFS-subst-2
description:
	Check leading whitespace after trim does not make a field
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	x="X 1 2"
	showargs 1 shift ${x#X}
expected-stdout:
	<1> <shift> <1> <2> .
---
name: IFS-subst-3-arr
description:
	Check leading IFS non-whitespace after trim does make a field
	but leading IFS whitespace does not, nor empty replacements
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	showargs 0 ${-+}
	IFS=:
	showargs 1 ${-+:foo:bar}
	IFS=' '
	showargs 2 ${-+ foo bar}
expected-stdout:
	<0> .
	<1> <> <foo> <bar> .
	<2> <foo> <bar> .
---
name: IFS-subst-3-ass
description:
	Check non-field semantics
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	showargs 0 x=${-+}
	IFS=:
	showargs 1 x=${-+:foo:bar}
	IFS=' '
	showargs 2 x=${-+ foo bar}
expected-stdout:
	<0> <x=> .
	<1> <x=> <foo> <bar> .
	<2> <x=> <foo> <bar> .
---
name: IFS-subst-3-lcl
description:
	Check non-field semantics, smaller corner case (LP#1381965)
stdin:
	set -x
	local regex=${2:-}
	exit 1
expected-exit: e != 0
expected-stderr-pattern:
	/regex=/
---
name: IFS-subst-4-1
description:
	reported by mikeserv
stdin:
	pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }
	a='space divded  argument
	here'
	IFS=\  ; set -- $a
	IFS= ; q="$*" ; nq=$*
	pfn "$*" $* "$q" "$nq"
	[ "$q" = "$nq" ] && echo =true || echo =false
expected-stdout:
	<spacedivdedargument
	here>
	<space>
	<divded>
	<argument
	here>
	<spacedivdedargument
	here>
	<spacedivdedargument
	here>
	=true
---
name: IFS-subst-4-2
description:
	extended testsuite based on problem by mikeserv
stdin:
	pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }
	a='space divded  argument
	here'
	IFS=\  ; set -- $a
	IFS= ; q="$@" ; nq=$@
	pfn "$*" $* "$q" "$nq"
	[ "$q" = "$nq" ] && echo =true || echo =false
expected-stdout:
	<spacedivdedargument
	here>
	<space>
	<divded>
	<argument
	here>
	<space divded argument
	here>
	<space divded argument
	here>
	=true
---
name: IFS-subst-4-3
description:
	extended testsuite based on problem by mikeserv
stdin:
	pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }
	a='space divded  argument
	here'
	IFS=\ ; set -- $a; IFS=
	qs="$*"
	nqs=$*
	qk="$@"
	nqk=$@
	print -nr -- '= qs '; pfn "$qs"
	print -nr -- '=nqs '; pfn "$nqs"
	print -nr -- '= qk '; pfn "$qk"
	print -nr -- '=nqk '; pfn "$nqk"
	print -nr -- '~ qs '; pfn "$*"
	print -nr -- '~nqs '; pfn $*
	print -nr -- '~ qk '; pfn "$@"
	print -nr -- '~nqk '; pfn $@
expected-stdout:
	= qs <spacedivdedargument
	here>
	=nqs <spacedivdedargument
	here>
	= qk <space divded argument
	here>
	=nqk <space divded argument
	here>
	~ qs <spacedivdedargument
	here>
	~nqs <space>
	<divded>
	<argument
	here>
	~ qk <space>
	<divded>
	<argument
	here>
	~nqk <space>
	<divded>
	<argument
	here>
---
name: IFS-subst-4-4
description:
	extended testsuite based on problem by mikeserv
stdin:
	pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }
	a='space divded  argument
	here'
	IFS=\ ; set -- $a; IFS=
	qs="$*"
	print -nr -- '= qs '; pfn "$qs"
	print -nr -- '~ qs '; pfn "$*"
	nqs=$*
	print -nr -- '=nqs '; pfn "$nqs"
	print -nr -- '~nqs '; pfn $*
	qk="$@"
	print -nr -- '= qk '; pfn "$qk"
	print -nr -- '~ qk '; pfn "$@"
	nqk=$@
	print -nr -- '=nqk '; pfn "$nqk"
	print -nr -- '~nqk '; pfn $@
expected-stdout:
	= qs <spacedivdedargument
	here>
	~ qs <spacedivdedargument
	here>
	=nqs <spacedivdedargument
	here>
	~nqs <space>
	<divded>
	<argument
	here>
	= qk <space divded argument
	here>
	~ qk <space>
	<divded>
	<argument
	here>
	=nqk <space divded argument
	here>
	~nqk <space>
	<divded>
	<argument
	here>
---
name: IFS-subst-4-4p
description:
	extended testsuite based on problem by mikeserv
stdin:
	pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }
	a='space divded  argument
	here'
	IFS=\ ; set -- $a; IFS=
	unset v
	qs=${v:-"$*"}
	print -nr -- '= qs '; pfn "$qs"
	print -nr -- '~ qs '; pfn ${v:-"$*"}
	nqs=${v:-$*}
	print -nr -- '=nqs '; pfn "$nqs"
	print -nr -- '~nqs '; pfn ${v:-$*}
	qk=${v:-"$@"}
	print -nr -- '= qk '; pfn "$qk"
	print -nr -- '~ qk '; pfn ${v:-"$@"}
	nqk=${v:-$@}
	print -nr -- '=nqk '; pfn "$nqk"
	print -nr -- '~nqk '; pfn ${v:-$@}
expected-stdout:
	= qs <spacedivdedargument
	here>
	~ qs <spacedivdedargument
	here>
	=nqs <spacedivdedargument
	here>
	~nqs <space>
	<divded>
	<argument
	here>
	= qk <space divded argument
	here>
	~ qk <space>
	<divded>
	<argument
	here>
	=nqk <space divded argument
	here>
	~nqk <space>
	<divded>
	<argument
	here>
---
name: IFS-subst-4-5
description:
	extended testsuite based on problem by mikeserv
stdin:
	pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }
	a='space divded  argument
	here'
	IFS=\ ; set -- $a; IFS=,
	qs="$*"
	print -nr -- '= qs '; pfn "$qs"
	print -nr -- '~ qs '; pfn "$*"
	nqs=$*
	print -nr -- '=nqs '; pfn "$nqs"
	print -nr -- '~nqs '; pfn $*
	qk="$@"
	print -nr -- '= qk '; pfn "$qk"
	print -nr -- '~ qk '; pfn "$@"
	nqk=$@
	print -nr -- '=nqk '; pfn "$nqk"
	print -nr -- '~nqk '; pfn $@
expected-stdout:
	= qs <space,divded,argument
	here>
	~ qs <space,divded,argument
	here>
	=nqs <space,divded,argument
	here>
	~nqs <space>
	<divded>
	<argument
	here>
	= qk <space divded argument
	here>
	~ qk <space>
	<divded>
	<argument
	here>
	=nqk <space divded argument
	here>
	~nqk <space>
	<divded>
	<argument
	here>
---
name: IFS-subst-4-5p
description:
	extended testsuite based on problem by mikeserv
stdin:
	pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; }
	a='space divded  argument
	here'
	IFS=\ ; set -- $a; IFS=,
	unset v
	qs=${v:-"$*"}
	print -nr -- '= qs '; pfn "$qs"
	print -nr -- '~ qs '; pfn ${v:-"$*"}
	nqs=${v:-$*}
	print -nr -- '=nqs '; pfn "$nqs"
	print -nr -- '~nqs '; pfn ${v:-$*}
	qk=${v:-"$@"}
	print -nr -- '= qk '; pfn "$qk"
	print -nr -- '~ qk '; pfn ${v:-"$@"}
	nqk=${v:-$@}
	print -nr -- '=nqk '; pfn "$nqk"
	print -nr -- '~nqk '; pfn ${v:-$@}
expected-stdout:
	= qs <space,divded,argument
	here>
	~ qs <space,divded,argument
	here>
	=nqs <space,divded,argument
	here>
	~nqs <space>
	<divded>
	<argument
	here>
	= qk <space divded argument
	here>
	~ qk <space>
	<divded>
	<argument
	here>
	=nqk <space divded argument
	here>
	~nqk <space>
	<divded>
	<argument
	here>
---
name: IFS-subst-5
description:
	extended testsuite based on IFS-subst-3
	differs slightly from ksh93:
	- omit trailing field in a3zna, a7ina (unquoted $@ expansion)
	- has extra middle fields in b5ins, b7ina (IFS_NWS unquoted expansion)
	differs slightly from bash:
	- omit leading field in a5ins, a7ina (IFS_NWS unquoted expansion)
	differs slightly from zsh:
	- differs in assignment, not expansion; probably zsh bug
	- has extra middle fields in b5ins, b7ina (IFS_NWS unquoted expansion)
	'emulate sh' zsh has extra fields in
	- a5ins (IFS_NWS unquoted $*)
	- b5ins, matching mksh’s
	!!WARNING!! more to come: http://austingroupbugs.net/view.php?id=888
stdin:
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=; set -- "" 2 ""; pfb $*; x=$*; pfn "$x"'
	echo '=a1zns'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=; set -- "" 2 ""; pfb "$*"; x="$*"; pfn "$x"'
	echo '=a2zqs'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=; set -- "" 2 ""; pfb $@; x=$@; pfn "$x"'
	echo '=a3zna'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=; set -- "" 2 ""; pfb "$@"; x="$@"; pfn "$x"'
	echo '=a4zqa'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=,; set -- "" 2 ""; pfb $*; x=$*; pfn "$x"'
	echo '=a5ins'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=,; set -- "" 2 ""; pfb "$*"; x="$*"; pfn "$x"'
	echo '=a6iqs'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=,; set -- "" 2 ""; pfb $@; x=$@; pfn "$x"'
	echo '=a7ina'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=,; set -- "" 2 ""; pfb "$@"; x="$@"; pfn "$x"'
	echo '=a8iqa'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=; set -- A B "" "" C; pfb $*; x=$*; pfn "$x"'
	echo '=b1zns'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=; set -- A B "" "" C; pfb "$*"; x="$*"; pfn "$x"'
	echo '=b2zqs'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=; set -- A B "" "" C; pfb $@; x=$@; pfn "$x"'
	echo '=b3zna'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=; set -- A B "" "" C; pfb "$@"; x="$@"; pfn "$x"'
	echo '=b4zqa'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=,; set -- A B "" "" C; pfb $*; x=$*; pfn "$x"'
	echo '=b5ins'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=,; set -- A B "" "" C; pfb "$*"; x="$*"; pfn "$x"'
	echo '=b6iqs'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=,; set -- A B "" "" C; pfb $@; x=$@; pfn "$x"'
	echo '=b7ina'
	"$__progname" -c 'pfb() { for s_arg in "$@"; do print -r -- "[$s_arg]"; done; }; pfn() { for s_arg in "$@"; do print -r -- "<$s_arg>"; done; };
		IFS=,; set -- A B "" "" C; pfb "$@"; x="$@"; pfn "$x"'
	echo '=b8iqa'
expected-stdout:
	[2]
	<2>
	=a1zns
	[2]
	<2>
	=a2zqs
	[2]
	< 2 >
	=a3zna
	[]
	[2]
	[]
	< 2 >
	=a4zqa
	[2]
	<,2,>
	=a5ins
	[,2,]
	<,2,>
	=a6iqs
	[2]
	< 2 >
	=a7ina
	[]
	[2]
	[]
	< 2 >
	=a8iqa
	[A]
	[B]
	[C]
	<ABC>
	=b1zns
	[ABC]
	<ABC>
	=b2zqs
	[A]
	[B]
	[C]
	<A B   C>
	=b3zna
	[A]
	[B]
	[]
	[]
	[C]
	<A B   C>
	=b4zqa
	[A]
	[B]
	[]
	[]
	[C]
	<A,B,,,C>
	=b5ins
	[A,B,,,C]
	<A,B,,,C>
	=b6iqs
	[A]
	[B]
	[]
	[]
	[C]
	<A B   C>
	=b7ina
	[A]
	[B]
	[]
	[]
	[C]
	<A B   C>
	=b8iqa
---
name: IFS-subst-6
description:
	Regression wrt. vector expansion in trim
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	IFS=
	x=abc
	set -- a b
	showargs ${x#$*}
expected-stdout:
	<c> .
---
name: IFS-subst-7
description:
	ksh93 bug wrt. vector expansion in trim
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	IFS="*"
	a=abcd
	set -- '' c
	showargs "$*" ${a##"$*"}
expected-stdout:
	<*c> <abcd> .
---
name: IFS-subst-8
description:
	http://austingroupbugs.net/view.php?id=221
stdin:
	n() { echo "$#"; }; n "${foo-$@}"
expected-stdout:
	1
---
name: IFS-subst-9
description:
	Scalar context for $*/$@ in [[ and case
stdin:
	"$__progname" -c 'IFS=; set a b; [[ $* = "$1$2" ]]; echo 1 $?' sh a b
	"$__progname" -c 'IFS=; [[ $* = ab ]]; echo 2 "$?"' sh a b
	"$__progname" -c 'IFS=; [[ "$*" = ab ]]; echo 3 "$?"' sh a b
	"$__progname" -c 'IFS=; [[ $* = a ]]; echo 4 "$?"' sh a b
	"$__progname" -c 'IFS=; [[ "$*" = a ]]; echo 5 "$?"' sh a b
	"$__progname" -c 'IFS=; [[ "$@" = a ]]; echo 6 "$?"' sh a b
	"$__progname" -c 'IFS=; case "$@" in a) echo 7 a;; ab) echo 7 b;; a\ b) echo 7 ok;; esac' sh a b
	"$__progname" -c 'IFS=; case $* in a) echo 8 a;; ab) echo 8 ok;; esac' sh a b
	"$__progname" -c 'pfsp() { for s_arg in "$@"; do print -nr -- "<$s_arg> "; done; print .; }; IFS=; star=$* at="$@"; pfsp 9 "$star" "$at"' sh a b
expected-stdout:
	1 0
	2 0
	3 0
	4 1
	5 1
	6 1
	7 ok
	8 ok
	<9> <ab> <a b> .
---
name: IFS-subst-10
description:
	Scalar context in ${var=$subst}
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	set -- one "two three" four
	unset -v var
	save_IFS=$IFS
	IFS=
	set -- ${var=$*}
	IFS=$save_IFS
	echo "var=$var"
	showargs "$@"
expected-stdout:
	var=onetwo threefour
	<onetwo threefour> .
---
name: IFS-subst-11
description:
	Check leading non-whitespace after trim makes only one field
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	v="foo!one!two!three"
	IFS="!"
	showargs x ${v:3} y
expected-stdout:
	<x> <> <one> <two> <three> <y> .
---
name: IFS-arith-1
description:
	http://austingroupbugs.net/view.php?id=832
stdin:
	${ZSH_VERSION+false} || emulate sh
	${BASH_VERSION+set -o posix}
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	IFS=0
	showargs $((1230456))
expected-stdout:
	<123> <456> .
---
name: integer-base-err-1
description:
	Can't have 0 base (causes shell to exit)
expected-exit: e != 0
stdin:
	typeset -i i
	i=3
	i=0#4
	echo $i
expected-stderr-pattern:
	/^.*:.*0#4.*\n$/
---
name: integer-base-err-2
description:
	Can't have multiple bases in a 'constant' (causes shell to exit)
	(ksh88 fails this test)
expected-exit: e != 0
stdin:
	typeset -i i
	i=3
	i=2#110#11
	echo $i
expected-stderr-pattern:
	/^.*:.*2#110#11.*\n$/
---
name: integer-base-err-3
description:
	Syntax errors in expressions and effects on bases
	(interactive so errors don't cause exits)
	(ksh88 fails this test - shell exits, even with -i)
need-ctty: yes
arguments: !-i!
stdin:
	PS1= # minimise prompt hassles
	typeset -i4 a=10
	typeset -i a=2+
	echo $a
	typeset -i4 a=10
	typeset -i2 a=2+
	echo $a
expected-stderr-pattern:
	/^([#\$] )?.*:.*2+.*\n.*:.*2+.*\n$/
expected-stdout:
	4#22
	4#22
---
name: integer-base-err-4
description:
	Are invalid digits (according to base) errors?
	(ksh93 fails this test)
expected-exit: e != 0
stdin:
	typeset -i i;
	i=3#4
expected-stderr-pattern:
	/^([#\$] )?.*:.*3#4.*\n$/
---
name: integer-base-1
description:
	Missing number after base is treated as 0.
stdin:
	typeset -i i
	i=3
	i=2#
	echo $i
expected-stdout:
	0
---
name: integer-base-2
description:
	Check 'stickyness' of base in various situations
stdin:
	typeset -i i=8
	echo $i
	echo ---------- A
	typeset -i4 j=8
	echo $j
	echo ---------- B
	typeset -i k=8
	typeset -i4 k=8
	echo $k
	echo ---------- C
	typeset -i4 l
	l=3#10
	echo $l
	echo ---------- D
	typeset -i m
	m=3#10
	echo $m
	echo ---------- E
	n=2#11
	typeset -i n
	echo $n
	n=10
	echo $n
	echo ---------- F
	typeset -i8 o=12
	typeset -i4 o
	echo $o
	echo ---------- G
	typeset -i p
	let p=8#12
	echo $p
expected-stdout:
	8
	---------- A
	4#20
	---------- B
	4#20
	---------- C
	4#3
	---------- D
	3#10
	---------- E
	2#11
	2#1010
	---------- F
	4#30
	---------- G
	8#12
---
name: integer-base-3
description:
	More base parsing (hmm doesn't test much..)
stdin:
	typeset -i aa
	aa=1+12#10+2
	echo $aa
	typeset -i bb
	bb=1+$aa
	echo $bb
	typeset -i bb
	bb=$aa
	echo $bb
	typeset -i cc
	cc=$aa
	echo $cc
expected-stdout:
	15
	16
	15
	15
---
name: integer-base-4
description:
	Check that things not declared as integers are not made integers,
	also, check if base is not reset by -i with no arguments.
	(ksh93 fails - prints 10#20 - go figure)
stdin:
	xx=20
	let xx=10
	typeset -i | grep '^xx='
	typeset -i4 a=10
	typeset -i a=20
	echo $a
expected-stdout:
	4#110
---
name: integer-base-5
description:
	More base stuff
stdin:
	typeset -i4 a=3#10
	echo $a
	echo --
	typeset -i j=3
	j='~3'
	echo $j
	echo --
	typeset -i k=1
	x[k=k+1]=3
	echo $k
	echo --
	typeset -i l
	for l in 1 2+3 4; do echo $l; done
expected-stdout:
	4#3
	--
	-4
	--
	2
	--
	1
	5
	4
---
name: integer-base-6
description:
	Even more base stuff
	(ksh93 fails this test - prints 0)
stdin:
	typeset -i7 i
	i=
	echo $i
expected-stdout:
	7#0
---
name: integer-base-7
description:
	Check that non-integer parameters don't get bases assigned
stdin:
	echo $(( zz = 8#100 ))
	echo $zz
expected-stdout:
	64
	64
---
name: integer-base-8
description:
	Check that base-36 works (full span)
stdin:
	echo 1:$((36#109AZ)).
	typeset -i36 x=1691675
	echo 2:$x.
	typeset -Uui36 x
	echo 3:$x.
expected-stdout:
	1:1691675.
	2:36#109az.
	3:36#109AZ.
---
name: integer-base-check-flat
description:
	Check behaviour does not match POSuX (except if set -o posix),
	because a not type-safe scripting language has *no* business
	interpreting the string "010" as octal number eight (dangerous).
stdin:
	echo 1 "$("$__progname" -c 'echo :$((10))/$((010)),$((0x10)):')" .
	echo 2 "$("$__progname" -o posix -c 'echo :$((10))/$((010)),$((0x10)):')" .
	echo 3 "$("$__progname" -o sh -c 'echo :$((10))/$((010)),$((0x10)):')" .
expected-stdout:
	1 :10/10,16: .
	2 :10/8,16: .
	3 :10/10,16: .
---
name: integer-base-check-numeric-from-1
description:
	Check behaviour for base one
category: !shell:ebcdic-yes
stdin:
	echo 1:$((1#1))0.
expected-stdout:
	1:490.
---
name: integer-base-check-numeric-from-1-ebcdic
description:
	Check behaviour for base one
category: !shell:ebcdic-no
stdin:
	echo 1:$((1#1))0.
expected-stdout:
	1:2410.
---
name: integer-base-check-numeric-from-2
description:
	Check behaviour for base two to 36, and that 37 degrades to 10
stdin:
	i=1
	while (( ++i <= 37 )); do
		eval 'echo '$i':$(('$i'#10)).'
	done
	echo 37:$($__progname -c 'echo $((37#10))').$?:
expected-stdout:
	2:2.
	3:3.
	4:4.
	5:5.
	6:6.
	7:7.
	8:8.
	9:9.
	10:10.
	11:11.
	12:12.
	13:13.
	14:14.
	15:15.
	16:16.
	17:17.
	18:18.
	19:19.
	20:20.
	21:21.
	22:22.
	23:23.
	24:24.
	25:25.
	26:26.
	27:27.
	28:28.
	29:29.
	30:30.
	31:31.
	32:32.
	33:33.
	34:34.
	35:35.
	36:36.
	37:10.
	37:10.0:
---
name: integer-base-check-numeric-to-1
description:
	Check behaviour for base one
category: !shell:ebcdic-yes
stdin:
	i=1
	typeset -Uui$i x=0x40
	eval "typeset -i10 y=$x"
	print $i:$x.$y.
expected-stdout:
	1:1#@.64.
---
name: integer-base-check-numeric-to-1-ebcdic
description:
	Check behaviour for base one
category: !shell:ebcdic-no
stdin:
	i=1
	typeset -Uui$i x=0x7C
	eval "typeset -i10 y=$x"
	print $i:$x.$y.
expected-stdout:
	1:1#@.124.
---
name: integer-base-check-numeric-to-2
description:
	Check behaviour for base two to 36, and that 37 degrades to 10
stdin:
	i=1
	while (( ++i <= 37 )); do
		typeset -Uui$i x=0x40
		eval "typeset -i10 y=$x"
		print $i:$x.$y.
	done
expected-stdout:
	2:2#1000000.64.
	3:3#2101.64.
	4:4#1000.64.
	5:5#224.64.
	6:6#144.64.
	7:7#121.64.
	8:8#100.64.
	9:9#71.64.
	10:64.64.
	11:11#59.64.
	12:12#54.64.
	13:13#4C.64.
	14:14#48.64.
	15:15#44.64.
	16:16#40.64.
	17:17#3D.64.
	18:18#3A.64.
	19:19#37.64.
	20:20#34.64.
	21:21#31.64.
	22:22#2K.64.
	23:23#2I.64.
	24:24#2G.64.
	25:25#2E.64.
	26:26#2C.64.
	27:27#2A.64.
	28:28#28.64.
	29:29#26.64.
	30:30#24.64.
	31:31#22.64.
	32:32#20.64.
	33:33#1V.64.
	34:34#1U.64.
	35:35#1T.64.
	36:36#1S.64.
	37:64.64.
---
name: integer-arithmetic-span
description:
	Check wraparound and size that is defined in mksh
category: int:32
stdin:
	echo s:$((2147483647+1)).$(((2147483647*2)+1)).$(((2147483647*2)+2)).
	echo u:$((#2147483647+1)).$((#(2147483647*2)+1)).$((#(2147483647*2)+2)).
expected-stdout:
	s:-2147483648.-1.0.
	u:2147483648.4294967295.0.
---
name: integer-arithmetic-span-64
description:
	Check wraparound and size that is defined in mksh
category: int:64
stdin:
	echo s:$((9223372036854775807+1)).$(((9223372036854775807*2)+1)).$(((9223372036854775807*2)+2)).
	echo u:$((#9223372036854775807+1)).$((#(9223372036854775807*2)+1)).$((#(9223372036854775807*2)+2)).
expected-stdout:
	s:-9223372036854775808.-1.0.
	u:9223372036854775808.18446744073709551615.0.
---
name: integer-size-FAIL-to-detect
description:
	Notify the user that their ints are not 32 or 64 bit
category: int:u
stdin:
	:
---
name: lineno-stdin
description:
	See if $LINENO is updated and can be modified.
stdin:
	echo A $LINENO
	echo B $LINENO
	LINENO=20
	echo C $LINENO
expected-stdout:
	A 1
	B 2
	C 20
---
name: lineno-inc
description:
	See if $LINENO is set for .'d files.
file-setup: file 644 "dotfile"
	echo dot A $LINENO
	echo dot B $LINENO
	LINENO=20
	echo dot C $LINENO
stdin:
	echo A $LINENO
	echo B $LINENO
	. ./dotfile
expected-stdout:
	A 1
	B 2
	dot A 1
	dot B 2
	dot C 20
---
name: lineno-func
description:
	See if $LINENO is set for commands in a function.
stdin:
	echo A $LINENO
	echo B $LINENO
	bar() {
	    echo func A $LINENO
	    echo func B $LINENO
	}
	bar
	echo C $LINENO
expected-stdout:
	A 1
	B 2
	func A 4
	func B 5
	C 8
---
name: lineno-unset
description:
	See if unsetting LINENO makes it non-magic.
file-setup: file 644 "dotfile"
	echo dot A $LINENO
	echo dot B $LINENO
stdin:
	unset LINENO
	echo A $LINENO
	echo B $LINENO
	bar() {
	    echo func A $LINENO
	    echo func B $LINENO
	}
	bar
	. ./dotfile
	echo C $LINENO
expected-stdout:
	A
	B
	func A
	func B
	dot A
	dot B
	C
---
name: lineno-unset-use
description:
	See if unsetting LINENO makes it non-magic even
	when it is re-used.
file-setup: file 644 "dotfile"
	echo dot A $LINENO
	echo dot B $LINENO
stdin:
	unset LINENO
	LINENO=3
	echo A $LINENO
	echo B $LINENO
	bar() {
	    echo func A $LINENO
	    echo func B $LINENO
	}
	bar
	. ./dotfile
	echo C $LINENO
expected-stdout:
	A 3
	B 3
	func A 3
	func B 3
	dot A 3
	dot B 3
	C 3
---
name: lineno-trap
description:
	Check if LINENO is tracked in traps
stdin:
	fail() {
		echo "line <$1>"
		exit 1
	}
	trap 'fail $LINENO' INT ERR
	false
expected-stdout:
	line <6>
expected-exit: 1
---
name: lineno-eval-alias
description:
	Check if LINENO is trapped in eval and aliases
stdin:
	${ZSH_VERSION+false} || emulate sh; echo $LINENO
	echo $LINENO
	eval '	echo $LINENO
		echo $LINENO
		echo $LINENO'
	echo $LINENO
expected-stdout:
	1
	2
	3
	3
	3
	6
---
name: unknown-trap
description:
	Ensure unknown traps are not a syntax error
stdin:
	(
	trap "echo trap 1 executed" UNKNOWNSIGNAL || echo "foo"
	echo =1
	trap "echo trap 2 executed" UNKNOWNSIGNAL EXIT 999999 FNORD
	echo = $?
	) 2>&1 | sed "s^${__progname%.exe}\.*e*x*e*: <stdin>\[[0-9]*]PROG"
expected-stdout:
	PROG: trap: bad signal 'UNKNOWNSIGNAL'
	foo
	=1
	PROG: trap: bad signal 'UNKNOWNSIGNAL'
	PROG: trap: bad signal '999999'
	PROG: trap: bad signal 'FNORD'
	= 1
	trap 2 executed
---
name: read-IFS-1
description:
	Simple test, default IFS
stdin:
	echo "A B " > IN
	unset x y z
	read x y z < IN
	echo 1: "x[$x] y[$y] z[$z]"
	echo 1a: ${z-z not set}
	read x < IN
	echo 2: "x[$x]"
expected-stdout:
	1: x[A] y[B] z[]
	1a:
	2: x[A B]
---
name: read-IFS-2
description:
	Complex tests, IFS either colon (IFS-NWS) or backslash (tricky)
stdin:
	n=0
	showargs() { print -nr "$1"; shift; for s_arg in "$@"; do print -nr -- " [$s_arg]"; done; print; }
	(IFS=\\ a=\<\\\>; showargs 3 $a)
	(IFS=: b=\<:\>; showargs 4 $b)
	print -r '<\>' | (IFS=\\ read f g; showargs 5 "$f" "$g")
	print -r '<\\>' | (IFS=\\ read f g; showargs 6 "$f" "$g")
	print '<\\\n>' | (IFS=\\ read f g; showargs 7 "$f" "$g")
	print -r '<\>' | (IFS=\\ read f; showargs 8 "$f")
	print -r '<\\>' | (IFS=\\ read f; showargs 9 "$f")
	print '<\\\n>' | (IFS=\\ read f; showargs 10 "$f")
	print -r '<\>' | (IFS=\\ read -r f g; showargs 11 "$f" "$g")
	print -r '<\\>' | (IFS=\\ read -r f g; showargs 12 "$f" "$g")
	print '<\\\n>' | (IFS=\\ read -r f g; showargs 13 "$f" "$g")
	print -r '<\>' | (IFS=\\ read -r f; showargs 14 "$f")
	print -r '<\\>' | (IFS=\\ read -r f; showargs 15 "$f")
	print '<\\\n>' | (IFS=\\ read -r f; showargs 16 "$f")
	print -r '<:>' | (IFS=: read f g; showargs 17 "$f" "$g")
	print -r '<::>' | (IFS=: read f g; showargs 18 "$f" "$g")
	print '<:\n>' | (IFS=: read f g; showargs 19 "$f" "$g")
	print -r '<:>' | (IFS=: read f; showargs 20 "$f")
	print -r '<::>' | (IFS=: read f; showargs 21 "$f")
	print '<:\n>' | (IFS=: read f; showargs 22 "$f")
	print -r '<:>' | (IFS=: read -r f g; showargs 23 "$f" "$g")
	print -r '<::>' | (IFS=: read -r f g; showargs 24 "$f" "$g")
	print '<:\n>' | (IFS=: read -r f g; showargs 25 "$f" "$g")
	print -r '<:>' | (IFS=: read -r f; showargs 26 "$f")
	print -r '<::>' | (IFS=: read -r f; showargs 27 "$f")
	print '<:\n>' | (IFS=: read -r f; showargs 28 "$f")
expected-stdout:
	3 [<] [>]
	4 [<] [>]
	5 [<] [>]
	6 [<] [>]
	7 [<>] []
	8 [<>]
	9 [<\>]
	10 [<>]
	11 [<] [>]
	12 [<] [\>]
	13 [<] []
	14 [<\>]
	15 [<\\>]
	16 [<]
	17 [<] [>]
	18 [<] [:>]
	19 [<] []
	20 [<:>]
	21 [<::>]
	22 [<]
	23 [<] [>]
	24 [<] [:>]
	25 [<] []
	26 [<:>]
	27 [<::>]
	28 [<]
---
name: read-ksh-1
description:
	If no var specified, REPLY is used
stdin:
	echo "abc" > IN
	read < IN
	echo "[$REPLY]";
expected-stdout:
	[abc]
---
name: read-regress-1
description:
	Check a regression of read
file-setup: file 644 "foo"
	foo bar
	baz
	blah
stdin:
	while read a b c; do
		read d
		break
	done <foo
	echo "<$a|$b|$c><$d>"
expected-stdout:
	<foo|bar|><baz>
---
name: read-delim-1
description:
	Check read with delimiters
stdin:
	emit() {
		print -n 'foo bar\tbaz\nblah \0blub\tblech\nmyok meck \0'
	}
	emit | while IFS= read -d "" foo; do print -r -- "<$foo>"; done
	emit | while read -d "" foo; do print -r -- "<$foo>"; done
	emit | while read -d "eh?" foo; do print -r -- "<$foo>"; done
expected-stdout:
	<foo bar	baz
	blah >
	<blub	blech
	myok meck >
	<foo bar	baz
	blah>
	<blub	blech
	myok meck>
	<foo bar	baz
	blah blub	bl>
	<ch
	myok m>
---
name: read-ext-1
description:
	Check read with number of bytes specified, and -A
stdin:
	print 'foo\nbar' >x1
	print -n x >x2
	print 'foo\\ bar baz' >x3
	x1a=u; read x1a <x1
	x1b=u; read -N-1 x1b <x1
	x2a=u; read x2a <x2; r2a=$?
	x2b=u; read -N2 x2c <x2; r2b=$?
	x2c=u; read -n2 x2c <x2; r2c=$?
	x3a=u; read -A x3a <x3
	print -r "x1a=<$x1a>"
	print -r "x1b=<$x1b>"
	print -r "x2a=$r2a<$x2a>"
	print -r "x2b=$r2b<$x2b>"
	print -r "x2c=$r2c<$x2c>"
	print -r "x3a=<${x3a[0]}|${x3a[1]}|${x3a[2]}>"
expected-stdout:
	x1a=<foo>
	x1b=<foo
	bar>
	x2a=1<x>
	x2b=1<u>
	x2c=0<x>
	x3a=<foo bar|baz|>
---
name: regression-1
description:
	Lex array code had problems with this.
stdin:
	echo foo[
	n=bar
	echo "hi[ $n ]=1"
expected-stdout:
	foo[
	hi[ bar ]=1
---
name: regression-2
description:
	When PATH is set before running a command, the new path is
	not used in doing the path search
		$ echo echo hi > /tmp/q ; chmod a+rx /tmp/q
		$ PATH=/tmp q
		q: not found
		$
	in comexec() the two lines
		while (*vp != NULL)
			(void) typeset(*vp++, xxx, 0);
	need to be moved out of the switch to before findcom() is
	called - I don't know what this will break.
stdin:
	: "${PWD:-`pwd 2> /dev/null`}"
	: "${PWD:?"PWD not set - cannot do test"}"
	mkdir Y
	cat > Y/xxxscript << EOF
	#!/bin/sh
	# Need to restore path so echo can be found (some shells don't have
	# it as a built-in)
	PATH=\$OLDPATH
	echo hi
	exit 0
	EOF
	chmod a+rx Y/xxxscript
	export OLDPATH="$PATH"
	PATH=$PWD/Y xxxscript
	exit $?
expected-stdout:
	hi
---
name: regression-6
description:
	Parsing of $(..) expressions is non-optimal.  It is
	impossible to have any parentheses inside the expression.
	I.e.,
		$ ksh -c 'echo $(echo \( )'
		no closing quote
		$ ksh -c 'echo $(echo "(" )'
		no closing quote
		$
	The solution is to hack the parsing clode in lex.c, the
	question is how to hack it: should any parentheses be
	escaped by a backslash, or should recursive parsing be done
	(so quotes could also be used to hide hem).  The former is
	easier, the later better...
stdin:
	echo $(echo \( )
	echo $(echo "(" )
expected-stdout:
	(
	(
---
name: regression-9
description:
	Continue in a for loop does not work right:
		for i in a b c ; do
			if [ $i = b ] ; then
				continue
			fi
			echo $i
		done
	Prints a forever...
stdin:
	first=yes
	for i in a b c ; do
		if [ $i = b ] ; then
			if [ $first = no ] ; then
				echo 'continue in for loop broken'
				break	# hope break isn't broken too :-)
			fi
			first=no
			continue
		fi
	done
	echo bye
expected-stdout:
	bye
---
name: regression-10
description:
	The following:
		set -- `false`
		echo $?
	should print 0 according to POSIX (dash, bash, ksh93, posh)
	but not 0 according to the getopt(1) manual page, ksh88, and
	Bourne sh (such as /bin/sh on Solaris).
	We honour POSIX except when -o sh is set.
category: shell:legacy-no
stdin:
	showf() {
		[[ -o posix ]]; FPOSIX=$((1-$?))
		[[ -o sh ]]; FSH=$((1-$?))
		echo -n "FPOSIX=$FPOSIX FSH=$FSH "
	}
	set +o posix +o sh
	showf
	set -- `false`
	echo rv=$?
	set -o sh
	showf
	set -- `false`
	echo rv=$?
	set -o posix
	showf
	set -- `false`
	echo rv=$?
	set -o posix -o sh
	showf
	set -- `false`
	echo rv=$?
expected-stdout:
	FPOSIX=0 FSH=0 rv=0
	FPOSIX=0 FSH=1 rv=1
	FPOSIX=1 FSH=0 rv=0
	FPOSIX=1 FSH=1 rv=0
---
name: regression-10-legacy
description:
	The following:
		set -- `false`
		echo $?
	should print 0 according to POSIX (dash, bash, ksh93, posh)
	but not 0 according to the getopt(1) manual page, ksh88, and
	Bourne sh (such as /bin/sh on Solaris).
category: shell:legacy-yes
stdin:
	showf() {
		[[ -o posix ]]; FPOSIX=$((1-$?))
		[[ -o sh ]]; FSH=$((1-$?))
		echo -n "FPOSIX=$FPOSIX FSH=$FSH "
	}
	set +o posix +o sh
	showf
	set -- `false`
	echo rv=$?
	set -o sh
	showf
	set -- `false`
	echo rv=$?
	set -o posix
	showf
	set -- `false`
	echo rv=$?
	set -o posix -o sh
	showf
	set -- `false`
	echo rv=$?
expected-stdout:
	FPOSIX=0 FSH=0 rv=1
	FPOSIX=0 FSH=1 rv=1
	FPOSIX=1 FSH=0 rv=0
	FPOSIX=1 FSH=1 rv=0
---
name: regression-11
description:
	The following:
		x=/foo/bar/blah
		echo ${x##*/}
	should echo blah but on some machines echos /foo/bar/blah.
stdin:
	x=/foo/bar/blah
	echo ${x##*/}
expected-stdout:
	blah
---
name: regression-12
description:
	Both of the following echos produce the same output under sh/ksh.att:
		#!/bin/sh
		x="foo	bar"
		echo "`echo \"$x\"`"
		echo "`echo "$x"`"
	pdksh produces different output for the former (foo instead of foo\tbar)
stdin:
	x="foo	bar"
	echo "`echo \"$x\"`"
	echo "`echo "$x"`"
expected-stdout:
	foo	bar
	foo	bar
---
name: regression-13
description:
	The following command hangs forever:
		$ (: ; cat /etc/termcap) | sleep 2
	This is because the shell forks a shell to run the (..) command
	and this shell has the pipe open.  When the sleep dies, the cat
	doesn't get a SIGPIPE 'cause a process (ie, the second shell)
	still has the pipe open.
	
	NOTE: this test provokes a bizarre bug in ksh93 (shell starts reading
	      commands from /etc/termcap..)
time-limit: 10
stdin:
	echo A line of text that will be duplicated quite a number of times.> t1
	cat t1 t1 t1 t1  t1 t1 t1 t1  t1 t1 t1 t1  t1 t1 t1 t1  > t2
	cat t2 t2 t2 t2  t2 t2 t2 t2  t2 t2 t2 t2  t2 t2 t2 t2  > t1
	cat t1 t1 t1 t1 > t2
	(: ; cat t2 2>/dev/null) | sleep 1
---
name: regression-14
description:
	The command
		$ (foobar) 2> /dev/null
	generates no output under /bin/sh, but pdksh produces the error
		foobar: not found
	Also, the command
		$ foobar 2> /dev/null
	generates an error under /bin/sh and pdksh, but AT&T ksh88 produces
	no error (redirected to /dev/null).
stdin:
	(you/should/not/see/this/error/1) 2> /dev/null
	you/should/not/see/this/error/2 2> /dev/null
	true
---
name: regression-15
description:
	The command
		$ whence foobar
	generates a blank line under pdksh and sets the exit status to 0.
	AT&T ksh88 generates no output and sets the exit status to 1.  Also,
	the command
		$ whence foobar cat
	generates no output under AT&T ksh88 (pdksh generates a blank line
	and /bin/cat).
stdin:
	whence does/not/exist > /dev/null
	echo 1: $?
	echo 2: $(whence does/not/exist | wc -l)
	echo 3: $(whence does/not/exist cat | wc -l)
expected-stdout:
	1: 1
	2: 0
	3: 0
---
name: regression-16
description:
	${var%%expr} seems to be broken in many places.  On the mips
	the commands
		$ read line < /etc/passwd
		$ echo $line
		root:0:1:...
		$ echo ${line%%:*}
		root
		$ echo $line
		root
		$
	change the value of line.  On sun4s & pas, the echo ${line%%:*} doesn't
	work.  Haven't checked elsewhere...
script:
	read x
	y=$x
	echo ${x%%:*}
	echo $x
stdin:
	root:asdjhasdasjhs:0:1:Root:/:/bin/sh
expected-stdout:
	root
	root:asdjhasdasjhs:0:1:Root:/:/bin/sh
---
name: regression-17
description:
	The command
		. /foo/bar
	should set the exit status to non-zero (sh and AT&T ksh88 do).
	XXX doting a non existent file is a fatal error for a script
stdin:
	. does/not/exist
expected-exit: e != 0
expected-stderr-pattern: /.?/
---
name: regression-19
description:
	Both of the following echos should produce the same thing, but don't:
		$ x=foo/bar
		$ echo ${x%/*}
		foo
		$ echo "${x%/*}"
		foo/bar
stdin:
	x=foo/bar
	echo "${x%/*}"
expected-stdout:
	foo
---
name: regression-21
description:
	backslash does not work as expected in case labels:
	$ x='-x'
	$ case $x in
	-\?) echo hi
	esac
	hi
	$ x='-?'
	$ case $x in
	-\\?) echo hi
	esac
	hi
	$
stdin:
	case -x in
	-\?)	echo fail
	esac
---
name: regression-22
description:
	Quoting backquotes inside backquotes doesn't work:
	$ echo `echo hi \`echo there\` folks`
	asks for more info.  sh and AT&T ksh88 both echo
	hi there folks
stdin:
	echo `echo hi \`echo there\` folks`
expected-stdout:
	hi there folks
---
name: regression-23
description:
	)) is not treated `correctly':
	    $ (echo hi ; (echo there ; echo folks))
	    missing ((
	    $
	instead of (as sh and ksh.att)
	    $ (echo hi ; (echo there ; echo folks))
	    hi
	    there
	    folks
	    $
stdin:
	( : ; ( : ; echo hi))
expected-stdout:
	hi
---
name: regression-25
description:
	Check reading stdin in a while loop.  The read should only read
	a single line, not a whole stdio buffer; the cat should get
	the rest.
stdin:
	(echo a; echo b) | while read x ; do
	    echo $x
	    cat > /dev/null
	done
expected-stdout:
	a
---
name: regression-26
description:
	Check reading stdin in a while loop.  The read should read both
	lines, not just the first.
script:
	a=
	while [ "$a" != xxx ] ; do
	    last=$x
	    read x
	    cat /dev/null | sed 's/x/y/'
	    a=x$a
	done
	echo $last
stdin:
	a
	b
expected-stdout:
	b
---
name: regression-27
description:
	The command
		. /does/not/exist
	should cause a script to exit.
stdin:
	. does/not/exist
	echo hi
expected-exit: e != 0
expected-stderr-pattern: /does\/not\/exist/
---
name: regression-28
description:
	variable assignments not detected well
stdin:
	a.x=1 echo hi
expected-exit: e != 0
expected-stderr-pattern: /a\.x=1/
---
name: regression-29
description:
	alias expansion different from AT&T ksh88
stdin:
	alias a='for ' b='i in'
	a b hi ; do echo $i ; done
expected-stdout:
	hi
---
name: regression-30
description:
	strange characters allowed inside ${...}
stdin:
	echo ${a{b}}
expected-exit: e != 0
expected-stderr-pattern: /.?/
---
name: regression-31
description:
	Does read handle partial lines correctly
script:
	a= ret=
	while [ "$a" != xxx ] ; do
	    read x y z
	    ret=$?
	    a=x$a
	done
	echo "[$x]"
	echo $ret
stdin: !
	a A aA
	b B Bb
	c
expected-stdout:
	[c]
	1
---
name: regression-32
description:
	Does read set variables to null at eof?
script:
	a=
	while [ "$a" != xxx ] ; do
	    read x y z
	    a=x$a
	done
	echo 1: ${x-x not set} ${y-y not set} ${z-z not set}
	echo 2: ${x:+x not null} ${y:+y not null} ${z:+z not null}
stdin:
	a A Aa
	b B Bb
expected-stdout:
	1:
	2:
---
name: regression-33
description:
	Does umask print a leading 0 when umask is 3 digits?
stdin:
	# on MiNT, the first umask call seems to fail
	umask 022
	# now, the test proper
	umask 222
	umask
expected-stdout:
	0222
---
name: regression-35
description:
	Temporay files used for here-docs in functions get trashed after
	the function is parsed (before it is executed)
stdin:
	f1() {
		cat <<- EOF
			F1
		EOF
		f2() {
			cat <<- EOF
				F2
			EOF
		}
	}
	f1
	f2
	unset -f f1
	f2
expected-stdout:
	F1
	F2
	F2
---
name: regression-36
description:
	Command substitution breaks reading in while loop
	(test from <sjg@void.zen.oz.au>)
stdin:
	(echo abcdef; echo; echo 123) |
	    while read line
	    do
	      # the following line breaks it
	      c=`echo $line | wc -c`
	      echo $c
	    done
expected-stdout:
	7
	1
	4
---
name: regression-37
description:
	Machines with broken times() (reported by <sjg@void.zen.oz.au>)
	time does not report correct real time
stdin:
	time sleep 1
expected-stderr-pattern: !/^\s*0\.0[\s\d]+real|^\s*real[\s]+0+\.0/
---
name: regression-38
description:
	set -e doesn't ignore exit codes for if/while/until/&&/||/!.
arguments: !-e!
stdin:
	if false; then echo hi ; fi
	false || true
	false && true
	while false; do echo hi; done
	echo ok
expected-stdout:
	ok
---
name: regression-39
description:
	Only posh and oksh(2013-07) say “hi” below; FreeBSD sh,
	GNU bash in POSIX mode, dash, ksh93, mksh don’t. All of
	them exit 0. The POSIX behaviour is needed by BSD make.
stdin:
	set -e
	echo `false; echo hi` $(<this-file-does-not-exist)
	echo $?
expected-stdout:
	
	0
expected-stderr-pattern: /this-file-does-not-exist/
---
name: regression-40
description:
	This used to cause a core dump
env-setup: !RANDOM=12!
stdin:
	echo hi
expected-stdout:
	hi
---
name: regression-41
description:
	foo should be set to bar (should not be empty)
stdin:
	foo=`
	echo bar`
	echo "($foo)"
expected-stdout:
	(bar)
---
name: regression-42
description:
	Can't use command line assignments to assign readonly parameters.
stdin:
	print '#!'"$__progname"'\nunset RANDOM\nexport | while IFS= read -r' \
	    'RANDOM; do eval '\''print -r -- "$RANDOM=$'\''"$RANDOM"'\'\"\'\; \
	    done >env; chmod +x env; PATH=.$PATHSEP$PATH
	foo=bar
	readonly foo
	foo=stuff env | grep '^foo'
expected-exit: e != 0
expected-stderr-pattern:
	/read-only/
---
name: regression-43
description:
	Can subshells be prefixed by redirections (historical shells allow
	this)
stdin:
	< /dev/null (sed 's/^/X/')
---
name: regression-45
description:
	Parameter assignments with [] recognised correctly
stdin:
	FOO=*[12]
	BAR=abc[
	MORE=[abc]
	JUNK=a[bc
	echo "<$FOO>"
	echo "<$BAR>"
	echo "<$MORE>"
	echo "<$JUNK>"
expected-stdout:
	<*[12]>
	<abc[>
	<[abc]>
	<a[bc>
---
name: regression-46
description:
	Check that alias expansion works in command substitutions and
	at the end of file.
stdin:
	alias x='echo hi'
	FOO="`x` "
	echo "[$FOO]"
	x
expected-stdout:
	[hi ]
	hi
---
name: regression-47
description:
	Check that aliases are fully read.
stdin:
	alias x='echo hi;
	echo there'
	x
	echo done
expected-stdout:
	hi
	there
	done
---
name: regression-48
description:
	Check that (here doc) temp files are not left behind after an exec.
stdin:
	mkdir foo || exit 1
	TMPDIR=$PWD/foo "$__progname" <<- 'EOF'
		x() {
			sed 's/^/X /' << E_O_F
			hi
			there
			folks
			E_O_F
			echo "done ($?)"
		}
		echo=echo; [ -x /bin/echo ] && echo=/bin/echo
		exec $echo subtest-1 hi
	EOF
	echo subtest-1 foo/*
	TMPDIR=$PWD/foo "$__progname" <<- 'EOF'
		echo=echo; [ -x /bin/echo ] && echo=/bin/echo
		sed 's/^/X /' << E_O_F; exec $echo subtest-2 hi
		a
		few
		lines
		E_O_F
	EOF
	echo subtest-2 foo/*
expected-stdout:
	subtest-1 hi
	subtest-1 foo/*
	X a
	X few
	X lines
	subtest-2 hi
	subtest-2 foo/*
---
name: regression-49
description:
	Check that unset params with attributes are reported by set, those
	sans attributes are not.
stdin:
	unset FOO BAR
	echo X$FOO
	export BAR
	typeset -i BLAH
	set | grep FOO
	set | grep BAR
	set | grep BLAH
expected-stdout:
	X
	BAR
	BLAH
---
name: regression-50
description:
	Check that aliases do not use continuation prompt after trailing
	semi-colon.
file-setup: file 644 "envf"
	PS1=Y
	PS2=X
env-setup: !ENV=./envf!
need-ctty: yes
arguments: !-i!
stdin:
	alias foo='echo hi ; '
	foo
	foo echo there
expected-stdout:
	hi
	hi
	there
expected-stderr: !
	YYYY
---
name: regression-51
description:
	Check that set allows both +o and -o options on same command line.
stdin:
	set a b c
	set -o noglob +o allexport
	echo A: $*, *
expected-stdout:
	A: a b c, *
---
name: regression-52
description:
	Check that globbing works in pipelined commands
file-setup: file 644 "envf"
	PS1=P
file-setup: file 644 "abc"
	stuff
env-setup: !ENV=./envf!
need-ctty: yes
arguments: !-i!
stdin:
	sed 's/^/X /' < ab*
	echo mark 1
	sed 's/^/X /' < ab* | sed 's/^/Y /'
	echo mark 2
expected-stdout:
	X stuff
	mark 1
	Y X stuff
	mark 2
expected-stderr: !
	PPPPP
---
name: regression-53
description:
	Check that getopts works in functions
stdin:
	bfunc() {
	    echo bfunc: enter "(args: $*; OPTIND=$OPTIND)"
	    while getopts B oc; do
		case $oc in
		  (B)
		    echo bfunc: B option
		    ;;
		  (*)
		    echo bfunc: odd option "($oc)"
		    ;;
		esac
	    done
	    echo bfunc: leave
	}
	
	function kfunc {
	    echo kfunc: enter "(args: $*; OPTIND=$OPTIND)"
	    while getopts K oc; do
		case $oc in
		  (K)
		    echo kfunc: K option
		    ;;
		  (*)
		    echo bfunc: odd option "($oc)"
		    ;;
		esac
	    done
	    echo kfunc: leave
	}
	
	set -- -f -b -k -l
	echo "line 1: OPTIND=$OPTIND"
	getopts kbfl optc
	echo "line 2: ret=$?, optc=$optc, OPTIND=$OPTIND"
	bfunc -BBB blah
	echo "line 3: OPTIND=$OPTIND"
	getopts kbfl optc
	echo "line 4: ret=$?, optc=$optc, OPTIND=$OPTIND"
	kfunc -KKK blah
	echo "line 5: OPTIND=$OPTIND"
	getopts kbfl optc
	echo "line 6: ret=$?, optc=$optc, OPTIND=$OPTIND"
	echo
	
	OPTIND=1
	set -- -fbkl
	echo "line 10: OPTIND=$OPTIND"
	getopts kbfl optc
	echo "line 20: ret=$?, optc=$optc, OPTIND=$OPTIND"
	bfunc -BBB blah
	echo "line 30: OPTIND=$OPTIND"
	getopts kbfl optc
	echo "line 40: ret=$?, optc=$optc, OPTIND=$OPTIND"
	kfunc -KKK blah
	echo "line 50: OPTIND=$OPTIND"
	getopts kbfl optc
	echo "line 60: ret=$?, optc=$optc, OPTIND=$OPTIND"
expected-stdout:
	line 1: OPTIND=1
	line 2: ret=0, optc=f, OPTIND=2
	bfunc: enter (args: -BBB blah; OPTIND=2)
	bfunc: B option
	bfunc: B option
	bfunc: leave
	line 3: OPTIND=2
	line 4: ret=0, optc=b, OPTIND=3
	kfunc: enter (args: -KKK blah; OPTIND=1)
	kfunc: K option
	kfunc: K option
	kfunc: K option
	kfunc: leave
	line 5: OPTIND=3
	line 6: ret=0, optc=k, OPTIND=4
	
	line 10: OPTIND=1
	line 20: ret=0, optc=f, OPTIND=2
	bfunc: enter (args: -BBB blah; OPTIND=2)
	bfunc: B option
	bfunc: B option
	bfunc: leave
	line 30: OPTIND=2
	line 40: ret=1, optc=?, OPTIND=2
	kfunc: enter (args: -KKK blah; OPTIND=1)
	kfunc: K option
	kfunc: K option
	kfunc: K option
	kfunc: leave
	line 50: OPTIND=2
	line 60: ret=1, optc=?, OPTIND=2
---
name: regression-54
description:
	Check that ; is not required before the then in if (( ... )) then ...
stdin:
	if (( 1 )) then
	    echo ok dparen
	fi
	if [[ -n 1 ]] then
	    echo ok dbrackets
	fi
expected-stdout:
	ok dparen
	ok dbrackets
---
name: regression-55
description:
	Check ${foo:%bar} is allowed (ksh88 allows it...)
stdin:
	x=fooXbarXblah
	echo 1 ${x%X*}
	echo 2 ${x:%X*}
	echo 3 ${x%%X*}
	echo 4 ${x:%%X*}
	echo 5 ${x#*X}
	echo 6 ${x:#*X}
	echo 7 ${x##*X}
	echo 8 ${x:##*X}
expected-stdout:
	1 fooXbar
	2 fooXbar
	3 foo
	4 foo
	5 barXblah
	6 barXblah
	7 blah
	8 blah
---
name: regression-57
description:
	Check if typeset output is correct for
	uninitialised array elements.
stdin:
	typeset -i xxx[4]
	echo A
	typeset -i | grep xxx | sed 's/^/    /'
	echo B
	typeset | grep xxx | sed 's/^/    /'
	
	xxx[1]=2+5
	echo M
	typeset -i | grep xxx | sed 's/^/    /'
	echo N
	typeset | grep xxx | sed 's/^/    /'
expected-stdout:
	A
	    xxx
	B
	    typeset -i xxx
	M
	    xxx[1]=7
	N
	    set -A xxx
	    typeset -i xxx[1]
---
name: regression-58
description:
	Check if trap exit is ok (exit not mistaken for signal name)
stdin:
	trap 'echo hi' exit
	trap exit 1
expected-stdout:
	hi
---
name: regression-59
description:
	Check if ${#array[*]} is calculated correctly.
stdin:
	a[12]=hi
	a[8]=there
	echo ${#a[*]}
expected-stdout:
	2
---
name: regression-60
description:
	Check if default exit status is previous command
stdin:
	(true; exit)
	echo A $?
	(false; exit)
	echo B $?
	( (exit 103) ; exit)
	echo C $?
expected-stdout:
	A 0
	B 1
	C 103
---
name: regression-61
description:
	Check if EXIT trap is executed for sub shells.
stdin:
	trap 'echo parent exit' EXIT
	echo start
	(echo A; echo A last)
	echo B
	(echo C; trap 'echo sub exit' EXIT; echo C last)
	echo parent last
expected-stdout:
	start
	A
	A last
	B
	C
	C last
	sub exit
	parent last
	parent exit
---
name: regression-62
description:
	Check if test -nt/-ot succeeds if second(first) file is missing.
stdin:
	matrix() {
		local a b c d e f g h
		test a -nt b; a=$?
		test b -nt a; b=$?
		test a -ot b; c=$?
		test b -ot a; d=$?
		test a -nt a; e=$?
		test b -nt b; f=$?
		test a -ot a; g=$?
		test b -ot b; h=$?
		echo $1 $a $b $c $d / $e $f $g $h .
	}
	matrix a
	:>a
	matrix b
	sleep 2		# mtime granularity for OS/2 and FAT
	:>b
	matrix c
	sleep 2
	echo dummy >a	# Debian GNU/Hurd #955270
	matrix d
	rm a
	matrix e
expected-stdout:
	a 1 1 1 1 / 1 1 1 1 .
	b 0 1 1 0 / 1 1 1 1 .
	c 1 0 0 1 / 1 1 1 1 .
	d 0 1 1 0 / 1 1 1 1 .
	e 1 0 0 1 / 1 1 1 1 .
---
name: regression-63
description:
	Check if typeset, export, and readonly work
stdin:
	{
		echo FNORD-0
		FNORD_A=1
		FNORD_B=2
		FNORD_C=3
		FNORD_D=4
		FNORD_E=5
		FNORD_F=6
		FNORD_G=7
		FNORD_H=8
		integer FNORD_E FNORD_F FNORD_G FNORD_H
		export FNORD_C FNORD_D FNORD_G FNORD_H
		readonly FNORD_B FNORD_D FNORD_F FNORD_H
		echo FNORD-1
		export
		echo FNORD-2
		export -p
		echo FNORD-3
		readonly
		echo FNORD-4
		readonly -p
		echo FNORD-5
		typeset
		echo FNORD-6
		typeset -p
		echo FNORD-7
		typeset -
		echo FNORD-8
	} | fgrep FNORD
	fnord=(42 23)
	typeset -p fnord
	echo FNORD-9
expected-stdout:
	FNORD-0
	FNORD-1
	FNORD_C
	FNORD_D
	FNORD_G
	FNORD_H
	FNORD-2
	export FNORD_C=3
	export FNORD_D=4
	export FNORD_G=7
	export FNORD_H=8
	FNORD-3
	FNORD_B
	FNORD_D
	FNORD_F
	FNORD_H
	FNORD-4
	readonly FNORD_B=2
	readonly FNORD_D=4
	readonly FNORD_F=6
	readonly FNORD_H=8
	FNORD-5
	typeset FNORD_A
	typeset -r FNORD_B
	typeset -x FNORD_C
	typeset -x -r FNORD_D
	typeset -i FNORD_E
	typeset -i -r FNORD_F
	typeset -i -x FNORD_G
	typeset -i -x -r FNORD_H
	FNORD-6
	typeset FNORD_A=1
	typeset -r FNORD_B=2
	typeset -x FNORD_C=3
	typeset -x -r FNORD_D=4
	typeset -i FNORD_E=5
	typeset -i -r FNORD_F=6
	typeset -i -x FNORD_G=7
	typeset -i -x -r FNORD_H=8
	FNORD-7
	FNORD_A=1
	FNORD_B=2
	FNORD_C=3
	FNORD_D=4
	FNORD_E=5
	FNORD_F=6
	FNORD_G=7
	FNORD_H=8
	FNORD-8
	set -A fnord
	typeset fnord[0]=42
	typeset fnord[1]=23
	FNORD-9
---
name: regression-64
description:
	Check that we can redefine functions calling time builtin
stdin:
	t() {
		time >/dev/null
	}
	t 2>/dev/null
	t() {
		time
	}
---
name: regression-65
description:
	check for a regression with sleep builtin and signal mask
category: !nojsig
time-limit: 5
stdin:
	sleep 1
	echo blub |&
	while read -p line; do :; done
	echo ok
expected-stdout:
	ok
---
name: regression-66
description:
	Check that quoting is sane
category: !nojsig
stdin:
	ac_space=' '
	ac_newline='
	'
	set | grep ^ac_ |&
	set -A lines
	while IFS= read -pr line; do
		if [[ $line = *space* ]]; then
			lines[0]=$line
		else
			lines[1]=$line
		fi
	done
	for line in "${lines[@]}"; do
		print -r -- "$line"
	done
expected-stdout:
	ac_space=' '
	ac_newline=$'\n'
---
name: regression-67
description:
	Check that we can both break and use source on the same line
stdin:
	for s in s; do break; done; print -s s
---
name: regression-68
description:
	Check that all common arithmetic operators work as expected
stdin:
	echo 1 $(( a = 5 )) .
	echo 2 $(( ++a )) , $(( a++ )) , $(( a )) .
	echo 3 $(( --a )) , $(( a-- )) , $(( a )) .
	echo 4 $(( a == 5 )) , $(( a == 6 )) .
	echo 5 $(( a != 5 )) , $(( a != 6 )) .
	echo 6 $(( a *= 3 )) .
	echo 7 $(( a /= 5 )) .
	echo 8 $(( a %= 2 )) .
	echo 9 $(( a += 9 )) .
	echo 10 $(( a -= 4 )) .
	echo 11 $(( a <<= 1 )) .
	echo 12 $(( a >>= 1 )) .
	echo 13 $(( a &= 4 )) .
	echo 14 $(( a ^= a )) .
	echo 15 $(( a |= 5 )) .
	echo 16 $(( 5 << 1 )) .
	echo 17 $(( 5 >> 1 )) .
	echo 18 $(( 5 <= 6 )) , $(( 5 <= 5 )) , $(( 5 <= 4 )) .
	echo 19 $(( 5 >= 6 )) , $(( 5 >= 5 )) , $(( 5 >= 4 )) .
	echo 20 $(( 5 < 6 )) , $(( 5 < 5 )) , $(( 5 < 4 )) .
	echo 21 $(( 5 > 6 )) , $(( 5 > 5 )) , $(( 5 > 4 )) .
	echo 22 $(( 0 && 0 )) , $(( 0 && 1 )) , $(( 1 && 0 )) , $(( 1 && 1 )) .
	echo 23 $(( 0 || 0 )) , $(( 0 || 1 )) , $(( 1 || 0 )) , $(( 1 || 1 )) .
	echo 24 $(( 5 * 3 )) .
	echo 25 $(( 7 / 2 )) .
	echo 26 $(( 5 % 5 )) , $(( 5 % 4 )) , $(( 5 % 1 )) , $(( 5 % -1 )) , $(( 5 % -2 )) .
	echo 27 $(( 5 + 2 )) , $(( 5 + 0 )) , $(( 5 + -2 )) .
	echo 28 $(( 5 - 2 )) , $(( 5 - 0 )) , $(( 5 - -2 )) .
	echo 29 $(( 6 & 4 )) , $(( 6 & 8 )) .
	echo 30 $(( 4 ^ 2 )) , $(( 4 ^ 4 )) .
	echo 31 $(( 4 | 2 )) , $(( 4 | 4 )) , $(( 4 | 0 )) .
	echo 32 $(( 0 ? 1 : 2 )) , $(( 3 ? 4 : 5 )) .
	echo 33 $(( 5 , 2 , 3 )) .
	echo 34 $(( ~0 )) , $(( ~1 )) , $(( ~~1 )) , $(( ~~2 )) .
	echo 35 $(( !0 )) , $(( !1 )) , $(( !!1 )) , $(( !!2 )) .
	echo 36 $(( (5) )) .
expected-stdout:
	1 5 .
	2 6 , 6 , 7 .
	3 6 , 6 , 5 .
	4 1 , 0 .
	5 0 , 1 .
	6 15 .
	7 3 .
	8 1 .
	9 10 .
	10 6 .
	11 12 .
	12 6 .
	13 4 .
	14 0 .
	15 5 .
	16 10 .
	17 2 .
	18 1 , 1 , 0 .
	19 0 , 1 , 1 .
	20 1 , 0 , 0 .
	21 0 , 0 , 1 .
	22 0 , 0 , 0 , 1 .
	23 0 , 1 , 1 , 1 .
	24 15 .
	25 3 .
	26 0 , 1 , 0 , 0 , 1 .
	27 7 , 5 , 3 .
	28 3 , 5 , 7 .
	29 4 , 0 .
	30 6 , 0 .
	31 6 , 4 , 4 .
	32 2 , 4 .
	33 3 .
	34 -1 , -2 , 1 , 2 .
	35 1 , 0 , 1 , 1 .
	36 5 .
---
name: regression-69
description:
	Check that all non-lksh arithmetic operators work as expected
category: shell:legacy-no
stdin:
	a=5 b=0x80000005
	echo 1 $(( a ^<= 1 )) , $(( b ^<= 1 )) .
	echo 2 $(( a ^>= 2 )) , $(( b ^>= 2 )) .
	echo 3 $(( 5 ^< 1 )) .
	echo 4 $(( 5 ^> 1 )) .
expected-stdout:
	1 10 , 11 .
	2 -2147483646 , -1073741822 .
	3 10 .
	4 -2147483646 .
---
name: export-1
description:
	Check allexport works, basic
stdin:
	qa=1
	set -A qb 2 3
	set -a
	qc=4
	set -A qd 5 6
	export -p | grep '^export q'
expected-stdout:
	export qc=4
	export qd[0]=5
	export qd[1]=6
---
name: readonly-0
description:
	Ensure readonly is honoured for assignments and unset
stdin:
	"$__progname" -c 'u=x; echo $? $u .' || echo aborted, $?
	echo =
	"$__progname" -c 'readonly u; u=x; echo $? $u .' || echo aborted, $?
	echo =
	"$__progname" -c 'u=x; readonly u; unset u; echo $? $u .' || echo aborted, $?
expected-stdout:
	0 x .
	=
	aborted, 2
	=
	1 x .
expected-stderr-pattern:
	/read-only/
---
name: readonly-1
description:
	http://austingroupbugs.net/view.php?id=367 for export
stdin:
	"$__progname" -c 'readonly foo; export foo=a; echo $?' || echo aborted, $?
expected-stdout:
	aborted, 2
expected-stderr-pattern:
	/read-only/
---
name: readonly-2a
description:
	Check that getopts works as intended, for readonly-2b to be valid
stdin:
	"$__progname" -c 'set -- -a b; getopts a c; echo $? $c .; getopts a c; echo $? $c .' || echo aborted, $?
expected-stdout:
	0 a .
	1 ? .
---
name: readonly-2b
description:
	http://austingroupbugs.net/view.php?id=367 for getopts
stdin:
	"$__progname" -c 'readonly c; set -- -a b; getopts a c; echo $? $c .' || echo aborted, $?
expected-stdout:
	2 .
expected-stderr-pattern:
	/read-only/
---
name: readonly-3
description:
	http://austingroupbugs.net/view.php?id=367 for read
stdin:
	echo x | "$__progname" -c 'read s; echo $? $s .' || echo aborted, $?
	echo y | "$__progname" -c 'readonly s; read s; echo $? $s .' || echo aborted, $?
expected-stdout:
	0 x .
	2 .
expected-stderr-pattern:
	/read-only/
---
name: readonly-4
description:
	Do not permit bypassing readonly for first array item
stdin:
	set -A arr -- foo bar
	readonly arr
	arr=baz
	print -r -- "${arr[@]}"
expected-exit: e != 0
expected-stderr-pattern:
	/read[ -]?only/
---
name: readonly-5
description:
	Ensure readonly is idempotent
stdin:
	readonly x=1
	readonly x
---
name: syntax-1
description:
	Check that lone ampersand is a syntax error
stdin:
	 &
expected-exit: e != 0
expected-stderr-pattern:
	/syntax error/
---
name: xxx-quoted-newline-1
description:
	Check that \<newline> works inside of ${}
stdin:
	abc=2
	echo ${ab\
	c}
expected-stdout:
	2
---
name: xxx-quoted-newline-2
description:
	Check that \<newline> works at the start of a here document
stdin:
	cat << EO\
	F
	hi
	EOF
expected-stdout:
	hi
---
name: xxx-quoted-newline-3
description:
	Check that \<newline> works at the end of a here document
stdin:
	cat << EOF
	hi
	EO\
	F
expected-stdout:
	hi
---
name: xxx-multi-assignment-cmd
description:
	Check that assignments in a command affect subsequent assignments
	in the same command
stdin:
	FOO=abc
	FOO=123 BAR=$FOO
	echo $BAR
expected-stdout:
	123
---
name: xxx-multi-assignment-posix-cmd
description:
	Check that the behaviour for multiple assignments with a
	command name matches POSIX. See:
	http://thread.gmane.org/gmane.comp.standards.posix.austin.general/1925
stdin:
	X=a Y=b; X=$Y Y=$X "$__progname" -c 'echo 1 $X $Y .'; echo 2 $X $Y .
	unset X Y Z
	X=a Y=${X=b} Z=$X "$__progname" -c 'echo 3 $Z .'
	unset X Y Z
	X=a Y=${X=b} Z=$X; echo 4 $Z .
expected-stdout:
	1 b a .
	2 a b .
	3 b .
	4 a .
---
name: xxx-multi-assignment-posix-nocmd
description:
	Check that the behaviour for multiple assignments with no
	command name matches POSIX (Debian #334182). See:
	http://thread.gmane.org/gmane.comp.standards.posix.austin.general/1925
stdin:
	X=a Y=b; X=$Y Y=$X; echo 1 $X $Y .
expected-stdout:
	1 b b .
---
name: xxx-multi-assignment-posix-subassign
description:
	Check that the behaviour for multiple assignments matches POSIX:
	- The assignment words shall be expanded in the current execution
	  environment.
	- The assignments happen in the temporary execution environment.
stdin:
	unset X Y Z
	Z=a Y=${X:=b} sh -c 'echo +$X+ +$Y+ +$Z+'
	echo /$X/
	# Now for the special case:
	unset X Y Z
	X= Y=${X:=b} sh -c 'echo +$X+ +$Y+'
	echo /$X/
expected-stdout:
	++ +b+ +a+
	/b/
	++ +b+
	/b/
---
name: xxx-exec-environment-1
description:
	Check to see if exec sets it's environment correctly
stdin:
	print '#!'"$__progname"'\nunset RANDOM\nexport | while IFS= read -r' \
	    'RANDOM; do eval '\''print -r -- "$RANDOM=$'\''"$RANDOM"'\'\"\'\; \
	    done >env; chmod +x env; PATH=.$PATHSEP$PATH
	FOO=bar exec env
expected-stdout-pattern:
	/(^|.*\n)FOO=bar\n/
---
name: xxx-exec-environment-2
description:
	Check to make sure exec doesn't change environment if a program
	isn't exec-ed
stdin:
	print '#!'"$__progname"'\nunset RANDOM\nexport | while IFS= read -r' \
	    'RANDOM; do eval '\''print -r -- "$RANDOM=$'\''"$RANDOM"'\'\"\'\; \
	    done >env; chmod +x env; PATH=.$PATHSEP$PATH
	env >bar1
	FOO=bar exec; env >bar2
	cmp -s bar1 bar2
---
name: exec-function-environment-1
description:
	Check assignments in function calls and whether they affect
	the current execution environment
stdin:
	f() { a=2; }; g() { b=3; echo y$c-; }; a=1 f; b=2; c=1 g
	echo x$a-$b- z$c-
expected-stdout:
	y1-
	x-3- z-
---
name: exec-modern-korn-shell
description:
	Check that exec can execute any command that makes it
	through syntax and parser
stdin:
	print '#!'"$__progname"'\necho tf' >lq
	chmod +x lq
	PATH=$PWD
	exec 2>&1
	foo() { print two; }
	print =1
	(exec print one)
	print =2
	(exec foo)
	print =3
	(exec ls)
	print =4
	(exec lq)
expected-stdout-pattern:
	/=1\none\n=2\ntwo\n=3\n.*: ls: inaccessible or not found\n=4\ntf\n/
---
name: exec-ksh88
description:
	Check that exec only executes after a PATH search
arguments: !-o!posix!
stdin:
	print '#!'"$__progname"'\necho tf' >lq
	chmod +x lq
	PATH=$PWD
	exec 2>&1
	foo() { print two; }
	print =1
	(exec print one)
	print =2
	(exec foo)
	print =3
	(exec ls)
	print =4
	(exec lq)
expected-stdout-pattern:
	/=1\n.*: print: inaccessible or not found\n=2\n.*: foo: inaccessible or not found\n=3\n.*: ls: inaccessible or not found\n=4\ntf\n/
---
name: xxx-what-do-you-call-this-1
stdin:
	echo "${foo:-"a"}*"
expected-stdout:
	a*
---
name: xxx-prefix-strip-1
stdin:
	foo='a cdef'
	echo ${foo#a c}
expected-stdout:
	def
---
name: xxx-prefix-strip-2
stdin:
	set a c
	x='a cdef'
	echo ${x#$*}
expected-stdout:
	def
---
name: xxx-variable-syntax-1
stdin:
	echo ${:}
expected-stderr-pattern:
	/bad substitution/
expected-exit: 1
---
name: xxx-variable-syntax-2
stdin:
	set 0
	echo ${*:0}
expected-stderr-pattern:
	/bad substitution/
expected-exit: 1
---
name: xxx-variable-syntax-3
stdin:
	set -A foo 0
	echo ${foo[*]:0}
expected-stderr-pattern:
	/bad substitution/
expected-exit: 1
---
name: xxx-variable-syntax-4
description:
	Not all kinds of trims are currently impossible, check those who do
stdin:
	foo() {
		echo "<$*> X${*:+ }X"
	}
	foo a b
	foo "" c
	foo ""
	foo "" ""
	IFS=:
	foo a b
	foo "" c
	foo ""
	foo "" ""
	IFS=
	foo a b
	foo "" c
	foo ""
	foo "" ""
expected-stdout:
	<a b> X X
	< c> X X
	<> XX
	< > X X
	<a:b> X X
	<:c> X X
	<> XX
	<:> X X
	<ab> X X
	<c> X X
	<> XX
	<> XX
---
name: xxx-substitution-eval-order
description:
	Check order of evaluation of expressions
stdin:
	i=1 x= y=
	set -A A abc def GHI j G k
	echo ${A[x=(i+=1)]#${A[y=(i+=2)]}}
	echo $x $y
expected-stdout:
	HI
	2 4
---
name: xxx-substitution-eval-order-2
description:
	Check some corner cases
stdin:
	unset var
	i=42
	: ${var+${q[i=777]}} required to be lazy by POSIX
	echo 1=$i
	var=meow
	i=42
	: ${var+${q[i=777]}} eval since var is now set
	echo 2=$i
	unset var
	i=42
	: ${var#${q[i=777]}} pattern is needed even if var is empty
	echo 3=$i
	var=meow
	i=42
	: ${var#${q[i=777]}}
	echo 4=$i
expected-stdout:
	1=42
	2=777
	3=777
	4=777
---
name: xxx-set-option-1
description:
	Check option parsing in set
stdin:
	set -vsA foo -- A 1 3 2
	echo ${foo[*]}
expected-stderr:
	echo ${foo[*]}
expected-stdout:
	1 2 3 A
---
name: xxx-exec-1
description:
	Check that exec exits for built-ins
need-ctty: yes
arguments: !-i!
stdin:
	exec echo hi
	echo still herre
expected-stdout:
	hi
expected-stderr-pattern: /.*/
---
name: xxx-while-1
description:
	Check the return value of while loops
	XXX need to do same for for/select/until loops
stdin:
	i=x
	while [ $i != xxx ] ; do
	    i=x$i
	    if [ $i = xxx ] ; then
		false
		continue
	    fi
	done
	echo loop1=$?
	
	i=x
	while [ $i != xxx ] ; do
	    i=x$i
	    if [ $i = xxx ] ; then
		false
		break
	    fi
	done
	echo loop2=$?
	
	i=x
	while [ $i != xxx ] ; do
	    i=x$i
	    false
	done
	echo loop3=$?
expected-stdout:
	loop1=0
	loop2=0
	loop3=1
---
name: xxx-status-1
description:
	Check that blank lines don't clear $?
need-ctty: yes
arguments: !-i!
stdin:
	(exit 1)
	echo $?
	(exit 1)
	
	echo $?
	true
expected-stdout:
	1
	1
expected-stderr-pattern: /.*/
---
name: xxx-status-2
description:
	Check that $? is preserved in subshells, includes, traps.
stdin:
	(exit 1)
	
	echo blank: $?
	
	(exit 2)
	(echo subshell: $?)
	
	echo 'echo include: $?' > foo
	(exit 3)
	. ./foo
	
	trap 'echo trap: $?' ERR
	(exit 4)
	echo exit: $?
expected-stdout:
	blank: 1
	subshell: 2
	include: 3
	trap: 4
	exit: 4
---
name: xxx-stat-1
description:
	Check that tests on files are consistent
	(fails when run as root, unfortunately)
category: disabled
stdin:
	mkdir a
	echo x >a/b
	test -e a/b; echo 1e $? .
	test -f a/b; echo 1f $? .
	chmod 0 a
	test -e a/b; echo 2e $? .
	test -f a/b; echo 2f $? .
	chmod 700 a
	test -e a/b; echo 3e $? .
	test -f a/b; echo 3f $? .
expected-stdout:
	1e 0 .
	1f 0 .
	2e 1 .
	2f 1 .
	3e 0 .
	3f 0 .
---
name: xxx-clean-chars-1
description:
	Check MAGIC character is stuffed correctly
stdin:
	echo `echo [`
expected-stdout:
	[
---
name: xxx-param-subst-qmark-1
description:
	Check suppresion of error message with null string.  According to
	POSIX, it shouldn't print the error as 'word' isn't omitted.
	ksh88/93, Solaris /bin/sh and /usr/xpg4/bin/sh all print the error.
stdin:
	unset foo
	x=
	echo x${foo?$x}
expected-exit: 1
expected-stderr-pattern: !/not set/
---
name: xxx-param-subst-qmark-namespec
description:
	Check special names are output correctly
stdin:
	doit() {
		"$__progname" -c "$@" >o1 2>o2
		rv=$?
		echo RETVAL: $rv
		sed -e "s^${__progname%.exe}\.*e*x*e*: PROG: " -e 's/^/STDOUT: /g' <o1
		sed -e "s^${__progname%.exe}\.*e*x*e*: PROG: " -e 's/^/STDERR: /g' <o2
	}
	doit 'echo ${1x}'
	doit 'echo "${1x}"'
	doit 'echo ${1?}'
	doit 'echo ${19?}'
	doit 'echo ${!:?}'
	doit -u 'echo ${*:?}' foo ""
expected-stdout:
	RETVAL: 1
	STDERR: PROG: ${1x}: bad substitution
	RETVAL: 1
	STDERR: PROG: ${1x}: bad substitution
	RETVAL: 1
	STDERR: PROG: 1: parameter null or not set
	RETVAL: 1
	STDERR: PROG: 19: parameter null or not set
	RETVAL: 1
	STDERR: PROG: !: parameter null or not set
	RETVAL: 1
	STDERR: foo: ${*:?}: bad substitution
---
name: xxx-param-_-1
# fails due to weirdness of execv stuff
category: !os:uwin-nt
description:
	Check c flag is set.
arguments: !-c!echo "[$-]"!
expected-stdout-pattern: /^\[.*c.*\]$/
---
name: tilde-expand-1
description:
	Check tilde expansion after equal signs
env-setup: !HOME=/sweet!
stdin:
	echo ${A=a=}~ b=~ c=d~ ~
	export e=~ f=d~
	command command export g=~ h=d~
	echo ". $e . $f ."
	echo ". $g . $h ."
	set -o posix
	unset A e f g h
	echo ${A=a=}~ b=~ c=d~ ~
	export e=~ f=d~
	command command export g=~ h=d~
	echo ". $e . $f ."
	echo ". $g . $h ."
expected-stdout:
	a=/sweet b=/sweet c=d~ /sweet
	. /sweet . d~ .
	. /sweet . d~ .
	a=~ b=~ c=d~ /sweet
	. /sweet . d~ .
	. /sweet . d~ .
---
name: tilde-expand-2
description:
	Check tilde expansion works
env-setup: !HOME=/sweet!
stdin:
	:>'c=a'
	typeset c=[ab]
	:>'d=a'
	x=typeset; $x d=[ab]
	echo "<$c>" "<$d>"
	wd=$PWD
	cd /
	plus=$(print -r -- ~+)
	minus=$(print -r -- ~-)
	nix=$(print -r -- ~)
	[[ $plus = / ]]; echo one $? .
	[[ $minus = "$wd" ]]; echo two $? .
	[[ $nix = /sweet ]]; echo nix $? .
expected-stdout:
	<[ab]> <a>
	one 0 .
	two 0 .
	nix 0 .
---
name: tilde-expand-3
description:
	Check mostly Austin 351 stuff
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	set "1 b=2" "3 d=4"
	export a=$1 \c=$2
	showargs 1 "$a" "$b" "$c" "$d"
	unset a b c d
	HOME=/tmp
	export \a=~ b=~
	command export c=~
	builtin export d=~
	\\builtin export e=~
	showargs 2 "$a" "$b" "$c" "$d" "$e" ksh
	unset a b c d e
	set -o posix
	export \a=~ b=~
	command export c=~
	builtin export d=~
	\\builtin export e=~
	showargs 3 "$a" "$b" "$c" "$d" "$e" posix
	unset a b c d e
	set +o posix
	export a=$1
	showargs 4 "$a" "$b" ksh
	unset a b
	showargs 5 a=$1 ksh
	export \a=$1
	showargs 6 "$a" "$b" ksh
	unset a b
	set -o posix
	export a=$1
	showargs 7 "$a" "$b" posix
	unset a b
	showargs 8 a=$1 posix
	export \a=$1
	showargs 9 "$a" "$b" posix
	unset a b
	set +o posix
	command echo 10 ksh a=~
	command command export a=~
	showargs 11 "$a"
	unset a
	set -o posix
	command echo 12 posix a=~
	command command export a=~
	showargs 13 "$a"
	unset a
	# unspecified whether /tmp or ~
	var=export; command $var a=~
	showargs 14 "$a"
	echo 'echo "<$foo>"' >bar
	"$__progname" bar
	var=foo
	export $var=1
	"$__progname" bar
	export $var=~
	"$__progname" bar
	# unspecified
	command -- export a=~
	showargs 18 "$a"
	set -A bla
	typeset bla[1]=~:~
	typeset -g gbl=~ g2=$1
	local lcl=~ l2=$1
	readonly ro=~ r2=$1
	showargs 19 "${bla[1]}" a=~ "$gbl" "$lcl" "$ro" "$g2" "$l2" "$r2"
	set +o posix
	echo "20 some arbitrary stuff "=~
	set -o posix
	echo "21 some arbitrary stuff "=~
expected-stdout:
	<1> <1 b=2> <> <3> <4> .
	<2> </tmp> </tmp> </tmp> </tmp> </tmp> <ksh> .
	<3> <~> </tmp> </tmp> <~> </tmp> <posix> .
	<4> <1 b=2> <> <ksh> .
	<5> <a=1> <b=2> <ksh> .
	<6> <1> <2> <ksh> .
	<7> <1 b=2> <> <posix> .
	<8> <a=1> <b=2> <posix> .
	<9> <1> <2> <posix> .
	10 ksh a=/tmp
	<11> </tmp> .
	12 posix a=~
	<13> </tmp> .
	<14> <~> .
	<>
	<1>
	<~>
	<18> <~> .
	<19> </tmp:/tmp> <a=~> </tmp> </tmp> </tmp> <1 b=2> <1 b=2> <1 b=2> .
	20 some arbitrary stuff =/tmp
	21 some arbitrary stuff =~
---
name: exit-err-1
description:
	Check some "exit on error" conditions
stdin:
	print '#!'"$__progname"'\nexec "$1"' >env
	print '#!'"$__progname"'\nexit 1' >false
	chmod +x env false
	PATH=.$PATHSEP$PATH
	set -ex
	env false && echo something
	echo END
expected-stdout:
	END
expected-stderr:
	+ env false
	+ echo END
---
name: exit-err-2
description:
	Check some "exit on error" edge conditions (POSIXly)
stdin:
	print '#!'"$__progname"'\nexec "$1"' >env
	print '#!'"$__progname"'\nexit 1' >false
	print '#!'"$__progname"'\nexit 0' >true
	chmod +x env false
	PATH=.$PATHSEP$PATH
	set -ex
	if env true; then
		env false && echo something
	fi
	echo END
expected-stdout:
	END
expected-stderr:
	+ env true
	+ env false
	+ echo END
---
name: exit-err-3
description:
	pdksh regression which AT&T ksh does right
	TFM says: [set] -e | errexit
		Exit (after executing the ERR trap) ...
stdin:
	trap 'echo EXIT' EXIT
	trap 'echo ERR' ERR
	set -e
	cd /XXXXX 2>/dev/null
	echo DONE
	exit 0
expected-stdout:
	ERR
	EXIT
expected-exit: e != 0
---
name: exit-err-4
description:
	"set -e" test suite (POSIX)
stdin:
	set -e
	echo pre
	if true ; then
		false && echo foo
	fi
	echo bar
expected-stdout:
	pre
	bar
---
name: exit-err-5
description:
	"set -e" test suite (POSIX)
stdin:
	set -e
	foo() {
		while [ "$1" ]; do
			for E in $x; do
				[ "$1" = "$E" ] && { shift ; continue 2 ; }
			done
			x="$x $1"
			shift
		done
		echo $x
	}
	echo pre
	foo a b b c
	echo post
expected-stdout:
	pre
	a b c
	post
---
name: exit-err-6
description:
	"set -e" test suite (BSD make)
category: os:mirbsd
stdin:
	mkdir zd zd/a zd/b
	print 'all:\n\t@echo eins\n\t@exit 42\n' >zd/a/Makefile
	print 'all:\n\t@echo zwei\n' >zd/b/Makefile
	wd=$(pwd)
	set -e
	for entry in a b; do (  set -e;  if [[ -d $wd/zd/$entry.i386 ]]; then  _newdir_="$entry.i386";  else  _newdir_="$entry";  fi;  if [[ -z $_THISDIR_ ]]; then  _nextdir_="$_newdir_";  else  _nextdir_="$_THISDIR_/$_newdir_";  fi;  _makefile_spec_=;  [[ ! -f $wd/zd/$_newdir_/Makefile.bsd-wrapper ]]  || _makefile_spec_="-f Makefile.bsd-wrapper";  subskipdir=;  for skipdir in ; do  subentry=${skipdir#$entry};  if [[ $subentry != $skipdir ]]; then  if [[ -z $subentry ]]; then  echo "($_nextdir_ skipped)";  break;  fi;  subskipdir="$subskipdir ${subentry#/}";  fi;  done;  if [[ -z $skipdir || -n $subentry ]]; then  echo "===> $_nextdir_";  cd $wd/zd/$_newdir_;  make SKIPDIR="$subskipdir" $_makefile_spec_  _THISDIR_="$_nextdir_"   all;  fi;  ) done 2>&1 | sed "s!$wd!WD!g"
expected-stdout:
	===> a
	eins
	*** Error code 42
	
	Stop in WD/zd/a (line 2 of Makefile).
---
name: exit-err-7
description:
	"set -e" regression (LP#1104543)
stdin:
	set -e
	bla() {
		[ -x $PWD/nonexistant ] && $PWD/nonexistant
	}
	echo x
	bla
	echo y$?
expected-stdout:
	x
expected-exit: 1
---
name: exit-err-8
description:
	"set -e" regression (Debian #700526)
stdin:
	set -e
	_db_cmd() { return $1; }
	db_input() { _db_cmd 30; }
	db_go() { _db_cmd 0; }
	db_input || :
	db_go
	exit 0
---
name: exit-err-9
description:
	"set -e" versus bang pipelines
stdin:
	set -e
	! false | false
	echo 1 ok
	! false && false
	echo 2 wrong
expected-stdout:
	1 ok
expected-exit: 1
---
name: exit-err-10
description:
	Debian #269067 (cf. regression-38 but with eval)
arguments: !-e!
stdin:
	eval false || true
	echo = $? .
expected-stdout:
	= 0 .
---
name: exit-err-11
description:
	Fix -e inside eval, from Martijn Dekker; expected-stdout from ksh93
stdin:
	"$__progname" -c 'eval '\''echo ${-//[!eh]}; false; echo phantom e'\''; echo x$?'
	echo = $?
	"$__progname" -ec 'eval '\''echo ${-//[!eh]}; false; echo phantom e'\''; echo x$?'
	echo = $?
expected-stdout:
	h
	phantom e
	x0
	= 0
	eh
	= 1
---
name: exit-enoent-1
description:
	SUSv4 says that the shell should exit with 126/127 in some situations
stdin:
	i=0
	(echo; echo :) >x
	"$__progname" ./x >/dev/null 2>&1; r=$?; echo $((i++)) $r .
	"$__progname" -c ./x >/dev/null 2>&1; r=$?; echo $((i++)) $r .
	echo exit 42 >x
	"$__progname" ./x >/dev/null 2>&1; r=$?; echo $((i++)) $r .
	"$__progname" -c ./x >/dev/null 2>&1; r=$?; echo $((i++)) $r .
	rm -f x
	"$__progname" ./x >/dev/null 2>&1; r=$?; echo $((i++)) $r .
	"$__progname" -c ./x >/dev/null 2>&1; r=$?; echo $((i++)) $r .
expected-stdout:
	0 0 .
	1 126 .
	2 42 .
	3 126 .
	4 127 .
	5 127 .
---
name: exit-eval-1
description:
	Check eval vs substitution exit codes (ksh93 alike)
stdin:
	(exit 12)
	eval $(false)
	echo A $?
	(exit 12)
	eval ' $(false)'
	echo B $?
	(exit 12)
	eval " $(false)"
	echo C $?
	(exit 12)
	eval "eval $(false)"
	echo D $?
	(exit 12)
	eval 'eval '"$(false)"
	echo E $?
	IFS="$IFS:"
	(exit 12)
	eval $(echo :; false)
	echo F $?
	echo -n "G "
	(exit 12)
	eval 'echo $?'
	echo H $?
expected-stdout:
	A 0
	B 1
	C 0
	D 0
	E 0
	F 0
	G 12
	H 0
---
name: exit-trap-1
description:
	Check that "exit" with no arguments behaves SUSv4 conformant.
stdin:
	trap 'echo hi; exit' EXIT
	exit 9
expected-stdout:
	hi
expected-exit: 9
---
name: exit-trap-2
description:
	Check that ERR and EXIT traps are run just like GNU bash does.
	ksh93 runs ERtrap after “parameter null or not set” (which mksh
	used to do) but (bug) continues “and out”, exit 0, in +e eval-undef.
file-setup: file 644 "x"
	v=; unset v
	trap 'echo EXtrap' EXIT
	trap 'echo ERtrap' ERR
	set $1
	echo "and run $2"
	eval $2
	echo and out
file-setup: file 644 "xt"
	v=; unset v
	trap 'echo EXtrap' EXIT
	trap 'echo ERtrap' ERR
	set $1
	echo 'and run true'
	true
	echo and out
file-setup: file 644 "xf"
	v=; unset v
	trap 'echo EXtrap' EXIT
	trap 'echo ERtrap' ERR
	set $1
	echo 'and run false'
	false
	echo and out
file-setup: file 644 "xu"
	v=; unset v
	trap 'echo EXtrap' EXIT
	trap 'echo ERtrap' ERR
	set $1
	echo 'and run ${v?}'
	${v?}
	echo and out
stdin:
	runtest() {
		rm -f rc
		(
			"$__progname" "$@"
			echo $? >rc
		) 2>&1 | sed \
		    -e 's/parameter not set/parameter null or not set/' \
		    -e 's/[[]6]//' -e 's/: eval: line 1//' -e 's/: line 6//' \
		    -e "s^${__progname%.exe}\.*e*x*e*: <stdin>\[[0-9]*]PROG"
	}
	xe=-e
	echo : $xe
	runtest x $xe true
	echo = eval-true $(<rc) .
	runtest x $xe false
	echo = eval-false $(<rc) .
	runtest x $xe '${v?}'
	echo = eval-undef $(<rc) .
	runtest xt $xe
	echo = noeval-true $(<rc) .
	runtest xf $xe
	echo = noeval-false $(<rc) .
	runtest xu $xe
	echo = noeval-undef $(<rc) .
	xe=+e
	echo : $xe
	runtest x $xe true
	echo = eval-true $(<rc) .
	runtest x $xe false
	echo = eval-false $(<rc) .
	runtest x $xe '${v?}'
	echo = eval-undef $(<rc) .
	runtest xt $xe
	echo = noeval-true $(<rc) .
	runtest xf $xe
	echo = noeval-false $(<rc) .
	runtest xu $xe
	echo = noeval-undef $(<rc) .
expected-stdout:
	: -e
	and run true
	and out
	EXtrap
	= eval-true 0 .
	and run false
	ERtrap
	EXtrap
	= eval-false 1 .
	and run ${v?}
	x: v: parameter null or not set
	EXtrap
	= eval-undef 1 .
	and run true
	and out
	EXtrap
	= noeval-true 0 .
	and run false
	ERtrap
	EXtrap
	= noeval-false 1 .
	and run ${v?}
	xu: v: parameter null or not set
	EXtrap
	= noeval-undef 1 .
	: +e
	and run true
	and out
	EXtrap
	= eval-true 0 .
	and run false
	ERtrap
	ERtrap
	and out
	EXtrap
	= eval-false 0 .
	and run ${v?}
	x: v: parameter null or not set
	EXtrap
	= eval-undef 1 .
	and run true
	and out
	EXtrap
	= noeval-true 0 .
	and run false
	ERtrap
	and out
	EXtrap
	= noeval-false 0 .
	and run ${v?}
	xu: v: parameter null or not set
	EXtrap
	= noeval-undef 1 .
---
name: exit-trap-3
description:
	Check that the EXIT trap is run in many places, Debian #910276
stdin:
	fkt() {
		trap -- "echo $1 >&2" EXIT
	}
	fkt shell_exit
	$(fkt fn_exit)
	$(trap -- "echo comsub_exit >&2" EXIT)
	(trap -- "echo subshell_exit >&2" EXIT)
expected-stderr:
	fn_exit
	comsub_exit
	subshell_exit
	shell_exit
---
name: exit-trap-interactive
description:
	Check that interactive shell doesn't exit via EXIT trap on syntax error
arguments: !-i!
stdin:
	trap -- EXIT
	echo Syntax error <
	echo 'After error 1'
	trap 'echo Exit trap' EXIT
	echo Syntax error <
	echo 'After error 2'
	trap 'echo Exit trap' EXIT
	exit
	echo 'After exit'
expected-stdout:
	After error 1
	After error 2
	Exit trap
expected-stderr-pattern:
	/syntax error: unexpected 'newline'/
---
name: test-stlt-1
description:
	Check that test also can handle string1 < string2 etc.
stdin:
	test 2005/10/08 '<' 2005/08/21 && echo ja || echo nein
	test 2005/08/21 \< 2005/10/08 && echo ja || echo nein
	test 2005/10/08 '>' 2005/08/21 && echo ja || echo nein
	test 2005/08/21 \> 2005/10/08 && echo ja || echo nein
expected-stdout:
	nein
	ja
	ja
	nein
expected-stderr-pattern: !/unexpected op/
---
name: test-str-pattern
description:
	Check that [[ x = $y ]] can take extglobs, like ksh93
stdin:
	[[ -n $BASH_VERSION ]] && shopt -s extglob
	function one {
		n=$1 x=$2 y=$3 z=${4:-$3}
		[[ $x = $y ]]; a=$?
		[[ $x = "$y" ]]; b=$?
		eval '[[ $x = '"$z"' ]]; c=$?'
		eval '[[ $x = "'"$z"'" ]]; d=$?'
		echo $n $a $b $c $d .
	}
	x='a\'
	[[ $x = a\  ]]; echo 01 $? .
	[[ $x = a\\ ]]; echo 02 $? .
	one 03 'a\'	'a\'	'a\\'
	one 04 'a\b'	'a\b'
	one 05 'a\b'	'a\\b'
	one 06 'foo'	'f+(o)'
	one 07 'f+(o)'	'f+(o)'
	one 08 'f+(o'	'f+(o'	'f+\(o'
	one 09 foo	'f+(o'	'f+\(o'
	one 10 abcde	'a\*e'
	one 11 'a*e'	'a\*e'
	one 12 'a\*e'	'a\*e'
	echo extras:
	x='f+(o'
	z='f+(o'
	eval '[[ $x = "'"$z"'" ]]; echo 14 $? "(08:4)" .'
	x=foo
	eval '[[ $x = "'"$z"'" ]]; echo 15 $? "(09:4)" .'
expected-stdout:
	01 1 .
	02 0 .
	03 0 0 0 0 .
	04 1 0 1 0 .
	05 0 1 0 0 .
	06 0 1 0 1 .
	07 1 0 1 0 .
	08 0 0 0 1 .
	09 1 1 1 1 .
	10 1 1 1 1 .
	11 0 1 0 1 .
	12 1 0 1 0 .
	extras:
	14 0 (08:4) .
	15 1 (09:4) .
---
name: test-precedence-1
description:
	Check a weird precedence case (and POSIX echo)
stdin:
	test \( -f = -f \)
	rv=$?
	echo $rv
expected-stdout:
	0
---
name: test-option-1
description:
	Test the test -o operator
stdin:
	runtest() {
		test -o $1; echo $?
		[ -o $1 ]; echo $?
		[[ -o $1 ]]; echo $?
	}
	if_test() {
		test -o $1 -o -o !$1; echo $?
		[ -o $1 -o -o !$1 ]; echo $?
		[[ -o $1 || -o !$1 ]]; echo $?
		test -o ?$1; echo $?
	}
	echo 0y $(if_test utf8-mode) =
	echo 0n $(if_test utf8-hack) =
	echo 1= $(runtest utf8-hack) =
	echo 2= $(runtest !utf8-hack) =
	echo 3= $(runtest ?utf8-hack) =
	set +U
	echo 1+ $(runtest utf8-mode) =
	echo 2+ $(runtest !utf8-mode) =
	echo 3+ $(runtest ?utf8-mode) =
	set -U
	echo 1- $(runtest utf8-mode) =
	echo 2- $(runtest !utf8-mode) =
	echo 3- $(runtest ?utf8-mode) =
	echo = short flags =
	echo 0y $(if_test -U) =
	echo 0y $(if_test +U) =
	echo 0n $(if_test -_) =
	echo 0n $(if_test -U-) =
	echo 1= $(runtest -_) =
	echo 2= $(runtest !-_) =
	echo 3= $(runtest ?-_) =
	set +U
	echo 1+ $(runtest -U) =
	echo 2+ $(runtest !-U) =
	echo 3+ $(runtest ?-U) =
	echo 1+ $(runtest +U) =
	echo 2+ $(runtest !+U) =
	echo 3+ $(runtest ?+U) =
	set -U
	echo 1- $(runtest -U) =
	echo 2- $(runtest !-U) =
	echo 3- $(runtest ?-U) =
	echo 1- $(runtest +U) =
	echo 2- $(runtest !+U) =
	echo 3- $(runtest ?+U) =
expected-stdout:
	0y 0 0 0 0 =
	0n 1 1 1 1 =
	1= 1 1 1 =
	2= 1 1 1 =
	3= 1 1 1 =
	1+ 1 1 1 =
	2+ 0 0 0 =
	3+ 0 0 0 =
	1- 0 0 0 =
	2- 1 1 1 =
	3- 0 0 0 =
	= short flags =
	0y 0 0 0 0 =
	0y 0 0 0 0 =
	0n 1 1 1 1 =
	0n 1 1 1 1 =
	1= 1 1 1 =
	2= 1 1 1 =
	3= 1 1 1 =
	1+ 1 1 1 =
	2+ 0 0 0 =
	3+ 0 0 0 =
	1+ 1 1 1 =
	2+ 0 0 0 =
	3+ 0 0 0 =
	1- 0 0 0 =
	2- 1 1 1 =
	3- 0 0 0 =
	1- 0 0 0 =
	2- 1 1 1 =
	3- 0 0 0 =
---
name: test-varset-1
description:
	Test the test -v operator
stdin:
	[[ -v a ]]
	rv=$?; echo $((++i)) $rv
	a=
	[[ -v a ]]
	rv=$?; echo $((++i)) $rv
	unset a
	[[ -v a ]]
	rv=$?; echo $((++i)) $rv
	a=x
	[[ -v a ]]
	rv=$?; echo $((++i)) $rv
	nameref b=a
	[[ -v b ]]
	rv=$?; echo $((++i)) $rv
	unset a
	[[ -v b ]]
	rv=$?; echo $((++i)) $rv
	x[1]=y
	[[ -v x ]]
	rv=$?; echo $((++i)) $rv
	[[ -v x[0] ]]
	rv=$?; echo $((++i)) $rv
	[[ -v x[1] ]]
	rv=$?; echo $((++i)) $rv
	[[ -v x[2] ]]
	rv=$?; echo $((++i)) $rv
expected-stdout:
	1 1
	2 0
	3 1
	4 0
	5 0
	6 1
	7 1
	8 1
	9 0
	10 1
---
name: test-varset-2
description:
	test -v works only on scalars
stdin:
	[[ -v x[*] ]]
	echo ok
expected-exit: e != 0
expected-stderr-pattern:
	/unexpected '\*'/
---
name: test-stnze-1
description:
	Check that the short form [ $x ] works
stdin:
	i=0
	[ -n $x ]
	rv=$?; echo $((++i)) $rv
	[ $x ]
	rv=$?; echo $((++i)) $rv
	[ -n "$x" ]
	rv=$?; echo $((++i)) $rv
	[ "$x" ]
	rv=$?; echo $((++i)) $rv
	x=0
	[ -n $x ]
	rv=$?; echo $((++i)) $rv
	[ $x ]
	rv=$?; echo $((++i)) $rv
	[ -n "$x" ]
	rv=$?; echo $((++i)) $rv
	[ "$x" ]
	rv=$?; echo $((++i)) $rv
	x='1 -a 1 = 2'
	[ -n $x ]
	rv=$?; echo $((++i)) $rv
	[ $x ]
	rv=$?; echo $((++i)) $rv
	[ -n "$x" ]
	rv=$?; echo $((++i)) $rv
	[ "$x" ]
	rv=$?; echo $((++i)) $rv
expected-stdout:
	1 0
	2 1
	3 1
	4 1
	5 0
	6 0
	7 0
	8 0
	9 1
	10 1
	11 0
	12 0
---
name: test-stnze-2
description:
	Check that the short form [[ $x ]] works (ksh93 extension)
stdin:
	i=0
	[[ -n $x ]]
	rv=$?; echo $((++i)) $rv
	[[ $x ]]
	rv=$?; echo $((++i)) $rv
	[[ -n "$x" ]]
	rv=$?; echo $((++i)) $rv
	[[ "$x" ]]
	rv=$?; echo $((++i)) $rv
	x=0
	[[ -n $x ]]
	rv=$?; echo $((++i)) $rv
	[[ $x ]]
	rv=$?; echo $((++i)) $rv
	[[ -n "$x" ]]
	rv=$?; echo $((++i)) $rv
	[[ "$x" ]]
	rv=$?; echo $((++i)) $rv
	x='1 -a 1 = 2'
	[[ -n $x ]]
	rv=$?; echo $((++i)) $rv
	[[ $x ]]
	rv=$?; echo $((++i)) $rv
	[[ -n "$x" ]]
	rv=$?; echo $((++i)) $rv
	[[ "$x" ]]
	rv=$?; echo $((++i)) $rv
expected-stdout:
	1 1
	2 1
	3 1
	4 1
	5 0
	6 0
	7 0
	8 0
	9 0
	10 0
	11 0
	12 0
---
name: test-numeq
description:
	Check numeric -eq works (R40d regression); spotted by Martijn Dekker
stdin:
	tst() {
		eval "$2"
		case $? in
		(0) echo yepp 0 \#"$*" ;;
		(1) echo nope 1 \#"$*" ;;
		(2) echo terr 2 \#"$*" ;;
		(*) echo wtf\? $? \#"$*" ;;
		esac
	}
	tst 1 'test 2 -eq 2'
	tst 2 'test 2 -eq 2a'
	tst 3 'test 2 -eq 3'
	tst 4 'test 2 -ne 2'
	tst 5 'test 2 -ne 2a'
	tst 6 'test 2 -ne 3'
	tst 7 'test \! 2 -eq 2'
	tst 8 'test \! 2 -eq 2a'
	tst 9 'test \! 2 -eq 3'
expected-stdout:
	yepp 0 #1 test 2 -eq 2
	terr 2 #2 test 2 -eq 2a
	nope 1 #3 test 2 -eq 3
	nope 1 #4 test 2 -ne 2
	terr 2 #5 test 2 -ne 2a
	yepp 0 #6 test 2 -ne 3
	nope 1 #7 test \! 2 -eq 2
	terr 2 #8 test \! 2 -eq 2a
	yepp 0 #9 test \! 2 -eq 3
expected-stderr-pattern:
	/bad number/
---
name: mkshrc-1
description:
	Check that ~/.mkshrc works correctly.
	Part 1: verify user environment is not read (internal)
stdin:
	echo x $FNORD
expected-stdout:
	x
---
name: mkshrc-2a
description:
	Check that ~/.mkshrc works correctly.
	Part 2: verify mkshrc is not read (non-interactive shells)
file-setup: file 644 ".mkshrc"
	FNORD=42
env-setup: !HOME=.!ENV=!
stdin:
	echo x $FNORD
expected-stdout:
	x
---
name: mkshrc-2b
description:
	Check that ~/.mkshrc works correctly.
	Part 2: verify mkshrc can be read (interactive shells)
file-setup: file 644 ".mkshrc"
	FNORD=42
need-ctty: yes
arguments: !-i!
env-setup: !HOME=.!ENV=!PS1=!
stdin:
	echo x $FNORD
expected-stdout:
	x 42
expected-stderr-pattern:
	/(# )*/
---
name: mkshrc-3
description:
	Check that ~/.mkshrc works correctly.
	Part 3: verify mkshrc can be turned off
file-setup: file 644 ".mkshrc"
	FNORD=42
env-setup: !HOME=.!ENV=nonexistant!
stdin:
	echo x $FNORD
expected-stdout:
	x
---
name: sh-mode-1
description:
	Check that sh mode turns braceexpand off
	and that that works correctly
stdin:
	set -o braceexpand
	set +o sh
	[[ -o sh ]] && echo sh
	[[ -o !sh ]] && echo nosh
	[[ -o braceexpand ]] && echo brex
	[[ -o !braceexpand ]] && echo nobrex
	echo {a,b,c}
	set +o braceexpand
	echo {a,b,c}
	set -o braceexpand
	echo {a,b,c}
	set -o sh
	echo {a,b,c}
	[[ -o sh ]] && echo sh
	[[ -o !sh ]] && echo nosh
	[[ -o braceexpand ]] && echo brex
	[[ -o !braceexpand ]] && echo nobrex
	set -o braceexpand
	echo {a,b,c}
	[[ -o sh ]] && echo sh
	[[ -o !sh ]] && echo nosh
	[[ -o braceexpand ]] && echo brex
	[[ -o !braceexpand ]] && echo nobrex
	[[ $(exec -a -set "$__progname" -o) = *login+(' ')on* ]]; echo $?
expected-stdout:
	nosh
	brex
	a b c
	{a,b,c}
	a b c
	{a,b,c}
	sh
	nobrex
	a b c
	sh
	brex
	0
---
name: sh-mode-2a
description:
	Check that posix or sh mode is *not* automatically turned on
category: !binsh
stdin:
	for shell in {,-}{,r}{,k,mk}sh {,-}{,R}{,K,MK}SH.EXE; do
		ln -s "$__progname" ./$shell || cp "$__progname" ./$shell
		print -- $shell $(./$shell +l -c '
			[[ -o sh || -o posix ]] && echo sh
			[[ -o !sh && -o !posix ]] && echo nosh
			[[ -o restricted ]] && echo lim || echo ok
		    ')
	done
expected-stdout:
	sh nosh ok
	ksh nosh ok
	mksh nosh ok
	rsh nosh lim
	rksh nosh lim
	rmksh nosh lim
	-sh nosh ok
	-ksh nosh ok
	-mksh nosh ok
	-rsh nosh lim
	-rksh nosh lim
	-rmksh nosh lim
	SH.EXE nosh ok
	KSH.EXE nosh ok
	MKSH.EXE nosh ok
	RSH.EXE nosh lim
	RKSH.EXE nosh lim
	RMKSH.EXE nosh lim
	-SH.EXE nosh ok
	-KSH.EXE nosh ok
	-MKSH.EXE nosh ok
	-RSH.EXE nosh lim
	-RKSH.EXE nosh lim
	-RMKSH.EXE nosh lim
---
name: sh-mode-2b
description:
	Check that posix or sh mode *is* automatically turned on
category: binsh
stdin:
	for shell in {,-}{,r}{,k,mk}sh {,-}{,R}{,K,MK}SH.EXE; do
		ln -s "$__progname" ./$shell || cp "$__progname" ./$shell
		print -- $shell $(./$shell +l -c '
			[[ -o sh || -o posix ]] && echo sh
			[[ -o !sh && -o !posix ]] && echo nosh
			[[ -o restricted ]] && echo lim || echo ok
		    ')
	done
expected-stdout:
	sh sh ok
	ksh nosh ok
	mksh nosh ok
	rsh sh lim
	rksh nosh lim
	rmksh nosh lim
	-sh sh ok
	-ksh nosh ok
	-mksh nosh ok
	-rsh sh lim
	-rksh nosh lim
	-rmksh nosh lim
	SH.EXE sh ok
	KSH.EXE nosh ok
	MKSH.EXE nosh ok
	RSH.EXE sh lim
	RKSH.EXE nosh lim
	RMKSH.EXE nosh lim
	-SH.EXE sh ok
	-KSH.EXE nosh ok
	-MKSH.EXE nosh ok
	-RSH.EXE sh lim
	-RKSH.EXE nosh lim
	-RMKSH.EXE nosh lim
---
name: sh-options
description:
	Check that "set +o" DTRT per POSIX
stdin:
	t() {
		[[ -o vi ]]; a=$?
		[[ -o pipefail ]]; b=$?
		echo $((++i)) $a $b .
	}
	set -e
	set -o vi
	set +o pipefail
	set +e
	t
	x=$(set +o)
	set +o vi
	set -o pipefail
	t
	eval "$x"
	t
expected-stdout:
	1 0 1 .
	2 1 0 .
	3 0 1 .
---
name: pipeline-1
description:
	pdksh bug: last command of a pipeline is executed in a
	subshell - make sure it still is, scripts depend on it
file-setup: file 644 "abcx"
file-setup: file 644 "abcy"
stdin:
	echo *
	echo a | while read d; do
		echo $d
		echo $d*
		echo *
		set -o noglob
		echo $d*
		echo *
	done
	echo *
expected-stdout:
	abcx abcy
	a
	abcx abcy
	abcx abcy
	a*
	*
	abcx abcy
---
name: pipeline-2
description:
	check that co-processes work with TCOMs, TPIPEs and TPARENs
category: !nojsig
stdin:
	"$__progname" -c 'i=100; echo hi |& while read -p line; do echo "$((i++)) $line"; done'
	"$__progname" -c 'i=200; echo hi | cat |& while read -p line; do echo "$((i++)) $line"; done'
	"$__progname" -c 'i=300; (echo hi | cat) |& while read -p line; do echo "$((i++)) $line"; done'
expected-stdout:
	100 hi
	200 hi
	300 hi
---
name: pipeline-3
description:
	Check that PIPESTATUS does what it's supposed to
stdin:
	echo 1 $PIPESTATUS .
	echo 2 ${PIPESTATUS[0]} .
	echo 3 ${PIPESTATUS[1]} .
	(echo x; exit 12) | (cat; exit 23) | (cat; exit 42)
	echo 5 $? , $PIPESTATUS , ${PIPESTATUS[0]} , ${PIPESTATUS[1]} , ${PIPESTATUS[2]} , ${PIPESTATUS[3]} .
	echo 6 ${PIPESTATUS[0]} .
	set | fgrep PIPESTATUS
	echo 8 $(set | fgrep PIPESTATUS) .
expected-stdout:
	1 0 .
	2 0 .
	3 .
	x
	5 42 , 12 , 12 , 23 , 42 , .
	6 0 .
	PIPESTATUS[0]=0
	8 PIPESTATUS[0]=0 PIPESTATUS[1]=0 .
---
name: pipeline-4
description:
	Check that "set -o pipefail" does what it's supposed to
stdin:
	echo 1 "$("$__progname" -c '(exit 12) | (exit 23) | (exit 42); echo $?')" .
	echo 2 "$("$__progname" -c '! (exit 12) | (exit 23) | (exit 42); echo $?')" .
	echo 3 "$("$__progname" -o pipefail -c '(exit 12) | (exit 23) | (exit 42); echo $?')" .
	echo 4 "$("$__progname" -o pipefail -c '! (exit 12) | (exit 23) | (exit 42); echo $?')" .
	echo 5 "$("$__progname" -c '(exit 23) | (exit 42) | :; echo $?')" .
	echo 6 "$("$__progname" -c '! (exit 23) | (exit 42) | :; echo $?')" .
	echo 7 "$("$__progname" -o pipefail -c '(exit 23) | (exit 42) | :; echo $?')" .
	echo 8 "$("$__progname" -o pipefail -c '! (exit 23) | (exit 42) | :; echo $?')" .
	echo 9 "$("$__progname" -o pipefail -c 'x=$( (exit 23) | (exit 42) | :); echo $?')" .
expected-stdout:
	1 42 .
	2 0 .
	3 42 .
	4 0 .
	5 0 .
	6 1 .
	7 42 .
	8 0 .
	9 42 .
---
name: persist-history-1
description:
	Check if persistent history saving works
category: !no-histfile
need-ctty: yes
arguments: !-i!
env-setup: !ENV=./Env!HISTFILE=hist.file!
file-setup: file 644 "Env"
	PS1=X
stdin:
	cat hist.file
expected-stdout-pattern:
	/cat hist.file/
expected-stderr-pattern:
	/^X*$/
---
name: typeset-1
description:
	Check that typeset -g works correctly
stdin:
	set -A arrfoo 65
	foo() {
		typeset -g -Uui16 arrfoo[*]
	}
	echo before ${arrfoo[0]} .
	foo
	echo after ${arrfoo[0]} .
	set -A arrbar 65
	bar() {
		echo inside before ${arrbar[0]} .
		arrbar[0]=97
		echo inside changed ${arrbar[0]} .
		typeset -g -Uui16 arrbar[*]
		echo inside typeset ${arrbar[0]} .
		arrbar[0]=48
		echo inside changed ${arrbar[0]} .
	}
	echo before ${arrbar[0]} .
	bar
	echo after ${arrbar[0]} .
expected-stdout:
	before 65 .
	after 16#41 .
	before 65 .
	inside before 65 .
	inside changed 97 .
	inside typeset 16#61 .
	inside changed 16#30 .
	after 16#30 .
---
name: typeset-2
description:
	Check that typeset -p on arrays works correctly
stdin:
	set -A x -- a b c
	echo =
	typeset -p x
	echo =
	typeset -p x[1]
expected-stdout:
	=
	set -A x
	typeset x[0]=a
	typeset x[1]=b
	typeset x[2]=c
	=
	typeset x[1]=b
---
name: typeset-padding-1
description:
	Check if left/right justification works as per TFM
stdin:
	typeset -L10 ln=0hall0
	typeset -R10 rn=0hall0
	typeset -ZL10 lz=0hall0
	typeset -ZR10 rz=0hall0
	typeset -Z10 rx=" hallo "
	echo "<$ln> <$rn> <$lz> <$rz> <$rx>"
expected-stdout:
	<0hall0    > <    0hall0> <hall0     > <00000hall0> <0000 hallo>
---
name: typeset-padding-2
description:
	Check if base-!10 integers are padded right
stdin:
	typeset -Uui16 -L9 ln=16#1
	typeset -Uui16 -R9 rn=16#1
	typeset -Uui16 -Z9 zn=16#1
	typeset -L9 ls=16#1
	typeset -R9 rs=16#1
	typeset -Z9 zs=16#1
	echo "<$ln> <$rn> <$zn> <$ls> <$rs> <$zs>"
expected-stdout:
	<16#1     > <     16#1> <16#000001> <16#1     > <     16#1> <0000016#1>
---
name: typeset-padding-3
description:
	Check for a regression in which UTF-8 wasn’t left-padded right
stdin:
	set -U
	nl=$'\n'
	typeset -L20 x='.  ak'
	typeset -R20 y='.  ak'
	print -r -- "<$x> (1$nl<12345678910 345678920$nl<$y> 1)"
	typeset -L20 x='.  aẞ'
	typeset -R20 y='.  aẞ'
	print -r -- "<$x> (2$nl<12345678910 345678920$nl<$y> 2)"
expected-stdout:
	<.  ak               > (1
	<12345678910 345678920
	<               .  ak> 1)
	<.  aẞ               > (2
	<12345678910 345678920
	<               .  aẞ> 2)
---
name: utf8bom-1
description:
	Check that the UTF-8 Byte Order Mark is ignored as the first
	multibyte character of the shell input (with -c, from standard
	input, as file, or as eval argument), but nowhere else
# breaks on Mac OSX (HFS+ non-standard UTF-8 canonical decomposition)
category: !os:darwin,!shell:ebcdic-yes
stdin:
	mkdir foo
	print '#!/bin/sh\necho ohne' >foo/fnord
	print '#!/bin/sh\necho mit' >foo/﻿fnord
	print '﻿fnord\nfnord\n﻿fnord\nfnord' >foo/bar
	print eval \''﻿fnord\nfnord\n﻿fnord\nfnord'\' >foo/zoo
	set -A anzahl -- foo/*
	echo got ${#anzahl[*]} files
	chmod +x foo/*
	export PATH=$(pwd)/foo$PATHSEP$PATH
	"$__progname" -c '﻿fnord'
	echo =
	"$__progname" -c '﻿fnord; fnord; ﻿fnord; fnord'
	echo =
	"$__progname" foo/bar
	echo =
	"$__progname" <foo/bar
	echo =
	"$__progname" foo/zoo
	echo =
	"$__progname" -c 'echo ﻿: $(﻿fnord)'
	rm -rf foo
expected-stdout:
	got 4 files
	ohne
	=
	ohne
	ohne
	mit
	ohne
	=
	ohne
	ohne
	mit
	ohne
	=
	ohne
	ohne
	mit
	ohne
	=
	ohne
	ohne
	mit
	ohne
	=
	﻿: ohne
---
name: utf8bom-2
description:
	Check that we can execute BOM-shebangs (failures not fatal)
	XXX if the OS can already execute them, we lose
	note: cygwin execve(2) doesn't return to us with ENOEXEC, we lose
	note: Ultrix perl5 t4 returns 65280 (exit-code 255) and no text
	note: A/UX perl5 returns 6400 (exit-code 25), passes #1-3
	XXX fails when LD_PRELOAD is set with -e and Perl chokes it (ASan)
need-pass: no
category: !os:aux,!os:cygwin,!os:midipix,!os:msys,!os:ultrix,!os:uwin-nt,!smksh
env-setup: !FOO=BAR!
stdin:
	print '#!'"$__progname"'\nprint "1 a=$ENV{FOO}";' >t1
	print '﻿#!'"$__progname"'\nprint "2 a=$ENV{FOO}";' >t2
	print '#!'"$__perlname"'\nprint "3 a=$ENV{FOO}\n";' >t3
	print '﻿#!'"$__perlname"'\nprint "4 a=$ENV{FOO}\n";' >t4
	chmod +x t?
	./t1
	./t2
	./t3
	./t4
expected-stdout:
	1 a=/nonexistant{FOO}
	2 a=/nonexistant{FOO}
	3 a=BAR
	4 a=BAR
expected-stderr-pattern:
	/(Unrecognized character .... ignored at \..t4 line 1)*/
---
name: utf8opt-1
description:
	Check that the utf8-mode flag is not set at non-interactive startup
env-setup: !PS1=!PS2=!LC_CTYPE=@utflocale@!
stdin:
	if [[ $- = *U* ]]; then
		echo is set
	else
		echo is not set
	fi
expected-stdout:
	is not set
---
name: utf8opt-2
description:
	Check that the utf8-mode flag is set at interactive startup.
	If your OS is old, try passing HAVE_SETLOCALE_CTYPE=0 to Build.sh
need-pass: no
category: !noutf8
need-ctty: yes
arguments: !-i!
env-setup: !PS1=!PS2=!LC_CTYPE=@utflocale@!
stdin:
	if [[ $- = *U* ]]; then
		echo is set
	else
		echo is not set
	fi
expected-stdout:
	is set
expected-stderr-pattern:
	/(# )*/
---
name: utf8opt-3a
description:
	Ensure ±U on the command line is honoured
	(these two tests may pass falsely depending on CPPFLAGS)
stdin:
	export i=0
	code='if [[ $- = *U* ]]; then echo $i on; else echo $i off; fi'
	let i++; "$__progname" -U -c "$code"
	let i++; "$__progname" +U -c "$code"
	echo $((++i)) done
expected-stdout:
	1 on
	2 off
	3 done
---
name: utf8opt-3b
description:
	Ensure ±U on the command line is honoured, interactive shells
need-ctty: yes
stdin:
	export i=0
	code='if [[ $- = *U* ]]; then echo $i on; else echo $i off; fi'
	let i++; "$__progname" -U -ic "$code"
	let i++; "$__progname" +U -ic "$code"
	echo $((++i)) done
expected-stdout:
	1 on
	2 off
	3 done
---
name: utf8bug-1
description:
	Ensure trailing combining characters are not lost
stdin:
	set -U
	a=a
	b=$'\u0301'
	x=$a$b
	print -r -- "<e$x>"
	x=$a
	x+=$b
	print -r -- "<e$x>"
	b=$'\u0301'b
	x=$a
	x+=$b
	print -r -- "<e$x>"
expected-stdout:
	<eá>
	<eá>
	<eáb>
---
name: aliases-1
description:
	Check if built-in shell aliases are okay
stdin:
	alias
	typeset -f
expected-stdout:
	autoload='\\builtin typeset -fu'
	functions='\\builtin typeset -f'
	hash='\\builtin alias -t'
	history='\\builtin fc -l'
	integer='\\builtin typeset -i'
	local='\\builtin typeset'
	login='\\builtin exec login'
	nameref='\\builtin typeset -n'
	nohup='nohup '
	r='\\builtin fc -e -'
	type='\\builtin whence -v'
---
name: aliases-2b
description:
	Check if “set -o sh” does not influence built-in aliases
arguments: !-o!sh!
stdin:
	alias
	typeset -f
expected-stdout:
	autoload='\\builtin typeset -fu'
	functions='\\builtin typeset -f'
	hash='\\builtin alias -t'
	history='\\builtin fc -l'
	integer='\\builtin typeset -i'
	local='\\builtin typeset'
	login='\\builtin exec login'
	nameref='\\builtin typeset -n'
	nohup='nohup '
	r='\\builtin fc -e -'
	type='\\builtin whence -v'
---
name: aliases-3b
description:
	Check if running as sh does not influence built-in aliases
stdin:
	cp "$__progname" sh
	./sh -c 'alias; typeset -f'
	rm -f sh
expected-stdout:
	autoload='\\builtin typeset -fu'
	functions='\\builtin typeset -f'
	hash='\\builtin alias -t'
	history='\\builtin fc -l'
	integer='\\builtin typeset -i'
	local='\\builtin typeset'
	login='\\builtin exec login'
	nameref='\\builtin typeset -n'
	nohup='nohup '
	r='\\builtin fc -e -'
	type='\\builtin whence -v'
---
name: aliases-cmdline
description:
	Check that aliases work from the command line (Debian #517009)
	Note that due to the nature of the lexing process, defining
	aliases in COMSUBs then immediately using them, and things
	like 'alias foo=bar && foo', still fail.
stdin:
	"$__progname" -c $'alias a="echo OK"\na'
expected-stdout:
	OK
---
name: aliases-funcdef-1
description:
	Check if POSIX functions take precedences over aliases
stdin:
	alias foo='echo makro'
	foo() {
		echo funktion
	}
	foo
expected-stdout:
	makro
---
name: aliases-funcdef-2
description:
	Check if POSIX functions take precedences over aliases
stdin:
	alias foo='echo makro'
	foo () {
		echo funktion
	}
	foo
expected-stdout:
	makro
---
name: aliases-funcdef-3
description:
	Check if aliases take precedences over Korn functions
stdin:
	alias foo='echo makro'
	function foo {
		echo funktion
	}
	foo
expected-stdout:
	makro
---
name: aliases-funcdef-4
description:
	Functions should only take over if actually being defined
stdin:
	alias local
	:|| local() { :; }
	alias local
expected-stdout:
	local='\\builtin typeset'
	local='\\builtin typeset'
---
name: arrays-1
description:
	Check if Korn Shell arrays work as expected
stdin:
	v="c d"
	set -A foo -- a \$v "$v" '$v' b
	echo "${#foo[*]}|${foo[0]}|${foo[1]}|${foo[2]}|${foo[3]}|${foo[4]}|"
expected-stdout:
	5|a|$v|c d|$v|b|
---
name: arrays-2a
description:
	Check if bash-style arrays work as expected
stdin:
	v="c d"
	foo=(a \$v "$v" '$v' b)
	echo "${#foo[*]}|${foo[0]}|${foo[1]}|${foo[2]}|${foo[3]}|${foo[4]}|"
expected-stdout:
	5|a|$v|c d|$v|b|
---
name: arrays-2b
description:
	Check if bash-style arrays work as expected, with newlines
stdin:
	print '#!'"$__progname"'\nfor x in "$@"; do print -nr -- "$x|"; done' >pfp
	chmod +x pfp
	test -n "$ZSH_VERSION" && setopt KSH_ARRAYS
	v="e f"
	foo=(a
		bc
		d \$v "$v" '$v' g
	)
	./pfp "${#foo[*]}" "${foo[0]}" "${foo[1]}" "${foo[2]}" "${foo[3]}" "${foo[4]}" "${foo[5]}" "${foo[6]}"; echo
	foo=(a\
		bc
		d \$v "$v" '$v' g
	)
	./pfp "${#foo[*]}" "${foo[0]}" "${foo[1]}" "${foo[2]}" "${foo[3]}" "${foo[4]}" "${foo[5]}" "${foo[6]}"; echo
	foo=(a\
	bc\\
		d \$v "$v" '$v'
	g)
	./pfp "${#foo[*]}" "${foo[0]}" "${foo[1]}" "${foo[2]}" "${foo[3]}" "${foo[4]}" "${foo[5]}" "${foo[6]}"; echo
expected-stdout:
	7|a|bc|d|$v|e f|$v|g|
	7|a|bc|d|$v|e f|$v|g|
	6|abc\|d|$v|e f|$v|g||
---
name: arrays-3
description:
	Check if array bounds are uint32_t
stdin:
	set -A foo a b c
	foo[4097]=d
	foo[2147483637]=e
	echo ${foo[*]}
	foo[-1]=f
	echo ${foo[4294967295]} g ${foo[*]}
expected-stdout:
	a b c d e
	f g a b c d e f
---
name: arrays-4
description:
	Check if Korn Shell arrays with specified indices work as expected
stdin:
	v="c d"
	set -A foo -- [1]=\$v [2]="$v" [4]='$v' [0]=a [5]=b
	echo "${#foo[*]}|${foo[0]}|${foo[1]}|${foo[2]}|${foo[3]}|${foo[4]}|${foo[5]}|"
	# we don't want this at all:
	#	5|a|$v|c d||$v|b|
	set -A arr "[5]=meh"
	echo "<${arr[0]}><${arr[5]}>"
expected-stdout:
	5|[1]=$v|[2]=c d|[4]=$v|[0]=a|[5]=b||
	<[5]=meh><>
---
name: arrays-5
description:
	Check if bash-style arrays with specified indices work as expected
	(taken out temporarily to fix arrays-4; see also arrays-9a comment)
category: disabled
stdin:
	v="c d"
	foo=([1]=\$v [2]="$v" [4]='$v' [0]=a [5]=b)
	echo "${#foo[*]}|${foo[0]}|${foo[1]}|${foo[2]}|${foo[3]}|${foo[4]}|${foo[5]}|"
	x=([128]=foo bar baz)
	echo k= ${!x[*]} .
	echo v= ${x[*]} .
	# Check that we do not break this by globbing
	:>b=blah
	bleh=5
	typeset -a arr
	arr+=([bleh]=blah)
	echo "<${arr[0]}><${arr[5]}>"
expected-stdout:
	5|a|$v|c d||$v|b|
	k= 128 129 130 .
	v= foo bar baz .
	<><blah>
---
name: arrays-6
description:
	Check if we can get the array keys (indices) for indexed arrays,
	Korn shell style
stdin:
	of() {
		i=0
		for x in "$@"; do
			echo -n "$((i++))<$x>"
		done
		echo
	}
	foo[1]=eins
	set | grep '^foo'
	echo =
	foo[0]=zwei
	foo[4]=drei
	set | grep '^foo'
	echo =
	echo a $(of ${foo[*]}) = $(of ${bar[*]}) a
	echo b $(of "${foo[*]}") = $(of "${bar[*]}") b
	echo c $(of ${foo[@]}) = $(of ${bar[@]}) c
	echo d $(of "${foo[@]}") = $(of "${bar[@]}") d
	echo e $(of ${!foo[*]}) = $(of ${!bar[*]}) e
	echo f $(of "${!foo[*]}") = $(of "${!bar[*]}") f
	echo g $(of ${!foo[@]}) = $(of ${!bar[@]}) g
	echo h $(of "${!foo[@]}") = $(of "${!bar[@]}") h
expected-stdout:
	foo[1]=eins
	=
	foo[0]=zwei
	foo[1]=eins
	foo[4]=drei
	=
	a 0<zwei>1<eins>2<drei> = a
	b 0<zwei eins drei> = 0<> b
	c 0<zwei>1<eins>2<drei> = c
	d 0<zwei>1<eins>2<drei> = d
	e 0<0>1<1>2<4> = e
	f 0<0 1 4> = 0<> f
	g 0<0>1<1>2<4> = g
	h 0<0>1<1>2<4> = h
---
name: arrays-7
description:
	Check if we can get the array keys (indices) for indexed arrays,
	Korn shell style, in some corner cases
stdin:
	echo !arz: ${!arz}
	echo !arz[0]: ${!arz[0]}
	echo !arz[1]: ${!arz[1]}
	arz=foo
	echo !arz: ${!arz}
	echo !arz[0]: ${!arz[0]}
	echo !arz[1]: ${!arz[1]}
	unset arz
	echo !arz: ${!arz}
	echo !arz[0]: ${!arz[0]}
	echo !arz[1]: ${!arz[1]}
expected-stdout:
	!arz: arz
	!arz[0]: arz[0]
	!arz[1]: arz[1]
	!arz: arz
	!arz[0]: arz[0]
	!arz[1]: arz[1]
	!arz: arz
	!arz[0]: arz[0]
	!arz[1]: arz[1]
---
name: arrays-8
description:
	Check some behavioural rules for arrays.
stdin:
	fna() {
		set -A aa 9
	}
	fnb() {
		typeset ab
		set -A ab 9
	}
	fnc() {
		typeset ac
		set -A ac 91
		unset ac
		set -A ac 92
	}
	fnd() {
		set +A ad 9
	}
	fne() {
		unset ae
		set +A ae 9
	}
	fnf() {
		unset af[0]
		set +A af 9
	}
	fng() {
		unset ag[*]
		set +A ag 9
	}
	set -A aa 1 2
	set -A ab 1 2
	set -A ac 1 2
	set -A ad 1 2
	set -A ae 1 2
	set -A af 1 2
	set -A ag 1 2
	set -A ah 1 2
	typeset -Z3 aa ab ac ad ae af ag
	print 1a ${aa[*]} .
	print 1b ${ab[*]} .
	print 1c ${ac[*]} .
	print 1d ${ad[*]} .
	print 1e ${ae[*]} .
	print 1f ${af[*]} .
	print 1g ${ag[*]} .
	print 1h ${ah[*]} .
	fna
	fnb
	fnc
	fnd
	fne
	fnf
	fng
	typeset -Z5 ah[*]
	print 2a ${aa[*]} .
	print 2b ${ab[*]} .
	print 2c ${ac[*]} .
	print 2d ${ad[*]} .
	print 2e ${ae[*]} .
	print 2f ${af[*]} .
	print 2g ${ag[*]} .
	print 2h ${ah[*]} .
expected-stdout:
	1a 001 002 .
	1b 001 002 .
	1c 001 002 .
	1d 001 002 .
	1e 001 002 .
	1f 001 002 .
	1g 001 002 .
	1h 1 2 .
	2a 9 .
	2b 001 002 .
	2c 92 .
	2d 009 002 .
	2e 9 .
	2f 9 002 .
	2g 009 .
	2h 00001 00002 .
---
name: arrays-9a
description:
	Check that we can concatenate arrays
stdin:
	unset foo; foo=(bar); foo+=(baz); echo 1 ${!foo[*]} : ${foo[*]} .
	unset foo; foo=(foo bar); foo+=(baz); echo 2 ${!foo[*]} : ${foo[*]} .
#	unset foo; foo=([2]=foo [0]=bar); foo+=(baz [5]=quux); echo 3 ${!foo[*]} : ${foo[*]} .
expected-stdout:
	1 0 1 : bar baz .
	2 0 1 2 : foo bar baz .
#	3 0 2 3 5 : bar foo baz quux .
---
name: arrays-9b
description:
	Check that we can concatenate parameters too
stdin:
	unset foo; foo=bar; foo+=baz; echo 1 $foo .
	unset foo; typeset -i16 foo=10; foo+=20; echo 2 $foo .
expected-stdout:
	1 barbaz .
	2 16#a20 .
---
name: arrassign-basic
description:
	Check basic whitespace conserving properties of wdarrassign
stdin:
	a=($(echo a  b))
	b=($(echo "a  b"))
	c=("$(echo "a  b")")
	d=("$(echo a  b)")
	a+=($(echo c  d))
	b+=($(echo "c  d"))
	c+=("$(echo "c  d")")
	d+=("$(echo c  d)")
	echo ".a:${a[0]}.${a[1]}.${a[2]}.${a[3]}:"
	echo ".b:${b[0]}.${b[1]}.${b[2]}.${b[3]}:"
	echo ".c:${c[0]}.${c[1]}.${c[2]}.${c[3]}:"
	echo ".d:${d[0]}.${d[1]}.${d[2]}.${d[3]}:"
expected-stdout:
	.a:a.b.c.d:
	.b:a.b.c.d:
	.c:a  b.c  d..:
	.d:a b.c d..:
---
name: arrassign-eol
description:
	Commands after array assignments are not permitted
stdin:
	foo=(a b) env
expected-exit: e != 0
expected-stderr-pattern:
	/syntax error: unexpected 'env'/
---
name: arrassign-fnc-none
description:
	Check locality of array access inside a function
stdin:
	function fn {
		x+=(f)
		echo ".fn:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	}
	function rfn {
		if [[ -n $BASH_VERSION ]]; then
			y=()
		else
			set -A y
		fi
		y+=(f)
		echo ".rfn:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	}
	x=(m m)
	y=(m m)
	echo ".f0:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	fn
	echo ".f1:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	fn
	echo ".f2:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	echo ".rf0:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	rfn
	echo ".rf1:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	rfn
	echo ".rf2:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
expected-stdout:
	.f0:m.m..:
	.fn:m.m.f.:
	.f1:m.m.f.:
	.fn:m.m.f.f:
	.f2:m.m.f.f:
	.rf0:m.m..:
	.rfn:f...:
	.rf1:f...:
	.rfn:f...:
	.rf2:f...:
---
name: arrassign-fnc-local
description:
	Check locality of array access inside a function
	with the bash/mksh/ksh93 local/typeset keyword
	(note: ksh93 has no local; typeset works only in FKSH)
stdin:
	function fn {
		typeset x
		x+=(f)
		echo ".fn:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	}
	function rfn {
		if [[ -n $BASH_VERSION ]]; then
			y=()
		else
			set -A y
		fi
		typeset y
		y+=(f)
		echo ".rfn:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	}
	function fnr {
		typeset z
		if [[ -n $BASH_VERSION ]]; then
			z=()
		else
			set -A z
		fi
		z+=(f)
		echo ".fnr:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
	}
	x=(m m)
	y=(m m)
	z=(m m)
	echo ".f0:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	fn
	echo ".f1:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	fn
	echo ".f2:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	echo ".rf0:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	rfn
	echo ".rf1:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	rfn
	echo ".rf2:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	echo ".f0r:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
	fnr
	echo ".f1r:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
	fnr
	echo ".f2r:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
expected-stdout:
	.f0:m.m..:
	.fn:f...:
	.f1:m.m..:
	.fn:f...:
	.f2:m.m..:
	.rf0:m.m..:
	.rfn:f...:
	.rf1:...:
	.rfn:f...:
	.rf2:...:
	.f0r:m.m..:
	.fnr:f...:
	.f1r:m.m..:
	.fnr:f...:
	.f2r:m.m..:
---
name: arrassign-fnc-global
description:
	Check locality of array access inside a function
	with the bash4/mksh/yash/zsh typeset -g keyword
stdin:
	function fn {
		typeset -g x
		x+=(f)
		echo ".fn:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	}
	function rfn {
		set -A y
		typeset -g y
		y+=(f)
		echo ".rfn:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	}
	function fnr {
		typeset -g z
		set -A z
		z+=(f)
		echo ".fnr:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
	}
	x=(m m)
	y=(m m)
	z=(m m)
	echo ".f0:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	fn
	echo ".f1:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	fn
	echo ".f2:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
	echo ".rf0:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	rfn
	echo ".rf1:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	rfn
	echo ".rf2:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
	echo ".f0r:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
	fnr
	echo ".f1r:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
	fnr
	echo ".f2r:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
expected-stdout:
	.f0:m.m..:
	.fn:m.m.f.:
	.f1:m.m.f.:
	.fn:m.m.f.f:
	.f2:m.m.f.f:
	.rf0:m.m..:
	.rfn:f...:
	.rf1:f...:
	.rfn:f...:
	.rf2:f...:
	.f0r:m.m..:
	.fnr:f...:
	.f1r:f...:
	.fnr:f...:
	.f2r:f...:
---
name: strassign-fnc-none
description:
	Check locality of string access inside a function
stdin:
	function fn {
		x+=f
		echo ".fn:$x:"
	}
	function rfn {
		y=
		y+=f
		echo ".rfn:$y:"
	}
	x=m
	y=m
	echo ".f0:$x:"
	fn
	echo ".f1:$x:"
	fn
	echo ".f2:$x:"
	echo ".rf0:$y:"
	rfn
	echo ".rf1:$y:"
	rfn
	echo ".rf2:$y:"
expected-stdout:
	.f0:m:
	.fn:mf:
	.f1:mf:
	.fn:mff:
	.f2:mff:
	.rf0:m:
	.rfn:f:
	.rf1:f:
	.rfn:f:
	.rf2:f:
---
name: strassign-fnc-local
description:
	Check locality of string access inside a function
	with the bash/mksh/ksh93 local/typeset keyword
	(note: ksh93 has no local; typeset works only in FKSH)
stdin:
	function fn {
		typeset x
		x+=f
		echo ".fn:$x:"
	}
	function rfn {
		y=
		typeset y
		y+=f
		echo ".rfn:$y:"
	}
	function fnr {
		typeset z
		z=
		z+=f
		echo ".fnr:$z:"
	}
	x=m
	y=m
	z=m
	echo ".f0:$x:"
	fn
	echo ".f1:$x:"
	fn
	echo ".f2:$x:"
	echo ".rf0:$y:"
	rfn
	echo ".rf1:$y:"
	rfn
	echo ".rf2:$y:"
	echo ".f0r:$z:"
	fnr
	echo ".f1r:$z:"
	fnr
	echo ".f2r:$z:"
expected-stdout:
	.f0:m:
	.fn:f:
	.f1:m:
	.fn:f:
	.f2:m:
	.rf0:m:
	.rfn:f:
	.rf1::
	.rfn:f:
	.rf2::
	.f0r:m:
	.fnr:f:
	.f1r:m:
	.fnr:f:
	.f2r:m:
---
name: strassign-fnc-global
description:
	Check locality of string access inside a function
	with the bash4/mksh/yash/zsh typeset -g keyword
stdin:
	function fn {
		typeset -g x
		x+=f
		echo ".fn:$x:"
	}
	function rfn {
		y=
		typeset -g y
		y+=f
		echo ".rfn:$y:"
	}
	function fnr {
		typeset -g z
		z=
		z+=f
		echo ".fnr:$z:"
	}
	x=m
	y=m
	z=m
	echo ".f0:$x:"
	fn
	echo ".f1:$x:"
	fn
	echo ".f2:$x:"
	echo ".rf0:$y:"
	rfn
	echo ".rf1:$y:"
	rfn
	echo ".rf2:$y:"
	echo ".f0r:$z:"
	fnr
	echo ".f1r:$z:"
	fnr
	echo ".f2r:$z:"
expected-stdout:
	.f0:m:
	.fn:mf:
	.f1:mf:
	.fn:mff:
	.f2:mff:
	.rf0:m:
	.rfn:f:
	.rf1:f:
	.rfn:f:
	.rf2:f:
	.f0r:m:
	.fnr:f:
	.f1r:f:
	.fnr:f:
	.f2r:f:
---
name: unset-fnc-local-ksh
description:
	Check that “unset” removes a previous “local”
	(ksh93 syntax compatible version); apparently,
	there are shells which fail this?
stdin:
	function f {
		echo f0: $x
		typeset x
		echo f1: $x
		x=fa
		echo f2: $x
		unset x
		echo f3: $x
		x=fb
		echo f4: $x
	}
	x=o
	echo before: $x
	f
	echo after: $x
expected-stdout:
	before: o
	f0: o
	f1:
	f2: fa
	f3: o
	f4: fb
	after: fb
---
name: unset-fnc-local-sh
description:
	Check that “unset” removes a previous “local”
	(Debian Policy §10.4 sh version); apparently,
	there are shells which fail this?
stdin:
	f() {
		echo f0: $x
		local x
		echo f1: $x
		x=fa
		echo f2: $x
		unset x
		echo f3: $x
		x=fb
		echo f4: $x
	}
	x=o
	echo before: $x
	f
	echo after: $x
expected-stdout:
	before: o
	f0: o
	f1:
	f2: fa
	f3: o
	f4: fb
	after: fb
---
name: varexpand-substr-1
description:
	Check if bash-style substring expansion works
	when using positive numerics
stdin:
	x=abcdefghi
	typeset -i y=123456789
	typeset -i 16 z=123456789	# 16#75bcd15
	echo a t${x:2:2} ${y:2:3} ${z:2:3} a
	echo b ${x::3} ${y::3} ${z::3} b
	echo c ${x:2:} ${y:2:} ${z:2:} c
	echo d ${x:2} ${y:2} ${z:2} d
	echo e ${x:2:6} ${y:2:6} ${z:2:7} e
	echo f ${x:2:7} ${y:2:7} ${z:2:8} f
	echo g ${x:2:8} ${y:2:8} ${z:2:9} g
expected-stdout:
	a tcd 345 #75 a
	b abc 123 16# b
	c c
	d cdefghi 3456789 #75bcd15 d
	e cdefgh 345678 #75bcd1 e
	f cdefghi 3456789 #75bcd15 f
	g cdefghi 3456789 #75bcd15 g
---
name: varexpand-substr-2
description:
	Check if bash-style substring expansion works
	when using negative numerics or expressions
stdin:
	x=abcdefghi
	typeset -i y=123456789
	typeset -i 16 z=123456789	# 16#75bcd15
	n=2
	echo a ${x:$n:3} ${y:$n:3} ${z:$n:3} a
	echo b ${x:(n):3} ${y:(n):3} ${z:(n):3} b
	echo c ${x:(-2):1} ${y:(-2):1} ${z:(-2):1} c
	echo d t${x: n:2} ${y: n:3} ${z: n:3} d
expected-stdout:
	a cde 345 #75 a
	b cde 345 #75 b
	c h 8 1 c
	d tcd 345 #75 d
---
name: varexpand-substr-3
description:
	Match bash5
stdin:
	export x=abcdefghi n=2
	"$__progname" -c 'echo v${x:(n)}x'
	"$__progname" -c 'echo w${x: n}x'
	"$__progname" -c 'echo x${x:n}x'
	"$__progname" -c 'echo y${x:}x'
	"$__progname" -c 'echo z${x}x'
	"$__progname" -c 'x=abcdef;y=123;echo q${x:${y:2:1}:2}q'
expected-stdout:
	vcdefghix
	wcdefghix
	xcdefghix
	zabcdefghix
	qdeq
expected-stderr-pattern:
	/x:}.*bad substitution/
---
name: varexpand-substr-4
description:
	Check corner cases for substring expansion
stdin:
	x=abcdefghi
	integer y=2
	echo a ${x:(y == 1 ? 2 : 3):4} a
expected-stdout:
	a defg a
---
name: varexpand-substr-5A
description:
	Check that substring expansions work on characters
stdin:
	set +U
	x=mäh
	echo a ${x::1} ${x: -1} a
	echo b ${x::3} ${x: -3} b
	echo c ${x:1:2} ${x: -3:2} c
	echo d ${#x} d
expected-stdout:
	a m h a
	b mä äh b
	c ä ä c
	d 4 d
---
name: varexpand-substr-5W
description:
	Check that substring expansions work on characters
stdin:
	set -U
	x=mäh
	echo a ${x::1} ${x: -1} a
	echo b ${x::2} ${x: -2} b
	echo c ${x:1:1} ${x: -2:1} c
	echo d ${#x} d
expected-stdout:
	a m h a
	b mä äh b
	c ä ä c
	d 3 d
---
name: varexpand-substr-6
description:
	Check that string substitution works correctly
stdin:
	foo=1
	bar=2
	baz=qwertyuiop
	echo a ${baz: foo: bar}
	echo b ${baz: foo: $bar}
	echo c ${baz: $foo: bar}
	echo d ${baz: $foo: $bar}
expected-stdout:
	a we
	b we
	c we
	d we
---
name: varexpand-special-hash
description:
	Check special ${var@x} expansion for x=hash
category: !shell:ebcdic-yes
stdin:
	typeset -i8 foo=10
	bar=baz
	unset baz
	print ${foo@#} ${bar@#} ${baz@#} .
expected-stdout:
	9B15FBFB CFBDD32B 00000000 .
---
name: varexpand-special-hash-ebcdic
description:
	Check special ${var@x} expansion for x=hash
category: !shell:ebcdic-no
stdin:
	typeset -i8 foo=10
	bar=baz
	unset baz
	print ${foo@#} ${bar@#} ${baz@#} .
expected-stdout:
	016AE33D 9769C4AF 00000000 .
---
name: varexpand-special-quote
description:
	Check special ${var@Q} expansion for quoted strings
category: !shell:faux-ebcdic
stdin:
	set +U
	i=x
	j=a\ b
	k=$'c
	d\xA0''e€f'
	print -r -- "<i=$i j=$j k=$k>"
	s="u=${i@Q} v=${j@Q} w=${k@Q}"
	print -r -- "s=\"$s\""
	eval "$s"
	typeset -p u v w
expected-stdout:
	<i=x j=a b k=c
	de€f>
	s="u=x v='a b' w=$'c\nd\240e\u20ACf'"
	typeset u=x
	typeset v='a b'
	typeset w=$'c\nd\240e\u20ACf'
---
name: varexpand-special-quote-faux-EBCDIC
description:
	Check special ${var@Q} expansion for quoted strings
category: shell:faux-ebcdic
stdin:
	set +U
	i=x
	j=a\ b
	k=$'c
	d\xA0''e€f'
	print -r -- "<i=$i j=$j k=$k>"
	s="u=${i@Q} v=${j@Q} w=${k@Q}"
	print -r -- "s=\"$s\""
	eval "$s"
	typeset -p u v w
expected-stdout:
	<i=x j=a b k=c
	de€f>
	s="u=x v='a b' w=$'c\nde\u20ACf'"
	typeset u=x
	typeset v='a b'
	typeset w=$'c\nde\u20ACf'
---
name: varexpand-null-1
description:
	Ensure empty strings expand emptily
stdin:
	print s ${a} . ${b} S
	print t ${a#?} . ${b%?} T
	print r ${a=} . ${b/c/d} R
	print q
	print s "${a}" . "${b}" S
	print t "${a#?}" . "${b%?}" T
	print r "${a=}" . "${b/c/d}" R
expected-stdout:
	s . S
	t . T
	r . R
	q
	s  .  S
	t  .  T
	r  .  R
---
name: varexpand-null-2
description:
	Ensure empty strings, when quoted, are expanded as empty strings
stdin:
	print '#!'"$__progname"'\nfor x in "$@"; do print -nr -- "<$x> "; done' >pfs
	chmod +x pfs
	./pfs 1 "${a}" 2 "${a#?}" + "${b%?}" 3 "${a=}" + "${b/c/d}"
	echo .
expected-stdout:
	<1> <> <2> <> <+> <> <3> <> <+> <> .
---
name: varexpand-null-3
description:
	Ensure concatenating behaviour matches other shells
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	showargs 0 ""$@
	x=; showargs 1 "$x"$@
	set A; showargs 2 "${@:+}"
	n() { echo "$#"; }
	unset e
	set -- a b
	n """$@"
	n "$@"
	n "$@"""
	n "$e""$@"
	n "$@"
	n "$@""$e"
	set --
	n """$@"
	n "$@"
	n "$@"""
	n "$e""$@"
	n "$@"
	n "$@""$e"
expected-stdout:
	<0> <> .
	<1> <> .
	<2> <> .
	2
	2
	2
	2
	2
	2
	1
	0
	1
	1
	0
	1
---
name: varexpand-funny-chars
description:
	Check some characters
	XXX \uEF80 is asymmetric, possibly buggy so we don’t check this
stdin:
	x=$'<\x00>'; typeset -p x
	x=$'<\x01>'; typeset -p x
	x=$'<\u0000>'; typeset -p x
	x=$'<\u0001>'; typeset -p x
expected-stdout:
	typeset x='<'
	typeset x=$'<\001>'
	typeset x='<'
	typeset x=$'<\001>'
---
name: print-funny-chars
description:
	Check print builtin's capability to output designated characters
stdin:
	{
		print '<\0144\0344\xDB\u00DB\u20AC\uDB\x40>'
		print '<\x00>'
		print '<\x01>'
		print '<\u0000>'
		print '<\u0001>'
	} | {
		# integer-base-one-3Ar
		typeset -Uui16 -Z11 pos=0
		typeset -Uui16 -Z5 hv=2147483647
		dasc=
		if read -arN -1 line; then
			typeset -i1 line
			i=0
			while (( i < ${#line[*]} )); do
				hv=${line[i++]}
				if (( (pos & 15) == 0 )); then
					(( pos )) && print -r -- "$dasc|"
					print -n "${pos#16#}  "
					dasc=' |'
				fi
				print -n "${hv#16#} "
				if (( (hv < 32) || (hv > 126) )); then
					dasc=$dasc.
				else
					dasc=$dasc${line[i-1]#1#}
				fi
				(( (pos++ & 15) == 7 )) && print -n -- '- '
			done
		fi
		while (( pos & 15 )); do
			print -n '   '
			(( (pos++ & 15) == 7 )) && print -n -- '- '
		done
		(( hv == 2147483647 )) || print -r -- "$dasc|"
	}
expected-stdout:
	00000000  3C 64 E4 DB C3 9B E2 82 - AC C3 9B 40 3E 0A 3C 00  |<d.........@>.<.|
	00000010  3E 0A 3C 01 3E 0A 3C 00 - 3E 0A 3C 01 3E 0A        |>.<.>.<.>.<.>.|
---
name: print-bksl-c
description:
	Check print builtin's \c escape
stdin:
	print '\ca'; print b
expected-stdout:
	ab
---
name: print-cr
description:
	Check that CR+LF is not collapsed into LF as some MSYS shells wrongly do
stdin:
	echo '#!'"$__progname" >foo
	cat >>foo <<-'EOF'
		print -n -- '220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT\r\n220->> Bitte keine Werbung einwerfen! <<\r\r\n220 Who do you wanna pretend to be today'
		print \?
	EOF
	chmod +x foo
	echo "[$(./foo)]"
	./foo | while IFS= read -r line; do
		print -r -- "{$line}"
	done
expected-stdout:
	[220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT
	220->> Bitte keine Werbung einwerfen! <<
	220 Who do you wanna pretend to be today?]
	{220-blau.mirbsd.org ESMTP ready at Thu, 25 Jul 2013 15:57:57 GMT}
	{220->> Bitte keine Werbung einwerfen! <<}
	{220 Who do you wanna pretend to be today?}
---
name: print-crlf
description:
	Check that CR+LF is shown and read as-is
category: shell:textmode-no
stdin:
	cat >foo <<-'EOF'
		x='bar
		' #
		echo .${#x} #
		if test x"$KSH_VERSION" = x""; then #
			printf '<%s>' "$x" #
		else #
			print -nr -- "<$x>" #
		fi #
	EOF
	echo "[$("$__progname" foo)]"
	"$__progname" foo | while IFS= read -r line; do
		print -r -- "{$line}"
	done
expected-stdout:
	[.5
	<bar
	>]
	{.5}
	{<bar}
---
name: print-crlf-textmode
description:
	Check that CR+LF is treated as newline
category: shell:textmode-yes
stdin:
	cat >foo <<-'EOF'
		x='bar
		' #
		echo .${#x} #
		if test x"$KSH_VERSION" = x""; then #
			printf '<%s>' "$x" #
		else #
			print -nr -- "<$x>" #
		fi #
	EOF
	echo "[$("$__progname" foo)]"
	"$__progname" foo | while IFS= read -r line; do
		print -r -- "{$line}"
	done
expected-stdout:
	[.4
	<bar
	>]
	{.4}
	{<bar}
---
name: print-lf
description:
	Check that LF-only is shown and read as-is
stdin:
	cat >foo <<-'EOF'
		x='bar
		' #
		echo .${#x} #
		if test x"$KSH_VERSION" = x""; then #
			printf '<%s>' "$x" #
		else #
			print -nr -- "<$x>" #
		fi #
	EOF
	echo "[$("$__progname" foo)]"
	"$__progname" foo | while IFS= read -r line; do
		print -r -- "{$line}"
	done
expected-stdout:
	[.4
	<bar
	>]
	{.4}
	{<bar}
---
name: print-nul-chars
description:
	Check handling of NUL characters for print and COMSUB
stdin:
	x=$(print '<\0>')
	print $(($(print '<\0>' | wc -c))) $(($(print "$x" | wc -c))) \
	    ${#x} "$x" '<\0>'
expected-stdout-pattern:
	/^4 3 2 <> <\0>$/
---
name: print-array
description:
	Check that print -A works as expected
stdin:
	print -An 0x20AC 0xC3 0xBC 8#101
	set -U
	print -A 0x20AC 0xC3 0xBC 8#102
expected-stdout:
	üA€Ã¼B
---
name: print-escapes
description:
	Check backslash expansion by the print builtin
stdin:
	print '\ \!\"\#\$\%\&'\\\''\(\)\*\+\,\-\.\/\0\1\2\3\4\5\6\7\8' \
	    '\9\:\;\<\=\>\?\@\A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T' \
	    '\U\V\W\X\Y\Z\[\\\]\^\_\`\a\b  \d\e\f\g\h\i\j\k\l\m\n\o\p' \
	    '\q\r\s\t\u\v\w\x\y\z\{\|\}\~' '\u20acd' '\U20acd' '\x123' \
	    '\0x' '\0123' '\01234' | {
		# integer-base-one-3As
		typeset -Uui16 -Z11 pos=0
		typeset -Uui16 -Z5 hv=2147483647
		typeset -i1 wc=0x0A
		dasc=
		nl=${wc#1#}
		while IFS= read -r line; do
			line=$line$nl
			while [[ -n $line ]]; do
				hv=1#${line::1}
				if (( (pos & 15) == 0 )); then
					(( pos )) && print -r -- "$dasc|"
					print -n "${pos#16#}  "
					dasc=' |'
				fi
				print -n "${hv#16#} "
				if (( (hv < 32) || (hv > 126) )); then
					dasc=$dasc.
				else
					dasc=$dasc${line::1}
				fi
				(( (pos++ & 15) == 7 )) && print -n -- '- '
				line=${line:1}
			done
		done
		while (( pos & 15 )); do
			print -n '   '
			(( (pos++ & 15) == 7 )) && print -n -- '- '
		done
		(( hv == 2147483647 )) || print -r -- "$dasc|"
	}
expected-stdout:
	00000000  5C 20 5C 21 5C 22 5C 23 - 5C 24 5C 25 5C 26 5C 27  |\ \!\"\#\$\%\&\'|
	00000010  5C 28 5C 29 5C 2A 5C 2B - 5C 2C 5C 2D 5C 2E 5C 2F  |\(\)\*\+\,\-\.\/|
	00000020  5C 31 5C 32 5C 33 5C 34 - 5C 35 5C 36 5C 37 5C 38  |\1\2\3\4\5\6\7\8|
	00000030  20 5C 39 5C 3A 5C 3B 5C - 3C 5C 3D 5C 3E 5C 3F 5C  | \9\:\;\<\=\>\?\|
	00000040  40 5C 41 5C 42 5C 43 5C - 44 1B 5C 46 5C 47 5C 48  |@\A\B\C\D.\F\G\H|
	00000050  5C 49 5C 4A 5C 4B 5C 4C - 5C 4D 5C 4E 5C 4F 5C 50  |\I\J\K\L\M\N\O\P|
	00000060  5C 51 5C 52 5C 53 5C 54 - 20 5C 55 5C 56 5C 57 5C  |\Q\R\S\T \U\V\W\|
	00000070  58 5C 59 5C 5A 5C 5B 5C - 5C 5D 5C 5E 5C 5F 5C 60  |X\Y\Z\[\\]\^\_\`|
	00000080  07 08 20 20 5C 64 1B 0C - 5C 67 5C 68 5C 69 5C 6A  |..  \d..\g\h\i\j|
	00000090  5C 6B 5C 6C 5C 6D 0A 5C - 6F 5C 70 20 5C 71 0D 5C  |\k\l\m.\o\p \q.\|
	000000A0  73 09 5C 75 0B 5C 77 5C - 78 5C 79 5C 7A 5C 7B 5C  |s.\u.\w\x\y\z\{\|
	000000B0  7C 5C 7D 5C 7E 20 E2 82 - AC 64 20 EF BF BD 20 12  ||\}\~ ...d ... .|
	000000C0  33 20 78 20 53 20 53 34 - 0A                       |3 x S S4.|
---
name: dollar-doublequoted-strings
description:
	Check that a $ preceding "…" is ignored
stdin:
	echo $"Localise me!"
	cat <<<$"Me too!"
	V=X
	aol=aol
	cat <<-$"aol"
		I do not take a $V for a V!
	aol
expected-stdout:
	Localise me!
	Me too!
	I do not take a $V for a V!
---
name: dollar-quoted-strings
description:
	Check backslash expansion by $'…' strings
stdin:
	print '#!'"$__progname"'\nfor x in "$@"; do print -r -- "$x"; done' >pfn
	chmod +x pfn
	./pfn $'\ \!\"\#\$\%\&\'\(\)\*\+\,\-\.\/ \1\2\3\4\5\6' \
	    $'a\0b' $'a\01b' $'\7\8\9\:\;\<\=\>\?\@\A\B\C\D\E\F\G\H\I' \
	    $'\J\K\L\M\N\O\P\Q\R\S\T\U1\V\W\X\Y\Z\[\\\]\^\_\`\a\b\d\e' \
	    $'\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u1\v\w\x1\y\z\{\|\}\~ $x' \
	    $'\u20acd' $'\U20acd' $'\x123' $'fn\x0rd' $'\0234' $'\234' \
	    $'\2345' $'\ca' $'\c!' $'\c?' $'\c…' $'a\
	b' | {
		# integer-base-one-3As
		typeset -Uui16 -Z11 pos=0
		typeset -Uui16 -Z5 hv=2147483647
		typeset -i1 wc=0x0A
		dasc=
		nl=${wc#1#}
		while IFS= read -r line; do
			line=$line$nl
			while [[ -n $line ]]; do
				hv=1#${line::1}
				if (( (pos & 15) == 0 )); then
					(( pos )) && print -r -- "$dasc|"
					print -n "${pos#16#}  "
					dasc=' |'
				fi
				print -n "${hv#16#} "
				if (( (hv < 32) || (hv > 126) )); then
					dasc=$dasc.
				else
					dasc=$dasc${line::1}
				fi
				(( (pos++ & 15) == 7 )) && print -n -- '- '
				line=${line:1}
			done
		done
		while (( pos & 15 )); do
			print -n '   '
			(( (pos++ & 15) == 7 )) && print -n -- '- '
		done
		(( hv == 2147483647 )) || print -r -- "$dasc|"
	}
expected-stdout:
	00000000  20 21 22 23 24 25 26 27 - 28 29 2A 2B 2C 2D 2E 2F  | !"#$%&'()*+,-./|
	00000010  20 01 02 03 04 05 06 0A - 61 0A 61 01 62 0A 07 38  | .......a.a.b..8|
	00000020  39 3A 3B 3C 3D 3E 3F 40 - 41 42 43 44 1B 46 47 48  |9:;<=>?@ABCD.FGH|
	00000030  49 0A 4A 4B 4C 4D 4E 4F - 50 51 52 53 54 01 56 57  |I.JKLMNOPQRST.VW|
	00000040  58 59 5A 5B 5C 5D 5E 5F - 60 07 08 64 1B 0A 0C 67  |XYZ[\]^_`..d...g|
	00000050  68 69 6A 6B 6C 6D 0A 6F - 70 71 0D 73 09 01 0B 77  |hijklm.opq.s...w|
	00000060  01 79 7A 7B 7C 7D 7E 20 - 24 78 0A E2 82 AC 64 0A  |.yz{|}~ $x....d.|
	00000070  EF BF BD 0A C4 A3 0A 66 - 6E 0A 13 34 0A 9C 0A 9C  |.......fn..4....|
	00000080  35 0A 01 0A 01 0A 7F 0A - 82 80 A6 0A 61 0A 62 0A  |5...........a.b.|
---
name: dollar-quotes-in-heredocs-strings
description:
	They are, however, not parsed in here documents, here strings
	(outside of string delimiters) or regular strings, but in
	parameter substitutions.
stdin:
	cat <<EOF
		dollar = strchr(s, '$');	/* ' */
		foo " bar \" baz
	EOF
	cat <<$'a\tb'
	a\tb
	a	b
	cat <<<"dollar = strchr(s, '$');	/* ' */"
	cat <<<'dollar = strchr(s, '\''$'\'');	/* '\'' */'
	x="dollar = strchr(s, '$');	/* ' */"
	cat <<<"$x"
	cat <<<$'a\E[0m\tb'
	unset nl; print -r -- "x${nl:=$'\n'}y"
	echo "1 foo\"bar"
	# cf & HEREDOC
	cat <<EOF
	2 foo\"bar
	EOF
	# probably never reached for here strings?
	cat <<<"3 foo\"bar"
	cat <<<"4 foo\\\"bar"
	cat <<<'5 foo\"bar'
	# old scripts use this (e.g. ncurses)
	echo "^$"
	# make sure this works, outside of quotes
	cat <<<'7'$'\t''.'
expected-stdout:
		dollar = strchr(s, '$');	/* ' */
		foo " bar \" baz
	a\tb
	dollar = strchr(s, '$');	/* ' */
	dollar = strchr(s, '$');	/* ' */
	dollar = strchr(s, '$');	/* ' */
	a[0m	b
	x
	y
	1 foo"bar
	2 foo\"bar
	3 foo"bar
	4 foo\"bar
	5 foo\"bar
	^$
	7	.
---
name: dot-needs-argument
description:
	check Debian #415167 solution: '.' without arguments should fail
stdin:
	"$__progname" -c .
	"$__progname" -c source
expected-exit: e != 0
expected-stderr-pattern:
	/\.: missing argument.*\n.*source: missing argument/
---
name: dot-errorlevel
description:
	Ensure dot resets $?
stdin:
	:>dotfile
	(exit 42)
	. ./dotfile
	echo 1 $? .
expected-stdout:
	1 0 .
---
name: alias-function-no-conflict
description:
	make aliases not conflict with function definitions
stdin:
	# POSIX function can be defined, but alias overrides it
	alias foo='echo bar'
	foo
	foo() {
		echo baz
	}
	foo
	unset -f foo
	foo 2>/dev/null || echo rab
	# alias overrides ksh function
	alias korn='echo bar'
	korn
	function korn {
		echo baz
	}
	korn
	# alias temporarily overrides POSIX function
	bla() {
		echo bfn
	}
	bla
	alias bla='echo bal'
	bla
	unalias bla
	bla
expected-stdout:
	bar
	bar
	bar
	bar
	bar
	bfn
	bal
	bfn
---
name: bash-function-parens
description:
	ensure the keyword function is ignored when preceding
	POSIX style function declarations (bashism)
stdin:
	mk() {
		echo '#!'"$__progname"
		echo "$1 {"
		echo '	echo "bar='\''$0'\'\"
		echo '}'
		print -r -- "${2:-foo}"
	}
	mk 'function foo' >f-korn
	mk 'foo ()' >f-dash
	mk 'function foo ()' >f-bash
	print '#!'"$__progname"'\nprint -r -- "${0%/f-argh}"' >f-argh
	chmod +x f-*
	u=$(./f-argh)
	x="korn: $(./f-korn)"; echo "${x/@("$u")/.}"
	x="dash: $(./f-dash)"; echo "${x/@("$u")/.}"
	x="bash: $(./f-bash)"; echo "${x/@("$u")/.}"
expected-stdout:
	korn: bar='foo'
	dash: bar='./f-dash'
	bash: bar='./f-bash'
---
name: integer-base-one-1
description:
	check if the use of fake integer base 1 works
stdin:
	set -U
	typeset -Uui16 i0=1# i1=1#€
	typeset -i1 o0a=64
	typeset -i1 o1a=0x263A
	typeset -Uui1 o0b=0x7E
	typeset -Uui1 o1b=0xFDD0
	integer px=0xCAFE 'p0=1# ' p1=1#… pl=1#f
	echo "in <$i0> <$i1>"
	echo "out <${o0a#1#}|${o0b#1#}> <${o1a#1#}|${o1b#1#}>"
	typeset -Uui1 i0 i1
	echo "pass <$px> <$p0> <$p1> <$pl> <${i0#1#}|${i1#1#}>"
	typeset -Uui16 tv1=1#~ tv2=1# tv3=1# tv4=1# tv5=1# tv6=1# tv7=1#  tv8=1#
	echo "specX <${tv1#16#}> <${tv2#16#}> <${tv3#16#}> <${tv4#16#}> <${tv5#16#}> <${tv6#16#}> <${tv7#16#}> <${tv8#16#}>"
	typeset -i1 tv1 tv2 tv3 tv4 tv5 tv6 tv7 tv8
	echo "specW <${tv1#1#}> <${tv2#1#}> <${tv3#1#}> <${tv4#1#}> <${tv5#1#}> <${tv6#1#}> <${tv7#1#}> <${tv8#1#}>"
	typeset -i1 xs1=0xEF7F xs2=0xEF80 xs3=0xFDD0
	echo "specU <${xs1#1#}> <${xs2#1#}> <${xs3#1#}>"
expected-stdout:
	in <16#EFEF> <16#20AC>
	out <@|~> <☺|﷐>
	pass <16#cafe> <1# > <1#…> <1#f> <|€>
	specX <7E> <7F> <EF80> <EF81> <EFC0> <EFC1> <A0> <80>
	specW <~> <> <> <> <> <> < > <>
	specU <> <> <﷐>
---
name: integer-base-one-2a
description:
	check if the use of fake integer base 1 stops at correct characters
stdin:
	set -U
	integer x=1#foo
	echo /$x/
expected-stderr-pattern:
	/1#foo: unexpected 'oo'/
expected-exit: e != 0
---
name: integer-base-one-2b
description:
	check if the use of fake integer base 1 stops at correct characters
stdin:
	set -U
	integer x=1#
	echo /$x/
expected-stderr-pattern:
	/1#: unexpected ''/
expected-exit: e != 0
---
name: integer-base-one-2c1
description:
	check if the use of fake integer base 1 stops at correct characters
stdin:
	set -U
	integer x=1#…
	echo /$x/
expected-stdout:
	/1#…/
---
name: integer-base-one-2c2
description:
	check if the use of fake integer base 1 stops at correct characters
stdin:
	set +U
	integer x=1#…
	echo /$x/
expected-stderr-pattern:
	/1#…: unexpected ''/
expected-exit: e != 0
---
name: integer-base-one-2d1
description:
	check if the use of fake integer base 1 handles octets okay
stdin:
	set -U
	typeset -i16 x=1#
	echo /$x/	# invalid utf-8
expected-stdout:
	/16#efff/
---
name: integer-base-one-2d2
description:
	check if the use of fake integer base 1 handles octets
stdin:
	set -U
	typeset -i16 x=1#
	echo /$x/	# invalid 2-byte
expected-stdout:
	/16#efc2/
---
name: integer-base-one-2d3
description:
	check if the use of fake integer base 1 handles octets
stdin:
	set -U
	typeset -i16 x=1#
	echo /$x/	# invalid 2-byte
expected-stdout:
	/16#efef/
---
name: integer-base-one-2d4
description:
	check if the use of fake integer base 1 stops at invalid input
stdin:
	set -U
	typeset -i16 x=1#
	echo /$x/	# invalid 3-byte
expected-stderr-pattern:
	/1#: unexpected ''/
expected-exit: e != 0
---
name: integer-base-one-2d5
description:
	check if the use of fake integer base 1 stops at invalid input
stdin:
	set -U
	typeset -i16 x=1#
	echo /$x/	# non-minimalistic
expected-stderr-pattern:
	/1#: unexpected ''/
expected-exit: e != 0
---
name: integer-base-one-2d6
description:
	check if the use of fake integer base 1 stops at invalid input
stdin:
	set -U
	typeset -i16 x=1#
	echo /$x/	# non-minimalistic
expected-stderr-pattern:
	/1#: unexpected ''/
expected-exit: e != 0
---
name: integer-base-one-3As
description:
	some sample code for hexdumping
	not NUL safe; input lines must be NL terminated
stdin:
	{
		print 'Hello, World!\\\nこんにちは！'
		typeset -Uui16 i=0x100
		# change that to 0xFF once we can handle embedded
		# NUL characters in strings / here documents
		while (( i++ < 0x1FF )); do
			print -n "\x${i#16#1}"
		done
		print '\0z'
	} | {
		# integer-base-one-3As
		typeset -Uui16 -Z11 pos=0
		typeset -Uui16 -Z5 hv=2147483647
		typeset -i1 wc=0x0A
		dasc=
		nl=${wc#1#}
		while IFS= read -r line; do
			line=$line$nl
			while [[ -n $line ]]; do
				hv=1#${line::1}
				if (( (pos & 15) == 0 )); then
					(( pos )) && print -r -- "$dasc|"
					print -n "${pos#16#}  "
					dasc=' |'
				fi
				print -n "${hv#16#} "
				if (( (hv < 32) || (hv > 126) )); then
					dasc=$dasc.
				else
					dasc=$dasc${line::1}
				fi
				(( (pos++ & 15) == 7 )) && print -n -- '- '
				line=${line:1}
			done
		done
		while (( pos & 15 )); do
			print -n '   '
			(( (pos++ & 15) == 7 )) && print -n -- '- '
		done
		(( hv == 2147483647 )) || print -r -- "$dasc|"
	}
expected-stdout:
	00000000  48 65 6C 6C 6F 2C 20 57 - 6F 72 6C 64 21 5C 0A E3  |Hello, World!\..|
	00000010  81 93 E3 82 93 E3 81 AB - E3 81 A1 E3 81 AF EF BC  |................|
	00000020  81 0A 01 02 03 04 05 06 - 07 08 09 0A 0B 0C 0D 0E  |................|
	00000030  0F 10 11 12 13 14 15 16 - 17 18 19 1A 1B 1C 1D 1E  |................|
	00000040  1F 20 21 22 23 24 25 26 - 27 28 29 2A 2B 2C 2D 2E  |. !"#$%&'()*+,-.|
	00000050  2F 30 31 32 33 34 35 36 - 37 38 39 3A 3B 3C 3D 3E  |/0123456789:;<=>|
	00000060  3F 40 41 42 43 44 45 46 - 47 48 49 4A 4B 4C 4D 4E  |?@ABCDEFGHIJKLMN|
	00000070  4F 50 51 52 53 54 55 56 - 57 58 59 5A 5B 5C 5D 5E  |OPQRSTUVWXYZ[\]^|
	00000080  5F 60 61 62 63 64 65 66 - 67 68 69 6A 6B 6C 6D 6E  |_`abcdefghijklmn|
	00000090  6F 70 71 72 73 74 75 76 - 77 78 79 7A 7B 7C 7D 7E  |opqrstuvwxyz{|}~|
	000000A0  7F 80 81 82 83 84 85 86 - 87 88 89 8A 8B 8C 8D 8E  |................|
	000000B0  8F 90 91 92 93 94 95 96 - 97 98 99 9A 9B 9C 9D 9E  |................|
	000000C0  9F A0 A1 A2 A3 A4 A5 A6 - A7 A8 A9 AA AB AC AD AE  |................|
	000000D0  AF B0 B1 B2 B3 B4 B5 B6 - B7 B8 B9 BA BB BC BD BE  |................|
	000000E0  BF C0 C1 C2 C3 C4 C5 C6 - C7 C8 C9 CA CB CC CD CE  |................|
	000000F0  CF D0 D1 D2 D3 D4 D5 D6 - D7 D8 D9 DA DB DC DD DE  |................|
	00000100  DF E0 E1 E2 E3 E4 E5 E6 - E7 E8 E9 EA EB EC ED EE  |................|
	00000110  EF F0 F1 F2 F3 F4 F5 F6 - F7 F8 F9 FA FB FC FD FE  |................|
	00000120  FF 7A 0A                -                          |.z.|
---
name: integer-base-one-3Ws
description:
	some sample code for hexdumping UCS-2
	not NUL safe; input lines must be NL terminated
stdin:
	set -U
	{
		print 'Hello, World!\\\nこんにちは！'
		typeset -Uui16 i=0x100
		# change that to 0xFF once we can handle embedded
		# NUL characters in strings / here documents
		while (( i++ < 0x1FF )); do
			print -n "\u${i#16#1}"
		done
		print
		print \\xff		# invalid utf-8
		print \\xc2		# invalid 2-byte
		print \\xef\\xbf\\xc0	# invalid 3-byte
		print \\xc0\\x80	# non-minimalistic
		print \\xe0\\x80\\x80	# non-minimalistic
		print '�￾￿'	# end of range
		print '\0z'		# embedded NUL
	} | {
		# integer-base-one-3Ws
		typeset -Uui16 -Z11 pos=0
		typeset -Uui16 -Z7 hv
		typeset -i1 wc=0x0A
		typeset -i lpos
		dasc=
		nl=${wc#1#}
		while IFS= read -r line; do
			line=$line$nl
			lpos=0
			while (( lpos < ${#line} )); do
				wc=1#${line:(lpos++):1}
				if (( (wc < 32) || \
				    ((wc > 126) && (wc < 160)) )); then
					dch=.
				elif (( (wc & 0xFF80) == 0xEF80 )); then
					dch=�
				else
					dch=${wc#1#}
				fi
				if (( (pos & 7) == 7 )); then
					dasc=$dasc$dch
					dch=
				elif (( (pos & 7) == 0 )); then
					(( pos )) && print -r -- "$dasc|"
					print -n "${pos#16#}  "
					dasc=' |'
				fi
				let hv=wc
				print -n "${hv#16#} "
				(( (pos++ & 7) == 3 )) && \
				    print -n -- '- '
				dasc=$dasc$dch
			done
		done
		while (( pos & 7 )); do
			print -n '     '
			(( (pos++ & 7) == 3 )) && print -n -- '- '
		done
		(( hv == 2147483647 )) || print -r -- "$dasc|"
	}
expected-stdout:
	00000000  0048 0065 006C 006C - 006F 002C 0020 0057  |Hello, W|
	00000008  006F 0072 006C 0064 - 0021 005C 000A 3053  |orld!\.こ|
	00000010  3093 306B 3061 306F - FF01 000A 0001 0002  |んにちは！...|
	00000018  0003 0004 0005 0006 - 0007 0008 0009 000A  |........|
	00000020  000B 000C 000D 000E - 000F 0010 0011 0012  |........|
	00000028  0013 0014 0015 0016 - 0017 0018 0019 001A  |........|
	00000030  001B 001C 001D 001E - 001F 0020 0021 0022  |..... !"|
	00000038  0023 0024 0025 0026 - 0027 0028 0029 002A  |#$%&'()*|
	00000040  002B 002C 002D 002E - 002F 0030 0031 0032  |+,-./012|
	00000048  0033 0034 0035 0036 - 0037 0038 0039 003A  |3456789:|
	00000050  003B 003C 003D 003E - 003F 0040 0041 0042  |;<=>?@AB|
	00000058  0043 0044 0045 0046 - 0047 0048 0049 004A  |CDEFGHIJ|
	00000060  004B 004C 004D 004E - 004F 0050 0051 0052  |KLMNOPQR|
	00000068  0053 0054 0055 0056 - 0057 0058 0059 005A  |STUVWXYZ|
	00000070  005B 005C 005D 005E - 005F 0060 0061 0062  |[\]^_`ab|
	00000078  0063 0064 0065 0066 - 0067 0068 0069 006A  |cdefghij|
	00000080  006B 006C 006D 006E - 006F 0070 0071 0072  |klmnopqr|
	00000088  0073 0074 0075 0076 - 0077 0078 0079 007A  |stuvwxyz|
	00000090  007B 007C 007D 007E - 007F 0080 0081 0082  |{|}~....|
	00000098  0083 0084 0085 0086 - 0087 0088 0089 008A  |........|
	000000A0  008B 008C 008D 008E - 008F 0090 0091 0092  |........|
	000000A8  0093 0094 0095 0096 - 0097 0098 0099 009A  |........|
	000000B0  009B 009C 009D 009E - 009F 00A0 00A1 00A2  |..... ¡¢|
	000000B8  00A3 00A4 00A5 00A6 - 00A7 00A8 00A9 00AA  |£¤¥¦§¨©ª|
	000000C0  00AB 00AC 00AD 00AE - 00AF 00B0 00B1 00B2  |«¬­®¯°±²|
	000000C8  00B3 00B4 00B5 00B6 - 00B7 00B8 00B9 00BA  |³´µ¶·¸¹º|
	000000D0  00BB 00BC 00BD 00BE - 00BF 00C0 00C1 00C2  |»¼½¾¿ÀÁÂ|
	000000D8  00C3 00C4 00C5 00C6 - 00C7 00C8 00C9 00CA  |ÃÄÅÆÇÈÉÊ|
	000000E0  00CB 00CC 00CD 00CE - 00CF 00D0 00D1 00D2  |ËÌÍÎÏÐÑÒ|
	000000E8  00D3 00D4 00D5 00D6 - 00D7 00D8 00D9 00DA  |ÓÔÕÖ×ØÙÚ|
	000000F0  00DB 00DC 00DD 00DE - 00DF 00E0 00E1 00E2  |ÛÜÝÞßàáâ|
	000000F8  00E3 00E4 00E5 00E6 - 00E7 00E8 00E9 00EA  |ãäåæçèéê|
	00000100  00EB 00EC 00ED 00EE - 00EF 00F0 00F1 00F2  |ëìíîïðñò|
	00000108  00F3 00F4 00F5 00F6 - 00F7 00F8 00F9 00FA  |óôõö÷øùú|
	00000110  00FB 00FC 00FD 00FE - 00FF 000A EFFF 000A  |ûüýþÿ.�.|
	00000118  EFC2 000A EFEF EFBF - EFC0 000A EFC0 EF80  |�.���.��|
	00000120  000A EFE0 EF80 EF80 - 000A FFFD EFEF EFBF  |.���.���|
	00000128  EFBE EFEF EFBF EFBF - 000A 007A 000A       |����.z.|
---
name: integer-base-one-3Ar
description:
	some sample code for hexdumping; NUL and binary safe
stdin:
	{
		print 'Hello, World!\\\nこんにちは！'
		typeset -Uui16 i=0x100
		# change that to 0xFF once we can handle embedded
		# NUL characters in strings / here documents
		while (( i++ < 0x1FF )); do
			print -n "\x${i#16#1}"
		done
		print '\0z'
	} | {
		# integer-base-one-3Ar
		typeset -Uui16 -Z11 pos=0
		typeset -Uui16 -Z5 hv=2147483647
		dasc=
		if read -arN -1 line; then
			typeset -i1 line
			i=0
			while (( i < ${#line[*]} )); do
				hv=${line[i++]}
				if (( (pos & 15) == 0 )); then
					(( pos )) && print -r -- "$dasc|"
					print -n "${pos#16#}  "
					dasc=' |'
				fi
				print -n "${hv#16#} "
				if (( (hv < 32) || (hv > 126) )); then
					dasc=$dasc.
				else
					dasc=$dasc${line[i-1]#1#}
				fi
				(( (pos++ & 15) == 7 )) && print -n -- '- '
			done
		fi
		while (( pos & 15 )); do
			print -n '   '
			(( (pos++ & 15) == 7 )) && print -n -- '- '
		done
		(( hv == 2147483647 )) || print -r -- "$dasc|"
	}
expected-stdout:
	00000000  48 65 6C 6C 6F 2C 20 57 - 6F 72 6C 64 21 5C 0A E3  |Hello, World!\..|
	00000010  81 93 E3 82 93 E3 81 AB - E3 81 A1 E3 81 AF EF BC  |................|
	00000020  81 0A 01 02 03 04 05 06 - 07 08 09 0A 0B 0C 0D 0E  |................|
	00000030  0F 10 11 12 13 14 15 16 - 17 18 19 1A 1B 1C 1D 1E  |................|
	00000040  1F 20 21 22 23 24 25 26 - 27 28 29 2A 2B 2C 2D 2E  |. !"#$%&'()*+,-.|
	00000050  2F 30 31 32 33 34 35 36 - 37 38 39 3A 3B 3C 3D 3E  |/0123456789:;<=>|
	00000060  3F 40 41 42 43 44 45 46 - 47 48 49 4A 4B 4C 4D 4E  |?@ABCDEFGHIJKLMN|
	00000070  4F 50 51 52 53 54 55 56 - 57 58 59 5A 5B 5C 5D 5E  |OPQRSTUVWXYZ[\]^|
	00000080  5F 60 61 62 63 64 65 66 - 67 68 69 6A 6B 6C 6D 6E  |_`abcdefghijklmn|
	00000090  6F 70 71 72 73 74 75 76 - 77 78 79 7A 7B 7C 7D 7E  |opqrstuvwxyz{|}~|
	000000A0  7F 80 81 82 83 84 85 86 - 87 88 89 8A 8B 8C 8D 8E  |................|
	000000B0  8F 90 91 92 93 94 95 96 - 97 98 99 9A 9B 9C 9D 9E  |................|
	000000C0  9F A0 A1 A2 A3 A4 A5 A6 - A7 A8 A9 AA AB AC AD AE  |................|
	000000D0  AF B0 B1 B2 B3 B4 B5 B6 - B7 B8 B9 BA BB BC BD BE  |................|
	000000E0  BF C0 C1 C2 C3 C4 C5 C6 - C7 C8 C9 CA CB CC CD CE  |................|
	000000F0  CF D0 D1 D2 D3 D4 D5 D6 - D7 D8 D9 DA DB DC DD DE  |................|
	00000100  DF E0 E1 E2 E3 E4 E5 E6 - E7 E8 E9 EA EB EC ED EE  |................|
	00000110  EF F0 F1 F2 F3 F4 F5 F6 - F7 F8 F9 FA FB FC FD FE  |................|
	00000120  FF 00 7A 0A             -                          |..z.|
---
name: integer-base-one-3Wr
description:
	some sample code for hexdumping UCS-2; NUL and binary safe
stdin:
	set -U
	{
		print 'Hello, World!\\\nこんにちは！'
		typeset -Uui16 i=0x100
		# change that to 0xFF once we can handle embedded
		# NUL characters in strings / here documents
		while (( i++ < 0x1FF )); do
			print -n "\u${i#16#1}"
		done
		print
		print \\xff		# invalid utf-8
		print \\xc2		# invalid 2-byte
		print \\xef\\xbf\\xc0	# invalid 3-byte
		print \\xc0\\x80	# non-minimalistic
		print \\xe0\\x80\\x80	# non-minimalistic
		print '�￾￿'	# end of range
		print '\0z'		# embedded NUL
	} | {
		# integer-base-one-3Wr
		typeset -Uui16 -Z11 pos=0
		typeset -Uui16 -Z7 hv=2147483647
		dasc=
		if read -arN -1 line; then
			typeset -i1 line
			i=0
			while (( i < ${#line[*]} )); do
				hv=${line[i++]}
				if (( (hv < 32) || \
				    ((hv > 126) && (hv < 160)) )); then
					dch=.
				elif (( (hv & 0xFF80) == 0xEF80 )); then
					dch=�
				else
					dch=${line[i-1]#1#}
				fi
				if (( (pos & 7) == 7 )); then
					dasc=$dasc$dch
					dch=
				elif (( (pos & 7) == 0 )); then
					(( pos )) && print -r -- "$dasc|"
					print -n "${pos#16#}  "
					dasc=' |'
				fi
				print -n "${hv#16#} "
				(( (pos++ & 7) == 3 )) && \
				    print -n -- '- '
				dasc=$dasc$dch
			done
		fi
		while (( pos & 7 )); do
			print -n '     '
			(( (pos++ & 7) == 3 )) && print -n -- '- '
		done
		(( hv == 2147483647 )) || print -r -- "$dasc|"
	}
expected-stdout:
	00000000  0048 0065 006C 006C - 006F 002C 0020 0057  |Hello, W|
	00000008  006F 0072 006C 0064 - 0021 005C 000A 3053  |orld!\.こ|
	00000010  3093 306B 3061 306F - FF01 000A 0001 0002  |んにちは！...|
	00000018  0003 0004 0005 0006 - 0007 0008 0009 000A  |........|
	00000020  000B 000C 000D 000E - 000F 0010 0011 0012  |........|
	00000028  0013 0014 0015 0016 - 0017 0018 0019 001A  |........|
	00000030  001B 001C 001D 001E - 001F 0020 0021 0022  |..... !"|
	00000038  0023 0024 0025 0026 - 0027 0028 0029 002A  |#$%&'()*|
	00000040  002B 002C 002D 002E - 002F 0030 0031 0032  |+,-./012|
	00000048  0033 0034 0035 0036 - 0037 0038 0039 003A  |3456789:|
	00000050  003B 003C 003D 003E - 003F 0040 0041 0042  |;<=>?@AB|
	00000058  0043 0044 0045 0046 - 0047 0048 0049 004A  |CDEFGHIJ|
	00000060  004B 004C 004D 004E - 004F 0050 0051 0052  |KLMNOPQR|
	00000068  0053 0054 0055 0056 - 0057 0058 0059 005A  |STUVWXYZ|
	00000070  005B 005C 005D 005E - 005F 0060 0061 0062  |[\]^_`ab|
	00000078  0063 0064 0065 0066 - 0067 0068 0069 006A  |cdefghij|
	00000080  006B 006C 006D 006E - 006F 0070 0071 0072  |klmnopqr|
	00000088  0073 0074 0075 0076 - 0077 0078 0079 007A  |stuvwxyz|
	00000090  007B 007C 007D 007E - 007F 0080 0081 0082  |{|}~....|
	00000098  0083 0084 0085 0086 - 0087 0088 0089 008A  |........|
	000000A0  008B 008C 008D 008E - 008F 0090 0091 0092  |........|
	000000A8  0093 0094 0095 0096 - 0097 0098 0099 009A  |........|
	000000B0  009B 009C 009D 009E - 009F 00A0 00A1 00A2  |..... ¡¢|
	000000B8  00A3 00A4 00A5 00A6 - 00A7 00A8 00A9 00AA  |£¤¥¦§¨©ª|
	000000C0  00AB 00AC 00AD 00AE - 00AF 00B0 00B1 00B2  |«¬­®¯°±²|
	000000C8  00B3 00B4 00B5 00B6 - 00B7 00B8 00B9 00BA  |³´µ¶·¸¹º|
	000000D0  00BB 00BC 00BD 00BE - 00BF 00C0 00C1 00C2  |»¼½¾¿ÀÁÂ|
	000000D8  00C3 00C4 00C5 00C6 - 00C7 00C8 00C9 00CA  |ÃÄÅÆÇÈÉÊ|
	000000E0  00CB 00CC 00CD 00CE - 00CF 00D0 00D1 00D2  |ËÌÍÎÏÐÑÒ|
	000000E8  00D3 00D4 00D5 00D6 - 00D7 00D8 00D9 00DA  |ÓÔÕÖ×ØÙÚ|
	000000F0  00DB 00DC 00DD 00DE - 00DF 00E0 00E1 00E2  |ÛÜÝÞßàáâ|
	000000F8  00E3 00E4 00E5 00E6 - 00E7 00E8 00E9 00EA  |ãäåæçèéê|
	00000100  00EB 00EC 00ED 00EE - 00EF 00F0 00F1 00F2  |ëìíîïðñò|
	00000108  00F3 00F4 00F5 00F6 - 00F7 00F8 00F9 00FA  |óôõö÷øùú|
	00000110  00FB 00FC 00FD 00FE - 00FF 000A EFFF 000A  |ûüýþÿ.�.|
	00000118  EFC2 000A EFEF EFBF - EFC0 000A EFC0 EF80  |�.���.��|
	00000120  000A EFE0 EF80 EF80 - 000A FFFD EFEF EFBF  |.���.���|
	00000128  EFBE EFEF EFBF EFBF - 000A 0000 007A 000A  |����..z.|
---
name: integer-base-one-4
description:
	Check if ksh93-style base-one integers work
category: !smksh
stdin:
	set -U
	echo 1 $(('a'))
	(echo 2f $(('aa'))) 2>&1 | sed "s/^[^']*'/2p '/"
	echo 3 $(('…'))
	x="'a'"
	echo "4 <$x>"
	echo 5 $(($x))
	echo 6 $((x))
expected-stdout:
	1 97
	2p 'aa': multi-character character constant
	3 8230
	4 <'a'>
	5 97
	6 97
---
name: integer-base-one-5A
description:
	Check to see that we’re NUL and UCS safe
category: !shell:ebcdic-yes
stdin:
	set +U
	print 'a\0b\xfdz' >x
	read -a y <x
	set -U
	typeset -Uui16 y
	print ${y[*]} .
expected-stdout:
	16#61 16#0 16#62 16#FD 16#7A .
---
name: integer-base-one-5E
description:
	Check to see that we’re NUL and UCS safe
category: !shell:ebcdic-no
stdin:
	set +U
	print 'a\0b\xfdz' >x
	read -a y <x
	set -U
	typeset -Uui16 y
	print ${y[*]} .
expected-stdout:
	16#81 16#0 16#82 16#FD 16#A9 .
---
name: integer-base-one-5W
description:
	Check to see that we’re NUL and UCS safe
stdin:
	set -U
	print 'a\0b€c' >x
	read -a y <x
	set +U
	typeset -Uui16 y
	print ${y[*]} .
expected-stdout:
	16#61 16#0 16#62 16#20AC 16#63 .
---
name: ulimit-1
description:
	Check that ulimit as used in dot.mksh works or is stubbed
stdin:
	ulimit -c 0
---
name: ulimit-2
description:
	Check if we can use a specific syntax idiom for ulimit
	XXX Haiku works, but only for -n and -V
category: !os:haiku,!os:syllable
stdin:
	if ! x=$(ulimit -d) || [[ $x = unknown ]]; then
		#echo expected to fail on this OS
		echo okay
	else
		ulimit -dS $x && echo okay
	fi
expected-stdout:
	okay
---
name: ulimit-3
description:
	Check that there are no duplicate limits (if this fails,
	immediately contact with system information the developers)
stdin:
	[[ -z $(set | grep ^opt) ]]; mis=$?
	set | grep ^opt | sed 's/^/unexpectedly set in environment: /'
	opta='<used for showing all limits>'
	optH='<used to set hard limits>'
	optS='<used to set soft limits>'
	ulimit -a >tmpf
	set -o noglob
	while IFS= read -r line; do
		x=${line:1:1}
		if [[ -z $x || ${#x}/${%x} != 1/1 ]]; then
			print -r -- "weird line: $line"
			(( mis |= 1 ))
			continue
		fi
		set -- $line
		nameref v=opt$x
		if [[ -n $v ]]; then
			print -r -- "duplicate -$x \"$2\" already seen as \"$v\""
			(( mis |= 2 ))
		fi
		v=$2
	done <tmpf
	if (( mis & 2 )); then
		echo failed
	elif (( mis & 1 )); then
		echo inconclusive
	else
		echo done
	fi
expected-stdout:
	done
---
name: redir-1
description:
	Check some of the most basic invariants of I/O redirection
stdin:
	i=0
	function d {
		print o$i.
		print -u2 e$((i++)).
	}
	d >a 2>b
	echo =1=
	cat a
	echo =2=
	cat b
	echo =3=
	d 2>&1 >c
	echo =4=
	cat c
	echo =5=
expected-stdout:
	=1=
	o0.
	=2=
	e0.
	=3=
	e1.
	=4=
	o1.
	=5=
---
name: bashiop-1
description:
	Check if GNU bash-like I/O redirection works
	Part 1: this is also supported by GNU bash
stdin:
	exec 3>&1
	function threeout {
		echo ras
		echo dwa >&2
		echo tri >&3
	}
	threeout &>foo
	echo ===
	cat foo
expected-stdout:
	tri
	===
	ras
	dwa
---
name: bashiop-2a
description:
	Check if GNU bash-like I/O redirection works
	Part 2: this is *not* supported by GNU bash
stdin:
	exec 3>&1
	function threeout {
		echo ras
		echo dwa >&2
		echo tri >&3
	}
	threeout 3&>foo
	echo ===
	cat foo
expected-stdout:
	ras
	===
	dwa
	tri
---
name: bashiop-2b
description:
	Check if GNU bash-like I/O redirection works
	Part 2: this is *not* supported by GNU bash
stdin:
	exec 3>&1
	function threeout {
		echo ras
		echo dwa >&2
		echo tri >&3
	}
	threeout 3>foo &>&3
	echo ===
	cat foo
expected-stdout:
	===
	ras
	dwa
	tri
---
name: bashiop-2c
description:
	Check if GNU bash-like I/O redirection works
	Part 2: this is supported by GNU bash 4 only
stdin:
	echo mir >foo
	set -o noclobber
	exec 3>&1
	function threeout {
		echo ras
		echo dwa >&2
		echo tri >&3
	}
	threeout &>>foo
	echo ===
	cat foo
expected-stdout:
	tri
	===
	mir
	ras
	dwa
---
name: bashiop-3a
description:
	Check if GNU bash-like I/O redirection fails correctly
	Part 1: this is also supported by GNU bash
stdin:
	echo mir >foo
	set -o noclobber
	exec 3>&1
	function threeout {
		echo ras
		echo dwa >&2
		echo tri >&3
	}
	threeout &>foo
	echo ===
	cat foo
expected-stdout:
	===
	mir
expected-stderr-pattern: /.*: can't (create|overwrite) .*/
---
name: bashiop-3b
description:
	Check if GNU bash-like I/O redirection fails correctly
	Part 2: this is *not* supported by GNU bash
stdin:
	echo mir >foo
	set -o noclobber
	exec 3>&1
	function threeout {
		echo ras
		echo dwa >&2
		echo tri >&3
	}
	threeout &>|foo
	echo ===
	cat foo
expected-stdout:
	tri
	===
	ras
	dwa
---
name: bashiop-4
description:
	Check if GNU bash-like I/O redirection works
	Part 4: this is also supported by GNU bash,
	but failed in some mksh versions
stdin:
	exec 3>&1
	function threeout {
		echo ras
		echo dwa >&2
		echo tri >&3
	}
	function blubb {
		[[ -e bar ]] && threeout "$bf" &>foo
	}
	blubb
	echo -n >bar
	blubb
	echo ===
	cat foo
expected-stdout:
	tri
	===
	ras
	dwa
---
name: bashiop-5
description:
	Check if GNU bash-like I/O redirection is only supported
	in !POSIX !sh mode as it breaks existing scripts' syntax
stdin:
	:>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
	:>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
	:>x; echo 3 "$("$__progname" -o sh -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
expected-stdout:
	1  = foo echo bar .
	2  = bar .
	3  = bar .
---
name: oksh-eval
description:
	Check expansions.
stdin:
	a=
	for n in ${a#*=}; do echo 1hu ${n} .; done
	for n in "${a#*=}"; do echo 1hq ${n} .; done
	for n in ${a##*=}; do echo 2hu ${n} .; done
	for n in "${a##*=}"; do echo 2hq ${n} .; done
	for n in ${a%=*}; do echo 1pu ${n} .; done
	for n in "${a%=*}"; do echo 1pq ${n} .; done
	for n in ${a%%=*}; do echo 2pu ${n} .; done
	for n in "${a%%=*}"; do echo 2pq ${n} .; done
expected-stdout:
	1hq .
	2hq .
	1pq .
	2pq .
---
name: oksh-and-list-error-1
description:
	Test exit status of rightmost element in 2 element && list in -e mode
stdin:
	true && false
	echo "should not print"
arguments: !-e!
expected-exit: e != 0
---
name: oksh-and-list-error-2
description:
	Test exit status of rightmost element in 3 element && list in -e mode
stdin:
	true && true && false
	echo "should not print"
arguments: !-e!
expected-exit: e != 0
---
name: oksh-or-list-error-1
description:
	Test exit status of || list in -e mode
stdin:
	false || false
	echo "should not print"
arguments: !-e!
expected-exit: e != 0
---
name: oksh-longline-crash
description:
	This used to cause a core dump
stdin:
	ulimit -c 0
	deplibs="-lz -lpng /usr/local/lib/libjpeg.la -ltiff -lm -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libglib.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgtk.la -ltiff -ljpeg -lz -lpng -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk_pixbuf.la -lz -lpng /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libglib.la -lm -lm /usr/local/lib/libaudiofile.la -lm -lm -laudiofile -L/usr/local/lib /usr/local/lib/libesd.la -lm -lz -L/usr/local/lib /usr/local/lib/libgnomesupport.la -lm -lz -lm -lglib -L/usr/local/lib /usr/local/lib/libgnome.la -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgtk.la -lICE -lSM -lz -lpng /usr/local/lib/libungif.la /usr/local/lib/libjpeg.la -ltiff -lm -lz -lpng /usr/local/lib/libungif.la -lz /usr/local/lib/libjpeg.la -ltiff -L/usr/local/lib -L/usr/X11R6/lib /usr/local/lib/libgdk_imlib.la -lm -L/usr/local/lib /usr/local/lib/libart_lgpl.la -lm -lz -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lICE -lSM -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -L/usr/X11R6/lib -lm -lz -lpng -lungif -lz -ljpeg -ltiff -ljpeg -lgdk_imlib -lglib -lm -laudiofile -lm -laudiofile -lesd -L/usr/local/lib /usr/local/lib/libgnomeui.la -lz -lz /usr/local/lib/libxml.la -lz -lz -lz /usr/local/lib/libxml.la -lm -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libglib.la /usr/local/lib/libgmodule.la -lintl -lglib -lgmodule /usr/local/lib/libgdk.la /usr/local/lib/libgtk.la -L/usr/X11R6/lib -L/usr/local/lib /usr/local/lib/libglade.la -lz -lz -lz /usr/local/lib/libxml.la /usr/local/lib/libglib.la -lm -lm /usr/local/lib/libaudiofile.la -lm -lm -laudiofile /usr/local/lib/libesd.la -lm -lz /usr/local/lib/libgnomesupport.la -lm -lz -lm -lglib /usr/local/lib/libgnome.la -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -lglib -lgmodule /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -lglib -lgmodule /usr/local/lib/libgtk.la -lICE -lSM -lz -lpng /usr/local/lib/libungif.la /usr/local/lib/libjpeg.la -ltiff -lm -lz -lz /usr/local/lib/libgdk_imlib.la /usr/local/lib/libart_lgpl.la -lm -lz -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lm -lz -lungif -lz -ljpeg -ljpeg -lgdk_imlib -lglib -lm -laudiofile -lm -laudiofile -lesd /usr/local/lib/libgnomeui.la -L/usr/X11R6/lib -L/usr/local/lib /usr/local/lib/libglade-gnome.la /usr/local/lib/libglib.la -lm -lm /usr/local/lib/libaudiofile.la -lm -lm -laudiofile -L/usr/local/lib /usr/local/lib/libesd.la -lm -lz -L/usr/local/lib /usr/local/lib/libgnomesupport.la -lm -lz -lm -lglib -L/usr/local/lib /usr/local/lib/libgnome.la -lX11 -lXext /usr/local/lib/libiconv.la -L/usr/local/lib -L/usr/ports/devel/gettext/w-gettext-0.10.40/gettext-0.10.40/intl/.libs /usr/local/lib/libintl.la /usr/local/lib/libgmodule.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgdk.la -lintl -lm -lX11 -lXext -L/usr/X11R6/lib -lglib -lgmodule -L/usr/local/lib /usr/local/lib/libgtk.la -lICE -lSM -lz -lpng /usr/local/lib/libungif.la /usr/local/lib/libjpeg.la -ltiff -lm -lz -lpng /usr/local/lib/libungif.la -lz /usr/local/lib/libjpeg.la -ltiff -L/usr/local/lib -L/usr/X11R6/lib /usr/local/lib/libgdk_imlib.la -lm -L/usr/local/lib /usr/local/lib/libart_lgpl.la -lm -lz -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -lICE -lSM -lm -lX11 -lXext -lintl -lglib -lgmodule -lgdk -lgtk -L/usr/X11R6/lib -lm -lz -lpng -lungif -lz -ljpeg -ltiff -ljpeg -lgdk_imlib -lglib -lm -laudiofile -lm -laudiofile -lesd -L/usr/local/lib /usr/local/lib/libgnomeui.la -L/usr/X11R6/lib -L/usr/local/lib"
	specialdeplibs="-lgnomeui -lart_lgpl -lgdk_imlib -ltiff -ljpeg -lungif -lpng -lz -lSM -lICE -lgtk -lgdk -lgmodule -lintl -lXext -lX11 -lgnome -lgnomesupport -lesd -laudiofile -lm -lglib"
	for deplib in $deplibs; do
		case $deplib in
		-L*)
			new_libs="$deplib $new_libs"
			;;
		*)
			case " $specialdeplibs " in
			*" $deplib "*)
				new_libs="$deplib $new_libs";;
			esac
			;;
		esac
	done
---
name: oksh-seterror-1
description:
	The -e flag should be ignored when executing a compound list
	followed by an if statement.
stdin:
	if true; then false && false; fi
	true
arguments: !-e!
expected-exit: e == 0
---
name: oksh-seterror-2
description:
	The -e flag should be ignored when executing a compound list
	followed by an if statement.
stdin:
	if true; then if true; then false && false; fi; fi
	true
arguments: !-e!
expected-exit: e == 0
---
name: oksh-seterror-3
description:
	The -e flag should be ignored when executing a compound list
	followed by an elif statement.
stdin:
	if true; then :; elif true; then false && false; fi
arguments: !-e!
expected-exit: e == 0
---
name: oksh-seterror-4
description:
	The -e flag should be ignored when executing a pipeline
	beginning with '!'
stdin:
	for i in 1 2 3
	do
		false && false
		true || false
	done
arguments: !-e!
expected-exit: e == 0
---
name: oksh-seterror-5
description:
	The -e flag should be ignored when executing a pipeline
	beginning with '!'
stdin:
	! true | false
	true
arguments: !-e!
expected-exit: e == 0
---
name: oksh-seterror-6
description:
	When trapping ERR and EXIT, both traps should run in -e mode
	when an error occurs.
stdin:
	trap 'echo EXIT' EXIT
	trap 'echo ERR' ERR
	set -e
	false
	echo DONE
	exit 0
arguments: !-e!
expected-exit: e != 0
expected-stdout:
	ERR
	EXIT
---
name: oksh-seterror-7
description:
	The -e flag within a command substitution should be honored
stdin:
	echo $( set -e; false; echo foo )
arguments: !-e!
expected-stdout:
	
---
name: oksh-input-comsub
description:
	A command substitution using input redirection should exit with
	failure if the input file does not exist.
stdin:
	var=$(< non-existent)
expected-exit: e != 0
expected-stderr-pattern: /non-existent/
---
name: oksh-empty-for-list
description:
	A for list which expands to zero items should not execute the body.
stdin:
	set foo bar baz ; for out in ; do echo $out ; done
---
name: oksh-varfunction-mod1
description:
	(Inspired by PR 2450 on OpenBSD.) Calling
		FOO=bar f
	where f is a ksh style function, should not set FOO in the current
	env. If f is a Bourne style function, (new) also not. Furthermore,
	the function should receive a correct value of FOO. However, differing
	from oksh, setting FOO in the function itself must change the value in
	setting FOO in the function itself should not change the value in
	global environment.
stdin:
	print '#!'"$__progname"'\nunset RANDOM\nexport | while IFS= read -r' \
	    'RANDOM; do eval '\''print -r -- "$RANDOM=$'\''"$RANDOM"'\'\"\'\; \
	    done >env; chmod +x env; PATH=.$PATHSEP$PATH
	function k {
		if [ x$FOO != xbar ]; then
			echo 1
			return 1
		fi
		x=$(env | grep FOO)
		if [ "x$x" != "xFOO=bar" ]; then
			echo 2
			return 1;
		fi
		FOO=foo
		return 0
	}
	b () {
		if [ x$FOO != xbar ]; then
			echo 3
			return 1
		fi
		x=$(env | grep FOO)
		if [ "x$x" != "xFOO=bar" ]; then
			echo 4
			return 1;
		fi
		FOO=foo
		return 0
	}
	FOO=bar k
	if [ $? != 0 ]; then
		exit 1
	fi
	if [ x$FOO != x ]; then
		exit 1
	fi
	FOO=bar b
	if [ $? != 0 ]; then
		exit 1
	fi
	if [ x$FOO != x ]; then
		exit 1
	fi
	FOO=barbar
	FOO=bar k
	if [ $? != 0 ]; then
		exit 1
	fi
	if [ x$FOO != xbarbar ]; then
		exit 1
	fi
	FOO=bar b
	if [ $? != 0 ]; then
		exit 1
	fi
	if [ x$FOO != xbarbar ]; then
		exit 1
	fi
---
name: fd-cloexec-1
description:
	Verify that file descriptors > 2 are private for Korn shells
	AT&T ksh93 does this still, which means we must keep it as well
stdin:
	cat >cld <<-EOF
		#!$__perlname
		open(FH, ">&9") or die "E: open \$!";
		syswrite(FH, "Fowl\\n", 5) or die "E: write \$!";
	EOF
	chmod +x cld
	exec 9>&1
	./cld
expected-exit: e != 0
expected-stderr-pattern:
	/E: open /
---
name: fd-cloexec-2
description:
	Verify that file descriptors > 2 are not private for POSIX shells
	See Debian Bug #154540, Closes: #499139
stdin:
	cat >cld <<-EOF
		#!$__perlname
		open(FH, ">&9") or die "E: open \$!";
		syswrite(FH, "Fowl\\n", 5) or die "E: write \$!";
	EOF
	chmod +x cld
	test -n "$POSH_VERSION" || set -o posix
	exec 9>&1
	./cld
expected-stdout:
	Fowl
---
name: fd-cloexec-3
description:
	Another check for close-on-exec
stdin:
	print '#!'"$__progname" >ts
	cat >>ts <<'EOF'
	s=ERR
	read -rN-1 -u$1 s 2>/dev/null; e=$?
	print -r -- "($1, $((!e)), $s)"
	EOF
	chmod +x ts
	print foo >tx
	runtest() {
		s=$1; shift
		print -r -- $("$__progname" "$@" -c "$s") "$@" .
	}
	runtest 'exec 3<tx; ./ts 3 3<&3; ./ts 3'
	runtest 'exec 3<tx; ./ts 3 3<&3; ./ts 3' -o posix
	runtest 'exec 3<tx; ./ts 3 3<&3; ./ts 3' -o sh
	runtest 'exec 3<tx; ./ts 4 4<&3; ./ts 4 4<&3'
	runtest 'exec 3<tx; ./ts 3 3<&3; ./ts 3 3<&3'
expected-stdout:
	(3, 1, foo) (3, 0, ERR) .
	(3, 1, foo) (3, 1, ) -o posix .
	(3, 1, foo) (3, 1, ) -o sh .
	(4, 1, foo) (4, 1, ) .
	(3, 1, foo) (3, 1, ) .
---
name: comsub-1a
description:
	COMSUB are now parsed recursively, so this works
	see also regression-6: matching parenthesēs bug
	Fails on: pdksh bash2 bash3 zsh
	Passes on: bash4 ksh93 mksh(20110313+)
stdin:
	echo 1 $(case 1 in (1) echo yes;; (2) echo no;; esac) .
	echo 2 $(case 1 in 1) echo yes;; 2) echo no;; esac) .
	TEST=1234; echo 3 ${TEST: $(case 1 in (1) echo 1;; (*) echo 2;; esac)} .
	TEST=5678; echo 4 ${TEST: $(case 1 in 1) echo 1;; *) echo 2;; esac)} .
	a=($(case 1 in (1) echo 1;; (*) echo 2;; esac)); echo 5 ${a[0]} .
	a=($(case 1 in 1) echo 1;; *) echo 2;; esac)); echo 6 ${a[0]} .
expected-stdout:
	1 yes .
	2 yes .
	3 234 .
	4 678 .
	5 1 .
	6 1 .
---
name: comsub-1b
description:
	COMSUB are now parsed recursively, so this works
	Fails on: pdksh bash2 bash3 bash4 zsh
	Passes on: ksh93 mksh(20110313+)
stdin:
	echo 1 $(($(case 1 in (1) echo 1;; (*) echo 2;; esac)+10)) .
	echo 2 $(($(case 1 in 1) echo 1;; *) echo 2;; esac)+20)) .
	(( a = $(case 1 in (1) echo 1;; (*) echo 2;; esac) )); echo 3 $a .
	(( a = $(case 1 in 1) echo 1;; *) echo 2;; esac) )); echo 4 $a .
	a=($(($(case 1 in (1) echo 1;; (*) echo 2;; esac)+10))); echo 5 ${a[0]} .
	a=($(($(case 1 in 1) echo 1;; *) echo 2;; esac)+20))); echo 6 ${a[0]} .
expected-stdout:
	1 11 .
	2 21 .
	3 1 .
	4 1 .
	5 11 .
	6 21 .
---
name: comsub-2
description:
	RedHat BZ#496791 – another case of missing recursion
	in parsing COMSUB expressions
	Fails on: pdksh bash2 bash3¹ bash4¹ zsh
	Passes on: ksh93 mksh(20110305+)
	① bash[34] seem to choke on comment ending with backslash-newline
stdin:
	# a comment with " ' \
	x=$(
	echo yes
	# a comment with " ' \
	)
	echo $x
expected-stdout:
	yes
---
name: comsub-3
description:
	Extended test for COMSUB explaining why a recursive parser
	is a must (a non-recursive parser cannot pass all three of
	these test cases, especially the ‘#’ is difficult)
stdin:
	print '#!'"$__progname"'\necho 1234' >id; chmod +x id; PATH=.$PATHSEP$PATH
	echo $(typeset -i10 x=16#20; echo $x)
	echo $(typeset -Uui16 x=16#$(id -u)
	) .
	echo $(c=1; d=1
	typeset -Uui16 a=36#foo; c=2
	typeset -Uui16 b=36 #foo; d=2
	echo $a $b $c $d)
expected-stdout:
	32
	.
	16#4F68 16#24 2 1
---
name: comsub-4
description:
	Check the tree dump functions for !MKSH_SMALL functionality
category: !smksh
stdin:
	x() { case $1 in u) echo x ;;& *) echo $1 ;; esac; }
	typeset -f x
expected-stdout:
	x() {
		case $1 in
		(u)
			\echo x 
			;|
		(*)
			\echo $1 
			;;
		esac 
	} 
---
name: comsub-5
description:
	Check COMSUB works with aliases (does not expand them twice)
	and reentrancy safety
stdin:
	print '#!'"$__progname"'\nfor x in "$@"; do print -r -- "$x"; done' >pfn
	chmod +x pfn
	alias echo='echo a'
	foo() {
		echo moo
		./pfn "$(echo foo)"
	}
	./pfn "$(echo b)"
	typeset -f foo >x
	cat x
	foo
	. ./x
	typeset -f foo
	foo
expected-stdout:
	a b
	foo() {
		\echo a moo 
		./pfn "$(\echo a foo )" 
	} 
	a moo
	a foo
	foo() {
		\echo a moo 
		./pfn "$(\echo a foo )" 
	} 
	a moo
	a foo
---
name: comsub-torture
description:
	Check the tree dump functions work correctly
stdin:
	if [[ -z $__progname ]]; then echo >&2 call me with __progname; exit 1; fi
	while IFS= read -r line; do
		if [[ $line = '#1' ]]; then
			lastf=0
			continue
		elif [[ $line = EOFN* ]]; then
			fbody=$fbody$'\n'$line
			continue
		elif [[ $line != '#'* ]]; then
			fbody=$fbody$'\n\t'$line
			continue
		fi
		if (( lastf )); then
			x="inline_${nextf}() {"$fbody$'\n}\n'
			print -nr -- "$x"
			print -r -- "${x}typeset -f inline_$nextf" | "$__progname"
			x="function comsub_$nextf { x=\$("$fbody$'\n); }\n'
			print -nr -- "$x"
			print -r -- "${x}typeset -f comsub_$nextf" | "$__progname"
			x="function reread_$nextf { x=\$(("$fbody$'\n)|tr u x); }\n'
			print -nr -- "$x"
			print -r -- "${x}typeset -f reread_$nextf" | "$__progname"
		fi
		lastf=1
		fbody=
		nextf=${line#?}
	done <<'EOD'
	#1
	#TCOM
	vara=1  varb='2  3'  cmd  arg1  $arg2  "$arg3  4"
	#TPAREN_TPIPE_TLIST
	(echo $foo  |  tr -dc 0-9; echo)
	#TAND_TOR
	cmd  &&  echo ja  ||  echo nein
	#TSELECT
	select  file  in  *;  do  echo  "<$file>" ;  break ;  done
	#TFOR_TTIME
	time  for  i  in  {1,2,3}  ;  do  echo  $i ;  done
	#TCASE
	case  $foo  in  1)  echo eins;& 2) echo zwei  ;| *) echo kann net bis drei zählen;;  esac
	#TIF_TBANG_TDBRACKET_TELIF
	if  !  [[  1  =  1  ]]  ;  then  echo eins;  elif [[ 1 = 2 ]]; then echo zwei  ;else echo drei; fi
	#TWHILE
	i=1; while (( i < 10 )); do echo $i; let ++i; done
	#TUNTIL
	i=10; until  (( !--i )) ; do echo $i; done
	#TCOPROC
	cat  *  |&  ls
	#TFUNCT_TBRACE_TASYNC
	function  korn  {  echo eins; echo zwei ;  }
	bourne  ()  {  logger *  &  }
	#IOREAD_IOCAT
	tr  x  u  0<foo  >>bar
	#IOWRITE_IOCLOB_IOHERE_noIOSKIP
	cat  >|bar  <<'EOFN'
	foo
	EOFN
	#IOWRITE_noIOCLOB_IOHERE_IOSKIP
	cat  1>bar  <<-EOFI
	foo
	EOFI
	#IORDWR_IODUP
	sh  1<>/dev/console  0<&1  2>&1
	#COMSUB_EXPRSUB_FUNSUB_VALSUB
	echo $(true) $((1+ 2)) ${  :;} ${| REPLY=x;}
	#QCHAR_OQUOTE_CQUOTE
	echo fo\ob\"a\`r\'b\$az
	echo "fo\ob\"a\`r\'b\$az"
	echo 'fo\ob\"a\`r'\''b\$az'
	#OSUBST_CSUBST_OPAT_SPAT_CPAT
	[[ ${foo#bl\(u\)b} = @(bar|baz) ]]
	#heredoc_closed
	x=$(cat <<EOFN
	note there must be no space between EOFN and )
	EOFN); echo $x
	#heredoc_space
	x=$(cat <<EOFN\ 
	note the space between EOFN and ) is actually part of the here document marker
	EOFN ); echo $x
	#patch_motd
	x=$(sysctl -n kern.version | sed 1q)
	[[ -s /etc/motd && "$([[ "$(head -1 /etc/motd)" != $x ]] && \
	    ed -s /etc/motd 2>&1 <<-EOF
		1,/^\$/d
		0a
			$x
	
		.
		wq
	EOF)" = @(?) ]] && rm -f /etc/motd
	if [[ ! -s /etc/motd ]]; then
		install -c -o root -g wheel -m 664 /dev/null /etc/motd
		print -- "$x\n" >/etc/motd
	fi
	#wdarrassign
	case x in
	x) a+=b; c+=(d e)
	esac
	#0
	EOD
expected-stdout:
	inline_TCOM() {
		vara=1  varb='2  3'  cmd  arg1  $arg2  "$arg3  4"
	}
	inline_TCOM() {
		vara=1 varb="2  3" \cmd arg1 $arg2 "$arg3  4" 
	} 
	function comsub_TCOM { x=$(
		vara=1  varb='2  3'  cmd  arg1  $arg2  "$arg3  4"
	); }
	function comsub_TCOM {
		x=$(vara=1 varb="2  3" \cmd arg1 $arg2 "$arg3  4" ) 
	} 
	function reread_TCOM { x=$((
		vara=1  varb='2  3'  cmd  arg1  $arg2  "$arg3  4"
	)|tr u x); }
	function reread_TCOM {
		x=$( ( vara=1 varb="2  3" \cmd arg1 $arg2 "$arg3  4" ) | \tr u x ) 
	} 
	inline_TPAREN_TPIPE_TLIST() {
		(echo $foo  |  tr -dc 0-9; echo)
	}
	inline_TPAREN_TPIPE_TLIST() {
		( \echo $foo | \tr -dc 0-9 
		  \echo ) 
	} 
	function comsub_TPAREN_TPIPE_TLIST { x=$(
		(echo $foo  |  tr -dc 0-9; echo)
	); }
	function comsub_TPAREN_TPIPE_TLIST {
		x=$( ( \echo $foo | \tr -dc 0-9 ; \echo ) ) 
	} 
	function reread_TPAREN_TPIPE_TLIST { x=$((
		(echo $foo  |  tr -dc 0-9; echo)
	)|tr u x); }
	function reread_TPAREN_TPIPE_TLIST {
		x=$( ( ( \echo $foo | \tr -dc 0-9 ; \echo ) ) | \tr u x ) 
	} 
	inline_TAND_TOR() {
		cmd  &&  echo ja  ||  echo nein
	}
	inline_TAND_TOR() {
		\cmd && \echo ja || \echo nein 
	} 
	function comsub_TAND_TOR { x=$(
		cmd  &&  echo ja  ||  echo nein
	); }
	function comsub_TAND_TOR {
		x=$(\cmd && \echo ja || \echo nein ) 
	} 
	function reread_TAND_TOR { x=$((
		cmd  &&  echo ja  ||  echo nein
	)|tr u x); }
	function reread_TAND_TOR {
		x=$( ( \cmd && \echo ja || \echo nein ) | \tr u x ) 
	} 
	inline_TSELECT() {
		select  file  in  *;  do  echo  "<$file>" ;  break ;  done
	}
	inline_TSELECT() {
		select file in * 
		do
			\echo "<$file>" 
			\break 
		done 
	} 
	function comsub_TSELECT { x=$(
		select  file  in  *;  do  echo  "<$file>" ;  break ;  done
	); }
	function comsub_TSELECT {
		x=$(select file in * ; do \echo "<$file>" ; \break ; done ) 
	} 
	function reread_TSELECT { x=$((
		select  file  in  *;  do  echo  "<$file>" ;  break ;  done
	)|tr u x); }
	function reread_TSELECT {
		x=$( ( select file in * ; do \echo "<$file>" ; \break ; done ) | \tr u x ) 
	} 
	inline_TFOR_TTIME() {
		time  for  i  in  {1,2,3}  ;  do  echo  $i ;  done
	}
	inline_TFOR_TTIME() {
		time for i in {1,2,3} 
		do
			\echo $i 
		done 
	} 
	function comsub_TFOR_TTIME { x=$(
		time  for  i  in  {1,2,3}  ;  do  echo  $i ;  done
	); }
	function comsub_TFOR_TTIME {
		x=$(time for i in {1,2,3} ; do \echo $i ; done ) 
	} 
	function reread_TFOR_TTIME { x=$((
		time  for  i  in  {1,2,3}  ;  do  echo  $i ;  done
	)|tr u x); }
	function reread_TFOR_TTIME {
		x=$( ( time for i in {1,2,3} ; do \echo $i ; done ) | \tr u x ) 
	} 
	inline_TCASE() {
		case  $foo  in  1)  echo eins;& 2) echo zwei  ;| *) echo kann net bis drei zählen;;  esac
	}
	inline_TCASE() {
		case $foo in
		(1)
			\echo eins 
			;&
		(2)
			\echo zwei 
			;|
		(*)
			\echo kann net bis drei zählen 
			;;
		esac 
	} 
	function comsub_TCASE { x=$(
		case  $foo  in  1)  echo eins;& 2) echo zwei  ;| *) echo kann net bis drei zählen;;  esac
	); }
	function comsub_TCASE {
		x=$(case $foo in (1) \echo eins  ;& (2) \echo zwei  ;| (*) \echo kann net bis drei zählen  ;; esac ) 
	} 
	function reread_TCASE { x=$((
		case  $foo  in  1)  echo eins;& 2) echo zwei  ;| *) echo kann net bis drei zählen;;  esac
	)|tr u x); }
	function reread_TCASE {
		x=$( ( case $foo in (1) \echo eins  ;& (2) \echo zwei  ;| (*) \echo kann net bis drei zählen  ;; esac ) | \tr u x ) 
	} 
	inline_TIF_TBANG_TDBRACKET_TELIF() {
		if  !  [[  1  =  1  ]]  ;  then  echo eins;  elif [[ 1 = 2 ]]; then echo zwei  ;else echo drei; fi
	}
	inline_TIF_TBANG_TDBRACKET_TELIF() {
		if ! [[ 1 = 1 ]] 
		then
			\echo eins 
		elif [[ 1 = 2 ]] 
		then
			\echo zwei 
		else
			\echo drei 
		fi 
	} 
	function comsub_TIF_TBANG_TDBRACKET_TELIF { x=$(
		if  !  [[  1  =  1  ]]  ;  then  echo eins;  elif [[ 1 = 2 ]]; then echo zwei  ;else echo drei; fi
	); }
	function comsub_TIF_TBANG_TDBRACKET_TELIF {
		x=$(if ! [[ 1 = 1 ]] ; then \echo eins ; elif [[ 1 = 2 ]] ; then \echo zwei ; else \echo drei ; fi ) 
	} 
	function reread_TIF_TBANG_TDBRACKET_TELIF { x=$((
		if  !  [[  1  =  1  ]]  ;  then  echo eins;  elif [[ 1 = 2 ]]; then echo zwei  ;else echo drei; fi
	)|tr u x); }
	function reread_TIF_TBANG_TDBRACKET_TELIF {
		x=$( ( if ! [[ 1 = 1 ]] ; then \echo eins ; elif [[ 1 = 2 ]] ; then \echo zwei ; else \echo drei ; fi ) | \tr u x ) 
	} 
	inline_TWHILE() {
		i=1; while (( i < 10 )); do echo $i; let ++i; done
	}
	inline_TWHILE() {
		i=1 
		while {
			      \\builtin let " i < 10 " 
		      } 
		do
			\echo $i 
			\let ++i 
		done 
	} 
	function comsub_TWHILE { x=$(
		i=1; while (( i < 10 )); do echo $i; let ++i; done
	); }
	function comsub_TWHILE {
		x=$(i=1 ; while { \\builtin let " i < 10 " ; } ; do \echo $i ; \let ++i ; done ) 
	} 
	function reread_TWHILE { x=$((
		i=1; while (( i < 10 )); do echo $i; let ++i; done
	)|tr u x); }
	function reread_TWHILE {
		x=$( ( i=1 ; while { \\builtin let " i < 10 " ; } ; do \echo $i ; \let ++i ; done ) | \tr u x ) 
	} 
	inline_TUNTIL() {
		i=10; until  (( !--i )) ; do echo $i; done
	}
	inline_TUNTIL() {
		i=10 
		until {
			      \\builtin let " !--i " 
		      } 
		do
			\echo $i 
		done 
	} 
	function comsub_TUNTIL { x=$(
		i=10; until  (( !--i )) ; do echo $i; done
	); }
	function comsub_TUNTIL {
		x=$(i=10 ; until { \\builtin let " !--i " ; } ; do \echo $i ; done ) 
	} 
	function reread_TUNTIL { x=$((
		i=10; until  (( !--i )) ; do echo $i; done
	)|tr u x); }
	function reread_TUNTIL {
		x=$( ( i=10 ; until { \\builtin let " !--i " ; } ; do \echo $i ; done ) | \tr u x ) 
	} 
	inline_TCOPROC() {
		cat  *  |&  ls
	}
	inline_TCOPROC() {
		\cat * |& 
		\ls 
	} 
	function comsub_TCOPROC { x=$(
		cat  *  |&  ls
	); }
	function comsub_TCOPROC {
		x=$(\cat * |&  \ls ) 
	} 
	function reread_TCOPROC { x=$((
		cat  *  |&  ls
	)|tr u x); }
	function reread_TCOPROC {
		x=$( ( \cat * |&  \ls ) | \tr u x ) 
	} 
	inline_TFUNCT_TBRACE_TASYNC() {
		function  korn  {  echo eins; echo zwei ;  }
		bourne  ()  {  logger *  &  }
	}
	inline_TFUNCT_TBRACE_TASYNC() {
		function korn {
			\echo eins 
			\echo zwei 
		} 
		bourne() {
			\logger * & 
		} 
	} 
	function comsub_TFUNCT_TBRACE_TASYNC { x=$(
		function  korn  {  echo eins; echo zwei ;  }
		bourne  ()  {  logger *  &  }
	); }
	function comsub_TFUNCT_TBRACE_TASYNC {
		x=$(function korn { \echo eins ; \echo zwei ; } ; bourne() { \logger * &  } ) 
	} 
	function reread_TFUNCT_TBRACE_TASYNC { x=$((
		function  korn  {  echo eins; echo zwei ;  }
		bourne  ()  {  logger *  &  }
	)|tr u x); }
	function reread_TFUNCT_TBRACE_TASYNC {
		x=$( ( function korn { \echo eins ; \echo zwei ; } ; bourne() { \logger * &  } ) | \tr u x ) 
	} 
	inline_IOREAD_IOCAT() {
		tr  x  u  0<foo  >>bar
	}
	inline_IOREAD_IOCAT() {
		\tr x u <foo >>bar 
	} 
	function comsub_IOREAD_IOCAT { x=$(
		tr  x  u  0<foo  >>bar
	); }
	function comsub_IOREAD_IOCAT {
		x=$(\tr x u <foo >>bar ) 
	} 
	function reread_IOREAD_IOCAT { x=$((
		tr  x  u  0<foo  >>bar
	)|tr u x); }
	function reread_IOREAD_IOCAT {
		x=$( ( \tr x u <foo >>bar ) | \tr u x ) 
	} 
	inline_IOWRITE_IOCLOB_IOHERE_noIOSKIP() {
		cat  >|bar  <<'EOFN'
		foo
	EOFN
	}
	inline_IOWRITE_IOCLOB_IOHERE_noIOSKIP() {
		\cat >|bar <<"EOFN" 
		foo
	EOFN
	
	} 
	function comsub_IOWRITE_IOCLOB_IOHERE_noIOSKIP { x=$(
		cat  >|bar  <<'EOFN'
		foo
	EOFN
	); }
	function comsub_IOWRITE_IOCLOB_IOHERE_noIOSKIP {
		x=$(\cat >|bar <<"EOFN" 
		foo
	EOFN
	) 
	} 
	function reread_IOWRITE_IOCLOB_IOHERE_noIOSKIP { x=$((
		cat  >|bar  <<'EOFN'
		foo
	EOFN
	)|tr u x); }
	function reread_IOWRITE_IOCLOB_IOHERE_noIOSKIP {
		x=$( ( \cat >|bar <<"EOFN" ) | \tr u x 
		foo
	EOFN
	) 
	} 
	inline_IOWRITE_noIOCLOB_IOHERE_IOSKIP() {
		cat  1>bar  <<-EOFI
		foo
		EOFI
	}
	inline_IOWRITE_noIOCLOB_IOHERE_IOSKIP() {
		\cat >bar <<-EOFI 
	foo
	EOFI
	
	} 
	function comsub_IOWRITE_noIOCLOB_IOHERE_IOSKIP { x=$(
		cat  1>bar  <<-EOFI
		foo
		EOFI
	); }
	function comsub_IOWRITE_noIOCLOB_IOHERE_IOSKIP {
		x=$(\cat >bar <<-EOFI 
	foo
	EOFI
	) 
	} 
	function reread_IOWRITE_noIOCLOB_IOHERE_IOSKIP { x=$((
		cat  1>bar  <<-EOFI
		foo
		EOFI
	)|tr u x); }
	function reread_IOWRITE_noIOCLOB_IOHERE_IOSKIP {
		x=$( ( \cat >bar <<-EOFI ) | \tr u x 
	foo
	EOFI
	) 
	} 
	inline_IORDWR_IODUP() {
		sh  1<>/dev/console  0<&1  2>&1
	}
	inline_IORDWR_IODUP() {
		\sh 1<>/dev/console <&1 2>&1 
	} 
	function comsub_IORDWR_IODUP { x=$(
		sh  1<>/dev/console  0<&1  2>&1
	); }
	function comsub_IORDWR_IODUP {
		x=$(\sh 1<>/dev/console <&1 2>&1 ) 
	} 
	function reread_IORDWR_IODUP { x=$((
		sh  1<>/dev/console  0<&1  2>&1
	)|tr u x); }
	function reread_IORDWR_IODUP {
		x=$( ( \sh 1<>/dev/console <&1 2>&1 ) | \tr u x ) 
	} 
	inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
		echo $(true) $((1+ 2)) ${  :;} ${| REPLY=x;}
	}
	inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
		\echo $(\true ) $((1+ 2)) ${ \: ;} ${|REPLY=x ;} 
	} 
	function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$(
		echo $(true) $((1+ 2)) ${  :;} ${| REPLY=x;}
	); }
	function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB {
		x=$(\echo $(\true ) $((1+ 2)) ${ \: ;} ${|REPLY=x ;} ) 
	} 
	function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$((
		echo $(true) $((1+ 2)) ${  :;} ${| REPLY=x;}
	)|tr u x); }
	function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB {
		x=$( ( \echo $(\true ) $((1+ 2)) ${ \: ;} ${|REPLY=x ;} ) | \tr u x ) 
	} 
	inline_QCHAR_OQUOTE_CQUOTE() {
		echo fo\ob\"a\`r\'b\$az
		echo "fo\ob\"a\`r\'b\$az"
		echo 'fo\ob\"a\`r'\''b\$az'
	}
	inline_QCHAR_OQUOTE_CQUOTE() {
		\echo fo\ob\"a\`r\'b\$az 
		\echo "fo\ob\"a\`r\'b\$az" 
		\echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" 
	} 
	function comsub_QCHAR_OQUOTE_CQUOTE { x=$(
		echo fo\ob\"a\`r\'b\$az
		echo "fo\ob\"a\`r\'b\$az"
		echo 'fo\ob\"a\`r'\''b\$az'
	); }
	function comsub_QCHAR_OQUOTE_CQUOTE {
		x=$(\echo fo\ob\"a\`r\'b\$az ; \echo "fo\ob\"a\`r\'b\$az" ; \echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" ) 
	} 
	function reread_QCHAR_OQUOTE_CQUOTE { x=$((
		echo fo\ob\"a\`r\'b\$az
		echo "fo\ob\"a\`r\'b\$az"
		echo 'fo\ob\"a\`r'\''b\$az'
	)|tr u x); }
	function reread_QCHAR_OQUOTE_CQUOTE {
		x=$( ( \echo fo\ob\"a\`r\'b\$az ; \echo "fo\ob\"a\`r\'b\$az" ; \echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" ) | \tr u x ) 
	} 
	inline_OSUBST_CSUBST_OPAT_SPAT_CPAT() {
		[[ ${foo#bl\(u\)b} = @(bar|baz) ]]
	}
	inline_OSUBST_CSUBST_OPAT_SPAT_CPAT() {
		[[ ${foo#bl\(u\)b} = @(bar|baz) ]] 
	} 
	function comsub_OSUBST_CSUBST_OPAT_SPAT_CPAT { x=$(
		[[ ${foo#bl\(u\)b} = @(bar|baz) ]]
	); }
	function comsub_OSUBST_CSUBST_OPAT_SPAT_CPAT {
		x=$([[ ${foo#bl\(u\)b} = @(bar|baz) ]] ) 
	} 
	function reread_OSUBST_CSUBST_OPAT_SPAT_CPAT { x=$((
		[[ ${foo#bl\(u\)b} = @(bar|baz) ]]
	)|tr u x); }
	function reread_OSUBST_CSUBST_OPAT_SPAT_CPAT {
		x=$( ( [[ ${foo#bl\(u\)b} = @(bar|baz) ]] ) | \tr u x ) 
	} 
	inline_heredoc_closed() {
		x=$(cat <<EOFN
		note there must be no space between EOFN and )
	EOFN); echo $x
	}
	inline_heredoc_closed() {
		x=$(\cat <<EOFN 
		note there must be no space between EOFN and )
	EOFN
	) 
		\echo $x 
	} 
	function comsub_heredoc_closed { x=$(
		x=$(cat <<EOFN
		note there must be no space between EOFN and )
	EOFN); echo $x
	); }
	function comsub_heredoc_closed {
		x=$(x=$(\cat <<EOFN 
		note there must be no space between EOFN and )
	EOFN
	) ; \echo $x ) 
	} 
	function reread_heredoc_closed { x=$((
		x=$(cat <<EOFN
		note there must be no space between EOFN and )
	EOFN); echo $x
	)|tr u x); }
	function reread_heredoc_closed {
		x=$( ( x=$(\cat <<EOFN 
		note there must be no space between EOFN and )
	EOFN
	) ; \echo $x ) | \tr u x ) 
	} 
	inline_heredoc_space() {
		x=$(cat <<EOFN\ 
		note the space between EOFN and ) is actually part of the here document marker
	EOFN ); echo $x
	}
	inline_heredoc_space() {
		x=$(\cat <<EOFN\  
		note the space between EOFN and ) is actually part of the here document marker
	EOFN 
	) 
		\echo $x 
	} 
	function comsub_heredoc_space { x=$(
		x=$(cat <<EOFN\ 
		note the space between EOFN and ) is actually part of the here document marker
	EOFN ); echo $x
	); }
	function comsub_heredoc_space {
		x=$(x=$(\cat <<EOFN\  
		note the space between EOFN and ) is actually part of the here document marker
	EOFN 
	) ; \echo $x ) 
	} 
	function reread_heredoc_space { x=$((
		x=$(cat <<EOFN\ 
		note the space between EOFN and ) is actually part of the here document marker
	EOFN ); echo $x
	)|tr u x); }
	function reread_heredoc_space {
		x=$( ( x=$(\cat <<EOFN\  
		note the space between EOFN and ) is actually part of the here document marker
	EOFN 
	) ; \echo $x ) | \tr u x ) 
	} 
	inline_patch_motd() {
		x=$(sysctl -n kern.version | sed 1q)
		[[ -s /etc/motd && "$([[ "$(head -1 /etc/motd)" != $x ]] && \
		    ed -s /etc/motd 2>&1 <<-EOF
			1,/^\$/d
			0a
				$x
		
			.
			wq
		EOF)" = @(?) ]] && rm -f /etc/motd
		if [[ ! -s /etc/motd ]]; then
			install -c -o root -g wheel -m 664 /dev/null /etc/motd
			print -- "$x\n" >/etc/motd
		fi
	}
	inline_patch_motd() {
		x=$(\sysctl -n kern.version | \sed 1q ) 
		[[ -s /etc/motd && "$([[ "$(\head -1 /etc/motd )" != $x ]] && \ed -s /etc/motd 2>&1 <<-EOF 
	1,/^\$/d
	0a
	$x
	
	.
	wq
	EOF
	)" = @(?) ]] && \rm -f /etc/motd 
		if [[ ! -s /etc/motd ]] 
		then
			\install -c -o root -g wheel -m 664 /dev/null /etc/motd 
			\print -- "$x\n" >/etc/motd 
		fi 
	} 
	function comsub_patch_motd { x=$(
		x=$(sysctl -n kern.version | sed 1q)
		[[ -s /etc/motd && "$([[ "$(head -1 /etc/motd)" != $x ]] && \
		    ed -s /etc/motd 2>&1 <<-EOF
			1,/^\$/d
			0a
				$x
		
			.
			wq
		EOF)" = @(?) ]] && rm -f /etc/motd
		if [[ ! -s /etc/motd ]]; then
			install -c -o root -g wheel -m 664 /dev/null /etc/motd
			print -- "$x\n" >/etc/motd
		fi
	); }
	function comsub_patch_motd {
		x=$(x=$(\sysctl -n kern.version | \sed 1q ) ; [[ -s /etc/motd && "$([[ "$(\head -1 /etc/motd )" != $x ]] && \ed -s /etc/motd 2>&1 <<-EOF 
	1,/^\$/d
	0a
	$x
	
	.
	wq
	EOF
	)" = @(?) ]] && \rm -f /etc/motd ; if [[ ! -s /etc/motd ]] ; then \install -c -o root -g wheel -m 664 /dev/null /etc/motd ; \print -- "$x\n" >/etc/motd ; fi ) 
	} 
	function reread_patch_motd { x=$((
		x=$(sysctl -n kern.version | sed 1q)
		[[ -s /etc/motd && "$([[ "$(head -1 /etc/motd)" != $x ]] && \
		    ed -s /etc/motd 2>&1 <<-EOF
			1,/^\$/d
			0a
				$x
		
			.
			wq
		EOF)" = @(?) ]] && rm -f /etc/motd
		if [[ ! -s /etc/motd ]]; then
			install -c -o root -g wheel -m 664 /dev/null /etc/motd
			print -- "$x\n" >/etc/motd
		fi
	)|tr u x); }
	function reread_patch_motd {
		x=$( ( x=$(\sysctl -n kern.version | \sed 1q ) ; [[ -s /etc/motd && "$([[ "$(\head -1 /etc/motd )" != $x ]] && \ed -s /etc/motd 2>&1 <<-EOF 
	1,/^\$/d
	0a
	$x
	
	.
	wq
	EOF
	)" = @(?) ]] && \rm -f /etc/motd ; if [[ ! -s /etc/motd ]] ; then \install -c -o root -g wheel -m 664 /dev/null /etc/motd ; \print -- "$x\n" >/etc/motd ; fi ) | \tr u x ) 
	} 
	inline_wdarrassign() {
		case x in
		x) a+=b; c+=(d e)
		esac
	}
	inline_wdarrassign() {
		case x in
		(x)
			a+=b 
			\\builtin set -A c+ -- d e 
			;;
		esac 
	} 
	function comsub_wdarrassign { x=$(
		case x in
		x) a+=b; c+=(d e)
		esac
	); }
	function comsub_wdarrassign {
		x=$(case x in (x) a+=b ; \\builtin set -A c+ -- d e  ;; esac ) 
	} 
	function reread_wdarrassign { x=$((
		case x in
		x) a+=b; c+=(d e)
		esac
	)|tr u x); }
	function reread_wdarrassign {
		x=$( ( case x in (x) a+=b ; \\builtin set -A c+ -- d e  ;; esac ) | \tr u x ) 
	} 
---
name: comsub-torture-io
description:
	Check the tree dump functions work correctly with I/O redirection
stdin:
	if [[ -z $__progname ]]; then echo >&2 call me with __progname; exit 1; fi
	while IFS= read -r line; do
		if [[ $line = '#1' ]]; then
			lastf=0
			continue
		elif [[ $line = EOFN* ]]; then
			fbody=$fbody$'\n'$line
			continue
		elif [[ $line != '#'* ]]; then
			fbody=$fbody$'\n\t'$line
			continue
		fi
		if (( lastf )); then
			x="inline_${nextf}() {"$fbody$'\n}\n'
			print -nr -- "$x"
			print -r -- "${x}typeset -f inline_$nextf" | "$__progname"
			x="function comsub_$nextf { x=\$("$fbody$'\n); }\n'
			print -nr -- "$x"
			print -r -- "${x}typeset -f comsub_$nextf" | "$__progname"
			x="function reread_$nextf { x=\$(("$fbody$'\n)|tr u x); }\n'
			print -nr -- "$x"
			print -r -- "${x}typeset -f reread_$nextf" | "$__progname"
		fi
		lastf=1
		fbody=
		nextf=${line#?}
	done <<'EOD'
	#1
	#TCOM
	vara=1  varb='2  3'  cmd  arg1  $arg2  "$arg3  4" >&3
	#TPAREN_TPIPE_TLIST
	(echo $foo  |  tr -dc 0-9 >&3; echo >&3) >&3
	#TAND_TOR
	cmd  >&3 &&  >&3 echo ja  ||  echo >&3 nein
	#TSELECT
	select  file  in  *;  do  echo  "<$file>" ;  break >&3 ;  done >&3
	#TFOR_TTIME
	for  i  in  {1,2,3}  ;  do  time  >&3 echo  $i ;  done >&3
	#TCASE
	case  $foo  in  1)  echo eins >&3;& 2) echo zwei >&3  ;| *) echo kann net bis drei zählen >&3;;  esac >&3
	#TIF_TBANG_TDBRACKET_TELIF
	if  !  [[  1  =  1  ]]  >&3 ;  then  echo eins;  elif [[ 1 = 2 ]] >&3; then echo zwei  ;else echo drei; fi >&3
	#TWHILE
	i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
	#TUNTIL
	i=10; until  (( !--i )) >&3 ; do echo $i; done >&3
	#TCOPROC
	cat  *  >&3 |&  >&3 ls
	#TFUNCT_TBRACE_TASYNC
	function  korn  {  echo eins; echo >&3 zwei ;  }
	bourne  ()  {  logger *  >&3 &  }
	#COMSUB_EXPRSUB
	echo $(true >&3) $((1+ 2))
	#0
	EOD
expected-stdout:
	inline_TCOM() {
		vara=1  varb='2  3'  cmd  arg1  $arg2  "$arg3  4" >&3
	}
	inline_TCOM() {
		vara=1 varb="2  3" \cmd arg1 $arg2 "$arg3  4" >&3 
	} 
	function comsub_TCOM { x=$(
		vara=1  varb='2  3'  cmd  arg1  $arg2  "$arg3  4" >&3
	); }
	function comsub_TCOM {
		x=$(vara=1 varb="2  3" \cmd arg1 $arg2 "$arg3  4" >&3 ) 
	} 
	function reread_TCOM { x=$((
		vara=1  varb='2  3'  cmd  arg1  $arg2  "$arg3  4" >&3
	)|tr u x); }
	function reread_TCOM {
		x=$( ( vara=1 varb="2  3" \cmd arg1 $arg2 "$arg3  4" >&3 ) | \tr u x ) 
	} 
	inline_TPAREN_TPIPE_TLIST() {
		(echo $foo  |  tr -dc 0-9 >&3; echo >&3) >&3
	}
	inline_TPAREN_TPIPE_TLIST() {
		( \echo $foo | \tr -dc 0-9 >&3 
		  \echo >&3 ) >&3 
	} 
	function comsub_TPAREN_TPIPE_TLIST { x=$(
		(echo $foo  |  tr -dc 0-9 >&3; echo >&3) >&3
	); }
	function comsub_TPAREN_TPIPE_TLIST {
		x=$( ( \echo $foo | \tr -dc 0-9 >&3 ; \echo >&3 ) >&3 ) 
	} 
	function reread_TPAREN_TPIPE_TLIST { x=$((
		(echo $foo  |  tr -dc 0-9 >&3; echo >&3) >&3
	)|tr u x); }
	function reread_TPAREN_TPIPE_TLIST {
		x=$( ( ( \echo $foo | \tr -dc 0-9 >&3 ; \echo >&3 ) >&3 ) | \tr u x ) 
	} 
	inline_TAND_TOR() {
		cmd  >&3 &&  >&3 echo ja  ||  echo >&3 nein
	}
	inline_TAND_TOR() {
		\cmd >&3 && \echo ja >&3 || \echo nein >&3 
	} 
	function comsub_TAND_TOR { x=$(
		cmd  >&3 &&  >&3 echo ja  ||  echo >&3 nein
	); }
	function comsub_TAND_TOR {
		x=$(\cmd >&3 && \echo ja >&3 || \echo nein >&3 ) 
	} 
	function reread_TAND_TOR { x=$((
		cmd  >&3 &&  >&3 echo ja  ||  echo >&3 nein
	)|tr u x); }
	function reread_TAND_TOR {
		x=$( ( \cmd >&3 && \echo ja >&3 || \echo nein >&3 ) | \tr u x ) 
	} 
	inline_TSELECT() {
		select  file  in  *;  do  echo  "<$file>" ;  break >&3 ;  done >&3
	}
	inline_TSELECT() {
		select file in * 
		do
			\echo "<$file>" 
			\break >&3 
		done >&3 
	} 
	function comsub_TSELECT { x=$(
		select  file  in  *;  do  echo  "<$file>" ;  break >&3 ;  done >&3
	); }
	function comsub_TSELECT {
		x=$(select file in * ; do \echo "<$file>" ; \break >&3 ; done >&3 ) 
	} 
	function reread_TSELECT { x=$((
		select  file  in  *;  do  echo  "<$file>" ;  break >&3 ;  done >&3
	)|tr u x); }
	function reread_TSELECT {
		x=$( ( select file in * ; do \echo "<$file>" ; \break >&3 ; done >&3 ) | \tr u x ) 
	} 
	inline_TFOR_TTIME() {
		for  i  in  {1,2,3}  ;  do  time  >&3 echo  $i ;  done >&3
	}
	inline_TFOR_TTIME() {
		for i in {1,2,3} 
		do
			time \echo $i >&3 
		done >&3 
	} 
	function comsub_TFOR_TTIME { x=$(
		for  i  in  {1,2,3}  ;  do  time  >&3 echo  $i ;  done >&3
	); }
	function comsub_TFOR_TTIME {
		x=$(for i in {1,2,3} ; do time \echo $i >&3 ; done >&3 ) 
	} 
	function reread_TFOR_TTIME { x=$((
		for  i  in  {1,2,3}  ;  do  time  >&3 echo  $i ;  done >&3
	)|tr u x); }
	function reread_TFOR_TTIME {
		x=$( ( for i in {1,2,3} ; do time \echo $i >&3 ; done >&3 ) | \tr u x ) 
	} 
	inline_TCASE() {
		case  $foo  in  1)  echo eins >&3;& 2) echo zwei >&3  ;| *) echo kann net bis drei zählen >&3;;  esac >&3
	}
	inline_TCASE() {
		case $foo in
		(1)
			\echo eins >&3 
			;&
		(2)
			\echo zwei >&3 
			;|
		(*)
			\echo kann net bis drei zählen >&3 
			;;
		esac >&3 
	} 
	function comsub_TCASE { x=$(
		case  $foo  in  1)  echo eins >&3;& 2) echo zwei >&3  ;| *) echo kann net bis drei zählen >&3;;  esac >&3
	); }
	function comsub_TCASE {
		x=$(case $foo in (1) \echo eins >&3  ;& (2) \echo zwei >&3  ;| (*) \echo kann net bis drei zählen >&3  ;; esac >&3 ) 
	} 
	function reread_TCASE { x=$((
		case  $foo  in  1)  echo eins >&3;& 2) echo zwei >&3  ;| *) echo kann net bis drei zählen >&3;;  esac >&3
	)|tr u x); }
	function reread_TCASE {
		x=$( ( case $foo in (1) \echo eins >&3  ;& (2) \echo zwei >&3  ;| (*) \echo kann net bis drei zählen >&3  ;; esac >&3 ) | \tr u x ) 
	} 
	inline_TIF_TBANG_TDBRACKET_TELIF() {
		if  !  [[  1  =  1  ]]  >&3 ;  then  echo eins;  elif [[ 1 = 2 ]] >&3; then echo zwei  ;else echo drei; fi >&3
	}
	inline_TIF_TBANG_TDBRACKET_TELIF() {
		if ! [[ 1 = 1 ]] >&3 
		then
			\echo eins 
		elif [[ 1 = 2 ]] >&3 
		then
			\echo zwei 
		else
			\echo drei 
		fi >&3 
	} 
	function comsub_TIF_TBANG_TDBRACKET_TELIF { x=$(
		if  !  [[  1  =  1  ]]  >&3 ;  then  echo eins;  elif [[ 1 = 2 ]] >&3; then echo zwei  ;else echo drei; fi >&3
	); }
	function comsub_TIF_TBANG_TDBRACKET_TELIF {
		x=$(if ! [[ 1 = 1 ]] >&3 ; then \echo eins ; elif [[ 1 = 2 ]] >&3 ; then \echo zwei ; else \echo drei ; fi >&3 ) 
	} 
	function reread_TIF_TBANG_TDBRACKET_TELIF { x=$((
		if  !  [[  1  =  1  ]]  >&3 ;  then  echo eins;  elif [[ 1 = 2 ]] >&3; then echo zwei  ;else echo drei; fi >&3
	)|tr u x); }
	function reread_TIF_TBANG_TDBRACKET_TELIF {
		x=$( ( if ! [[ 1 = 1 ]] >&3 ; then \echo eins ; elif [[ 1 = 2 ]] >&3 ; then \echo zwei ; else \echo drei ; fi >&3 ) | \tr u x ) 
	} 
	inline_TWHILE() {
		i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
	}
	inline_TWHILE() {
		i=1 
		while {
			      \\builtin let " i < 10 " 
		      } >&3 
		do
			\echo $i 
			\let ++i 
		done >&3 
	} 
	function comsub_TWHILE { x=$(
		i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
	); }
	function comsub_TWHILE {
		x=$(i=1 ; while { \\builtin let " i < 10 " ; } >&3 ; do \echo $i ; \let ++i ; done >&3 ) 
	} 
	function reread_TWHILE { x=$((
		i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
	)|tr u x); }
	function reread_TWHILE {
		x=$( ( i=1 ; while { \\builtin let " i < 10 " ; } >&3 ; do \echo $i ; \let ++i ; done >&3 ) | \tr u x ) 
	} 
	inline_TUNTIL() {
		i=10; until  (( !--i )) >&3 ; do echo $i; done >&3
	}
	inline_TUNTIL() {
		i=10 
		until {
			      \\builtin let " !--i " 
		      } >&3 
		do
			\echo $i 
		done >&3 
	} 
	function comsub_TUNTIL { x=$(
		i=10; until  (( !--i )) >&3 ; do echo $i; done >&3
	); }
	function comsub_TUNTIL {
		x=$(i=10 ; until { \\builtin let " !--i " ; } >&3 ; do \echo $i ; done >&3 ) 
	} 
	function reread_TUNTIL { x=$((
		i=10; until  (( !--i )) >&3 ; do echo $i; done >&3
	)|tr u x); }
	function reread_TUNTIL {
		x=$( ( i=10 ; until { \\builtin let " !--i " ; } >&3 ; do \echo $i ; done >&3 ) | \tr u x ) 
	} 
	inline_TCOPROC() {
		cat  *  >&3 |&  >&3 ls
	}
	inline_TCOPROC() {
		\cat * >&3 |& 
		\ls >&3 
	} 
	function comsub_TCOPROC { x=$(
		cat  *  >&3 |&  >&3 ls
	); }
	function comsub_TCOPROC {
		x=$(\cat * >&3 |&  \ls >&3 ) 
	} 
	function reread_TCOPROC { x=$((
		cat  *  >&3 |&  >&3 ls
	)|tr u x); }
	function reread_TCOPROC {
		x=$( ( \cat * >&3 |&  \ls >&3 ) | \tr u x ) 
	} 
	inline_TFUNCT_TBRACE_TASYNC() {
		function  korn  {  echo eins; echo >&3 zwei ;  }
		bourne  ()  {  logger *  >&3 &  }
	}
	inline_TFUNCT_TBRACE_TASYNC() {
		function korn {
			\echo eins 
			\echo zwei >&3 
		} 
		bourne() {
			\logger * >&3 & 
		} 
	} 
	function comsub_TFUNCT_TBRACE_TASYNC { x=$(
		function  korn  {  echo eins; echo >&3 zwei ;  }
		bourne  ()  {  logger *  >&3 &  }
	); }
	function comsub_TFUNCT_TBRACE_TASYNC {
		x=$(function korn { \echo eins ; \echo zwei >&3 ; } ; bourne() { \logger * >&3 &  } ) 
	} 
	function reread_TFUNCT_TBRACE_TASYNC { x=$((
		function  korn  {  echo eins; echo >&3 zwei ;  }
		bourne  ()  {  logger *  >&3 &  }
	)|tr u x); }
	function reread_TFUNCT_TBRACE_TASYNC {
		x=$( ( function korn { \echo eins ; \echo zwei >&3 ; } ; bourne() { \logger * >&3 &  } ) | \tr u x ) 
	} 
	inline_COMSUB_EXPRSUB() {
		echo $(true >&3) $((1+ 2))
	}
	inline_COMSUB_EXPRSUB() {
		\echo $(\true >&3 ) $((1+ 2)) 
	} 
	function comsub_COMSUB_EXPRSUB { x=$(
		echo $(true >&3) $((1+ 2))
	); }
	function comsub_COMSUB_EXPRSUB {
		x=$(\echo $(\true >&3 ) $((1+ 2)) ) 
	} 
	function reread_COMSUB_EXPRSUB { x=$((
		echo $(true >&3) $((1+ 2))
	)|tr u x); }
	function reread_COMSUB_EXPRSUB {
		x=$( ( \echo $(\true >&3 ) $((1+ 2)) ) | \tr u x ) 
	} 
---
name: funsub-1
description:
	Check that non-subenvironment command substitution works
stdin:
	set -e
	foo=bar
	echo "ob $foo ."
	echo "${
		echo "ib $foo :"
		foo=baz
		echo "ia $foo :"
		false
	}" .
	echo "oa $foo ."
expected-stdout:
	ob bar .
	ib bar :
	ia baz : .
	oa baz .
---
name: funsub-2
description:
	You can now reliably use local and return in funsubs
	(not exit though)
stdin:
	x=q; e=1; x=${ echo a; e=2; echo x$e;}; echo 1:y$x,$e,$?.
	x=q; e=1; x=${ echo a; typeset e=2; echo x$e;}; echo 2:y$x,$e,$?.
	x=q; e=1; x=${ echo a; typeset e=2; return 3; echo x$e;}; echo 3:y$x,$e,$?.
expected-stdout:
	1:ya x2,2,0.
	2:ya x2,1,0.
	3:ya,1,3.
---
name: valsub-1
description:
	Check that "value substitutions" work as advertised
stdin:
	x=1
	y=2
	z=3
	REPLY=4
	echo "before:	x<$x> y<$y> z<$z> R<$REPLY>"
	x=${|
		local y
		echo "start:	x<$x> y<$y> z<$z> R<$REPLY>"
		x=5
		y=6
		z=7
		REPLY=8
		echo "end:	x<$x> y<$y> z<$z> R<$REPLY>"
	}
	echo "after:	x<$x> y<$y> z<$z> R<$REPLY>"
	# ensure trailing newlines are kept
	t=${|REPLY=$'foo\n\n';}
	typeset -p t
	echo -n this used to segfault
	echo ${|true;}$(true).
expected-stdout:
	before:	x<1> y<2> z<3> R<4>
	start:	x<1> y<> z<3> R<>
	end:	x<5> y<6> z<7> R<8>
	after:	x<8> y<2> z<7> R<4>
	typeset t=$'foo\n\n'
	this used to segfault.
---
name: event-subst-3
description:
	Check that '!' substitution in noninteractive mode is ignored
file-setup: file 755 "falsetto"
	#! /bin/sh
	echo molto bene
	exit 42
file-setup: file 755 "!false"
	#! /bin/sh
	echo si
stdin:
	export PATH=.$PATHSEP$PATH
	falsetto
	echo yeap
	!false
	echo meow
	! false
	echo = $?
	if
	! false; then echo foo; else echo bar; fi
expected-stdout:
	molto bene
	yeap
	si
	meow
	= 0
	foo
---
name: event-subst-0
description:
	Check that '!' substitution in interactive mode is ignored
need-ctty: yes
arguments: !-i!
file-setup: file 755 "falsetto"
	#! /bin/sh
	echo molto bene
	exit 42
file-setup: file 755 "!false"
	#! /bin/sh
	echo si
stdin:
	export PATH=.$PATHSEP$PATH
	falsetto
	echo yeap
	!false
	echo meow
	! false
	echo = $?
	if
	! false; then echo foo; else echo bar; fi
expected-stdout:
	molto bene
	yeap
	si
	meow
	= 0
	foo
expected-stderr-pattern:
	/.*/
---
name: nounset-1
description:
	Check that "set -u" matches (future) SUSv4 requirement
stdin:
	(set -u
	try() {
		local v
		eval v=\$$1
		if [[ -n $v ]]; then
			echo $1=nz
		else
			echo $1=zf
		fi
	}
	x=y
	(echo $x)
	echo =1
	(echo $y)
	echo =2
	(try x)
	echo =3
	(try y)
	echo =4
	(try 0)
	echo =5
	(try 2)
	echo =6
	(try)
	echo =7
	(echo at=$@)
	echo =8
	(echo asterisk=$*)
	echo =9
	(echo $?)
	echo =10
	(echo $!)
	echo =11
	(echo $-)
	echo =12
	#(echo $_)
	#echo =13
	(echo $#)
	echo =14
	(mypid=$$; try mypid)
	echo =15
	) 2>&1 | sed -e 's/^[A-Za-z]://' -e 's/^[^]]*]//' -e 's/^[^:]*: *//'
	exit ${PIPESTATUS[0]}
expected-stdout:
	y
	=1
	y: parameter not set
	=2
	x=nz
	=3
	y: parameter not set
	=4
	0=nz
	=5
	2: parameter not set
	=6
	1: parameter not set
	=7
	at=
	=8
	asterisk=
	=9
	0
	=10
	!: parameter not set
	=11
	ush
	=12
	0
	=14
	mypid=nz
	=15
---
name: nameref-1
description:
	Testsuite for nameref (bound variables)
stdin:
	bar=global
	typeset -n ir2=bar
	typeset -n ind=ir2
	echo !ind: ${!ind}
	echo ind: $ind
	echo !ir2: ${!ir2}
	echo ir2: $ir2
	typeset +n ind
	echo !ind: ${!ind}
	echo ind: $ind
	typeset -n ir2=ind
	echo !ir2: ${!ir2}
	echo ir2: $ir2
	set|grep ^ir2|sed 's/^/s1: /'
	typeset|grep ' ir2'|sed -e 's/^/s2: /' -e 's/nameref/typeset -n/'
	set -A blub -- e1 e2 e3
	typeset -n ind=blub
	typeset -n ir2=blub[2]
	echo !ind[1]: ${!ind[1]}
	echo !ir2: $!ir2
	echo ind[1]: ${ind[1]}
	echo ir2: $ir2
expected-stdout:
	!ind: bar
	ind: global
	!ir2: bar
	ir2: global
	!ind: ind
	ind: ir2
	!ir2: ind
	ir2: ir2
	s1: ir2=ind
	s2: typeset -n ir2
	!ind[1]: blub[1]
	!ir2: ir2
	ind[1]: e2
	ir2: e3
---
name: nameref-2da
description:
	Testsuite for nameref (bound variables)
	Functions, argument given directly, after local
stdin:
	function foo {
		typeset bar=lokal baz=auch
		typeset -n v=bar
		echo entering
		echo !v: ${!v}
		echo !bar: ${!bar}
		echo !baz: ${!baz}
		echo bar: $bar
		echo v: $v
		v=123
		echo bar: $bar
		echo v: $v
		echo exiting
	}
	bar=global
	echo bar: $bar
	foo bar
	echo bar: $bar
expected-stdout:
	bar: global
	entering
	!v: bar
	!bar: bar
	!baz: baz
	bar: lokal
	v: lokal
	bar: 123
	v: 123
	exiting
	bar: global
---
name: nameref-3
description:
	Advanced testsuite for bound variables (ksh93 fails this)
stdin:
	typeset -n foo=bar[i]
	set -A bar -- b c a
	for i in 0 1 2 3; do
		print $i $foo .
	done
expected-stdout:
	0 b .
	1 c .
	2 a .
	3 .
---
name: nameref-4
description:
	Ensure we don't run in an infinite loop
time-limit: 3
stdin:
	baz() {
		typeset -n foo=fnord fnord=foo
		foo[0]=bar
	}
	set -A foo bad
	echo sind $foo .
	baz
	echo blah $foo .
expected-stdout:
	sind bad .
	blah bad .
expected-stderr-pattern:
	/fnord: expression recurses on parameter/
---
name: better-parens-1a
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	if ( (echo fubar)|tr u x); then
		echo ja
	else
		echo nein
	fi
expected-stdout:
	fxbar
	ja
---
name: better-parens-1b
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	echo $( (echo fubar)|tr u x) $?
expected-stdout:
	fxbar 0
---
name: better-parens-1c
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	x=$( (echo fubar)|tr u x); echo $x $?
expected-stdout:
	fxbar 0
---
name: better-parens-2a
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	if ((echo fubar)|tr u x); then
		echo ja
	else
		echo nein
	fi
expected-stdout:
	fxbar
	ja
---
name: better-parens-2b
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	echo $((echo fubar)|tr u x) $?
expected-stdout:
	fxbar 0
---
name: better-parens-2c
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	x=$((echo fubar)|tr u x); echo $x $?
expected-stdout:
	fxbar 0
---
name: better-parens-3a
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	if ( (echo fubar)|(tr u x)); then
		echo ja
	else
		echo nein
	fi
expected-stdout:
	fxbar
	ja
---
name: better-parens-3b
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	echo $( (echo fubar)|(tr u x)) $?
expected-stdout:
	fxbar 0
---
name: better-parens-3c
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	x=$( (echo fubar)|(tr u x)); echo $x $?
expected-stdout:
	fxbar 0
---
name: better-parens-4a
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	if ((echo fubar)|(tr u x)); then
		echo ja
	else
		echo nein
	fi
expected-stdout:
	fxbar
	ja
---
name: better-parens-4b
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	echo $((echo fubar)|(tr u x)) $?
expected-stdout:
	fxbar 0
---
name: better-parens-4c
description:
	Check support for ((…)) and $((…)) vs (…) and $(…)
stdin:
	x=$((echo fubar)|(tr u x)); echo $x $?
expected-stdout:
	fxbar 0
---
name: better-parens-5
description:
	Another corner case
stdin:
	( (echo 'fo	o$bar' "baz\$bla\"" m\$eh) | tr a A)
	((echo 'fo	o$bar' "baz\$bla\"" m\$eh) | tr a A)
expected-stdout:
	fo	o$bAr bAz$blA" m$eh
	fo	o$bAr bAz$blA" m$eh
---
name: echo-test-1
description:
	Test what the echo builtin does (mksh)
category: !shell:ebcdic-yes
stdin:
	echo -n 'foo\x40bar'
	echo -e '\tbaz'
expected-stdout:
	foo@bar	baz
---
name: echo-test-1-ebcdic
description:
	Test what the echo builtin does (mksh)
category: !shell:ebcdic-no
stdin:
	echo -n 'foo\x7Cbar'
	echo -e '\tbaz'
expected-stdout:
	foo@bar	baz
---
name: echo-test-2
description:
	Test what the echo builtin does (POSIX)
	Note: this follows Debian Policy 10.4 which mandates
	that -n shall be treated as an option, not XSI which
	mandates it shall be treated as string but escapes
	shall be expanded.
stdin:
	test -n "$POSH_VERSION" || set -o posix
	echo -n 'foo\x40bar'
	echo -e '\tbaz'
expected-stdout:
	foo\x40bar-e \tbaz
---
name: echo-test-3-mnbsd
description:
	Test what the echo builtin does, and test a compatibility flag.
category: mnbsdash
stdin:
	"$__progname" -c 'echo -n 1=\\x40$1; echo -e \\x2E' -- foo bar
	"$__progname" -o posix -c 'echo -n 2=\\x40$1; echo -e \\x2E' -- foo bar
	"$__progname" -o sh -c 'echo -n 3=\\x40$1; echo -e \\x2E' -- foo bar
expected-stdout:
	1=@foo.
	2=\x40foo-e \x2E
	3=\x40bar.
---
name: echo-test-3-normal
description:
	Test what the echo builtin does, and test a compatibility flag.
category: !mnbsdash,!shell:ebcdic-yes
stdin:
	"$__progname" -c 'echo -n 1=\\x40$1; echo -e \\x2E' -- foo bar
	"$__progname" -o posix -c 'echo -n 2=\\x40$1; echo -e \\x2E' -- foo bar
	"$__progname" -o sh -c 'echo -n 3=\\x40$1; echo -e \\x2E' -- foo bar
expected-stdout:
	1=@foo.
	2=\x40foo-e \x2E
	3=\x40foo-e \x2E
---
name: echo-test-3-ebcdic
description:
	Test what the echo builtin does, and test a compatibility flag.
category: !mnbsdash,!shell:ebcdic-no
stdin:
	"$__progname" -c 'echo -n 1=\\x7C$1; echo -e \\x4B' -- foo bar
	"$__progname" -o posix -c 'echo -n 2=\\x7C$1; echo -e \\x4B' -- foo bar
	"$__progname" -o sh -c 'echo -n 3=\\x7C$1; echo -e \\x4B' -- foo bar
expected-stdout:
	1=@foo.
	2=\x7Cfoo-e \x4B
	3=\x7Cfoo-e \x4B
---
name: utilities-getopts-1
description:
	getopts sets OPTIND correctly for unparsed option
stdin:
	set -- -a -a -x
	while getopts :a optc; do
	    echo "OPTARG=$OPTARG, OPTIND=$OPTIND, optc=$optc."
	done
	echo done
expected-stdout:
	OPTARG=, OPTIND=2, optc=a.
	OPTARG=, OPTIND=3, optc=a.
	OPTARG=x, OPTIND=4, optc=?.
	done
---
name: utilities-getopts-2
description:
	Check OPTARG
stdin:
	set -- -a Mary -x
	while getopts a: optc; do
	    echo "OPTARG=$OPTARG, OPTIND=$OPTIND, optc=$optc."
	done
	echo done
expected-stdout:
	OPTARG=Mary, OPTIND=3, optc=a.
	OPTARG=, OPTIND=4, optc=?.
	done
expected-stderr-pattern: /.*-x.*option/
---
name: utilities-getopts-3
description:
	Check unsetting OPTARG
stdin:
	set -- -x arg -y
	getopts x:y opt && echo "${OPTARG-unset}"
	getopts x:y opt && echo "${OPTARG-unset}"
expected-stdout:
	arg
	unset
---
name: wcswidth-1
description:
	Check the new wcswidth feature
stdin:
	s=何
	set +U
	print octets: ${#s} .
	print 8-bit width: ${%s} .
	set -U
	print characters: ${#s} .
	print columns: ${%s} .
	s=�
	set +U
	print octets: ${#s} .
	print 8-bit width: ${%s} .
	set -U
	print characters: ${#s} .
	print columns: ${%s} .
expected-stdout:
	octets: 3 .
	8-bit width: -1 .
	characters: 1 .
	columns: 2 .
	octets: 3 .
	8-bit width: 3 .
	characters: 1 .
	columns: 1 .
---
name: wcswidth-2
description:
	Check some corner cases
stdin:
	print % $% .
	set -U
	x='a	b'
	print c ${%x} .
	set +U
	x='a	b'
	print d ${%x} .
expected-stdout:
	% $% .
	c -1 .
	d -1 .
---
name: wcswidth-3
description:
	Check some corner cases
stdin:
	print ${%} .
expected-stderr-pattern:
	/bad substitution/
expected-exit: 1
---
name: wcswidth-4a
description:
	Check some corner cases
stdin:
	print ${%*} .
expected-stderr-pattern:
	/bad substitution/
expected-exit: 1
---
name: wcswidth-4b
description:
	Check some corner cases
stdin:
	print ${%@} .
expected-stderr-pattern:
	/bad substitution/
expected-exit: 1
---
name: wcswidth-4c
description:
	Check some corner cases
stdin:
	:
	print ${%?} .
expected-stdout:
	1 .
---
name: realpath-1
description:
	Check proper return values for realpath
category: os:mirbsd
stdin:
	wd=$(realpath .)
	mkdir dir
	:>file
	:>dir/file
	ln -s dir lndir
	ln -s file lnfile
	ln -s nix lnnix
	ln -s . lnself
	i=0
	chk() {
		typeset x y
		x=$(realpath "$wd/$1" 2>&1); y=$?
		print $((++i)) "?$1" =${x##*$wd/} !$y
	}
	chk dir
	chk dir/
	chk dir/file
	chk dir/nix
	chk file
	chk file/
	chk file/file
	chk file/nix
	chk nix
	chk nix/
	chk nix/file
	chk nix/nix
	chk lndir
	chk lndir/
	chk lndir/file
	chk lndir/nix
	chk lnfile
	chk lnfile/
	chk lnfile/file
	chk lnfile/nix
	chk lnnix
	chk lnnix/
	chk lnnix/file
	chk lnnix/nix
	chk lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself
	rm lnself
expected-stdout:
	1 ?dir =dir !0
	2 ?dir/ =dir !0
	3 ?dir/file =dir/file !0
	4 ?dir/nix =dir/nix !0
	5 ?file =file !0
	6 ?file/ =file/: Not a directory !20
	7 ?file/file =file/file: Not a directory !20
	8 ?file/nix =file/nix: Not a directory !20
	9 ?nix =nix !0
	10 ?nix/ =nix !0
	11 ?nix/file =nix/file: No such file or directory !2
	12 ?nix/nix =nix/nix: No such file or directory !2
	13 ?lndir =dir !0
	14 ?lndir/ =dir !0
	15 ?lndir/file =dir/file !0
	16 ?lndir/nix =dir/nix !0
	17 ?lnfile =file !0
	18 ?lnfile/ =lnfile/: Not a directory !20
	19 ?lnfile/file =lnfile/file: Not a directory !20
	20 ?lnfile/nix =lnfile/nix: Not a directory !20
	21 ?lnnix =nix !0
	22 ?lnnix/ =nix !0
	23 ?lnnix/file =lnnix/file: No such file or directory !2
	24 ?lnnix/nix =lnnix/nix: No such file or directory !2
	25 ?lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself =lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself: Too many levels of symbolic links !62
---
name: realpath-2
description:
	Ensure that exactly two leading slashes are not collapsed
	POSIX guarantees this exception, e.g. for UNC paths on Cygwin
category: os:mirbsd
stdin:
	ln -s /bin t1
	ln -s //bin t2
	ln -s ///bin t3
	realpath /bin
	realpath //bin
	realpath ///bin
	realpath /usr/bin
	realpath /usr//bin
	realpath /usr///bin
	realpath t1
	realpath t2
	realpath t3
	rm -f t1 t2 t3
	cd //usr/bin
	pwd
	cd ../lib
	pwd
	realpath //usr/include/../bin
expected-stdout:
	/bin
	//bin
	/bin
	/usr/bin
	/usr/bin
	/usr/bin
	/bin
	//bin
	/bin
	//usr/bin
	//usr/lib
	//usr/bin
---
name: crash-1
description:
	Crashed during March 2011, fixed on vernal equinōx ☺
category: os:mirbsd,os:openbsd
stdin:
	export MALLOC_OPTIONS=FGJRSX
	"$__progname" -c 'x=$(tr z r <<<baz); echo $x'
expected-stdout:
	bar
---
name: debian-117-1
description:
	Check test - bug#465250
stdin:
	test \( ! -e \) ; echo $?
expected-stdout:
	1
---
name: debian-117-2
description:
	Check test - bug#465250
stdin:
	test \(  -e \) ; echo $?
expected-stdout:
	0
---
name: debian-117-3
description:
	Check test - bug#465250
stdin:
	test ! -e  ; echo $?
expected-stdout:
	1
---
name: debian-117-4
description:
	Check test - bug#465250
stdin:
	test  -e  ; echo $?
expected-stdout:
	0
---
name: case-zsh
description:
	Check that zsh case variants work
stdin:
	case 'b' in
	  a) echo a ;;
	  b) echo b ;;
	  c) echo c ;;
	  *) echo x ;;
	esac
	echo =
	case 'b' in
	  a) echo a ;&
	  b) echo b ;&
	  c) echo c ;&
	  *) echo x ;&
	esac
	echo =
	case 'b' in
	  a) echo a ;|
	  b) echo b ;|
	  c) echo c ;|
	  *) echo x ;|
	esac
expected-stdout:
	b
	=
	b
	c
	x
	=
	b
	x
---
name: case-braces
description:
	Check that case end tokens are not mixed up (Debian #220272)
stdin:
	i=0
	for value in 'x' '}' 'esac'; do
		print -n "$((++i))($value)bourne "
		case $value in
		}) echo brace ;;
		*) echo no ;;
		esac
		print -n "$((++i))($value)korn "
		case $value {
		esac) echo esac ;;
		*) echo no ;;
		}
	done
expected-stdout:
	1(x)bourne no
	2(x)korn no
	3(})bourne brace
	4(})korn no
	5(esac)bourne no
	6(esac)korn esac
---
name: command-shift
description:
	Check that 'command shift' works
stdin:
	function snc {
		echo "before	0='$0' 1='$1' 2='$2'"
		shift
		echo "after	0='$0' 1='$1' 2='$2'"
	}
	function swc {
		echo "before	0='$0' 1='$1' 2='$2'"
		command shift
		echo "after	0='$0' 1='$1' 2='$2'"
	}
	echo = without command
	snc 一 二
	echo = with command
	swc 一 二
	echo = done
expected-stdout:
	= without command
	before	0='snc' 1='一' 2='二'
	after	0='snc' 1='二' 2=''
	= with command
	before	0='swc' 1='一' 2='二'
	after	0='swc' 1='二' 2=''
	= done
---
name: command-set
description:
	Same but with set
stdin:
	showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
	showargs 1 "$@"
	set -- foo bar baz
	showargs 2 "$@"
	command set -- miau 'meow nyao'
	showargs 3 "$@"
expected-stdout:
	<1> .
	<2> <foo> <bar> <baz> .
	<3> <miau> <meow nyao> .
---
name: command-readonly
description:
	These should not exit on error when prefixed
stdin:
	exec 2>/dev/null
	"$__progname" -c 'readonly v; export v=foo || echo ok'
	echo ef=$?
	"$__progname" -c 'readonly v; command export v=foo || echo ok'
	echo en=$?
	"$__progname" -c 'readonly v; readonly v=foo || echo ok'
	echo rf=$?
	"$__progname" -c 'readonly v; command readonly v=foo || echo ok'
	echo rn=$?
expected-stdout:
	ef=2
	ok
	en=0
	rf=2
	ok
	rn=0
---
name: command-dot-regression
description:
	Check a regression in fixing the above does not appear
stdin:
	cat >test.mksh <<\EOF
	set -- one two
	shift
	for s_arg in "$#" "$@"; do echo -n "<$s_arg> "; done; echo .
	EOF
	"$__progname" -c '. ./test.mksh' dummy oh dear this is not good
	echo =
	"$__progname" -c 'command . ./test.mksh' dummy oh dear this is not good
expected-stdout:
	<1> <two> .
	=
	<1> <two> .
---
name: command-pvV-posix-priorities
description:
	For POSIX compatibility, command -v should find aliases and reserved
	words, and command -p[vV] should find aliases, reserved words, and
	builtins over external commands.
stdin:
	# extra checks prep
	mkdir mrr
	:>mrr/miau
	chmod +x mrr/miau
	# priorities
	PATH=/bin:/usr/bin
	alias foo="bar baz"
	alias '[ab]=:'
	bar() { :; }
	for word in 'if' 'foo' 'bar' 'set' 'true' '[ab]'; do
		command -v "$word"
		command -pv "$word"
		command -V "$word"
		command -pV "$word"
	done
	# extra checks
	alias '[ab]'
	whence '[ab]'
	PATH=mrr
	case $(command -v miau) {
	(mrr/miau) echo fail ;;
	(!(/*|[A-Z]:/*)) echo fail2 ;;
	($PWD/mrr/miau) echo ok ;;
	(/*|[A-Z]:/*) echo pwd bad? ;;
	(*) echo not reached ;;
	}
expected-stdout:
	if
	if
	if is a reserved word
	if is a reserved word
	alias foo='bar baz'
	alias foo='bar baz'
	foo is an alias for 'bar baz'
	foo is an alias for 'bar baz'
	bar
	bar
	bar is a function
	bar is a function
	set
	set
	set is a special shell builtin
	set is a special shell builtin
	true
	true
	true is a shell builtin
	true is a shell builtin
	alias '[ab]'=:
	alias '[ab]'=:
	'[ab]' is an alias for :
	'[ab]' is an alias for :
	'[ab]'=:
	:
	ok
---
name: whence-preserve-tradition
description:
	This regression test is to ensure that the POSIX compatibility
	changes for 'command' (see previous test) do not affect traditional
	'whence' behaviour.
category: os:mirbsd
stdin:
	PATH=/bin:/usr/bin
	alias foo="bar baz"
	bar() { :; }
	for word in 'if' 'foo' 'bar' 'set' 'true'; do
		whence "$word"
		whence -p "$word"
		whence -v "$word"
		whence -pv "$word"
	done
expected-stdout:
	if
	if is a reserved word
	if not found
	'bar baz'
	foo is an alias for 'bar baz'
	foo not found
	bar
	bar is a function
	bar not found
	set
	set is a special shell builtin
	set not found
	true
	/bin/true
	true is a shell builtin
	true is a tracked alias for /bin/true
---
name: duffs-device
description:
	Check that the compiler did not optimise-break them
	(lex.c has got a similar one in SHEREDELIM)
category: !shell:faux-ebcdic,!shell:ebcdic-yes
stdin:
	set +U
	s=
	typeset -i1 i=0
	while (( ++i < 256 )); do
		s+=${i#1#}
	done
	s+=$'\xC2\xA0\xE2\x82\xAC\xEF\xBF\xBD\xEF\xBF\xBE\xEF\xBF\xBF\xF0\x90\x80\x80.'
	typeset -p s
expected-stdout:
	typeset s=$'\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\E\034\035\036\037 !"#$%&\047()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\u00A0\u20AC\uFFFD\357\277\276\357\277\277\360\220\200\200.'
---
name: duffs-device-ebcdic
description:
	Check that the compiler did not optimise-break them
category: !shell:ebcdic-no
stdin:
	set +U
	s=
	typeset -i1 i=0
	while (( ++i < 256 )); do
		s+=${i#1#}
	done
	#s+=$'\xC2\xA0\xE2\x82\xAC\xEF\xBF\xBD\xEF\xBF\xBE\xEF\xBF\xBF\xF0\x90\x80\x80.' #XXX
	typeset -p s
expected-stdout:
	typeset s=$'\001\002\003\004\t\006\007\010\011\012\v\f\r\016\017\020\021\022\023\024\n\b\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\E\050\051\052\053\054\055\056\a\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077 .<(+|&!$*);^-/Ѧ,%_>?`:#@\175="abcdefghijklmnopqrƤ~stuvwxyz[ޮݨ]{ABCDEFGHI}JKLMNOPQR\\STUVWXYZ0123456789\377'
---
name: duffs-device-faux-EBCDIC
description:
	Check that the compiler did not optimise-break them
category: shell:faux-ebcdic
stdin:
	set +U
	s=
	typeset -i1 i=0
	while (( ++i < 256 )); do
		s+=${i#1#}
	done
	s+=$'\xC2\xA0\xE2\x82\xAC\xEF\xBF\xBD\xEF\xBF\xBE\xEF\xBF\xBF\xF0\x90\x80\x80.'
	typeset -p s
expected-stdout:
	typeset s=$'\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\E\034\035\036\037 !"#$%&\047()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\u00A0\u20AC\uFFFD￾￿\220\200\200.'
---
name: stateptr-underflow
description:
	This check overflows an Xrestpos stored in a short in R40
category: fastbox
stdin:
	function Lb64decode {
		[[ -o utf8-mode ]]; local u=$?
		set +U
		local c s="$*" t=
		[[ -n $s ]] || { s=$(cat;print x); s=${s%x}; }
		local -i i=0 n=${#s} p=0 v x
		local -i16 o
	
		while (( i < n )); do
			c=${s:(i++):1}
			case $c {
			(=)	break ;;
			([A-Z])	(( v = 1#$c - 65 )) ;;
			([a-z])	(( v = 1#$c - 71 )) ;;
			([0-9])	(( v = 1#$c + 4 )) ;;
			(+)	v=62 ;;
			(/)	v=63 ;;
			(*)	continue ;;
			}
			(( x = (x << 6) | v ))
			case $((p++)) {
			(0)	continue ;;
			(1)	(( o = (x >> 4) & 255 )) ;;
			(2)	(( o = (x >> 2) & 255 )) ;;
			(3)	(( o = x & 255 ))
				p=0
				;;
			}
			t=$t\\x${o#16#}
		done
		print -n $t
		(( u )) || set -U
	}
	
	i=-1
	s=
	while (( ++i < 12120 )); do
		s+=a
	done
	Lb64decode $s >/dev/null
---
name: xtrace-1
description:
	Check that "set -x" doesn't redirect too quickly
stdin:
	print '#!'"$__progname" >bash
	cat >>bash <<'EOF'
	echo 'GNU bash, version 2.05b.0(1)-release (i386-ecce-mirbsd10)
	Copyright (C) 2002 Free Software Foundation, Inc.'
	EOF
	chmod +x bash
	"$__progname" -xc 'foo=$(./bash --version 2>&1 | sed q); echo "=$foo="'
expected-stdout:
	=GNU bash, version 2.05b.0(1)-release (i386-ecce-mirbsd10)=
expected-stderr-pattern:
	/.*/
---
name: xtrace-2
description:
	Check that "set -x" is off during PS4 expansion
stdin:
	f() {
		print -n "(f1:$-)"
		set -x
		print -n "(f2:$-)"
	}
	PS4='[(p:$-)$(f)] '
	print "(o0:$-)"
	set -x -o inherit-xtrace
	print "(o1:$-)"
	set +x
	print "(o2:$-)"
expected-stdout:
	(o0:sh)
	(o1:shx)
	(o2:sh)
expected-stderr:
	[(p:sh)(f1:sh)(f2:sh)] print '(o1:shx)'
	[(p:sh)(f1:sh)(f2:sh)] set +x
---
name: fksh-flags
description:
	Check that FKSH functions have their own shell flags
category: shell:legacy-no
stdin:
	[[ $KSH_VERSION = Version* ]] && set +B
	function foo {
		set +f
		set -e
		echo 2 "${-/s}" .
	}
	set -fh
	echo 1 "${-/s}" .
	foo
	echo 3 "${-/s}" .
expected-stdout:
	1 fh .
	2 eh .
	3 fh .
---
name: fksh-flags-legacy
description:
	Check that even FKSH functions share the shell flags
category: shell:legacy-yes
stdin:
	[[ $KSH_VERSION = Version* ]] && set +B
	foo() {
		set +f
		set -e
		echo 2 "${-/s}" .
	}
	set -fh
	echo 1 "${-/s}" .
	foo
	echo 3 "${-/s}" .
expected-stdout:
	1 fh .
	2 eh .
	3 eh .
---
name: fsh-flags
description:
	Check that !FKSH functions share the shell flags
stdin:
	[[ $KSH_VERSION = Version* ]] && set +B
	foo() {
		set +f
		set -e
		echo 2 "${-/s}" .
	}
	set -fh
	echo 1 "${-/s}" .
	foo
	echo 3 "${-/s}" .
expected-stdout:
	1 fh .
	2 eh .
	3 eh .
---
