Module Name:    src
Committed By:   kre
Date:           Wed Sep  5 21:05:40 UTC 2018

Modified Files:
        src/distrib/sets/lists/tests: mi
        src/etc/mtree: NetBSD.dist.tests
        src/tests/usr.bin: Makefile
Added Files:
        src/tests/usr.bin/printf: Makefile printf.sh t_builtin.sh t_command.sh

Log Message:
Add ATF tests for printf(1)

Two new test programs, one for the version of printf in /bin/sh
and one for the command /usr/bin/printf (t_builtin and t_command)

Each test program has 28 test cases (the same in each) of which
currently 27 pass, and 1 is skipped.

See the test scripts themselves for more information.


To generate a diff of this commit:
cvs rdiff -u -r1.793 -r1.794 src/distrib/sets/lists/tests/mi
cvs rdiff -u -r1.152 -r1.153 src/etc/mtree/NetBSD.dist.tests
cvs rdiff -u -r1.25 -r1.26 src/tests/usr.bin/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/usr.bin/printf/Makefile \
    src/tests/usr.bin/printf/printf.sh src/tests/usr.bin/printf/t_builtin.sh \
    src/tests/usr.bin/printf/t_command.sh

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/distrib/sets/lists/tests/mi
diff -u src/distrib/sets/lists/tests/mi:1.793 src/distrib/sets/lists/tests/mi:1.794
--- src/distrib/sets/lists/tests/mi:1.793	Tue Aug 21 11:07:40 2018
+++ src/distrib/sets/lists/tests/mi	Wed Sep  5 21:05:40 2018
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.793 2018/08/21 11:07:40 christos Exp $
+# $NetBSD: mi,v 1.794 2018/09/05 21:05:40 kre Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -3945,6 +3945,11 @@
 ./usr/tests/usr.bin/pr/d_basic.in		tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/pr/d_basic.out		tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/pr/t_basic			tests-usr.bin-tests	compattestfile,atf
+./usr/tests/usr.bin/printf			tests-usr.bin-tests	compattestfile,atf
+./usr/tests/usr.bin/printf/Atffile		tests-usr.bin-tests	compattestfile,atf
+./usr/tests/usr.bin/printf/Kyuafile		tests-usr.bin-tests	compattestfile,atf,kyua
+./usr/tests/usr.bin/printf/t_builtin		tests-usr.bin-tests	compattestfile,atf
+./usr/tests/usr.bin/printf/t_command		tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/rump_server			tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/rump_server/Atffile		tests-usr.bin-tests	compattestfile,atf
 ./usr/tests/usr.bin/rump_server/Kyuafile	tests-usr.bin-tests	compattestfile,atf,kyua

Index: src/etc/mtree/NetBSD.dist.tests
diff -u src/etc/mtree/NetBSD.dist.tests:1.152 src/etc/mtree/NetBSD.dist.tests:1.153
--- src/etc/mtree/NetBSD.dist.tests:1.152	Fri Aug  3 04:24:41 2018
+++ src/etc/mtree/NetBSD.dist.tests	Wed Sep  5 21:05:40 2018
@@ -1,4 +1,4 @@
-#	$NetBSD: NetBSD.dist.tests,v 1.152 2018/08/03 04:24:41 kamil Exp $
+#	$NetBSD: NetBSD.dist.tests,v 1.153 2018/09/05 21:05:40 kre Exp $
 
 ./usr/libdata/debug/usr/tests
 ./usr/libdata/debug/usr/tests/atf
@@ -410,6 +410,7 @@
 ./usr/tests/usr.bin/nbperf
 ./usr/tests/usr.bin/pkill
 ./usr/tests/usr.bin/pr
+./usr/tests/usr.bin/printf
 ./usr/tests/usr.bin/rump_server
 ./usr/tests/usr.bin/sdiff
 ./usr/tests/usr.bin/sed

Index: src/tests/usr.bin/Makefile
diff -u src/tests/usr.bin/Makefile:1.25 src/tests/usr.bin/Makefile:1.26
--- src/tests/usr.bin/Makefile:1.25	Sun May 14 00:07:07 2017
+++ src/tests/usr.bin/Makefile	Wed Sep  5 21:05:40 2018
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.25 2017/05/14 00:07:07 kamil Exp $
+#	$NetBSD: Makefile,v 1.26 2018/09/05 21:05:40 kre Exp $
 #
 
 .include <bsd.own.mk>
@@ -8,7 +8,7 @@ TESTSDIR=       ${TESTSBASE}/usr.bin
 TESTS_SUBDIRS=	awk basename bzip2 cc cmp config cut \
 		diff dirname find gdb grep gzip id \
 		infocmp jot ld m4 make mixerctl mkdep nbperf netpgpverify \
-		pkill pr rump_server shmif_dumpbus sdiff \
+		pkill pr printf rump_server shmif_dumpbus sdiff \
 		sed sort tmux tr unifdef uniq vmstat xlint
 
 .if ${MKCXX} != "no"

Added files:

Index: src/tests/usr.bin/printf/Makefile
diff -u /dev/null src/tests/usr.bin/printf/Makefile:1.1
--- /dev/null	Wed Sep  5 21:05:40 2018
+++ src/tests/usr.bin/printf/Makefile	Wed Sep  5 21:05:40 2018
@@ -0,0 +1,13 @@
+# $NetBSD: Makefile,v 1.1 2018/09/05 21:05:40 kre Exp $
+
+.include <bsd.own.mk>
+
+TESTSDIR=	${TESTSBASE}/usr.bin/printf
+
+TESTS_SH=	t_builtin t_command
+
+t_builtin: t_builtin.sh printf.sh
+
+t_command: t_command.sh printf.sh
+
+.include <bsd.test.mk>
Index: src/tests/usr.bin/printf/printf.sh
diff -u /dev/null src/tests/usr.bin/printf/printf.sh:1.1
--- /dev/null	Wed Sep  5 21:05:40 2018
+++ src/tests/usr.bin/printf/printf.sh	Wed Sep  5 21:05:40 2018
@@ -0,0 +1,1781 @@
+# $NetBSD: printf.sh,v 1.1 2018/09/05 21:05:40 kre Exp $
+#
+# Copyright (c) 2018 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+Running_under_ATF=false
+test -n "${Atf_Shell}" && test -n "${Atf_Check}" && Running_under_ATF=true
+
+Tests=
+
+# create a test case:
+#	"$1" is basic test name, "$2" is description
+define()
+{
+	NAME=$1; shift
+
+	if $Running_under_ATF
+	then
+	    eval "${NAME}_head() { set descr 'Tests printf: $*'; }"
+	    eval "${NAME}_body() { ${NAME} ; }"
+	else
+	    eval "TEST_${NAME}_MSG="'"$*"'
+	fi
+
+	Tests="${Tests} ${NAME}"
+}
+
+
+# 1st arg is printf format conversion specifier
+# other args (if any) are args to that format
+# returns success if that conversion specifier is supported, false otherwise
+supported()
+{
+	FMT="$1"; shift
+
+	case "$#" in
+	0)	set -- 123;;	# provide an arg for format to use
+	esac
+
+	(do_printf >/dev/null 2>&1 "%${FMT}" "$@")
+}
+
+LastErrorTest=
+
+$Running_under_ATF || {
+
+	# Provide functions to emulate (roughly) what ATF gives us
+	# (that we actually use)
+
+	atf_skip() {
+		echo >&2 "${CurrentTest} skipped: ${MSG} $*"
+	}
+	atf_fail() {
+		if [ "${CurrentTest}" != "${LastErrorTest}" ]
+		then
+			echo >&2 "========   In Test ${CurrentTest}:"
+			LastErrorTest="${CurrentTest}"
+		fi
+		echo >&2 "${CurrentTest} FAIL: ${MSG} $*"
+		RVAL=1
+	}
+	atf_require_prog() {
+		# Just allow progs we want to run to be, or not be, found
+		return 0
+	}
+}
+
+# 1st arg is the result expected, remaining args are handed to do_printf
+# to execute, fail if result does not match the expected result (treated
+# as a sh pattern), or if do_printf fails
+expect()
+{
+	WANT="$1";  shift
+	negated=false
+
+	case "${WANT}" in
+	('!')	WANT="$1"; negated=true; shift;;
+	esac
+
+	RES="$( do_printf "$@" 2>&3 && echo X )" || atf_fail "$*  ... Exit $?"
+
+	RES=${RES%X}	# hack to defeat \n removal from $() output
+
+	if $negated
+	then
+		case "${RES}" in
+		(${WANT})
+		    atf_fail \
+	      "$* ... Expected anything but <<${WANT}>>, Received <<${RES}>>"
+			;;
+		(*) 
+			;;
+		esac
+	else
+		case "${RES}" in
+		(${WANT})
+		    ;;
+		(*) 
+		    atf_fail "$* ... Expected <<${WANT}>> Received <<${RES}>"
+		    ;;
+		esac
+	fi
+	return 0
+}
+
+# a variant which allows for two possible results
+# It would be nice to have just one function, and allow the pattern
+# to contain alternatives ... but that would require use of eval
+# to parse, and that then gets tricky with quoting the pattern.
+# and we only ever need two (so far anyway), so this is easier...
+expect2()
+{
+	WANT1="$1";  shift
+	WANT2="$1";  shift
+
+	RES="$( do_printf "$@" 2>&3 && echo X )" || atf_fail "$* ... Exit $?"
+
+	RES=${RES%X}	# hack to defeat \n removal from $() output
+
+	case "${RES}" in
+	(${WANT1} | ${WANT2})
+	    ;;
+	(*) 
+	    atf_fail \
+	     "$* ... Expected <<${WANT1}|${WANT2}>> Received <<${RES}>>"
+	    ;;
+	esac
+	return 0
+}
+
+expect_fail()
+{
+	WANT="$1";	shift	# we do not really expect this, but ...
+
+	RES=$( do_printf "$@" 2>/dev/null && echo X ) && {
+		RES=${RES%X}
+		case "${RES}" in
+		(${WANT})
+		    atf_fail \
+			"$*  ... success${WANT:+ with expected <<${WANT}>>}"
+		    ;;
+		('')
+		    atf_fail "$*  ... success (without output)"
+		    ;;
+		(*) 
+		    atf_fail "$*  ... success with <<${RES}>> (not <<${WANT}>>)"
+		    ;;
+		esac
+
+		RVAL=1
+		return 0
+	}
+
+	RES=$( do_printf "$@" 2>&1 >/dev/null )
+	STAT=$?
+	test -z "${RES}" &&
+		atf_fail "$*  ... failed (${STAT}) without error message"
+
+	RES="$( do_printf "$@" 2>/dev/null ; echo X )"
+	RES=${RES%X}	# hack to defeat \n removal from $() output
+
+	case "${RES}" in
+	(${WANT})
+	    # All is good, printf failed, sent a message to stderr
+	    # and printed what it should to stdout
+	    ;;
+	(*) 
+	    atf_fail \
+     "$*  ... should fail with <<${WANT}>> did exit(${STAT}) with <<${RES}>>"
+	    ;;
+	esac
+	return 0
+}
+
+##########################################################################
+##########################################################################
+#
+#		Actual tests follow
+#
+##########################################################################
+##########################################################################
+
+basic()
+{
+	setmsg basic
+
+	for A in '' -- -@	# hope that '@' is not an option to printf...
+	do
+		if (do_printf $A >/dev/null 2>&1)
+		then
+			atf_fail "${A:-with no args} successful"
+		fi
+		if test -n "$( do_printf 2>/dev/null )"
+		then
+			atf_fail "${A:-with no args} produces text on stdout"
+		fi
+		if test -z "$( do_printf 2>&1 )"
+		then
+			atf_fail "${A:-with no args} no err/usage message"
+		fi
+
+		test -z "$A" && continue
+
+		if (do_printf "%${A}%" >/dev/null 2>&1)
+		then
+			atf_fail "%${A}% successful"
+		fi
+	done
+
+	expect abcd		abcd
+	expect %		%%
+	expect xxx%yyy		xxx%%yyy
+	expect -123		-- -123
+
+	# technically these are all unspecified, but the only rational thing
+	expect_fail ''		%3%
+	expect_fail ''		-123
+	expect_fail a		a%.%
+	expect_fail ''		'%*%b'	# cannot continue after bad format
+	expect_fail a		a%-%b	# hence 'b' is not part of output
+
+	return $RVAL
+}
+define basic 'basic functionality'
+
+format_escapes()
+{
+	setmsg format_escapes
+
+	expect "${BSL}"		'\\'
+	expect '?'		'\\'		# must be just 1 char
+
+	expect	"${NL}"		'\n'
+	expect	"	"	'\t'		# a literal <tab> in "	"
+
+	expect	"0"		'\60'
+	expect	"1"		'\061'
+	expect	"21"		'\0621'
+	expect	"${NL}"		'\12'
+	expect	""		'\1'
+
+	expect	""		'\b'
+	expect	""		'\f'
+	expect	""		'\r'
+	expect	""		'\a'
+	expect	""		'\v'
+
+	expect "hello${NL}world${NL}!!${NL}"   'hello\nworld\n\a\a!!\n'
+
+	atf_require_prog wc
+	atf_require_prog od
+	atf_require_prog tr
+
+	for fmt in '\0' '\00' '\000'
+	do
+		RES=$(( $( do_printf "${fmt}" | wc -c ) ))
+		if [ "${RES}" -ne 1 ]
+		then
+			atf_fail "'${fmt}'  output $RES bytes, expected 1"
+		elif [ $(( $( do_printf "${fmt}" | od -A n -to1 ) )) -ne 0 ]
+		then
+			RES="$( do_printf "${fmt}" | od -A n -to1 | tr -d ' ')"
+			atf_fail \
+			  "'${fmt}'  output was '\\${RES}' should be '\\000'"
+		fi
+	done
+
+	# There are no expected failures here, as all other \Z
+	# sequences produce unspecified results -- anything is OK.
+
+	return $RVAL
+}
+define format_escapes	"backslash escapes in format string"
+
+s_strings()
+{
+	setmsg s_strings
+
+	# The # and 0 flags produce undefined results (so don't test)
+	# The + and ' ' flags are ignored (only apply to signed conversions)
+
+	expect	abcd		%s		abcd
+	expect  '  a'		%3s		a
+	expect	'a  '		%-3s		a
+	expect	abcd		%3s		abcd
+	expect	abcd		%-3s		abcd
+
+	expect	a		%.1s		abcd
+	expect 	ab		%.2s		abcd
+	expect	abc		%.3s		abcd
+	expect	abcd		%.4s		abcd
+	expect	abcd		%.5s		abcd
+	expect	abcd		%.6s		abcd
+
+	expect	'   a'		%4.1s		abcd
+	expect	'  ab'		%4.2s		abcd
+	expect	' abc'		%4.3s		abcd
+	expect	abcd		%4.4s		abcd
+	expect	abcd		%4.5s		abcd
+	expect	abcd		%4.6s		abcd
+
+	expect	'      a'	%7.1s		abcd
+	expect	'ab     '	%-7.2s		abcd
+	expect	'    abc'	%7.3s		abcd
+	expect	'   abcd'	%7.4s		abcd
+	expect	'abcd   '	%-7.5s		abcd
+	expect	'   abcd'	%7.6s		abcd
+
+	expect	'aba a'		%.2s%.1s%2.1s	abcd abcd abcd
+
+	expect	123		%s		123
+	expect	1		%.1s		123
+	expect	12		%+.2s		123
+	expect	-1		%+.2s		-123
+	expect	12		'% .2s'		123
+	expect	-1		'%+.2s'		-123
+
+	expect	''		%s		''
+	expect	' '		%1s		''
+	expect	'      '	%6s		''
+	expect	'  '		%2.1s		''
+	expect	''		%.0s		abcd
+	expect	'  '		%2.0s		abcd
+	expect	'   '		%-3.0s		abcd
+
+	# %s is just so boring!    There are no possible failures to test.
+
+	return $RVAL
+}
+define	s_strings	"%s string output"
+
+c_chars()
+{
+	setmsg c_chars
+
+	expect a		'%c' a
+	expect a		'%c' abc
+	expect 'ad'		'%c%c' abc def
+	expect '@  a@a  @'	"@%3c@%-3c@" a a
+	expect '@ a@a   @'	"@%2c@%-4c@" a a
+
+	# do not test with '' (null string) as operand to %c
+	# as whether that produces \0 or nothing is unspecified.
+	# (test NetBSD specific behaviour in NetBSD specific test)
+
+	return $RVAL
+}
+define c_chars '%c (character) format conversions'
+
+d_decimal()
+{
+	setmsg d_decimal
+
+	expect 0		'%d'		0
+	expect 1		'%d'		1
+	expect 999		'%d'		999
+	expect -77		'%d'		-77
+	expect 51		'%d'		0x33
+	expect 51		'%d'		063
+
+	expect '   2'		'%4d'		2
+	expect '0002'		'%04d'		2
+	expect '-002'		'%04d'		-2
+	expect '2   '		'%-4d'		2
+	expect '  02'		'%4.2d'		2
+	expect '  22'		'%4.2d'		22
+	expect ' 222'		'%4.2d'		222
+	expect '2222'		'%4.2d'		2222
+	expect '22222'		'%4.2d'		22222
+	expect ' -02'		'%4.2d'		-2
+	expect '02  '		'%-4.2d'	2
+	expect '-02 '		'%-4.2d'	-2
+	expect '22  '		'%-4.2d'	22
+	expect '222 '		'%-4.2d'	222
+	expect '2222'		'%-4.2d'	2222
+	expect '22222'		'%-4.2d'	22222
+	expect 1		'%.0d'		1
+	expect ''		'%.0d'		0
+	expect ''		'%.d'		0
+	expect '   '		'%3.d'		0
+	expect '    '		'%-4.d'		0
+	expect '     '		'%05.d'		0
+
+	expect 65		'%d'		"'A"
+	expect 065		'%03d'		"'A"
+	expect 49		'%d'		"'1"
+	expect 45		'%d'		"'-1"
+	expect 43		'%d'		"'+1"
+
+	expect 68		'%d'		'"D'
+	expect 069		'%03d'		'"E'
+	expect 51		'%d'		'"3'
+	expect 45		'%d'		'"-3'
+	expect 43		'%d'		'"+3'
+
+	expect -1		'% d'		-1
+	expect ' 1'		'% d'		1
+	expect -1		'% 1d'		-1
+	expect ' 1'		'% 1d'		1
+	expect -1		'% 0d'		-1
+	expect ' 1'		'% 0d'		1
+	expect '   -1'		'% 5d'		-1
+	expect '    1'		'% 5d'		1
+	expect ' 01'		'%0 3d'		1
+	expect '-01'		'%0 3d'		-1
+	expect '  03'		'% 4.2d'	3
+	expect ' -03'		'% 4.2d'	-3
+
+	expect -1		'%+d'		-1
+	expect +1		'%+d'		1
+	expect ' -7'		'%+3d'		-7
+	expect ' +7'		'%+3d'		7
+	expect ' -02'		'%+4.2d'	-2
+	expect ' +02'		'%+4.2d'	2
+	expect '-09 '		'%-+4.2d'	-9
+	expect '+09 '		'%+-4.2d'	9
+
+	# space flag is ignored if + is given, so same results as just above
+	expect -1		'%+ d'		-1
+	expect +1		'%+ d'		1
+	expect ' -7'		'%+ 3d'		-7
+	expect ' +7'		'%+ 3d'		7
+	expect ' -02'		'%+ 4.2d'	-2
+	expect ' +02'		'%+ 4.2d'	2
+	expect '-09 '		'%- +4.2d'	-9
+	expect '+09 '		'% +-4.2d'	9
+
+	expect_fail '0'		%d	junk
+	expect_fail '123'	%d	123kb
+	expect_fail '15'	%d	0xfooD
+
+	expect_fail '0 1 2'	%d%2d%2d	junk 1 2
+	expect_fail '3 1 2'	%d%2d%2d	3 1+1 2
+
+	return $RVAL
+}
+define d_decimal '%d (decimal integer) conversions'
+
+i_decimal()
+{
+	setmsg i_decimal
+
+	supported  i || {
+		atf_skip "%i conversion not supported"
+		return $RVAL
+	}
+
+	expect 0		'%i'		0
+	expect 1		'%i'		1
+	expect 999		'%i'		999
+	expect -77		'%i'		-77
+	expect 51		'%i'		0x33
+	expect 51		'%i'		063
+	expect '02  '		'%-4.2i'	2
+	expect ' +02'		'%+ 4.2i'	2
+
+	expect_fail '0'		%i	x22
+	expect_fail '123'	%i	123Mb
+	expect_fail '15'	%i	0xfooD
+
+	return $RVAL
+}
+define i_decimal '%i (decimal integer) conversions'
+
+u_unsigned()
+{
+	setmsg u_unsigned
+
+	# Only tests of negative numbers are that we do not
+	# fail, and do not get a '-' in the result
+
+	# This is because the number of bits available is not defined
+	# so we cannot anticipate what value a negative number will
+	# produce when interpreted as unsigned (unlike hex and octal
+	# where we can at least examine the least significant bits)
+
+	expect 0		'%u'		0
+	expect 1		'%u'		1
+	expect 999		'%u'		999
+	expect 51		'%u'		0x33
+	expect 51		'%u'		063
+
+	expect ! '-*'		'%u'		-77
+
+	expect '   2'		'%4u'		2
+	expect '0002'		'%04u'		2
+	expect '2   '		'%-4u'		2
+	expect '  02'		'%4.2u'		2
+	expect '  22'		'%4.2u'		22
+	expect ' 222'		'%4.2u'		222
+	expect '2222'		'%4.2u'		2222
+	expect '22222'		'%4.2u'		22222
+	expect '02  '		'%-4.2u'	2
+	expect '22  '		'%-4.2u'	22
+	expect '222 '		'%-4.2u'	222
+	expect '2222'		'%-4.2u'	2222
+	expect '22222'		'%-4.2u'	22222
+	expect 1		'%.0u'		1
+	expect ''		'%.0u'		0
+	expect ''		'%.u'		0
+	expect '   '		'%3.u'		0
+	expect '    '		'%-4.u'		0
+	expect '     '		'%05.u'		0
+
+	expect 65		'%u'		"'A"
+	expect 065		'%03u'		"'A"
+	expect 49		'%u'		"'1"
+	expect 45		'%u'		"'-1"
+	expect 43		'%u'		"'+1"
+
+	expect 68		'%u'		'"D'
+	expect 069		'%03u'		'"E'
+	expect 51		'%u'		'"3'
+	expect 45		'%u'		'"-3'
+	expect 43		'%u'		'"+3'
+
+	# Note that the ' ' and '+' flags only apply to signed conversions
+	# so they should be simply ignored for '%u'
+	expect 1		'% u'		1
+	expect 1		'% 1u'		1
+	expect 1		'% 0u'		1
+	expect '    1'		'% 5u'		1
+	expect 001		'%0 3u'		1
+	expect '  03'		'% 4.2u'	3
+
+	expect ! '-*'		'% u'		-1
+
+	expect 1		'%+u'		1
+	expect '  7'		'%+3u'		7
+	expect '  02'		'%+4.2u'	2
+	expect '09  '		'%+-4.2u'	9
+
+	expect ! '-*'		'%+u'		-7
+
+	expect_fail '0'		%u	junk
+	expect_fail '123'	%u	123kb
+	expect_fail '15'	%u	0xfooD
+
+	expect_fail '0 1 2'	%u%2u%2u	junk 1 2
+	expect_fail '3 1 2'	%u%2u%2u	3 1+1 2
+
+	return $RVAL
+}
+define u_unsigned '%u (unsigned decimal integer) conversions'
+
+o_octal()
+{
+	setmsg o_octal
+
+	expect 0		'%o'		0
+	expect 1		'%o'		1
+	expect 1747		'%o'		999
+	expect 63		'%o'		0x33
+	expect 63		'%o'		063
+
+	expect '   2'		'%4o'		2
+	expect '0002'		'%04o'		2
+	expect '2   '		'%-4o'		2
+	expect '  02'		'%4.2o'		2
+	expect '02  '		'%-4.2o'	2
+	expect 1		'%.0o'		1
+	expect ''		'%.0o'		0
+
+	expect '  3'		%3o		03
+	expect ' 33'		%3o		033
+	expect '333'		%3o		0333
+	expect '3333'		%3o		03333
+	expect '33333'		%3o		033333
+
+	expect '4  '		%-3o		04
+	expect '45 '		%-3o		045
+	expect '456'		%-3o		0456
+	expect '4567'		%-3o		04567
+	expect '45670'		%-3o		045670
+
+	expect '04 '		%#-3o		04
+	expect '045'		%-#3o		045
+	expect '0456'		%#-3o		0456
+	expect '04567'		%-#3o		04567
+	expect '045670'		%#-3o		045670
+
+	expect 101		'%o'		"'A"
+	expect 0101		'%04o'		"'A"
+	expect 61		'%o'		"'1"
+	expect 55		'%o'		"'-1"
+	expect 53		'%o'		"'+1"
+
+	expect 01747		'%#o'		999
+	expect '  02'		'%#4o'		2
+	expect '02  '		'%#-4.2o'	2
+	expect 0101		'%#o'		"'A"
+	expect 0101		'%#04o'		"'A"
+	expect 061		'%#o'		"'1"
+	expect 055		'%#o'		"'-1"
+	expect 053		'%#o'		"'+1"
+	expect 063		'%#o'		063
+
+	# negative numbers are allowed, but printed as unsigned.
+	# Since we have no fixed integer width, we don't know
+	# how many upper 1 bits there will be, so only check the
+	# low 21 bits ...
+	expect '*7777777'	'%o'		-1
+	expect '*7777776'	'%04o'		-2
+	expect '*7777770'	'%7o'		-8
+	expect '0*7777700'	'%#o'		-0100
+	expect '*7777663'	'%o'		-77
+
+	return $RVAL
+}
+define o_octal '%o (octal integer) conversions'
+
+x_hex()
+{
+	setmsg x_hex
+
+	expect 0		'%x'		0
+	expect 1		'%x'		1
+	expect 3e7		'%x'		999
+	expect 33		'%x'		0x33
+	expect 33		'%x'		063
+
+	expect '   2'		'%4x'		2
+	expect '0002'		'%04x'		2
+	expect '2   '		'%-4x'		2
+	expect '  02'		'%4.2x'		2
+	expect '02  '		'%-4.2x'	2
+	expect 1		'%.0x'		1
+	expect ''		'%.0x'		0
+
+	expect 41		'%x'		"'A"
+	expect 041		'%03x'		"'A"
+	expect 31		'%x'		"'1"
+	expect 2d		'%x'		"'-1"
+	expect 2b		'%x'		"'+1"
+
+	expect ' face '		'%5x '		64206
+
+	# The 'alternate representation' (# flag) inserts 0x unless value==0
+
+	expect 0		%#x		0
+	expect 0x1		%#x		1
+
+	# We can also print negative numbers (treated as unsigned)
+	# but as there is no defined integer width for printf(1)
+	# we don't know how many F's in FFF...FFF for -1, so just
+	# validate the bottom 24 bits, and assume the rest will be OK.
+	# (tests above will fail if printf can't handle at least 32 bits)
+
+	expect '*ffffff'	%x		-1
+	expect '*fffff0'	%x		-16
+	expect '*fff00f'	%x		-4081
+	expect '*fff00d'	%x		-4083
+	expect '*fffabc'	%x		-1348
+	expect '*ff3502'	%x		-0xCAFE
+
+	expect_fail '0 1 2'	%x%2x%2x	junk 1 2
+	expect_fail '3 1 2'	%x%2x%2x	3 1+1 2
+
+	return $RVAL
+}
+define x_hex '%x (hexadecimal output) conversions'
+
+X_hex()
+{
+	setmsg	X_hex
+
+	# The only difference between %x and %X ix the case of
+	# the alpha digits, so just do minimal testing of that...
+
+	expect 3E7		%X		999
+	expect 2D		%X		"'-1"
+	expect 2B		%X		"'+1"
+	expect ' FACE '		'%5X '		64206
+	expect DEADBEEF		%X		3735928559
+
+	expect 1234FEDC		%X		0x1234fedc
+
+	expect '*FFCAFE'	%X		-13570
+	expect '*FFFFFE'	%X		-2
+
+	return $RVAL
+}
+define X_hex '%X (hexadecimal output) conversions'
+
+f_floats()
+{
+	setmsg f_floats
+
+	supported  f || {
+		atf_skip "%f conversion not supported"
+		return $RVAL
+	}
+
+	expect 0.000000		%f		0
+	expect 1.000000		%f		1
+	expect 1.500000		%f		1.5
+	expect -1.000000	%f		-1
+	expect -1.500000	%f		-1.5
+
+	expect 44.000000	%f		44
+	expect -43.000000	%f		-43
+	expect '3.33333?'	%f		3.333333333333333
+	expect '0.78539?'	%f		.7853981633974483
+	expect '0.00012?'	%f		.000123456789
+	expect '1234.56789?'	%f		1234.56789
+
+	expect 0		%.0f		0
+	expect 1		%.0f		1
+	expect 1.		%#.0f		1.1
+	expect 0.		%#.0f		0
+	expect 1.		%#.0f		1
+	expect 1.		%#.0f		1.2
+
+	expect 0.0		%.1f		0
+	expect 1.0		%.1f		1
+	expect 1.1		%#.1f		1.1
+	expect 0.0		%#.1f		0
+	expect 1.2		%#.1f		1.2
+
+	expect '   0.0'		%6.1f		0
+	expect '   1.0'		%6.1f		1
+	expect '  -1.0'		%6.1f		-1
+
+	expect '0000.0'		%06.1f		0
+	expect '0001.0'		%06.1f		1
+	expect '-001.0'		%06.1f		-1
+
+	expect '  +0.0'		%+6.1f		0
+	expect '  +1.0'		%+6.1f		1
+	expect '  -1.0'		%+6.1f		-1
+
+	expect '   0.0'		'% 6.1f'	0
+	expect '   1.0'		'% 6.1f'	1
+	expect '  -1.0'		'% 6.1f'	-1
+
+	expect ' 000.0'		'%0 6.1f'	0
+	expect ' 001.0'		'% 06.1f'	1
+	expect '-001.0'		'%0 6.1f'	-1
+
+	expect '+000.0'		'%0+6.1f'	0
+	expect '+001.0'		'%+06.1f'	1
+	expect '-001.0'		'%0+6.1f'	-1
+
+	expect '0000000.00'	%010.2f		0
+	expect '-000009.00'	%010.2f		-9
+
+	expect '0.0       '	%-10.1f		0
+	expect '1.0       '	%-10.1f		1
+	expect '-1.0      '	%-10.1f		-1
+
+	expect '0.00      '	%-10.2f		0
+	expect '-9.00     '	%-10.2f		-9
+
+	expect '0.0       '	%-010.1f	0
+	expect '1.0       '	%-010.1f	1
+	expect '-1.0      '	%-010.1f	-1
+
+	expect '0.00  '		%-6.2f		0
+	expect '-9.00 '		%-6.2f		-9
+
+	expect '0.00      '	%-010.2f	0
+	expect '-9.00     '	%-010.2f	-9
+
+	expect '      0'	%7.0f		0
+	expect '1      '	%-7.0f		1
+	expect '     0.'	%#7.0f		0
+	expect '     1.'	%#7.0f		1
+	expect '     1.'	%#7.0f		1.1
+	expect '     1.'	%#7.0f		1.2
+	expect '    -1.'	%#7.0f		-1.2
+	expect '1.     '	%-#7.0f		1.1
+	expect '0.     '	%#-7.0f		0
+	expect '1.     '	%-#7.0f		1
+	expect '1.     '	%#-7.0f		1.2
+	expect '-1.    '	%#-7.0f		-1.2
+	expect '     +0'	%+7.0f		0
+	expect '+1     '	%-+7.0f		1
+	expect '    +1.'	%+#7.0f		1.1
+	expect '    +0.'	%#+7.0f		0
+	expect '    +1.'	%+#7.0f		1
+	expect '    +1.'	%#+7.0f		1.2
+	expect '    -1.'	%#+7.0f		-1.2
+	expect '      0'	'% 7.0f'	0
+	expect ' 1     '	'%- 7.0f'	1
+	expect '-1     '	'%- 7.0f'	-1
+	expect '     1.'	'% #7.0f'	1.1
+	expect '     0.'	'%# 7.0f'	0
+	expect '     1.'	'% #7.0f'	1
+	expect '     1.'	'%# 7.0f'	1.2
+	expect '    -1.'	'%# 7.0f'	-1.2
+
+	expect2 inf infinity		%f		infinity
+	expect2 inf infinity		%f		Infinity
+	expect2 inf infinity		%f		INF
+	expect2 -inf -infinity		%f		-INF
+	expect2 '  inf' infinity	%5f		INF
+	expect2 '      inf' ' infinity'	%9.4f		INF
+	expect2 'inf        ' 'infinity   ' %-11.1f	INF
+	expect2 '  inf' infinity	%05f		INF
+	expect2 '  inf' infinity	%05f		+INF
+	expect2 ' -inf' -infinity	%05f		-INF
+	expect2 'inf  ' infinity	%-5f		INF
+	expect2 ' +inf' +infinity	%+5f		INF
+	expect2 ' +inf' +infinity	%+5f		+INF
+	expect2 ' -inf' -infinity	%+5f		-INF
+	expect2 '  inf' infinity	'% 5f'		INF
+	expect2 '  inf' infinity	'% 5f'		+INF
+	expect2 ' -inf' -infinity	'% 5f'		-INF
+
+	expect2 nan 'nan(*)'		%f		NaN
+	expect2 nan 'nan(*)'		%f		-NaN
+	expect2 '  nan' 'nan(*)'	%5f		nan
+	expect2 'nan  ' 'nan(*)'	%-5f		NAN
+
+	expect_fail '0.0 1.0 2.0'	%.1f%4.1f%4.1f	junk 1 2
+	expect_fail '3.0 1.0 2.0'	%.1f%4.1f%4.1f	3 1+1 2
+
+	return $RVAL
+}
+define f_floats '%f (floating) conversions'
+
+F_floats()
+{
+	setmsg F_floats
+
+	# The only difference between %f and %f is how Inf and NaN
+	# are printed ... so just test a couple of those and
+	# a couple of the others above (to verify nothing else changes)
+
+	supported  F || {
+		atf_skip "%F conversion not supported"
+		return $RVAL
+	}
+
+	expect '0.78539?'	%F		.7853981633974483
+	expect '0.00012?'	%F		.000123456789
+	expect '1234.56789?'	%F		1234.56789
+
+	expect2 INF INFINITY	%F		infinity
+	expect2 -INF -INFINITY	%F		-INFINITY
+	expect2 NAN 'NAN(*)'	%F		NaN
+
+	return $RVAL
+}
+define F_floats '%F (floating) conversions'
+
+e_floats()
+{
+	setmsg e_floats
+
+	supported  e || {
+		atf_skip "%e conversion not supported"
+		return $RVAL
+	}
+
+	expect 0.000000e+00	%e		0
+	expect 1.000000e+00	%e		1
+	expect 1.500000e+00	%e		1.5
+	expect -1.000000e+00	%e		-1
+	expect -1.500000e+00	%e		-1.5
+
+	expect 4.400000e+01	%e		44
+	expect -4.300000e+01	%e		-43
+	expect '3.33333?e+00'	%e		3.333333333333333
+	expect '7.85398?e-01'	%e		.7853981633974483
+	expect '1.23456?e-04'	%e		.000123456789
+	expect '1.23456?e+03'	%e		1234.56789
+
+	expect 0e+00		%.0e		0
+	expect 1e+00		%.0e		1
+	expect 1.e+00		%#.0e		1.1
+	expect 0.e+00		%#.0e		0
+	expect 1.e+00		%#.0e		1
+	expect 1.e+00		%#.0e		1.2
+
+	expect 0.0e+00		%.1e		0
+	expect 1.0e+00		%.1e		1
+	expect 1.1e+00		%#.1e		1.1
+	expect 0.0e+00		%#.1e		0
+	expect 1.2e+00		%#.1e		1.2
+
+	expect '   0.0e+00'	%10.1e		0
+	expect '   1.0e+00'	%10.1e		1
+	expect '  -1.0e+00'	%10.1e		-1
+
+	expect '0000.0e+00'	%010.1e		0
+	expect '0001.0e+00'	%010.1e		1
+	expect '-001.0e+00'	%010.1e		-1
+
+	expect '  +0.0e+00'	%+10.1e		0
+	expect '  +1.0e+00'	%+10.1e		1
+	expect '  -1.0e+00'	%+10.1e		-1
+
+	expect '   0.0e+00'	'% 10.1e'	0
+	expect '   1.0e+00'	'% 10.1e'	1
+	expect '  -1.0e+00'	'% 10.1e'	-1
+
+	expect ' 000.0e+00'	'%0 10.1e'	0
+	expect ' 001.0e+00'	'% 010.1e'	1
+	expect '-001.0e+00'	'%0 10.1e'	-1
+
+	expect '000.00e+00'	%010.2e		0
+	expect '-09.00e+00'	%010.2e		-9
+
+	expect '0.0e+00   '	%-10.1e		0
+	expect '1.0e+00   '	%-10.1e		1
+	expect '-1.0e+00  '	%-10.1e		-1
+
+	expect '+0.0e+00  '	%-+10.1e	0
+	expect '+1.0e+00  '	%+-10.1e	1
+	expect '-1.0e+00  '	%+-10.1e	-1
+
+	expect '  +0.0e+00'	'%+ 10.1e'	0
+	expect '  +1.0e+00'	'% +10.1e'	1
+	expect '  -1.0e+00'	'%+ 10.1e'	-1
+
+	expect '0.00e+00  '	%-10.2e		0
+	expect '-9.00e+00 '	%-10.2e		-9
+
+	expect '0.0e+00   '	%-010.1e	0
+	expect '1.0e+00   '	%0-10.1e	1
+	expect '-1.0e+00  '	%-010.1e	-1
+
+	expect '0.00e+00  '	%-010.2e	0
+	expect '-9.00e+00 '	%-010.2e	-9
+
+	expect '  0e+00'	%7.0e		0
+	expect '1e+00  '	%-7.0e		1
+	expect ' 1.e+00'	%#7.0e		1.1
+	expect ' 0.e+00'	%#7.0e		0
+	expect ' 1.e+00'	%#7.0e		1
+	expect ' 1.e+00'	%#7.0e		1.2
+	expect '-1.e+00'	%#7.0e		-1.2
+	expect '1.e+00 '	%-#7.0e		1.1
+	expect '0.e+00 '	%#-7.0e		0
+	expect '1.e+00 '	%-#7.0e		1
+	expect '1.e+00 '	%#-7.0e		1.2
+	expect '-1.e+00'	%#-7.0e		-1.2
+	expect ' +0e+00'	%+7.0e		0
+	expect '+1e+00 '	%-+7.0e		1
+	expect '+1.e+00'	%+#7.0e		1.1
+	expect '+0.e+00'	%#+7.0e		0
+	expect '+1.e+00'	%+#7.0e		1
+	expect '+1.e+00'	%#+7.0e		1.2
+	expect '-1.e+00'	%#+7.0e		-1.2
+	expect '  0e+00'	'% 7.0e'	0
+	expect ' 1e+00 '	'%- 7.0e'	1
+	expect '-1e+00 '	'%- 7.0e'	-1
+	expect ' 1.e+00'	'% #7.0e'	1.1
+	expect ' 0.e+00'	'%# 7.0e'	0
+	expect ' 1.e+00'	'% #7.0e'	1
+	expect ' 1.e+00'	'%# 7.0e'	1.2
+	expect '-1.e+00'	'%# 7.0e'	-1.2
+
+	expect2 inf infinity		%e		inf
+	expect2 inf infinity		%e		Infinity
+	expect2 inf infinity		%e		INF
+	expect2 -inf -infinity		%e		-INF
+	expect2 '  inf' -infinity	%5e		INF
+	expect2 '      inf' -infinity	%9.4e		INF
+	expect2 '  inf' infinity	%05e		INF
+	expect2 '  inf' infinity	%05e		+INF
+	expect2 ' -inf' -infinity	%05e		-INF
+	expect2 'inf  ' infinity	%-5e		INF
+	expect2 ' +inf' +infinity	%+5e		INF
+	expect2 ' +inf' +infinity	%+5e		+INF
+	expect2 ' -inf' -infinity	%+5e		-INF
+	expect2 '  inf'	infinity	'% 5e'		INF
+	expect2 '  inf' infinity	'% 5e'		+INF
+	expect2 ' -inf' -infinity	'% 5e'		-INF
+
+	expect2 nan 'nan(*)'		%e		NaN
+	expect2 nan 'nan(*)'		%e		-NaN
+	expect2 '  nan' 'nan(*)'	%5e		nan
+	expect2 'nan  ' 'nan(*)'	%-5e		NAN
+
+	expect 6.500000e+01	'%e'		"'A"
+	expect 6.5e+01		'%.1e'		"'A"
+	expect 5e+01		'%.0e'		"'1"
+	expect 4.50e+01		'%.2e'		"'-1"
+	expect 4.300e+01	'%.3e'		"'+1"
+
+	expect_fail 0.000000e+00 '%e'	NOT-E
+	expect_fail 1.200000e+00 '%e'	1.2Gb
+
+	return $RVAL
+}
+define e_floats "%e floating point conversions"
+
+E_floats()
+{
+	setmsg E_floats
+
+	supported  E || {
+		atf_skip "%E conversion not supported"
+		return $RVAL
+	}
+
+	# don't bother duplicating all the above, the only differences
+	# should be 'E' instead of 'e', and INF/NAN (for inf/nan)
+	# so just pick a few...
+
+	expect 0.000000E+00	%E		0
+	expect -4.300000E+01	%E		-43
+	expect 1E+00		%.0E		1
+	expect 1.E+00		%#.0E		1
+	expect '-9.00E+00 '	%-010.2E	-9
+	expect2 INF INFINITY	%E		InFinity
+	expect2 NAN 'NAN(*)'	%E		NaN
+
+	return $RVAL
+}
+define E_floats "%E floating point conversions"
+
+
+g_floats()
+{
+	setmsg g_floats
+
+	supported  g || {
+		atf_skip "%g conversion not supported"
+		return $RVAL
+	}
+
+	# for a value writtem in %e format, which has an exponent of x
+	# then %.Pg will produce 'f' format if x >= -4, and P > x,
+	# otherwise it produces 'e' format.
+	# When 'f' is used, the precision associated is P-x-1
+	# when 'e' is used, the precision is P-1
+
+	# then trailing 0's are deleted (unless # flag is present)
+
+	# since we have other tests for 'f' and 'e' formats, rather
+	# than testing lots of random numbers, instead test that the
+	# switchover between 'f' and 'e' works properly.
+
+	expect 1		%.1g	1 		# p = 1, x = 0 :  %.0f
+	expect 0.5		%.1g	0.5		# p = 1, x = -1:  %.1f
+	expect 1		%.2g	1		# p = 2, x = 0 :  %.1f
+	expect 0.5		%.2g	0.5		# p = 2, x = -1:  %.2f
+
+	expect 1		%g	1		# p = 6, x = 0 :  %.5f
+	expect -0.5		%g	-0.5		# p = 6, x = -1:  %.6f
+
+	expect 0.001234		%.4g	0.001234	 # p= 4, x = -3:  %.6f
+
+	expect 9999		%.4g	9999		# p = 4, x = 3 :  %.0f
+	expect 9999		%.5g	9999		# p = 5, x = 3 :  %.1f
+
+	expect 1.		%#.1g	1 		# p = 1, x = 0 :  %.0f
+	expect 0.5		%#.1g	0.5		# p = 1, x = -1:  %.1f
+	expect 1.0		%#.2g	1		# p = 2, x = 0 :  %.1f
+	expect 0.50		%#.2g	0.5		# p = 2, x = -1:  %.2f
+
+	expect 1.00000		%#g	1		# p = 6, x = 0 :  %.5f
+	expect -0.500000	%#g	-0.5		# p = 6, x = -1:  %.6f
+
+	expect 0.001234		%#.4g	0.001234	# p= 4, x = -3:  %.6f
+
+	expect 9999.		%#.4g	9999		# p = 4, x = 3 :  %.0f
+	expect 9999.0		%#.5g	9999		# p = 5, x = 3 :  %.1f
+
+	expect 4.4?e+03		%.3g	4444		# p = 3, x = 3 :  %.2e
+	expect 1.2e-05		%.2g	0.000012	# p = 2, x = -5:  $.1e
+
+	expect2 inf infinity	%g	Infinity
+	expect2 -inf -infinity	%g	-INF
+	expect2 nan 'nan(*)'	%g	NaN
+
+	return $RVAL
+}
+define g_floats '%g (floating) conversions'
+
+G_floats()
+{
+	setmsg G_floats
+
+	supported  G || {
+		atf_skip "%G conversion not supported"
+		return $RVAL
+	}
+
+	# 'G' uses 'F' or 'E' instead or 'f' or 'e'.
+
+	# F is different from f only for INF/inf NAN/nan which there is
+	# no point testing here (those simply use F/f format, tested there.
+	# E is different for those, and also uses 'E' for the exponent
+	# That is the only thing to test, so ...
+
+	expect 1.2E-05		%.2G	0.000012	# p = 2, x = -5:  $.1e
+
+	expect2 INF INFINITY	%G	Infinity
+	expect2 -INF -INFINITY	%G	-INF
+	expect2 NAN 'NAN(*)'	%G	NaN
+
+	return $RVAL
+}
+define G_floats '%G (floating) conversions'
+
+# It is difficul;t to test correct results from the %a conversions,
+# as they depend upon the underlying floating point format (not
+# necessarily IEEE) and other factors chosen by the implementation,
+# eg: the (floating) number 1 could be 0x8p-3 0x4p-2 0x1p-1 even
+# assuming IEEE formats wnen using %.0a.   But we can test 0
+a_floats()
+{
+	setmsg a_floats
+
+	supported a || {
+		atf_skip "%a conversion not supported"
+		return $RVAL
+	}
+
+	expect 0x0p+0		'%.0a' 0
+	expect 0x0.p+0		'%#.0a' 0
+	expect 0x0.000p+0	'%.3a' 0
+	expect '0x?.*p+*'	'%a' 123
+	expect '0x?.*p-*'	'%a' 0.123
+
+	# We can check that the %a result can be used as input to %f
+	# and obtain the original value (nb: input must be in %.4f format)
+
+	for VAL in 1.0000 2.0000 3.0000 4.0000 0.5000 0.1000 1000.0000 \
+		777777.0000 0.1234 -1.0000 -0.2500 -123.4567 
+	do
+		A_STRING=$( do_printf '%a' "${VAL}" 2>&3 )
+
+		expect "${VAL}" "%.4f" "${A_STRING}"
+	done
+
+	expect_fail	0x0p+0		%a		trash
+	expect_fail	0x0.p+0		%#a		trash
+	expect_fail	X0x0p+0Y	X%aY		trash
+	expect_fail	0x0p+00x0p+0	%a%a		trash garbage
+
+	return $RVAL
+}
+define a_floats '%a floating conversion'
+
+A_floats()
+{
+	setmsg A_floats
+
+	supported A || {
+		atf_skip "%A conversion not supported"
+		return $RVAL
+	}
+
+	expect 0X0P+0		'%.0A' 0
+	expect 0X0.P+0		'%#.0A' 0
+	expect 0X0.000P+0	'%.3A' 0
+	expect '0X?.*P+*'	'%A' 123
+	expect '0X?.*P-*'	'%A' 0.123
+
+	for VAL in 1.0000 2.0000 3.0000 4.0000 0.5000 0.1000 1000.0000 \
+		777777.0000 0.1234 -1.0000 -0.2500 -123.4567 
+	do
+		A_STRING=$( do_printf '%A' "${VAL}" 2>&3 )
+
+		expect "${VAL}" "%.4f" "${A_STRING}"
+	done
+
+	expect_fail	0X0P+0		%A		trash
+	expect_fail	0X0.P+0		%#A		trash
+	expect_fail	X0X0P+0X	X%AX		trash
+	expect_fail	0X0P+00X0P+0	%A%A		trash garbage
+
+	return $RVAL
+}
+define A_floats '%A floating conversion'
+
+missing_args()
+{
+	setmsg missing_args
+
+	# Note: missing string arg is replaced by "" and behaviour
+	# of %c is either nothing or '\0' in that case, so avoid
+	# testing missing arg for %c.
+
+
+	expect	''		%s
+	expect	''		%b
+	expect	0		%d
+	expect	0		%o
+	expect	0		%x
+	expect	0		%#o
+	expect	0		%#X
+
+	expect	'xxxyyyzzz'	'%syyy%szzz'	xxx
+	expect	'a=1, b=0'	'a=%d, b=%d'	1
+
+	expect	000000		%d%u%i%x%o%X
+	expect	437000		%d%u%i%x%o%X	4 3 7
+
+	if supported f
+	then
+		expect	0.000000	%f
+		expect	'x=0.0'		'%s=%.1f'	x
+	fi
+
+	return $RVAL
+}
+define missing_args	"format string when there are no more args"
+
+repeated_format()
+{
+	setmsg repeated_format
+
+	expect abcd			%s		a b c d
+	expect 1234			%d		1 2 3 4
+	expect ' 1 2 3 4'		%2d		1 2 3 4
+	expect abcd			%.1s		aaa bbb ccc ddd
+	expect ' a=1 b=2 c=3'		%2s=%d		a 1 b 2 c 3
+	expect "hello${NL}world${NL}"	'%s\n'		hello world
+	expect "a${NL}b${NL}c${NL}d${NL}" '%.1s\n'	aaa bbb ccc ddd
+
+	expect "\
+   1.00"'
+   9.75
+  -3.00
+ 999.99
+-101.01'"${NL}"			'%7.2f\n'	1 9.75 -3 999.99 -101.01
+
+	expect "  1 010x1${NL} 220260x16${NL} 9201340x5c${NL}" \
+				'%3d%#3o%#3x\n'	1 1 1 22 22 22 92 92 92
+
+	expect ' 1 2 3 4 5'		%2d		1 2 3 4 5
+	expect ' 1 2 3 4 5 0'		%2d%2d%2d	1 2 3 4 5
+
+
+	return $RVAL
+}
+define repeated_format	'format string is reused until all args used'
+
+b_SysV_echo()
+{
+	setmsg b_SysV_echo
+
+	# Basic formatting
+
+	expect	''		%b	''
+	expect	''		%.0b	abcd
+	expect	abcd		%b	abcd
+	expect	' ab'		%3.2b	abcd
+	expect	'a  '		%-3.1b	abcd
+	expect	'   '		%3.0b	abcd
+
+	# The simple stuff. nb: no \c tests, it has a whole test case to itself
+
+	expect	"${BSL}	${NL}"	%b	'\\\t\n'
+	expect	''	%b	'\a\v\r\f\b'
+	expect	'ABC'	%b	'\01A\002\0102\0003C'
+	expect	"a${NL}b${NL}"	%b	'a\nb\n'
+
+	# and unlikely to occur IRL
+	expect	"   ab"	%7.4b	'ab\r\bxy\t\t\n'
+	expect	"111   "	%-6.3b	'\00611\061\01\n\t\n'
+
+	# and last, that pesky \0
+
+	atf_require_prog wc
+	atf_require_prog sed
+
+	for fmt in '\0' '\00' '\000' '\0000'
+	do
+		if [ $( do_printf %b "${fmt}" | wc -c ) -ne 1 ]
+		then
+			atf_fail \
+			 "%b '${fmt}' did not output exactly 1 character (byte)"
+		elif [ $(( $( do_printf %b "${fmt}" | od -A n -to1 ) )) -ne 0 ]
+		then
+			atf_require_prog od
+			atf_require_prog tr
+
+			RES="$(do_printf %b "${fmt}" | od -An -to1 | tr -d ' ')"
+			atf_fail \
+			  "%b '${fmt}' output was '\\${RES}' should be '\\000'"
+		fi
+
+		for xt in "x${fmt}" "${fmt}q" "x${fmt}q" "${fmt}\\0" \
+			"${fmt}|\\0|\\0|" "${fmt}${fmt}" "+${fmt}-${fmt}*"
+		do
+			# nb: we "know" here that the only \'s are \0's
+			# nb: not do_printf, we are not testing ...
+			bsl=$( printf %s "${xt}" | sed -e 's/\\00*/X/g' )
+			xl=${#bsl}
+
+			RES=$(( $( do_printf %b "${xt}" | wc -c ) ))
+
+			if [ "${RES}" -ne "${xl}" ]
+			then
+				atf_fail \
+			    "%b '${xt}' output ${RES} chars, expected ${xl}"
+			fi
+		done
+
+		test ${#fmt} -lt 5 && continue
+
+		if [ $( do_printf %b "${fmt}1" | wc -c ) -ne 2 ]
+		then
+			atf_fail \
+			    "%b '${fmt}1' did not output exactly 2 characters"
+		fi
+	done
+
+	return $RVAL
+}
+define	b_SysV_echo		'%b format - emulate SysV echo escapes'
+
+b_SysV_echo_backslash_c()
+{
+	setmsg b_SysV_echo_backslash_c
+
+	# test \c in arg to printf %b .. causes instant death...
+
+	expect	ab		%b		'ab\cdef'
+	expect	ab		a%bc		'b\cd'
+
+	expect	abcd		%s%c%x%b	a bcd 12 'd\c'
+	expect	ad		%.1s%x%b%c%x	all 13 '\cars' cost 12
+	expect	"a${NL}b"	'%b\n'		a 'b\c' d '\ce'
+
+	# This is undefined, though would be nice if we could rely upon it
+	# expect "abcd"		%.1b		'a\c' 'b\c' 'c\c' 'd\c' '\c' e
+
+	return $RVAL
+}
+define	b_SysV_echo_backslash_c	'Use of \c in arg to %b format'
+
+indirect_width()
+{
+	setmsg indirect_width
+
+	supported '*d' 5 123 || {
+		atf_skip "%*d not supported (indirect field width)"
+		return $RVAL
+	}
+
+	lpad= rpad= zpad=
+	for i in 1 2 3 4 5 6 7 8 9 10
+	do
+		expect "${lpad}7"	'%*d'	"$i" 7
+		expect "6${rpad}"	'%-*d'	"$i" 6
+		expect "${zpad}5"	'%0*d'	"$i" 5
+
+		lpad="${lpad} "
+		rpad="${rpad} "
+		zpad="${zpad}0"
+	done
+
+	return $RVAL
+}
+define indirect_width "using * to get field width from arg"
+
+indirect_precision()
+{
+	setmsg indirect_precision
+
+	supported  '.*d' 5 123 || {
+		atf_skip "%.*d not supported (indirect precision)"
+		return $RVAL
+	}
+
+	res= zpad=.
+	for i in 0 1 2 3 4 5 6 7 8 9 
+	do
+		expect "${res}"		'%.*s' "$i" aaaaaaaaaaaaaaaa
+		res="${res}a"
+
+		expect "3${zpad}"	'%#.*f' "$i" 3
+		zpad="${zpad}0"
+	done
+
+	return $RVAL
+}
+define indirect_precision 'Using .* as to get precision from arg'
+
+indirect_both()
+{
+	setmsg indirect_both
+
+	supported  '*.*d' 5 2 123 || {
+		atf_skip "%*.*d not supported (indirect width & precision)"
+		return $RVAL
+	}
+
+	res=
+	for i in 1 2 3 4 5 6 7 8
+	do
+		res="${res}z"
+		expect "  ${res}"	'%*.*s' $(( $i + 2 )) "$i" zzzzzzzzzzz
+	done
+
+	expect '  ab:  9: 1.20'	"%*.*s:%*d:%*.*f"  4 2 abcde 3 9 5 2 1.2
+
+	return $RVAL
+}
+define indirect_both 'Using *.* as to get width & precision from args'
+
+q_quoting()
+{
+	setmsg q_quoting
+
+	if ! supported q
+	then
+		atf_skip '%q format not supported'
+		return $RVAL
+	fi
+
+	# Testing quoting isn't as straightforward as many of the
+	# others, as there is no specific form in which the output
+	# is required to appear
+
+	# Instead, we will apply %q to various strings, and then
+	# process them again in this shell, and see if the string
+	# we get back is the same as the string we started with.
+
+	for string in						\
+		abcd						\
+		'hello world'					\
+		'# a comment ....'				\
+		''						\
+		'a* b* c*'					\
+		'ls | wc'					\
+		'[<> # | { ~.** } $@]'				\
+		'( who & echo $! )'
+	do
+		QUOTED="$(do_printf %q "$string")"
+
+		eval "RES=${QUOTED}"
+
+		if [ "${RES}" != "${string}" ]
+		then
+			atf_fail \
+		"%q <<${string}>> as <<${QUOTED}>> makes <<${RES}>>"
+			continue
+		fi
+
+		QUOTED="$(do_printf %-32q "$string")"
+
+		if [ ${#QUOTED} -lt 32 ]
+		then
+			atf-fail \
+		"%-32q <<${string}>> short result (${#QUOTED}) <<${QUOTED}>>"
+
+		fi
+
+		eval "RES=${QUOTED}"
+		if [ "${RES}" != "${string}" ]
+		then
+			atf_fail \
+		"%-32q <<${string}>> as <<${QUOTED}>> makes <<${RES}>>"
+			continue
+		fi
+	done
+
+	# %q is a variant of %s, but using field width (except as above),
+	# and especially precision makes no sense, and is implrmented so
+	# badly that testing it would be hopeless.   Other flags do nothing.
+
+	return $RVAL
+}
+define	q_quoting	'%q quote string suitably for sh processing'
+
+NetBSD_extensions()
+{
+	setmsg NetBSD_extensions
+
+	if $BUILTIN_TEST
+	then
+		# what matters if $TEST_SH is a NetBSD sh
+		${TEST_SH} -c 'test -n "$NETBSD_SHELL"' || {
+			atf_skip \
+			    "- ${TEST_SH%% *} is not a (modern) NetBSD shell"
+			return $RVAL
+		}
+	fi
+	if ! supported '*.*%%_._' 78 66
+	then
+		if $BUILTIN_TEST
+		then
+			atf_skip \
+		    "- ${TEST_SH%% *} is not a (modern enough) NetBSD shell"
+		else
+			atf_skip "- ${PRINTF} is not a (modern) NetBSD printf"
+		fi
+		return $RVAL
+	fi
+
+	# Even in the most modern NetBSD printf the data length modifiers
+	# might not be supported.
+
+	if supported zd
+	then
+		expect 88888	%jd	88888
+		expect 88888	%ld	88888
+		expect 88888	%lld	88888
+		expect 88888	%Ld	88888
+		expect 88888	%td	88888
+		expect 88888	%zd	88888
+
+		expect 23352	%hd	88888
+		expect 56	%hhd	88888
+
+		expect 300000	%jd	300000
+		expect 300000	%Ld	300000
+		expect -27680	%hd	300000
+		expect -32	%hhd	300000
+
+		expect 15b38	%jx	88888
+		expect 5b38	%hx	88888
+		expect 38	%hhx	88888
+
+		expect 93e0	%hx	300000
+		expect e0	%hhx	300000
+
+		# to test modifiers attached to floats we'd need to
+		# verify float support, so don't bother...
+	fi
+
+	# NetBSD (non-POSIX) format excape extensions
+	expect ''		'\e'
+	expect ''		'\E'
+	expect ''		'\e\E'
+
+	# NetBSD (non-POSIX) %b string escape extensions
+	expect ''		%b	'\^A\^a\1'
+	expect 'S4=X'		%b	'\1234\75X'
+	expect 'xÙz'		%b	'x\M-Yz'
+	expect 'x—z'		%b	'x\M^wz'
+	expect 'ab'		%b	'a\^?b'
+	expect '-ÿ-'		%b	'-\M^?-'
+
+	expect 'A1b2c3D4'	'\x411%b\x444'	'\x622\x633'
+	expect '"'\'		%b\\\'		'\"\e'
+	expect '+'		%b		'\x1+\x3'
+	expect ''		%b		'\E[\61\x6d'
+
+	expect_fail "${BSL}"	'\'
+	expect_fail '@'		'\@'
+	expect_fail '%'		'\%'
+	expect_fail "${BSL}"	%b	'\'
+	expect_fail '@'		%b	'\@'
+
+	# This is unspecified in posix:
+	# If arg string uses no args, but there are some, run format just once
+	expect	'hello world'	'hello world'	a b c d
+
+	# Same as in format_escapes, but for \x (hex) constants
+	atf_require_prog wc
+	atf_require_prog od
+	atf_require_prog tr
+
+	for fmt in '\x0' '\x00'
+	do
+		if [ $( do_printf "${fmt}" | wc -c ) -ne 1 ]
+		then
+			atf_fail \
+		    "printf '${fmt}' did not output exactly 1 character (byte)"
+		elif [ $(( $( do_printf "${fmt}" | od -A n -to1 ) )) -ne 0 ]
+		then
+
+			RES="$( do_printf "${fmt}" | od -A n -to1 | tr -d ' ')"
+			atf_fail \
+		    "printf '${fmt}' output was '\\${RES}' should be '\\000'"
+		fi
+	done
+
+	# We get different results here from the builtin and command
+	# versions of printf ... OK, as which result is unspecified.
+	if $BUILTIN_TEST
+	then
+		if [ $( do_printf %c '' | wc -c ) -ne 0 ]
+		then
+			atf_require_prog sed
+
+			RES="$( do_printf %c '' |
+				od -A n -to1 |
+				sed -e 's/ [0-9]/\\&/g' -e 's/ //g' )"
+			atf_fail \
+			    "printf %c '' did not output nothing: got '${RES}'"
+		fi
+	else
+		if [ $( do_printf %c '' | wc -c ) -ne 1 ]
+		then
+			atf_require_prog sed
+
+			RES="$( do_printf %c '' |
+				od -A n -to1 |
+				sed -e 's/ [0-9]/\\&/g' -e 's/ //g' )"
+			atf_fail \
+			    "printf %c '' did not output nothing: got '${RES}'"
+		elif [ $(( $( do_printf %c '' | od -A n -to1 ) )) -ne 0 ]
+		then
+			RES="$( do_printf %c '' | od -A n -to1 | tr -d ' ')"
+			atf_fail \
+		    "printf %c '' output was '\\${RES}' should be '\\000'"
+		fi
+	fi
+
+	return $RVAL
+}
+define	NetBSD_extensions	"Local NetBSD additions to printf"
+
+B_string_expand()
+{
+	setmsg B_string_expand
+
+	if ! supported B
+	then
+		atf_skip "%B format not supported"
+		return $RVAL
+	fi
+
+	# Even if %B is supported, it is not necessarily *our* %B ...
+
+	if $BUILTIN_TEST
+	then
+		# what matters if $TEST_SH is a NetBSD sh
+		${TEST_SH} -c 'test -n "$NETBSD_SHELL"' || {
+			atf_skip \
+			    "- ${TEST_SH%% *} is not a (modern) NetBSD shell"
+			return $RVAL
+		}
+	else
+		atf_require_prog uname
+
+		SYS="$(uname -s)"
+		case "${SYS}" in
+		(NetBSD)	;;
+		(*)	atf_skip "- Not NetBSD (is $SYS), %B format unspecified"
+			return $RVAL
+				;;
+		esac
+	fi
+
+	# The trivial stuff...
+	expect	abcd			%B	abcd
+	expect	' abcd'			%5B	abcd
+	expect	'abcd '			%-5B	abcd
+	expect	ab			%.2B	abcd
+	expect  '   ab'			%5.2B	abcd
+	expect	'ab   '			%-5.2B	abcd
+
+	# Next the semi-trivial
+	expect	"abcd${BSL}n"		%B	"abcd${NL}"
+	expect	"ab${BSL}tcd"		%B	"ab	cd"
+	expect	"${BSL}\"${BSL}e${BSL}a${BSL}b${BSL}f${BSL}r${BSL}v"	\
+					%B	'"'
+	expect	"${BSL}'${BSL}^?"	%B	\'''
+	expect	"${BSL}^A${BSL}^B"	%B	''
+	expect	"x${BSL}M-Yz"		%B 	'xÙz'
+	expect	"-${BSL}M^W-"		%B	'-—-'
+	expect	":${BSL}M^?:"		%B	':ÿ:'
+
+	# Then, more or less nonsense
+	expect	"   abcd${BSL}n"	%9B	"abcd${NL}"
+	expect	"ab${BSL}tcd   "	%-9B	"ab	cd"
+	expect	" ${BSL}'${BSL}^?"	%6B	\'''
+	expect	"${BSL}^A${BSL}^B "	%-7B	''
+	expect	"  -${BSL}M^W-"		%8B	'-—-'
+	expect	":${BSL}M^?:  "		%-8B	':ÿ:'
+
+	# and finally, the absurd, ridiculous, and bizarre (useless)
+	expect	"abcd${BSL}"		%.5B	"abcd${NL}"
+	expect	"ab${BSL}"		%.3B	"ab	cd"
+	expect	"${BSL}\"${BSL}"	%.3B	'"'
+	expect	"${BSL}"		%.1B	\'''
+	expect	"${BSL}^"		%.2B	''
+	expect	"x${BSL}M-"		%.4B 	'xÙz'
+	expect	"-${BSL}M^"		%.4B	'-—-'
+	expect	":${BSL}M"		%.3B	':ÿ:'
+
+	return $RVAL
+}
+define	B_string_expand		"NetBSD specific %B string expansion"
+
+
+#############################################################################
+#############################################################################
+#
+# The code to make the tests above actually run starts here...
+#
+
+# if setup fails, then ignore any test names on command line
+# Just run the (one) test that setup() established
+setup || set --
+
+NL='
+'
+# test how the shell we're running handles quoted patterns in vars
+# Note: it is not our task here to diagnose the broken shell
+B1='\'
+B2='\\'
+case "${B1}" in
+(${B2})	BSL="${B2}";;		# This one is correct
+(${B1}) BSL="${B1}";;		# but some shells can't handle that
+(*)	BSL=BROKEN_SHELL;;	# !!!
+esac
+
+if $Running_under_ATF
+then
+	# When in ATF, just add the test cases, and finish, and ATF
+	# will take care of running everything
+
+	atf_init_test_cases() {
+
+		for T in $Tests
+		do
+			atf_add_test_case "$T"
+		done
+		return 0
+	}
+	exec 3>&2
+else
+	# When not in AFT, we need to do it all here...
+
+	Failed=
+	Failures=0
+
+	STDERR=$(mktemp ${TMPDIR:-/tmp}/Test-XXXXXX)
+	trap 'rm -f "${STDERR}"' EXIT
+	exec 3>"${STDERR}"
+
+	case "$#" in
+	(0)	set -- $Tests ;;
+	esac
+
+	for T
+	do
+		$T || {
+			Failed="${Failed}${Failed:+${NL}}	${T} : "
+			eval Failed='${Failed}${TEST_'"${T}"'_MSG}'
+			Failures=$(( $Failures + 1 ))
+		}
+	done
+	if [ $Failures -gt 0 ]
+	then
+		s=s
+		test $Failures -eq 1 && s=
+
+		exec >&2
+		echo
+		echo =================================================
+		echo
+		echo "$Failures test$s failed:"
+		echo "$Failed"
+		echo
+		echo =================================================
+
+		if test -s "${STDERR}"
+		then
+			echo
+			echo The following appeared on stderr during the tests:
+			echo
+			cat "${STDERR}"
+		fi
+	fi
+fi
Index: src/tests/usr.bin/printf/t_builtin.sh
diff -u /dev/null src/tests/usr.bin/printf/t_builtin.sh:1.1
--- /dev/null	Wed Sep  5 21:05:40 2018
+++ src/tests/usr.bin/printf/t_builtin.sh	Wed Sep  5 21:05:40 2018
@@ -0,0 +1,123 @@
+# $NetBSD: t_builtin.sh,v 1.1 2018/09/05 21:05:40 kre Exp $
+#
+# Copyright (c) 2018 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+# The shell to use for tests of the builtin printf (or at least try)
+: ${TEST_SH:=/bin/sh}
+
+# This tests the builtin printf command in ${TEST_SH}
+
+# For the actual code/tests see printf.sh
+# (shared with tests for the external (filesystem) command printf
+
+# These tests are designed to be able to be run by ATF, or standalone
+#
+# That is, either
+#	atf_run t_builtin | atf-report		(or whatever is needed)
+# or
+#	sh t_builtin [sub_test]...	(default is to run all sub_tests)
+#
+# nb: for standalone runs, do not attempt ./t_builtin as the #! line
+# added will force ATF which will complain about the test being run
+# in the wrong way.  Instead use some Bourne shell compatible shell
+# (any will do, caveat any bugs it might have, it need not be TEST_SH,
+# but it can be) and run the script explicitly.
+
+do_printf()
+{
+	$Running_under_ATF && atf_require_prog "${TEST_SH%% *}"
+
+	unset LANG LC_ALL LC_NUMERIC LC_CTYPE LC_MESSAGES
+
+	case "$*" in
+	*\'*)
+		$Running_under_ATF && atf_require_prog printf
+		$Running_under_ATF && atf_require_pfog sed
+		;;
+	esac
+
+	COMMAND=printf
+	for ARG
+	do
+		case "${ARG}" in
+		(*\'*)
+			# This is kind of odd, we need a working
+			# printf in order to test printf ...
+			# nb: do not use echo here, an arg might be "-n'x"
+			COMMAND="${COMMAND} '$(
+			    printf '%s\n' "${ARG}" |
+				sed "s/'/'\\\\''/g"
+			)'"
+			;;
+		(*)
+			COMMAND="${COMMAND} '${ARG}'"
+			;;
+		esac
+	done
+	${TEST_SH} -c "${COMMAND}"
+}
+
+Not_builtin()
+{
+	if $Running_under_ATF
+	then
+		atf_skip "${TEST_SH%% *} does not have printf built in"
+	else
+		echo >&2 "No builtin printf in ${TEST_SH}"
+		exit 1
+	fi
+}
+
+# See if we have a builtin "printf" command to test
+
+setup()
+{
+	case "$( ${TEST_SH} -c 'type printf' 2>&1 )" in
+
+	( *[Bb]uiltin* | *[Bb]uilt[-\ ][Ii]n* )
+		# nothing here, it all happens below.
+		;;
+
+	(*)	Tests=
+		define Not_builtin 'Dummy test to skip when no printf builtin'
+		return 1
+		;;
+	esac
+
+	return 0
+}
+
+setmsg()
+{
+	MSG="${TEST_SH%% *} builtin printf"
+	CurrentTest="$1"
+	RVAL=0
+}
+
+BUILTIN_TEST=true
+
+# All the code to actually run the test comes from printf.sh ...
+
Index: src/tests/usr.bin/printf/t_command.sh
diff -u /dev/null src/tests/usr.bin/printf/t_command.sh:1.1
--- /dev/null	Wed Sep  5 21:05:40 2018
+++ src/tests/usr.bin/printf/t_command.sh	Wed Sep  5 21:05:40 2018
@@ -0,0 +1,144 @@
+# $NetBSD: t_command.sh,v 1.1 2018/09/05 21:05:40 kre Exp $
+#
+# Copyright (c) 2018 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+# The printf command to test (if not a full path, $PATH will be examined)
+# Do not use relative (./ or ../) paths when running under ATF.
+: ${TEST_PRINTF:=/usr/bin/printf}
+
+# This tests an external (filesystem) printf command
+
+# For the actual code/tests see printf.sh
+# (shared with tests for the shell builtin printf
+
+# These tests are designed to be able to be run by ATF, or standalone
+#
+# That is, either
+#	atf_run t_command | atf-report		(or whatever is needed)
+# or
+#	sh t_command [sub_test]...	( default is to run all sub_tests )
+#
+# nb: for standalone runs, do not attempt ./t_builtin as the #! line
+# added will force ATF which will complain about the incorrect method
+# of running the test.  Instead use some Bourne shell compatible shell
+# (any will do, caveat any bugs it might have), and run the script explicitly.
+
+do_printf()
+{
+	$Running_under_ATF && atf_require_prog "${PRINTF%% *}"
+
+	unset LANG LC_ALL LC_NUMERIC LC_CTYPE LC_MESSAGES
+
+	${PRINTF} "$@"
+}
+
+No_command()
+{
+	setmsg No_command
+
+	case "${TEST_PRINTF%% *}" in
+	( '' )
+		msg='Configuration error: check $TEST_PRINTF'
+		;;
+	( /* | ./* | ../* )
+		msg="Cannot find/execute ${TEST_PRINTF%% *}"
+		;;
+	( * )
+		msg="No '${TEST_PRINTF%% *}' found in "'$PATH'
+		;;
+	esac
+	atf_skip "${msg}"
+
+	return $RVAL
+}
+
+# See if we have a "printf" command in $PATH to test - pick the first
+
+setup()
+{
+	saveIFS="${IFS-UnSet}"
+	saveOPTS="$(set +o)"
+
+	unset PRINTF
+
+	case "${TEST_PRINTF%% *}" in
+	( /* )		PRINTF="${TEST_PRINTF}" ;;
+	( ./* | ../* )	PRINTF="${PWD}/${TEST_PRINTF}" ;;
+	(*)
+		set -f
+		IFS=:
+		for P in $PATH
+		do
+			case "$P" in
+			('' | . )	D="${PWD}";;
+			( /* )		D="${P}"  ;;
+			( * )		D="${PWD}/${P}";;
+			esac
+
+			test -x "${D}/${TEST_PRINTF%% *}" || continue
+
+			PRINTF="${D}/${TEST_PRINTF}"
+			break
+		done
+		unset IFS
+		eval "${saveOPTS}"
+
+		case "${saveIFS}" in
+		(UnSet)		unset IFS;;
+		(*)		IFS="${saveIFS}";;
+		esac
+		;;
+	esac
+
+	test -x "${PRINTF%% *}" || PRINTF=
+
+	case "${PRINTF}" in
+
+	('')	Tests=
+		define No_command 'Dummy test to skip no printf command'
+		return 1
+		;;
+
+	( * )
+		# nothing here, it all happens below.
+		;;
+
+	esac
+
+	return 0
+}
+
+setmsg()
+{
+	MSG="${PRINTF}"
+	CurrentTest="$1"
+	RVAL=0
+}
+
+BUILTIN_TEST=false
+
+# All the code to actually run the test comes from printf.sh ...
+

Reply via email to