1########################################################################
2#                                                                      #
3#               This software is part of the ast package               #
4#          Copyright (c) 1982-2012 AT&T Intellectual Property          #
5#                      and is licensed under the                       #
6#                 Eclipse Public License, Version 1.0                  #
7#                    by AT&T Intellectual Property                     #
8#                                                                      #
9#                A copy of the License is available at                 #
10#          http://www.eclipse.org/org/documents/epl-v10.html           #
11#         (with md5 checksum b35adb5213ca9657e911e9befb180842)         #
12#                                                                      #
13#              Information and Software Systems Research               #
14#                            AT&T Research                             #
15#                           Florham Park NJ                            #
16#                                                                      #
17#                  David Korn <dgk@research.att.com>                   #
18#                                                                      #
19########################################################################
20function err_exit
21{
22	print -u2 -n "\t"
23	print -u2 -r ${Command}[$1]: "${@:2}"
24	let Errors+=1
25}
26alias err_exit='err_exit $LINENO'
27
28Command=${0##*/}
29integer Errors=0
30
31tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; }
32trap "cd /; rm -rf $tmp" EXIT
33
34[[ ${.sh.version} == "$KSH_VERSION" ]] || err_exit '.sh.version != KSH_VERSION'
35unset ss
36[[ ${@ss} ]] && err_exit '${@ss} should be empty string when ss is unset'
37[[ ${!ss} == ss ]] ||  err_exit '${!ss} should be ss when ss is unset'
38[[ ${#ss} == 0 ]] ||  err_exit '${#ss} should be 0 when ss is unset'
39# RANDOM
40if	(( RANDOM==RANDOM || $RANDOM==$RANDOM ))
41then	err_exit RANDOM variable not working
42fi
43# SECONDS
44sleep 3
45if	(( SECONDS < 2 ))
46then	err_exit SECONDS variable not working
47fi
48# _
49set abc def
50if	[[ $_ != def ]]
51then	err_exit _ variable not working
52fi
53# ERRNO
54#set abc def
55#rm -f foobar#
56#ERRNO=
57#2> /dev/null < foobar#
58#if	(( ERRNO == 0 ))
59#then	err_exit ERRNO variable not working
60#fi
61# PWD
62if	[[ !  $PWD -ef . ]]
63then	err_exit PWD variable failed, not equivalent to .
64fi
65# PPID
66exp=$$
67got=${ $SHELL -c 'print $PPID'; }
68if	[[ ${ $SHELL -c 'print $PPID'; } != $$ ]]
69then	err_exit "PPID variable failed -- expected '$exp', got '$got'"
70fi
71# OLDPWD
72old=$PWD
73cd /
74if	[[ $OLDPWD != $old ]]
75then	err_exit "OLDPWD variable failed -- expected '$old', got '$OLDPWD'"
76fi
77cd $old || err_exit cd failed
78# REPLY
79read <<-!
80	foobar
81	!
82if	[[ $REPLY != foobar ]]
83then	err_exit REPLY variable not working
84fi
85integer save=$LINENO
86# LINENO
87LINENO=10
88#
89#  These lines intentionally left blank
90#
91if	(( LINENO != 13))
92then	err_exit LINENO variable not working
93fi
94LINENO=save+10
95IFS=:
96x=a::b::c
97if	[[ $x != a::b::c ]]
98then	err_exit "word splitting on constants"
99fi
100set -- $x
101if	[[ $# != 5 ]]
102then	err_exit ":: doesn't separate null arguments "
103fi
104set x
105if	x$1=0 2> /dev/null
106then	err_exit "x\$1=value treated as an assignment"
107fi
108# check for attributes across subshells
109typeset -i x=3
110y=1/0
111if	( x=y ) 2> /dev/null
112then	err_exit "attributes not passed to subshells"
113fi
114unset x
115function x.set
116{
117	nameref foo=${.sh.name}.save
118	foo=${.sh.value}
119	.sh.value=$0
120}
121x=bar
122if	[[ $x != x.set ]]
123then	err_exit 'x.set does not override assignment'
124fi
125x.get()
126{
127	nameref foo=${.sh.name}.save
128	.sh.value=$foo
129}
130
131if	[[ $x != bar ]]
132then	err_exit 'x.get does not work correctly'
133fi
134typeset +n foo
135unset foo
136foo=bar
137(
138	unset foo
139	set +u
140	if	[[ $foo != '' ]]
141	then	err_exit '$foo not null after unset in subsehll'
142	fi
143)
144if	[[ $foo != bar ]]
145then	err_exit 'unset foo in subshell produces side effect '
146fi
147unset foo
148if	[[ $( { : ${foo?hi there} ; } 2>&1) != *'hi there' ]]
149then	err_exit '${foo?hi there} with foo unset does not print hi there on 2'
150fi
151x=$0
152set foobar
153if	[[ ${@:0} != "$x foobar" ]]
154then	err_exit '${@:0} not expanding correctly'
155fi
156set --
157if	[[ ${*:0:1} != "$0" ]]
158then	err_exit '${@:0} not expanding correctly'
159fi
160ACCESS=0
161function COUNT.set
162{
163        (( ACCESS++ ))
164}
165COUNT=0
166(( COUNT++ ))
167if	(( COUNT != 1 || ACCESS!=2 ))
168then	err_exit " set discipline failure COUNT=$COUNT ACCESS=$ACCESS"
169fi
170LANG=C > /dev/null 2>&1
171if	[[ $LANG != C ]]
172then	err_exit "C locale not working"
173fi
174unset RANDOM
175unset -n foo
176foo=junk
177function foo.get
178{
179	.sh.value=stuff
180	unset -f foo.get
181}
182if	[[ $foo != stuff ]]
183then	err_exit "foo.get discipline not working"
184fi
185if	[[ $foo != junk ]]
186then	err_exit "foo.get discipline not working after unset"
187fi
188# special variables
189set -- 1 2 3 4 5 6 7 8 9 10
190sleep 1000 &
191if	[[ $(print -r -- ${#10}) != 2 ]]
192then	err_exit '${#10}, where ${10}=10 not working'
193fi
194for i in @ '*' ! '#' - '?' '$'
195do	false
196	eval foo='$'$i bar='$'{$i}
197	if	[[ ${foo} != "${bar}" ]]
198	then	err_exit "\$$i not equal to \${$i}"
199	fi
200	command eval bar='$'{$i%?} 2> /dev/null || err_exit "\${$i%?} gives syntax error"
201	if	[[ $i != [@*] && ${foo%?} != "$bar"  ]]
202	then	err_exit "\${$i%?} not correct"
203	fi
204	command eval bar='$'{$i#?} 2> /dev/null || err_exit "\${$i#?} gives syntax error"
205	if	[[ $i != [@*] && ${foo#?} != "$bar"  ]]
206	then	err_exit "\${$i#?} not correct"
207	fi
208	command eval foo='$'{$i} bar='$'{#$i} || err_exit "\${#$i} gives synta
209x error"
210	if	[[ $i != @([@*]) && ${#foo} != "$bar" ]]
211	then	err_exit "\${#$i} not correct"
212	fi
213done
214kill $!
215unset x
216CDPATH=/
217x=$(cd ${tmp#/})
218if	[[ $x != $tmp ]]
219then	err_exit 'CDPATH does not display new directory'
220fi
221CDPATH=/:
222x=$(cd ${tmp%/*}; cd ${tmp##*/})
223if	[[ $x ]]
224then	err_exit 'CDPATH displays new directory when not used'
225fi
226x=$(cd ${tmp#/})
227if	[[ $x != $tmp ]]
228then	err_exit "CDPATH ${tmp#/} does not display new directory"
229fi
230TMOUT=100
231(TMOUT=20)
232if	(( TMOUT !=100 ))
233then	err_exit 'setting TMOUT in subshell affects parent'
234fi
235unset y
236function setdisc # var
237{
238        eval function $1.get'
239        {
240                .sh.value=good
241        }
242        '
243}
244y=bad
245setdisc y
246if	[[ $y != good ]]
247then	err_exit 'setdisc function not working'
248fi
249integer x=$LINENO
250: $'\
251'
252if	(( LINENO != x+3  ))
253then	err_exit '\<newline> gets linenumber count wrong'
254fi
255set --
256set -- "${@-}"
257if	(( $# !=1 ))
258then	err_exit	'"${@-}" not expanding to null string'
259fi
260for i in : % + / 3b '**' '***' '@@' '{' '[' '}' !!  '*a' '$foo'
261do      (eval : \${"$i"} 2> /dev/null) && err_exit "\${$i} not an syntax error"
262done
263unset IFS
264( IFS='  ' ; read -r a b c <<-!
265	x  y z
266	!
267	if	[[ $b ]]
268	then	err_exit 'IFS="  " not causing adjacent space to be null string'
269	fi
270)
271read -r a b c <<-!
272x  y z
273!
274if	[[ $b != y ]]
275then	err_exit 'IFS not restored after subshell'
276fi
277
278# The next part generates 3428 IFS set/read tests.
279
280unset IFS x
281function split
282{
283	i=$1 s=$2 r=$3
284	IFS=': '
285	set -- $i
286	IFS=' '
287	g="[$#]"
288	while	:
289	do	case $# in
290		0)	break ;;
291		esac
292		g="$g($1)"
293		shift
294	done
295	case "$g" in
296	"$s")	;;
297	*)	err_exit "IFS=': '; set -- '$i'; expected '$s' got '$g'" ;;
298	esac
299	print "$i" | IFS=": " read arg rem; g="($arg)($rem)"
300	case "$g" in
301	"$r")	;;
302	*)	err_exit "IFS=': '; read '$i'; expected '$r' got '$g'" ;;
303	esac
304}
305for str in 	\
306	'-'	\
307	'a'	\
308	'- -'	\
309	'- a'	\
310	'a -'	\
311	'a b'	\
312	'- - -'	\
313	'- - a'	\
314	'- a -'	\
315	'- a b'	\
316	'a - -'	\
317	'a - b'	\
318	'a b -'	\
319	'a b c'
320do
321	IFS=' '
322	set x $str
323	shift
324	case $# in
325	0)	continue ;;
326	esac
327	f1=$1
328	case $f1 in
329	'-')	f1='' ;;
330	esac
331	shift
332	case $# in
333	0)	for d0 in '' ' '
334		do
335			for d1 in '' ' ' ':' ' :' ': ' ' : '
336			do
337				case $f1$d1 in
338				'')	split "$d0$f1$d1" "[0]" "()()" ;;
339				' ')	;;
340				*)	split "$d0$f1$d1" "[1]($f1)" "($f1)()" ;;
341				esac
342			done
343		done
344		continue
345		;;
346	esac
347	f2=$1
348	case $f2 in
349	'-')	f2='' ;;
350	esac
351	shift
352	case $# in
353	0)	for d0 in '' ' '
354		do
355			for d1 in ' ' ':' ' :' ': ' ' : '
356			do
357				case ' ' in
358				$f1$d1|$d1$f2)	continue ;;
359				esac
360				for d2 in '' ' ' ':' ' :' ': ' ' : '
361				do
362					case $f2$d2 in
363					'')	split "$d0$f1$d1$f2$d2" "[1]($f1)" "($f1)()" ;;
364					' ')	;;
365					*)	split "$d0$f1$d1$f2$d2" "[2]($f1)($f2)" "($f1)($f2)" ;;
366					esac
367				done
368			done
369		done
370		continue
371		;;
372	esac
373	f3=$1
374	case $f3 in
375	'-')	f3='' ;;
376	esac
377	shift
378	case $# in
379	0)	for d0 in '' ' '
380		do
381			for d1 in ':' ' :' ': ' ' : '
382			do
383				case ' ' in
384				$f1$d1|$d1$f2)	continue ;;
385				esac
386				for d2 in ' ' ':' ' :' ': ' ' : '
387				do
388					case $f2$d2 in
389					' ')	continue ;;
390					esac
391					case ' ' in
392					$f2$d2|$d2$f3)	continue ;;
393					esac
394					for d3 in '' ' ' ':' ' :' ': ' ' : '
395					do
396						case $f3$d3 in
397						'')	split "$d0$f1$d1$f2$d2$f3$d3" "[2]($f1)($f2)" "($f1)($f2)" ;;
398						' ')	;;
399						*)	x=$f2$d2$f3$d3
400							x=${x#' '}
401							x=${x%' '}
402							split "$d0$f1$d1$f2$d2$f3$d3" "[3]($f1)($f2)($f3)" "($f1)($x)"
403							;;
404						esac
405					done
406				done
407			done
408		done
409		continue
410		;;
411	esac
412done
413unset IFS
414
415if	[[ $( (print ${12345:?}) 2>&1) != *12345* ]]
416then	err_exit 'incorrect error message with ${12345?}'
417fi
418unset foobar
419if	[[ $( (print ${foobar:?}) 2>&1) != *foobar* ]]
420then	err_exit 'incorrect error message with ${foobar?}'
421fi
422unset bar
423if	[[ $( (print ${bar:?bam}) 2>&1) != *bar*bam* ]]
424then	err_exit 'incorrect error message with ${foobar?}'
425fi
426{ $SHELL -c '
427function foo
428{
429	typeset SECONDS=0
430	sleep 1.5
431	print $SECONDS
432
433}
434x=$(foo)
435(( x >1 && x < 2 ))
436'
437} 2> /dev/null   || err_exit 'SECONDS not working in function'
438cat > $tmp/script <<-\!
439	posixfun()
440	{
441		unset x
442	 	nameref x=$1
443	 	print  -r -- "$x"
444	}
445	function fun
446	{
447	 	nameref x=$1
448	 	print  -r -- "$x"
449	}
450	if	[[ $1 ]]
451	then	file=${.sh.file}
452	else	print -r -- "${.sh.file}"
453	fi
454!
455chmod +x $tmp/script
456. $tmp/script  1
457[[ $file == $tmp/script ]] || err_exit ".sh.file not working for dot scripts"
458[[ $($SHELL $tmp/script) == $tmp/script ]] || err_exit ".sh.file not working for scripts"
459[[ $(posixfun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for posix functions"
460[[ $(fun .sh.file) == $tmp/script ]] || err_exit ".sh.file not working for functions"
461[[ $(posixfun .sh.fun) == posixfun ]] || err_exit ".sh.fun not working for posix functions"
462[[ $(fun .sh.fun) == fun ]] || err_exit ".sh.fun not working for functions"
463[[ $(posixfun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for posix functions"
464[[ $(fun .sh.subshell) == 1 ]] || err_exit ".sh.subshell not working for functions"
465(
466    [[ $(posixfun .sh.subshell) == 2 ]]  || err_exit ".sh.subshell not working for posix functions in subshells"
467    [[ $(fun .sh.subshell) == 2 ]]  || err_exit ".sh.subshell not working for functions in subshells"
468    (( .sh.subshell == 1 )) || err_exit ".sh.subshell not working in a subshell"
469)
470TIMEFORMAT='this is a test'
471[[ $({ { time :;} 2>&1;}) == "$TIMEFORMAT" ]] || err_exit 'TIMEFORMAT not working'
472: ${.sh.version}
473[[ $(alias integer) == *.sh.* ]] && err_exit '.sh. prefixed to alias name'
474: ${.sh.version}
475[[ $(whence rm) == *.sh.* ]] && err_exit '.sh. prefixed to tracked alias name'
476: ${.sh.version}
477[[ $(cd /bin;env | grep PWD=) == *.sh.* ]] && err_exit '.sh. prefixed to PWD'
478# unset discipline bug fix
479dave=dave
480function dave.unset
481{
482    unset dave
483}
484unset dave
485[[ $(typeset +f) == *dave.* ]] && err_exit 'unset discipline not removed'
486
487x=$(
488	dave=dave
489	function dave.unset
490	{
491		print dave.unset
492	}
493)
494[[ $x == dave.unset ]] || err_exit 'unset discipline not called with subset completion'
495
496print 'print ${VAR}' > $tmp/script
497unset VAR
498VAR=new $tmp/script > $tmp/out
499got=$(<$tmp/out)
500[[ $got == new ]] || err_exit "previously unset environment variable not passed to script, expected 'new', got '$got'"
501[[ ! $VAR ]] || err_exit "previously unset environment variable set after script, expected '', got '$VAR'"
502unset VAR
503VAR=old
504VAR=new $tmp/script > $tmp/out
505got=$(<$tmp/out)
506[[ $got == new ]] || err_exit "environment variable covering local variable not passed to script, expected 'new', got '$got'"
507[[ $VAR == old ]] || err_exit "previously set local variable changed after script, expected 'old', got '$VAR'"
508unset VAR
509export VAR=old
510VAR=new $tmp/script > $tmp/out
511got=$(<$tmp/out)
512[[ $got == new ]] || err_exit "environment variable covering environment variable not passed to script, expected 'new', got '$got'"
513[[ $VAR == old ]] || err_exit "previously set environment variable changed after script, expected 'old', got '$VAR'"
514
515(
516	unset dave
517	function  dave.append
518	{
519		.sh.value+=$dave
520		dave=
521	}
522	dave=foo; dave+=bar
523	[[ $dave == barfoo ]] || exit 2
524) 2> /dev/null
525case $? in
5260)	 ;;
5271)	 err_exit 'append discipline not implemented';;
528*)	 err_exit 'append discipline not working';;
529esac
530.sh.foobar=hello
531{
532	function .sh.foobar.get
533	{
534		.sh.value=world
535	}
536} 2> /dev/null || err_exit "cannot add get discipline to .sh.foobar"
537[[ ${.sh.foobar} == world ]]  || err_exit 'get discipline for .sh.foobar not working'
538x='a|b'
539IFS='|'
540set -- $x
541[[ $2 == b ]] || err_exit '$2 should be b after set'
542exec 3>&2 2> /dev/null
543set -x
544( IFS= ) 2> /dev/null
545set +x
546exec 2>&3-
547set -- $x
548[[ $2 == b ]] || err_exit '$2 should be b after subshell'
549: & pid=$!
550( : & )
551[[ $pid == $! ]] || err_exit '$! value not preserved across subshells'
552unset foo
553typeset -A foo
554function foo.set
555{
556	case ${.sh.subscript} in
557	bar)	if	((.sh.value > 1 ))
558	        then	.sh.value=5
559			foo[barrier_hit]=yes
560		fi
561		;;
562	barrier_hit)
563		if	[[ ${.sh.value} == yes ]]
564		then	foo[barrier_not_hit]=no
565		else	foo[barrier_not_hit]=yes
566		fi
567		;;
568	esac
569}
570foo[barrier_hit]=no
571foo[bar]=1
572(( foo[bar] == 1 )) || err_exit 'foo[bar] should be 1'
573[[ ${foo[barrier_hit]} == no ]] || err_exit 'foo[barrier_hit] should be no'
574[[ ${foo[barrier_not_hit]} == yes ]] || err_exit 'foo[barrier_not_hit] should be yes'
575foo[barrier_hit]=no
576foo[bar]=2
577(( foo[bar] == 5 )) || err_exit 'foo[bar] should be 5'
578[[ ${foo[barrier_hit]} == yes ]] || err_exit 'foo[barrier_hit] should be yes'
579[[ ${foo[barrier_not_hit]} == no ]] || err_exit 'foo[barrier_not_hit] should be no'
580unset x
581typeset -i x
582function x.set
583{
584	typeset sub=${.sh.subscript}
585	(( sub > 0 )) && (( x[sub-1]= x[sub-1] + .sh.value ))
586}
587x[0]=0 x[1]=1 x[2]=2 x[3]=3
588[[ ${x[@]} == '12 8 5 3' ]] || err_exit 'set discipline for indexed array not working correctly'
589float seconds
590((SECONDS=3*4))
591seconds=SECONDS
592(( seconds < 12 || seconds > 12.1 )) &&  err_exit "SECONDS is $seconds and should be close to 12"
593unset a
594function a.set
595{
596	print -r -- "${.sh.name}=${.sh.value}"
597}
598[[ $(a=1) == a=1 ]] || err_exit 'set discipline not working in subshell assignment'
599[[ $(a=1 :) == a=1 ]] || err_exit 'set discipline not working in subshell command'
600
601[[ ${.sh.subshell} == 0 ]] || err_exit '${.sh.subshell} should be 0'
602(
603	[[ ${.sh.subshell} == 1 ]] || err_exit '${.sh.subshell} should be 1'
604	(
605		[[ ${.sh.subshell} == 2 ]] || err_exit '${.sh.subshell} should be 2'
606	)
607)
608
609set -- {1..32768}
610(( $# == 32768 )) || err_exit "\$# failed -- expected 32768, got $#"
611set --
612
613unset r v x
614path=$PATH
615x=foo
616for v in EDITOR VISUAL OPTIND CDPATH FPATH PATH ENV LINENO RANDOM SECONDS _
617do	nameref r=$v
618	unset $v
619	if	( $SHELL -c "unset $v; : \$$v" ) 2>/dev/null
620	then	[[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'"
621		r=$x
622		[[ $r == $x ]] || err_exit "$v=$x failed -- expected '$x', got '$r'"
623	else	err_exit "unset $v; : \$$v failed"
624	fi
625done
626
627x=x
628for v in LC_ALL LC_CTYPE LC_MESSAGES LC_COLLATE LC_NUMERIC
629do	nameref r=$v
630	unset $v
631	[[ $r ]] && err_exit "unset $v failed -- expected '', got '$r'"
632	d=$($SHELL -c "$v=$x" 2>&1)
633	[[ $d ]] || err_exit "$v=$x failed -- expected locale diagnostic"
634	{ g=$( r=$x; print -- $r ); } 2>/dev/null
635	[[ $g == '' ]] || err_exit "$v=$x failed -- expected '', got '$g'"
636	{ g=$( r=C; r=$x; print -- $r ); } 2>/dev/null
637	[[ $g == 'C' ]] || err_exit "$v=C; $v=$x failed -- expected 'C', got '$g'"
638done
639PATH=$path
640
641cd $tmp
642
643print print -n zzz > zzz
644chmod +x zzz
645exp='aaazzz'
646got=$($SHELL -c 'unset SHLVL; print -n aaa; ./zzz' 2>&1) >/dev/null 2>&1
647[[ $got == "$exp" ]] || err_exit "unset SHLVL causes script failure -- expected '$exp', got '$got'"
648
649mkdir glean
650for cmd in date ok
651do	exp="$cmd ok"
652	rm -f $cmd
653	print print $exp > glean/$cmd
654	chmod +x glean/$cmd
655	got=$(CDPATH=:.. $SHELL -c "PATH=:/bin:/usr/bin; date > /dev/null; cd glean && ./$cmd" 2>&1)
656	[[ $got == "$exp" ]] || err_exit "cd with CDPATH after PATH change failed -- expected '$exp', got '$got'"
657done
658
659v=LC_CTYPE
660unset $v
661[[ -v $v ]] && err_exit "unset $v; [[ -v $v ]] failed"
662eval $v=C
663[[ -v $v ]] || err_exit "$v=C; [[ -v $v ]] failed"
664
665cmd='set --nounset; unset foo; : ${!foo*}'
666$SHELL -c "$cmd" 2>/dev/null || err_exit "'$cmd' exit status $?, expected 0"
667
668SHLVL=1
669level=$($SHELL -c $'$SHELL -c \'print -r "$SHLVL"\'')
670[[ $level  == 3 ]]  || err_exit "SHLVL should be 3 not $level"
671
672[[ $($SHELL -c '{ x=1; : ${x.};print ok;}' 2> /dev/null) == ok ]] || err_exit '${x.} where x is a simple variable causes shell to abort'
673
674$SHELL -c 'unset .sh' 2> /dev/null
675[[ $? == 1 ]] || err_exit 'unset .sh should return 1'
676
677# Keep the list in sync (minus ".sh") with shtab_variables[] in
678# src/cmd/ksh93/data/variables.c Note: as long as changing $PATH forks a
679# virtual subshell, "PATH" should also be excluded below.
680set -- \
681	"PS1" \
682	"PS2" \
683	"IFS" \
684	"PWD" \
685	"HOME" \
686	"MAIL" \
687	"REPLY" \
688	"SHELL" \
689	"EDITOR" \
690	"MAILCHECK" \
691	"RANDOM" \
692	"ENV" \
693	"HISTFILE" \
694	"HISTSIZE" \
695	"HISTEDIT" \
696	"HISTCMD" \
697	"FCEDIT" \
698	"CDPATH" \
699	"MAILPATH" \
700	"PS3" \
701	"OLDPWD" \
702	"VISUAL" \
703	"COLUMNS" \
704	"LINES" \
705	"PPID" \
706	"_" \
707	"TMOUT" \
708	"SECONDS" \
709	"LINENO" \
710	"OPTARG" \
711	"OPTIND" \
712	"PS4" \
713	"FPATH" \
714	"LANG" \
715	"LC_ALL" \
716	"LC_COLLATE" \
717	"LC_CTYPE" \
718	"LC_MESSAGES" \
719	"LC_NUMERIC" \
720	"FIGNORE" \
721	"KSH_VERSION" \
722	"JOBMAX" \
723	".sh.edchar" \
724	".sh.edcol" \
725	".sh.edtext" \
726	".sh.edmode" \
727	".sh.name" \
728	".sh.subscript" \
729	".sh.value" \
730	".sh.version" \
731	".sh.dollar" \
732	".sh.match" \
733	".sh.command" \
734	".sh.file" \
735	".sh.fun" \
736	".sh.lineno" \
737	".sh.subshell" \
738	".sh.level" \
739	".sh.stats" \
740	".sh.math" \
741	".sh.pool" \
742	".sh.pid" \
743	"SHLVL" \
744	"CSWIDTH"
745
746# ... upper/lowercase test
747$SHELL -c '
748       typeset -u upper
749       typeset -l lower
750       errors=0
751       PS1=/dev/null/test_my_case_too
752       PS2=$PS1 PS3=$PS1 PS4=$PS1 OPTARG=$PS1 IFS=$PS1 FPATH=$PS1 FIGNORE=$PS1 CSWIDTH=$PS1
753       for var
754       do      case $var in
755               RANDOM | HISTCMD | _ | SECONDS | LINENO | JOBMAX | .sh.stats)
756                       # these are expected to fail below as their values change; just test against crashing
757                       typeset -u "$var"
758                       typeset -l "$var"
759                       continue ;;
760               esac
761               nameref val=$var
762               upper=$val
763               lower=$val
764               typeset -u "$var"
765               if      [[ $val != "$upper" ]]
766               then    echo "  $0: typeset -u does not work on special variable $var" \
767                               "(expected $(printf %q "$upper"), got $(printf %q "$val"))" >&2
768                       let errors++
769               fi
770               typeset -l "$var"
771               if      [[ $val != "$lower" ]]
772               then    echo "  $0: typeset -l does not work on special variable $var" \
773                               "(expected $(printf %q "$lower"), got $(printf %q "$val"))" >&2
774                       let errors++
775               fi
776       done
777       exit $((errors + 1))
778' changecase_test "$@" PATH    # do include PATH here as well
779(((e = $?) == 1)) || err_exit "typeset -l/-u doesn't work on special variables" \
780       "(exit status $e$( ((e>128)) && print -n / && kill -l "$e"))"
781
782exit $((Errors<125?Errors:125))
783