1#! test/for/moderni/sh
2# See the file LICENSE in the main modernish directory for the licence.
3
4# Regression tests related to string and text processing.
5
6TEST title="whitespace/non-whitespace IFS delimiters"
7	IFS=': '
8	v='  ::  \on\e :\tw'\''o \th\'\''re\e :\\'\''fo\u\r:   : :  '
9	set -- $v
10	IFS=
11	v=${#},${1-U},${2-U},${3-U},${4-U},${5-U},${6-U},${7-U},${8-U},${9-U},${10-U},${11-U},${12-U}
12	case $v in
13	( '8,,,\on\e,\tw'\''o,\th\'\''re\e,\\'\''fo\u\r,,,U,U,U,U' )
14		mustNotHave QRK_IFSFINAL ;;
15	( '9,,,\on\e,\tw'\''o,\th\'\''re\e,\\'\''fo\u\r,,,,U,U,U' )
16		mustHave QRK_IFSFINAL ;;
17	( '11,,,\on\e,,\tw'\''o,\th\'\''re\e,,\\'\''fo\u\r,,,,U,' )
18		# pdksh
19		failmsg="incorrect IFS whitespace removal"
20		return 1 ;;
21	( '9,,,on\e,tw'\''o,th\'\''re\e,\'\''fo\u\r,,,,U,U,U,' )
22		# yash 2.8 to 2.37
23		failmsg=="split eats initial backslashes"
24		return 1 ;;
25	( '9,,,\on\e,\tw'\''o,\th\'\''re\e,\'\''fo\u\r,,,,U,U,U,' )
26		# zsh up to 4.2.6
27		failmsg="split eats first of double backslash"
28		return 1 ;;
29	( '8,,\on\e,\tw'\''o,\th\'\''re\e,\\'\''fo\u\r,,,,U,U,U,U,' )
30		# ksh93 Version M 1993-12-28 p
31		# Bug with IFS whitespace: an initial empty whitespace-separated field
32		# appears at the end of the expansion result instead of the start
33		# if IFS contains both whitespace and non-whitespace characters.
34		failmsg="split moves empty field to end of expansion"
35		return 1 ;;
36	( '7,::,\on\e,:\tw'\''o,\th\'\''re\e,:\\'\''fo\u\r:,:,:,U,U,U,U,U,' )
37		# ksh93 with a DEBUG trap set
38		failmsg="non-whitespace ignored in split"
39		return 1 ;;
40	( '1,  ::  \on\e :\tw'\''o \th\'\''re\e :\\'\''fo\u\r:   : :  ,U,U,U,U,U,U,U,U,U,U,U,' )
41		failmsg="no split (native zsh?)"
42		return 1 ;;
43	( * )	return 1 ;;
44	esac
45ENDT
46
47TEST title='tolower (ASCII)'
48	v=ABCDEFGHIJKLMNOPQRSTUVWXYZ
49	tolower v
50	str eq $v abcdefghijklmnopqrstuvwxyz
51ENDT
52
53TEST title='toupper (ASCII)'
54	v=abcdefghijklmnopqrstuvwxyz
55	toupper v
56	str eq $v ABCDEFGHIJKLMNOPQRSTUVWXYZ
57ENDT
58
59TEST title='tolower (UTF-8)'
60	utf8Locale || return
61	v='ABCDÉFIJN_ΑΒΓΔΕΖ_АБВГДЕ_ԱԲԳԴԵԶ'
62	tolower v
63	case $v in
64	( 'abcdéfijn_αβγδεζ_абвгде_աբգդեզ' )
65		not isset MSH_2UP2LOW_NOUTF8 ;;
66	( 'abcdÉfIJn_ΑΒΓΔΕΖ_АБВГДЕ_ԱԲԳԴԵԶ' )
67		xfailmsg='no UTF-8'
68		isset MSH_2UP2LOW_NOUTF8 && return 2 ;;
69	( * )	return 1 ;;
70	esac
71ENDT
72
73TEST title='toupper (UTF-8)'
74	utf8Locale || return
75	v='abcdéfijn_αβγδεζ_абвгде_աբգդեզ'
76	toupper v
77	case $v in
78	( 'ABCDÉFIJN_ΑΒΓΔΕΖ_АБВГДЕ_ԱԲԳԴԵԶ' )
79		not isset MSH_2UP2LOW_NOUTF8 ;;
80	( 'ABCDéFijN_αβγδεζ_абвгде_աբգդեզ' )
81		xfailmsg='no UTF-8'
82		isset MSH_2UP2LOW_NOUTF8 && return 2 ;;
83	( * )	return 1 ;;
84	esac
85ENDT
86
87TEST title='backslash in nonexpanding here-document'
88	command eval 'v=$(thisshellhas BUG_HDOCMASK && umask 077
89		cat <<-\EOT'$CCn$CCt'abc \'$CCn$CCt'def \\'$CCn$CCt'ghi' \
90		'\\\'$CCn$CCt'jkl \\\\'$CCn$CCt'end'$CCn$CCt'EOT'$CCn$CCt')'
91	case $v in
92	( 'abc \'$CCn'def \\'$CCn'ghi \\\'$CCn'jkl \\\\'$CCn'end' )
93		mustNotHave BUG_CSNHDBKSL ;;
94	( 'abc '$CCt'def \\'$CCn'ghi \\'$CCt'jkl \\\\'$CCn'end' \
95	| 'abc '$CCt'def \'$CCt'ghi \\'$CCt'jkl \\\'$CCt'end' )  # bash 2 and 3; bash 4.4
96		mustHave BUG_CSNHDBKSL ;;
97	( * )	return 1 ;;
98	esac
99ENDT
100
101TEST title='single-quoted pattern in param subst'
102	v="${CCn}one${CCt}two'three/four'five"
103	case "${v#${CCn}'one'${CCt}'two'\''three'}" in
104	( "/four'five" )
105		mustNotHave BUG_PSUBSQUOT ;;
106	( "$v" )
107		mustHave BUG_PSUBSQUOT ;;
108	( * )	return 1 ;;
109	esac
110ENDT
111
112TEST title='quoting within param subst in here-doc'
113
114	v=$(thisshellhas BUG_HDOCMASK && umask 077
115	unset -v S U foo bar
116	S=set
117	# Of the test expansions below, only ${S#"se"}, ${S%"et"}, ${S##"se"} and ${S%%"et"}
118	# have defined behaviour under POSIX (the double quotes must be removed).
119	{ read -r foo; read -r bar; } <<-EOF
120	${U-"1"}${U-'2'}${U:-"3"}${U:-'4'}${S+"5"}${S+'6'}${S:+"7"}${S:+'8'}
121	${S#"se"}${S#'se'}${S%"et"}${S%'et'}${S##"se"}${S##'se'}${S%%"et"}${S%%'et'}
122	EOF
123	putln $foo$bar)
124
125	case $v in
126	( \"1\"\'2\'\"3\"\'4\'\"5\"\'6\'\"7\"\'8\'ttssttss \
127	| \"1\"\'2\'\"3\"\'4\'\"5\"\'6\'\"7\"\'8\'tsetssettsetsset )
128	# 1. FreeBSD sh; 2. bosh
129		mustHave QRK_HDPARQUOT ;;
130	( 12345678ttssttss \
131	| 1\'2\'3\'4\'5\'6\'7\'8\'ttssttss \
132	| 1\'2\'3\'4\'5\'6\'7\'8\'tsetssettsetsset )
133	# 1. yash; 2. bash, dash, ksh93, zsh; 3. pdksh/mksh/lksh
134		mustNotHave QRK_HDPARQUOT ;;
135	( * )	failmsg="unknown quirk/bug [$foo$bar]"
136		return 1 ;;
137	esac
138ENDT
139
140TEST title="trimming of IFS whitespace by 'read'"
141
142	v=$(thisshellhas BUG_HDOCMASK && umask 077
143	# (NOTE: in here-document below: two leading spaces and two trailing spaces!)
144	IFS=' ' read foo <<-EOF
145	  ab  cd  
146	EOF
147	putln $foo)
148
149	case $v in
150	( 'ab  cd' )
151		mustNotHave BUG_READWHSP ;;
152	( 'ab  cd  ' )
153		mustHave BUG_READWHSP ;;	# dash 0.5.7, 0.5.8
154	( * )	failmsg="[$v]"
155		return 1 ;;
156	esac
157ENDT
158
159TEST title='line continuation in expanding here-doc'
160	FIN() {
161		:
162	}
163	command eval 'v=$(thisshellhas BUG_HDOCMASK && umask 077
164		cat <<-FIN'$CCn$CCt'def \'$CCn$CCt'ghi'$CCn$CCt'jkl\'$CCn$CCt'FIN'$CCn$CCt'FIN'$CCn')'
165	unset -f FIN
166	case $v in
167	( 'def '$CCt'ghi'$CCn'jkl'$CCt'FIN' )
168		mustNotHave BUG_HDOCBKSL ;;
169	( 'def ghi'$CCn'jkl' )  # zsh up to 5.4.2
170		mustHave BUG_HDOCBKSL ;;
171	( * )	return 1 ;;
172	esac
173ENDT
174
175TEST title='double quotes properly deactivate glob'
176	case \\foo in
177	( "\*" )
178		case \\fx in
179		( "\?x" )
180			mustHave BUG_DQGLOB ;;
181		( * )	failmsg='unknown variant of BUG_DQGLOB'
182			return 1 ;;
183		esac ;;
184	( "\foo" )
185		mustNotHave BUG_DQGLOB ;;
186	( * )	return 1 ;;
187	esac
188ENDT
189
190TEST title='trim quoted pattern in here-doc'
191	v=ababcdcd
192	v=$(thisshellhas BUG_HDOCMASK && umask 077
193		cat <<-EOF
194		${v#*ab},${v##*ab},${v%cd*},${v%%cd*}
195		${v#*\a\b},${v##*\ab},${v%c\d*},${v%%\c\d*}
196		${v#*"ab"},${v##*"a"b},${v%c"d"*},${v%%"cd"*}
197		${v#*'ab'},${v##*'a'b},${v%c'd'*},${v%%'cd'*}
198		EOF
199	)
200	vOK=abcdcd,cdcd,ababcd,abab
201	vBUG=ababcdcd,ababcdcd,ababcdcd,ababcdcd
202	case $v in
203	( "$vOK$CCn$vOK$CCn$vOK$CCn$vOK" )
204		mustNotHave BUG_PSUBSQHD ;;
205	( "$vOK$CCn$vOK$CCn$vOK$CCn$vBUG" )
206		mustHave BUG_PSUBSQHD ;;
207	( * )	return 1 ;;
208	esac
209ENDT
210
211TEST title='here-doc can be read regardless of umask'
212	# note: 'umask 777' is active in the test suite: zero perms
213	{
214		command : <<-EOF
215		EOF
216	} 2>/dev/null
217	case $? in
218	( 0 )	mustNotHave BUG_HDOCMASK ;;
219	( * )	mustHave BUG_HDOCMASK ;;
220	esac
221ENDT
222
223TEST title='newlines from expansion in param subst'
224	# Note that AT&T ksh93 does not nest quotes in parameter substitutions, so some
225	# inner parts are unquoted on that shell; but the test runs with split and glob
226	# disabled, so it's irrelevant. Another gotcha eliminated by 'use safe'.
227	unset -v v
228	for v in \
229		${v-abc${CCn}def${CCn}ghi} \
230		${v-abc"${CCn}"def"${CCn}"ghi} \
231		${v-"abc${CCn}def${CCn}ghi"} \
232		${v-"abc"${CCn}"def"${CCn}"ghi"} \
233		"${v-abc${CCn}def${CCn}ghi}" \
234		"${v-abc"${CCn}"def"${CCn}"ghi}" \
235		"${v-"abc${CCn}def${CCn}ghi"}" \
236		"${v-"abc"${CCn}"def"${CCn}"ghi"}"
237	do
238		case $v in
239		( abc${CCn}def${CCn}ghi ) ;;
240		( * ) return 1 ;;
241		esac
242	done
243ENDT
244
245TEST title='literal newlines in param subst'
246	# Same test as the previous one, but with literal newlines.
247	# Wrap in subshell and 'eval' for BUG_PSUBNEWLN compatibility.
248	unset -v v
249	( eval 'for v in \
250		${v-abc
251def
252ghi} \
253		${v-abc"
254"def"
255"ghi} \
256		${v-"abc
257def
258ghi"} \
259		${v-"abc"
260"def"
261"ghi"} \
262		"${v-abc
263def
264ghi}" \
265		"${v-abc"
266"def"
267"ghi}" \
268		"${v-"abc
269def
270ghi"}" \
271		"${v-"abc"
272"def"
273"ghi"}"
274	do
275		case $v in
276		( abc${CCn}def${CCn}ghi ) ;;
277		( * ) exit 147 ;;
278		esac
279	done' ) 2>/dev/null
280	case $? in
281	( 0 )	;;
282	( 147 )	# syntax was parsed, but check failed
283		return 1 ;;
284	( * )	# syntax error
285		mustHave BUG_PSUBNEWLN ;;
286	esac
287ENDT
288
289TEST title='additive string assignment'
290	v=foo
291	{ v=$(	MSH_NOT_FOUND_OK=y
292		v+=bar$v 2>/dev/null
293		putln $v
294	); }
295	case $v in
296	( foo )	mustNotHave ADDASSIGN && return 3;;
297	( foobarfoo )
298		mustHave ADDASSIGN ;;
299	( * )	return 1 ;;
300	esac
301ENDT
302
303TEST title='glob patterns work for all values of IFS'
304	push IFS
305	IFS='?*[]'		# on bash < 4.4, BUG_IFSGLOBC now breaks 'case' and hence all of modernish
306	case foo in
307	( ??? )	case foo in
308		( * )	case foo in
309			( *[of]* )
310				pop IFS
311				mustNotHave BUG_IFSGLOBC
312				return ;;
313			esac ;;
314		esac ;;
315	esac
316	IFS='no glob chars'	# unbreak modernish on bash < 4.4 before popping
317	pop IFS
318	mustHave BUG_IFSGLOBC
319ENDT
320
321TEST title='multibyte UTF-8 char can be IFS char'
322	utf8Locale || return
323
324	# test field splitting
325	push IFS
326	IFS='£'			# £ = C2 A3
327	v='abc§def ghi§jkl'	# § = C2 A7 (same initial byte)
328	set -- $v
329	pop IFS
330	v=${#},${1-},${2-},${3-}
331	case $v in
332	( '1,abc§def ghi§jkl,,' )
333		;; # continue below
334	( * )	w=$(printf '\247')	# second byte of § (A7)
335		case $v in
336		( "1,abc${w}def ghi${w}jkl,," | "3,abc,${w}def ghi,${w}jkl" )  # ksh93 | mksh, FreeBSD sh
337			mustHave WRN_MULTIBYTE
338			ne v=$? 1 && return $v
339			mustHave BUG_MULTIBIFS
340			return ;;
341		( * )	return 1 ;;
342		esac ;;
343	esac
344
345	# test "$*"
346	push IFS
347	IFS='§'
348	set -- 'abc' 'def ghi' 'jkl'
349	v="$*"			# BUG_PP_* compat: quote
350	pop IFS
351	case $v in
352	( 'abc§def ghi§jkl' )
353		mustNotHave WRN_MULTIBYTE && mustNotHave BUG_MULTIBIFS ;;
354	( abc?def\ ghi?jkl )
355		mustHave WRN_MULTIBYTE
356		ne v=$? 1 && return $v
357		mustHave BUG_MULTIBIFS ;;
358	( * )	return 1 ;;
359	esac
360ENDT
361
362TEST title='${var+set}'
363	r=
364	unset -v v
365	for i in 1 2 3 4; do
366		case ${v+s} in
367		( s )	r=${r}s; unset -v v ;;
368		( '' )	r=${r}u; v= ;;
369		esac
370	done
371	case $r in
372	(uuuu)	mustHave BUG_ISSETLOOP ;;
373	(usus)	mustNotHave BUG_ISSETLOOP ;;
374	( * )	return 1 ;;
375	esac
376ENDT
377
378TEST title='${var:+nonempty}'
379	r=
380	v=
381	for i in 1 2 3 4; do
382		case ${v:+n} in
383		( n )	r=${r}n; v= ;;
384		( '' )	r=${r}e; v=foo ;;
385		esac
386	done
387	case $r in
388	(enen)	;;
389	( * )	return 1 ;;
390	esac
391ENDT
392
393TEST title='${var-unset}'
394	r=
395	unset -v v
396	for i in 1 2 3 4; do
397		case ${v-u} in
398		( '' )	r=${r}s; unset -v v ;;
399		( u )	r=${r}u; v= ;;
400		esac
401	done
402	case $r in
403	(usus)	;;
404	( * )	return 1 ;;
405	esac
406ENDT
407
408TEST title='${var:-empty}'
409	r=
410	v=
411	for i in 1 2 3 4; do
412		case ${v:-e} in
413		( n )	r=${r}n; v= ;;
414		( e )	r=${r}e; v=n ;;
415		esac
416	done
417	case $r in
418	(enen)	;;
419	( * )	return 1 ;;
420	esac
421ENDT
422
423TEST title="pattern is not matched as literal string"
424	case [abc] in
425	( [abc] )
426		case [0-9] in
427		( [0-9] )
428			case [:alnum:] in
429			( [:alnum:] )
430				mustHave BUG_CASELIT
431				return ;;
432			esac ;;
433		esac ;;
434	esac
435	mustNotHave BUG_CASELIT
436ENDT
437
438TEST title="'case' matches escaped literal ctl chars"
439	# bash 2.05b, 3.0 and 3.1 have bugs with literal $CC01 and $CC7F, but test them all
440	# (except linefeed which signifies line continuation so would be removed when escaped).
441	IFS=
442	for v in	    $CC02 $CC03 $CC04 $CC05 $CC06 $CC07 $CC08 $CC09       $CC0B $CC0C $CC0D $CC0E $CC0F \
443		$CC10 $CC11 $CC12 $CC13 $CC14 $CC15 $CC16 $CC17 $CC18 $CC19 $CC1A $CC1B $CC1C $CC1D $CC1E $CC1F
444	do
445		eval 	'case ${CC01}a${CC7F}b${v}X${CC01}c${CC7F} in' \
446			"( \\${CC01}\\a\\${CC7F}\\b\\${v}\\X\\${CC01}\\c\\${CC7F} )" \
447			'	;;' \
448			'( * )	return 1 ;;' \
449			'esac'
450	done
451ENDT
452
453TEST title="'case' handles empty bracket expressions"
454	# Empty bracket expressions such as [] or v=; [$v] should always be a non-match.
455	# FTL_EMPTYBRE causes [] | [] to be taken as a single bracket expression: ["] | ["].
456	case ] in
457	( [] | [] )
458		failmsg=FTL_EMPTYBRE; return 1 ;;
459	( []] )	;;
460	( * )	return 1 ;;
461	esac
462ENDT
463
464TEST title="'case' handles unbalanced parenthesis"
465	v=ini
466	{ v=$(	eval 'v=$(
467			case $v in
468			foo )	/dev/null/bar ;;
469			( baz )	/dev/null/quux ;;
470			ini )	putln OK ;;
471			* )	putln WRONG ;;
472			esac
473		)'
474		putln $v
475	); } 2>/dev/null
476	case $v in
477	( OK )	mustNotHave BUG_CASEPAREN ;;
478	( ini )	mustHave BUG_CASEPAREN ;;
479	( * )	failmsg="v=$v"; return 1 ;;
480	esac
481ENDT
482
483TEST title='bracket expressions support char classes'
484	case / in
485	( [[:punct:]] )
486		mustNotHave BUG_NOCHCLASS ;;
487	( * )	mustHave BUG_NOCHCLASS ;;
488	esac
489ENDT
490
491TEST title='quoted param expansion handles escaped }'
492	unset -v v
493	v="${v-ab\}cd\}ef\}gh}"
494	case $v in
495	( 'ab\}cd\}ef\}gh' )
496		mustHave BUG_PSUBBKSL1 ;;
497	( 'ab}cd}ef}gh' )
498		mustNotHave BUG_PSUBBKSL1 ;;
499	( * )	return 1 ;;
500	esac
501ENDT
502
503TEST title='shell assignments are independent of IFS'
504	IFS="d ${CC01}b${CCt}c${CCn}d"
505	v=d${CCn}c${CC01}b${CCt}a
506	v=$v	# trigger BUG_ASGNCC01
507	IFS=
508	case $v in
509	( d${CCn}c${CC01}b${CCt}a )
510		mustNotHave BUG_ASGNCC01 ;;
511	( d${CCn}cb${CCt}a )
512		mustHave BUG_ASGNCC01 ;;
513	( * )	return 1 ;;
514	esac
515ENDT
516
517TEST title='empty removal of unqoted unset variables'
518	v=a
519	w=
520	unset -v x
521	set +u
522	IFS=
523	# test nonempty (v), empty (w), and unset (x) variables
524	set $v ${v-} ${v:-} ${v+$v} ${v:+$v} $w ${w-} ${w:-} ${w+$w} ${w:+$w} $x ${x-} ${x:-} ${x+$x} ${x:+$x}
525	IFS=,
526	v="$*"
527	IFS=
528	set -u
529	case $v in
530	( 'a,a,a,a,a' )
531		mustNotHave BUG_PSUBEMPT ;;
532	( 'a,a,a,a,a,,,' )
533		mustHave BUG_PSUBEMPT ;;
534	( * )	return 1 ;;
535	esac
536ENDT
537
538TEST title="assignment in parameter substitution"
539	# Regression test for BUG_PSUBASNCC.
540	unset -v foo bar
541	set -- ${foo=$ASCIICHARS} "${bar=$ASCIICHARS}"
542	# check that the assignment succeeds
543	str eq $foo$bar $ASCIICHARS$ASCIICHARS || return 1
544	# check that the parameter substitution returns identical results
545	if str eq $1$2 $ASCIICHARS$ASCIICHARS; then
546		mustNotHave BUG_PSUBASNCC
547		return
548	fi
549	# if not, check for BUG_PSUBASNCC
550	foo=$ASCIICHARS; replacein foo $CC01 ''; replacein foo $CC7F ''
551	bar=$ASCIICHARS; replacein bar $CC01 ''
552	str eq $1,$2 $foo,$bar && mustHave BUG_PSUBASNCC
553ENDT
554
555TEST title="str lt/gt: sorts before/after"
556	str lt abcd efgh && str gt EFGH ABCD
557ENDT
558
559TEST title="closing brace does not terminate string"
560	# this was a bug in dash-git, fixed in commit 878514712c5
561	v=vvv
562	v=12${#v}45
563	str eq $v 12345
564ENDT
565
566TEST title='${v#P*}, ${v##P*}, ${v%*P}, ${v%%*P}'
567	v=barbarfoofoo
568	v=${v#bar*},${v##bar*},${v%*foo},${v%%*foo}
569	case $v in
570	( 'barfoofoo,,barbarfoo,' )
571		;;
572	( * )	return 1 ;;	# FTL_PSUB (yash 2.19-2.39)
573	esac
574ENDT
575
576TEST title='splitting ${var#foo}, non-whitespace'
577	v="foo!one!two!three"
578	v=$(IFS="!"; printf '%s@' ${v#foo} ${v##foo})
579	case $v in
580	( '@@one@two@three@@@one@two@three@' )
581		mustHave BUG_PSUBIFSNW ;;
582	( '@one@two@three@@one@two@three@' )
583		mustNotHave BUG_PSUBIFSNW ;;
584	( * )	failmsg=$v; return 1 ;;
585	esac
586ENDT
587
588TEST title='splitting ${var#foo}, whitespace'
589	v="foo${CCt}one${CCt}two${CCt}three"
590	v=$(IFS=$CCt; printf '%s@' ${v#foo} ${v##foo})
591	case $v in
592	( '@one@two@three@@one@two@three@' )
593		mustHave BUG_PSUBIFSWH ;;
594	( 'one@two@three@one@two@three@' )
595		mustNotHave BUG_PSUBIFSWH ;;
596	( * )	failmsg=$v; return 1 ;;
597	esac
598ENDT
599
600TEST title='splitting ${var%foo}, non-whitespace'
601	v="XabXcdXefX"
602	v=$(IFS="X"; printf '%s@' ${v%efX} ${v%%efX})
603	case $v in
604	( '@@ab@cd@@@ab@cd@' )
605		mustNotHave QRK_IFSFINAL && mustHave BUG_PSUBIFSNW ;;
606	( '@ab@cd@@ab@cd@' )
607		mustNotHave BUG_PSUBIFSNW && mustNotHave QRK_IFSFINAL ;;
608	( '@ab@cd@@@ab@cd@@' )
609		mustNotHave BUG_PSUBIFSNW && mustHave QRK_IFSFINAL ;;
610	( * )	failmsg=$v; return 1 ;;
611	esac
612ENDT
613
614TEST title='splitting ${var%foo}, whitespace'
615	v="${CCn}ab${CCn}cd${CCn}ef${CCn}"
616	v=$(IFS=$CCn; printf '%s@' ${v%ef?} ${v%%ef?})
617	case $v in
618	( '@ab@cd@@ab@cd@' )
619		mustHave BUG_PSUBIFSWH ;;
620	( 'ab@cd@ab@cd@' )
621		mustNotHave BUG_PSUBIFSWH ;;
622	( * )	failmsg=$v; return 1 ;;
623	esac
624ENDT
625