Module Name:    src
Committed By:   rillig
Date:           Mon Feb 19 23:22:03 UTC 2024

Modified Files:
        src/tests/lib/libutil: t_snprintb.c

Log Message:
tests/snprintb: add more tests, especially for snprintb_m


To generate a diff of this commit:
cvs rdiff -u -r1.20 -r1.21 src/tests/lib/libutil/t_snprintb.c

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

Modified files:

Index: src/tests/lib/libutil/t_snprintb.c
diff -u src/tests/lib/libutil/t_snprintb.c:1.20 src/tests/lib/libutil/t_snprintb.c:1.21
--- src/tests/lib/libutil/t_snprintb.c:1.20	Fri Feb 16 19:53:40 2024
+++ src/tests/lib/libutil/t_snprintb.c	Mon Feb 19 23:22:03 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: t_snprintb.c,v 1.20 2024/02/16 19:53:40 rillig Exp $ */
+/* $NetBSD: t_snprintb.c,v 1.21 2024/02/19 23:22:03 rillig Exp $ */
 
 /*
  * Copyright (c) 2002, 2004, 2008, 2010, 2024 The NetBSD Foundation, Inc.
@@ -30,9 +30,9 @@
  */
 
 #include <sys/cdefs.h>
-__COPYRIGHT("@(#) Copyright (c) 2008, 2010\
+__COPYRIGHT("@(#) Copyright (c) 2008, 2010, 2024\
  The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_snprintb.c,v 1.20 2024/02/16 19:53:40 rillig Exp $");
+__RCSID("$NetBSD: t_snprintb.c,v 1.21 2024/02/19 23:22:03 rillig Exp $");
 
 #include <stdio.h>
 #include <string.h>
@@ -58,40 +58,43 @@ static void
 check_unmodified_loc(const char *file, size_t line,
     const char *arr, size_t begin, size_t end)
 {
-	size_t mod_begin = begin, mod_end = end;
-	while (mod_begin < mod_end && arr[mod_begin] == 'Z')
-		mod_begin++;
-	while (mod_begin < mod_end && arr[mod_end - 1] == 'Z')
-		mod_end--;
+	while (begin < end && arr[begin] == 'Z')
+		begin++;
+	while (begin < end && arr[end - 1] == 'Z')
+		end--;
 	ATF_CHECK_MSG(
-	    mod_begin == mod_end,
+	    begin == end,
 	    "failed:\n"
 	    "\ttest case: %s:%zu\n"
 	    "\tout-of-bounds write from %zu to %zu: %s\n",
 	    file, line,
-	    mod_begin, mod_end, vis_arr(arr + mod_begin, mod_end - mod_begin));
+	    begin, end, vis_arr(arr + begin, end - begin));
 }
 
 static void
 h_snprintb_loc(const char *file, size_t line,
-    size_t bufsize, const char *fmt, size_t fmtlen, uint64_t val,
-    int exp_rv, const char *res, size_t reslen)
+    size_t bufsize, const char *bitfmt, size_t bitfmtlen, uint64_t val,
+    int want_rv, const char *want_buf, size_t want_bufsize)
 {
 	char buf[1024];
 
 	ATF_REQUIRE(bufsize <= sizeof(buf));
-	ATF_REQUIRE(reslen <= sizeof(buf));
+	ATF_REQUIRE(want_bufsize <= sizeof(buf));
+	if (bitfmtlen > 2 && bitfmt[0] == '\177')
+		ATF_REQUIRE_MSG(bitfmt[bitfmtlen - 1] == '\0',
+		    "%s:%zu: missing trailing '\\0' in bitfmt",
+		    file, line);
+	if (bufsize == 0 && want_bufsize == 1)
+		want_bufsize = 0;
 
 	memset(buf, 'Z', sizeof(buf));
-	int rv = snprintb(buf, bufsize, fmt, val);
+	int rv = snprintb(buf, bufsize, bitfmt, val);
 	ATF_REQUIRE(rv >= 0);
 	size_t rlen = rv;
 
-	if (bufsize == 0 && reslen == 1)
-		reslen = 0;
 	ATF_CHECK_MSG(
-	    rv == exp_rv
-	    && memcmp(buf, res, reslen) == 0
+	    rv == want_rv
+	    && memcmp(buf, want_buf, want_bufsize) == 0
 	    && buf[rlen < bufsize ? rlen : bufsize - 1] == '\0',
 	    "failed:\n"
 	    "\ttest case: %s:%zu\n"
@@ -100,28 +103,28 @@ h_snprintb_loc(const char *file, size_t 
 	    "\twant: %d bytes %s\n"
 	    "\thave: %d bytes %s\n",
 	    file, line,
-	    vis_arr(fmt, fmtlen),
+	    vis_arr(bitfmt, bitfmtlen),
 	    (uintmax_t)val,
-	    exp_rv, vis_arr(res, reslen),
-	    rv, vis_arr(buf, reslen));
-	check_unmodified_loc(file, line, buf, reslen, sizeof(buf));
+	    want_rv, vis_arr(want_buf, want_bufsize),
+	    rv, vis_arr(buf, want_bufsize));
+	check_unmodified_loc(file, line, buf, want_bufsize, sizeof(buf));
 }
 
-#define	h_snprintb_len(bufsize, fmt, val, exp_rv, res)			\
+#define	h_snprintb_len(bufsize, bitfmt, val, want_rv, want_buf)		\
 	h_snprintb_loc(__FILE__, __LINE__,				\
-	    bufsize, fmt, sizeof(fmt) - 1, val,				\
-	    exp_rv, res, sizeof(res))
-#define	h_snprintb(fmt, val, res)					\
-	h_snprintb_len(1024, fmt, val, sizeof(res) - 1, res)
+	    bufsize, bitfmt, sizeof(bitfmt) - 1, val,			\
+	    want_rv, want_buf, sizeof(want_buf))
+#define	h_snprintb(bitfmt, val, want_buf)				\
+	h_snprintb_len(1024, bitfmt, val, sizeof(want_buf) - 1, want_buf)
 
 static void
 h_snprintb_error_loc(const char *file, size_t line,
-    const char *fmt, size_t fmtlen)
+    const char *bitfmt, size_t bitfmtlen)
 {
 	char buf[1024];
 
 	memset(buf, 'Z', sizeof(buf));
-	int rv = snprintb(buf, sizeof(buf), fmt, 0);
+	int rv = snprintb(buf, sizeof(buf), bitfmt, 0);
 	size_t buflen = rv;
 
 	ATF_REQUIRE(rv >= -1);
@@ -131,12 +134,12 @@ h_snprintb_error_loc(const char *file, s
 	    "\tformat: %s\n"
 	    "\tresult: %zu bytes %s\n",
 	    file, line,
-	    vis_arr(fmt, fmtlen),
+	    vis_arr(bitfmt, bitfmtlen),
 	    buflen, vis_arr(buf, buflen));
 }
 
-#define	h_snprintb_error(fmt)						\
-	h_snprintb_error_loc(__FILE__, __LINE__, fmt, sizeof(fmt) - 1)
+#define	h_snprintb_error(bitfmt)					\
+	h_snprintb_error_loc(__FILE__, __LINE__, bitfmt, sizeof(bitfmt) - 1)
 
 ATF_TC(snprintb);
 ATF_TC_HEAD(snprintb, tc)
@@ -146,430 +149,876 @@ ATF_TC_HEAD(snprintb, tc)
 ATF_TC_BODY(snprintb, tc)
 {
 
-	// old-style format, octal
+	// style and number base, old style, octal, zero value
+	//
+	// The value 0 does not get a leading '0'.
 	h_snprintb(
-	    "\010"
-	    "\002BITTWO"
-	    "\001BITONE",
-	    3,
-	    "03<BITTWO,BITONE>");
+	    "\010",
+	    0,
+	    "0");
 
-	// old-style format, decimal
+	// style and number base, old style, octal, nonzero value
+	//
+	// Nonzero octal values get a leading '0'.
 	h_snprintb(
-	    "\012"
-	    "\0011"
-	    "\0119"
-	    "\02117"
-	    "\04032",
-	    0xffffffff,
-	    "4294967295<1,9,17,32>");
-
-	// old-style format, hexadecimal, from msb downto lsb
-	h_snprintb(
-	    "\020"
-	    "\04032"
-	    "\03024"
-	    "\02016"
-	    "\0108"
-	    "\0077"
-	    "\0066"
-	    "\0055"
-	    "\0044"
-	    "\0033"
-	    "\0022"
-	    "\0011"
-	    // The old-style format supports only 32 bits, interpreting the
-	    // \041 as part of the text belonging to bit 1.
-	    "\04133",
-	    0x0000ffff00ff0f35,
-	    "0xffff00ff0f35<24,6,5,3,1!33>");
+	    "\010",
+	    0xff,
+	    "0377");
 
-	// old-style format, hexadecimal, from lsb to msb
+	// style and number base, old style, decimal, zero value
 	h_snprintb(
-	    "\020"
-	    "\0011"
-	    "\0022"
-	    "\0033"
-	    "\0044"
-	    "\0055"
-	    "\0066"
-	    "\0077"
-	    "\0108"
-	    "\02016"
-	    "\03024"
-	    "\04032"
-	    // The old-style format supports only 32 bits, interpreting the
-	    // \041 as part of the text belonging to bit 32.
-	    "\04133",
-	    0xffff0000ff00f0ca,
-	    "0xffff0000ff00f0ca<2,4,7,8,16,32!33>");
-
-	// The bits can be listed in arbitrary order, there can also be
-	// duplicates. A bit's description can be empty, resulting in several
-	// commas in a row.
+	    "\012",
+	    0,
+	    "0");
+
+	// style and number base, old style, decimal, nonzero value
 	h_snprintb(
-	    "\020"
-	    "\001lsb"
-	    "\040msb"
-	    "\011"
-	    "\012"
-	    "\002above-lsb"
-	    "\037below-msb"
-	    "\001lsb-again"
-	    "\040msb-again",
-	    0xc0000303,
-	    "0xc0000303<lsb,msb,,,above-lsb,below-msb,lsb-again,msb-again>");
-
-#if 0
-	// If the first bit number is 33 or more, snprintb invokes undefined
-	// behavior due to an out-of-bounds bit shift, though undetected by
-	// -ftrapv. Later bit numbers are properly checked.
-	h_snprintb(
-	    "\020"
-	    "\177undefined_behavior"
-	    "\001lsb",
-	    0xffffffffffffffff,
-	    "0xffffffffffffffff<?>");
-#endif
+	    "\012",
+	    0xff,
+	    "255");
+
+	// style and number base, old style, hexadecimal, zero value
+	//
+	// The value 0 does not get a leading '0x'.
+	h_snprintb(
+	    "\020",
+	    0,
+	    "0");
 
-	// old-style format, invalid number base 0
+	// style and number base, old style, hexadecimal, nonzero value
+	//
+	// Nonzero hexadecimal values get a leading '0x'.
+	h_snprintb(
+	    "\177\020",
+	    0xff,
+	    "0xff");
+
+	// style and number base, old style, invalid base 0
 	h_snprintb_error(
 	    "");
 
-	// old-style format, invalid number base 2
+	// style and number base, old style, invalid base 2
 	h_snprintb_error(
 	    "\002");
 
-	// old-style format, invalid number base 255 or -1
+	// style and number base, old style, invalid base 255 or -1
 	h_snprintb_error(
 	    "\377");
 
-	// old-style format, small buffers
+	// style and number base, new style, octal, zero value
+	//
+	// The value 0 does not get a leading '0'.
+	h_snprintb(
+	    "\177\010",
+	    0,
+	    "0");
+
+	// style and number base, new style, octal, nonzero value
+	//
+	// Nonzero octal values get a leading '0'.
+	h_snprintb(
+	    "\177\010",
+	    0xff,
+	    "0377");
+
+	// style and number base, new style, decimal, zero value
+	h_snprintb(
+	    "\177\012",
+	    0,
+	    "0");
+
+	// style and number base, new style, decimal, nonzero value
+	h_snprintb(
+	    "\177\012",
+	    0xff,
+	    "255");
+
+	// style and number base, new style, hexadecimal, zero value
+	//
+	// The value 0 does not get a leading '0x'.
+	h_snprintb(
+	    "\177\020",
+	    0,
+	    "0");
+
+	// style and number base, new style, hexadecimal, nonzero value
+	//
+	// Nonzero hexadecimal values get a leading '0x'.
+	h_snprintb(
+	    "\177\020",
+	    0xff,
+	    "0xff");
+
+	// style and number base, new style, invalid number base 0
+	h_snprintb_error(
+	    "\177");
+
+	// style and number base, new style, invalid number base 2
+	h_snprintb_error(
+	    "\177\002");
+
+	// style and number base, new style, invalid number base 255 or -1
+	h_snprintb_error(
+	    "\177\377");
+
+	// old style, from lsb to msb
+	h_snprintb(
+	    "\020"
+	    "\001bit1"
+	    "\002bit2"
+	    "\037bit31"
+	    "\040bit32",
+	    0xffffffff80000001,
+	    "0xffffffff80000001<bit1,bit32>");
+
+	// old style, invalid bit number, at the beginning
+#if 0 /* undefined behavior due to out-of-bounds bit shift */
+	h_snprintb_error(
+	    "\020"
+	    "\041invalid");
+#endif
+
+	// old style, invalid bit number, in the middle
+	//
+	// The old-style format supports only 32 bits, interpreting the
+	// \041 as part of the text belonging to bit 1.
+	h_snprintb(
+	    "\020"
+	    "\001bit1"
+	    "\041bit33",
+	    0x1,
+	    "0x1<bit1!bit33>");
+
+	// old style, repeated bit numbers
+	//
+	// When a bit number is mentioned more than once,
+	// this is most likely a typo.
+	h_snprintb(
+	    "\020"
+	    "\001once"
+	    "\001again",
+	    0x1,
+	    "0x1<once,again>");
+
+	// old style, non-printable description
+	//
+	// The characters ' ' and '\t' are interpreted as bit numbers,
+	// not as part of the description; the visual arrangement is
+	// misleading.
+	h_snprintb(
+	    "\020"
+	    "\001least significant"
+	    "\002horizontal\ttab",
+	    0xff,
+	    "0xff<least,horizontal>");
+
+	// old style, empty description
+	//
+	// Empty descriptions result in multiple commas in a row, which is a
+	// mistake.
+	h_snprintb(
+	    "\020"
+	    "\001lsb"
+	    "\004"
+	    "\005"
+	    "\010msb",
+	    0xff,
+	    "0xff<lsb,,,msb>");
+
+	// old style, buffer size 0
+	//
+	// With the buffer size being 0, the buffer is not modified at all.
+	// In kernel mode, the buffer is zeroed out and thus must not be null.
 	h_snprintb_len(
 	    0, "\020", 0,
 	    1, "");
+
+	// old style, buffer too small for value
 	h_snprintb_len(
 	    1, "\020", 0,
 	    1, "");
+
+	// old style, buffer large enough for zero value
 	h_snprintb_len(
 	    2, "\020", 0,
 	    1, "0");
+
+	// old style, buffer larger than necessary for zero value
 	h_snprintb_len(
 	    3, "\020", 0,
 	    1, "0");
+
+	// old style, buffer too small for nonzero value
 	h_snprintb_len(
 	    3, "\020", 7,
 	    3, "0x");
+
+	// old style, buffer large enough for nonzero value
 	h_snprintb_len(
 	    4, "\020", 7,
 	    3, "0x7");
+
+	// old style, buffer too small for '<'
+	h_snprintb_len(
+	    4, "\020\001lsb", 7,
+	    8, "0x7");
+
+	// old style, buffer too small for description
 	h_snprintb_len(
 	    7, "\020\001lsb", 7,
 	    8, "0x7<ls");
+
+	// old style, buffer too small for '>'
 	h_snprintb_len(
 	    8, "\020\001lsb", 7,
 	    8, "0x7<lsb");
+
+	// old style, buffer large enough for '<'
 	h_snprintb_len(
 	    9, "\020\001lsb", 7,
 	    8, "0x7<lsb>");
+
+	// old style, buffer too small for second description
 	h_snprintb_len(
 	    9, "\020\001one\002two", 7,
 	    12, "0x7<one,");
+
+	// old style, buffer too small for second description
 	h_snprintb_len(
 	    10, "\020\001one\002two", 7,
 	    12, "0x7<one,t");
+
+	// old style, buffer too small for '>' after second description
 	h_snprintb_len(
 	    12, "\020\001one\002two", 7,
 	    12, "0x7<one,two");
+
+	// old style, buffer large enough for '>' after second description
 	h_snprintb_len(
 	    13, "\020\001one\002two", 7,
 	    12, "0x7<one,two>");
 
-	// new-style format, single bits, octal
+	// new style single bits
 	h_snprintb(
-	    "\177\010"
-	    "b\000bit0\0"
+	    "\177\020"
+	    "b\000lsb\0"
+	    "b\001above-lsb\0"
 	    "b\037bit31\0"
 	    "b\040bit32\0"
-	    "b\077bit63\0",
-	    0xf000000ff000000f,
-	    "01700000000776000000017<bit0,bit31,bit32,bit63>");
+	    "b\076below-msb\0"
+	    "b\077msb\0",
+	    0x8000000180000001,
+	    "0x8000000180000001<lsb,bit31,bit32,msb>");
 
-	// new-style format, single bits, decimal
+	// new style single bits, duplicate bits
 	h_snprintb(
-	    "\177\012"
-	    "b\000bit0\0"
-	    "b\037bit31\0"
-	    "b\040bit32\0"
-	    "b\077bit63\0",
-	    0xf000000ff000000f,
-	    "17293822637553745935<bit0,bit31,bit32,bit63>");
+	    "\177\020"
+	    "b\000lsb\0"
+	    "b\000lsb\0"
+	    "b\000lsb\0",
+	    0xff,
+	    "0xff<lsb,lsb,lsb>");
 
-	// new-style format, single bits, hexadecimal
+	// new style single bits, empty description
 	h_snprintb(
 	    "\177\020"
-	    "b\000bit0\0"
-	    "b\037bit31\0"
-	    "b\040bit32\0"
-	    "b\077bit63\0",
-	    0xf000000ff000000f,
-	    "0xf000000ff000000f<bit0,bit31,bit32,bit63>");
+	    "b\000lsb\0"
+	    "b\001\0"
+	    "b\002\0"
+	    "b\007msb\0"
+	    ,
+	    0xff,
+	    "0xff<lsb,,,msb>");
 
-	// new-style format, invalid number base 2
+	// new style single bits, invalid
+#if 0 /* undefined behavior due to out-of-bounds bit shift */
 	h_snprintb_error(
-	    "\177\002");
-
-	// new-style format, invalid number base 255 or -1
+	    "\177\020"
+	    "b\100too-high\0");
+#endif
+#if 0 /* undefined behavior due to out-of-bounds bit shift */
 	h_snprintb_error(
-	    "\177\377");
+	    "\177\020"
+	    "b\377too-high\0");
+#endif
 
-	// new-style format, single bits, edge cases
+	// new style single bits, non-printable description
 	//
-	// The bits can be listed in arbitrary order, there can also be
-	// duplicates. A bit's description can be empty, resulting in several
-	// commas in a row.
-	h_snprintb(
-	    "\177\020"
-	    "b\01lsb\0"
-	    "b\02\0"
-	    "b\03\0"
-	    "b\05NOTBOOT\0"
-	    "b\06FPP\0"
-	    "b\13SDVMA\0"
-	    "b\15VIDEO\0"
-	    "b\20LORES\0"
-	    "b\21FPA\0"
-	    "b\22DIAG\0"
-	    "b\16CACHE\0"
-	    "b\17IOCACHE\0"
-	    "b\22LOOPBACK\0"
-	    "b\04DBGCACHE\0",
-	    0xe86f,
-	    "0xe86f<lsb,,,NOTBOOT,FPP,SDVMA,VIDEO,CACHE,IOCACHE>");
+	// Contrary to the old-style format, the new-style format allows
+	// arbitrary characters in the description, even control characters
+	// and non-ASCII characters.
+	h_snprintb(
+	    "\177\020"
+	    "b\000space \t \xC3\xA4\0",
+	    0x1,
+	    "0x1<space \t \xC3\xA4>");
 
-	// new-style format, octal, named bit-field
+	// new style named bit-field, octal
+	//
+	// The bit-field value gets a leading '0' iff it is nonzero.
 	h_snprintb(
 	    "\177\010"
-	    "f\010\004Field\0"
-		"=\001one\0"
-		"=\002two\0",
-	    0x100,
-	    "0400<Field=01=one>");
+	    "f\000\010byte0\0"
+	    "f\010\010byte1\0",
+	    0x0100,
+	    "0400<byte0=0,byte1=01>");
 
-	// new-style format, decimal, named bit-field
+	// new style named bit-field, decimal
 	h_snprintb(
 	    "\177\012"
-	    "f\010\004Field\0"
-		"=\1one\0"
-		"=\2two\0",
-	    0x100,
-	    "256<Field=1=one>");
+	    "f\000\010byte0\0"
+	    "f\010\010byte1\0",
+	    0x0100,
+	    "256<byte0=0,byte1=1>");
 
-	// new-style format, hexadecimal, named bit-field
+	// new style named bit-field, hexadecimal
 	h_snprintb(
 	    "\177\020"
-	    "f\010\004Field\0"
-		"=\1one\0"
-		"=\2two\0",
-	    0x100,
-	    "0x100<Field=0x1=one>");
+	    "f\000\010byte0\0"
+	    "f\010\010byte1\0",
+	    0x0100,
+	    "0x100<byte0=0,byte1=0x1>");
 
-	// new-style format, octal, unnamed bit-field
+	// new style bit-field, from 0 width 0
 	h_snprintb(
-	    "\177\010"
-	    "F\010\004Field\0"
-		":\001one\0"
-		":\002two\0",
-	    0x100,
-	    "0400<one>");
+	    "\177\020"
+	    "f\000\000zero-width\0"
+		"=\000zero\0",
+	    0xffff,
+	    "0xffff<zero-width=0=zero>");
 
-	// new-style format, decimal, unnamed bit-field
+	// new style bit-field, from 0 width 1
 	h_snprintb(
-	    "\177\012"
-	    "F\010\004Field\0"
-		":\1one\0"
-		":\2two\0",
-	    0x100,
-	    "256<one>");
+	    "\177\020"
+	    "f\000\001lsb\0"
+		"=\000zero\0"
+		"=\001one\0",
+	    0x0,
+	    "0<lsb=0=zero>");
+	h_snprintb(
+	    "\177\020"
+	    "f\000\001lsb\0"
+		"=\000zero\0"
+		"=\001one\0",
+	    0x1,
+	    "0x1<lsb=0x1=one>");
 
-	// new-style format, hexadecimal, unnamed bit-field
+	// new style bit-field, from 0 width 63
 	h_snprintb(
 	    "\177\020"
-	    "F\010\004Field\0"
-		":\1one\0"
-		":\2two\0",
-	    0x100,
-	    "0x100<one>");
+	    "f\000\077uint63\0"
+		"=\125match\0",
+	    0xaaaa5555aaaa5555,
+	    "0xaaaa5555aaaa5555<uint63=0x2aaa5555aaaa5555>");
+
+	// new style bit-field, from 0 width 64
+#if 0 /* undefined behavior due to out-of-bounds bit shift */
+	h_snprintb(
+	    "\177\020"
+	    "f\000\100uint64\0"
+		"=\125match\0",
+	    0xaaaa5555aaaa5555,
+	    "0xaaaa5555aaaa5555<uint64=0xaaaa5555aaaa5555>");
+#endif
+
+	// new style bit-field, from 0 width 65
+#if 0 /* undefined behavior due to out-of-bounds bit shift */
+	h_snprintb_error(
+	    "\177\020"
+	    "f\000\101uint65\0");
+#endif
+
+	// new style bit-field, from 1 width 8
+	h_snprintb(
+	    "\177\020"
+	    "f\001\010uint8\0"
+		"=\203match\0",
+	    0x0106,
+	    "0x106<uint8=0x83=match>");
 
-	// new-style format, hexadecimal, named bit-field, edge cases
+	// new style bit-field, from 1 width 9
 	//
-	// Field values can be listed in arbitrary order, there can also be
-	// duplicates. A field value's description can be empty, resulting in
-	// several '=' in a row. The ':' directive can emulate the '='
-	// directive, but not vice versa.
+	// The '=' and ':' directives can only match a bit-field value between
+	// 0 and 255, independent of the bit-field's width.
 	h_snprintb(
-	    "\177\20"
-	    "f\0\4Field\0"
-		"=\1one\0"
-		"=\1one-again\0"
-		"=\1\0"
-		"=\1\0"
-		":\1double\0"
-		":\1-colon\0"
-		":\1=equal\0"
-		"=\2TWO\0",
-	    1,
-	    "0x1<Field=0x1=one=one-again==double-colon=equal>");
+	    "\177\020"
+	    "f\001\011uint9\0"
+		"=\203match\0"
+		"*=other-f\0"
+	    "F\001\011\0"
+		":\203match\0"
+		"*other-F\0",
+	    0x0306,
+	    "0x306<uint9=0x183=other-f,other-F>");
+
+	// new style bit-field, from 32 width 32
+	h_snprintb(
+	    "\177\020"
+	    "f\040\040uint32\0",
+	    0xaaaa555500000000,
+	    "0xaaaa555500000000<uint32=0xaaaa5555>");
+
+	// new style bit-field, from 60 width 4
+	h_snprintb(
+	    "\177\020"
+	    "f\074\004uint4\0",
+	    0xf555555555555555,
+	    "0xf555555555555555<uint4=0xf>");
 
-	// new-style format, hexadecimal, unnamed bit-field, edge cases
+	// new style bit-field, from 60 width 5
 	//
-	// Combining the 'F' and '=' directives generates output that doesn't
-	// look well-formed.
+	// The end of the bit-field is out of bounds.
 	h_snprintb(
-	    "\177\20"
-	        "=\0all-zero\0"
-	        "=\1all-one\0"
-	        ":\1-continued\0"
-	    "F\0\4Field\0"
-		"=\1one\0"
-		"=\1one-again\0"
-		"=\1\0"
-		"=\1\0"
-		":\1double\0"
-		":\1-colon\0"
-		":\1=equal\0"
-		"=\2TWO\0",
-	    1,
-	    "0x1=all-one-continued<=one=one-again==double-colon=equal>");
+	    "\177\020"
+	    "f\074\005uint5\0",
+	    0xf555555555555555,
+	    "0xf555555555555555<uint5=0xf>");
 
-	// new-style format, bit-fields with fixed fallback value
+	// new style bit-field, from 64 width 0
 	//
-	// Only the first fallback value is used, all others are ignored.
+	// The beginning of the bit-field is out of bounds, the end is fine.
+#if 0 /* undefined behavior due to out-of-bounds bit shift */
+	h_snprintb_error(
+	    "\177\020"
+	    "f\100\000uint0\0");
+#endif
+
+	// new style bit-field, from 65 width 0
+	//
+	// The beginning and end of the bit-field are out of bounds.
+#if 0 /* undefined behavior due to out-of-bounds bit shift */
+	h_snprintb_error(
+	    "\177\020"
+	    "f\101\000uint0\0");
+#endif
+
+	// new style bit-field, empty field description
+	//
+	// The description of a field may be empty, though this is probably a
+	// mistake, as it outputs an isolated '='.
 	h_snprintb(
 	    "\177\020"
-	    "f\0\4Field\0"
-		"=\1one\0"
-		"=\2two\0"
-		"*=other\0"
-		"*=yet-another\0"
-	    "b\1separator\0"
-	    "F\0\4Field\0"
-		":\1one\0"
-		":\2two\0"
-		"*other\0"
-		"*yet-another\0",
-	    3,
-	    "0x3<Field=0x3=other,separator,other>");
+	    "f\000\004\0"
+		"=\001one\0",
+	    0x1,
+	    "0x1<=0x1=one>");
 
-	// new-style format, bit-fields with numeric fallback value
+	// new style bit-field, non-printable description
+	//
+	// Contrary to the old-style format, the new-style format allows
+	// arbitrary characters in the description, even control characters
+	// and non-ASCII characters.
 	h_snprintb(
 	    "\177\020"
-	    "f\010\004Field\0"
-		"*=other(%04ju)\0"
-	    "b\000separator\0"
-	    "F\010\004Field\0"
-		"*other(%04ju)\0",
-	    0x301,
-	    "0x301<Field=0x3=other(0003),separator,other(0003)>");
+	    "f\000\010\t \xC3\xA4\0"
+		"=\001\t \xC3\xA4\0"
+	    "F\000\010\0"
+		":\001\t \xC3\xA4\0"
+	    "F\000\010\0"
+		"*\t \xC3\xA4\0",
+	    0x1,
+	    "0x1<\t \xC3\xA4=0x1=\t \xC3\xA4,\t \xC3\xA4,\t \xC3\xA4>");
 
-	// new-style format, bit-field with more than 8 bits
+	// new style bit-field, '=' with empty description
 	//
-	// The '=' and ':' directives can only match values from 0 to 255, so
-	// the fallback value always steps in. The complete value of the
-	// bit-field appears in the output, though.
+	// The description of a '=' directive may be empty, though this is
+	// probably a mistake, as it outputs several '=' in a row.
 	h_snprintb(
 	    "\177\020"
-	    "f\010\020Field\0"
-		"=\377ones\0"
-		"*=other(%jx)\0"
-	    "F\010\020\0"
-		":\377ones\0"
-		"*other(%jx)\0",
-	    0x77ff55,
-	    "0x77ff55<Field=0x77ff=other(77ff),other(77ff)>");
+	    "f\000\004f\0"
+		"=\001one\0"
+		"=\001\0"
+		"=\001\0",
+	    0x1,
+	    "0x1<f=0x1=one==>");
 
-	// new-style format, bit-field with 8 bits
+	// new style bit-field, 'F' followed by ':' with empty description
+	//
+	// The description of a ':' directive may be empty, though this is
+	// probably a mistake, as it leads to empty angle brackets.
 	h_snprintb(
 	    "\177\020"
-	    "F\010\010\0"
-		":\377all\0"
-		"*other\0",
-	    0xff00,
-	    "0xff00<all>");
+	    "F\000\004\0"
+		":\001\0"
+		"*default\0",
+	    0x1,
+	    "0x1<>");
+
+	// new style bit-field, 'F', ':' with empty description, '*'
+	//
+	// The ':' directive could be used to suppress a following '*'
+	// directive, but this combination is probably a mistake, as a
+	// matching ':' leads to empty angle brackets.
+	h_snprintb(
+	    "\177\020"
+	    "F\000\004\0"
+		":\001\0"
+		"*default\0",
+	    0x2,
+	    "0x2<default>");
 
-	// new-style format, bit-fields with no match
+	// new style bit-field, 'f' with non-exhaustive '='
 	h_snprintb(
 	    "\177\020"
-	    "f\010\004Field\0"
+	    "f\000\004Field\0"
 		"=\1one\0"
 		"=\2two\0",
-	    0x301,
-	    "0x301<Field=0x3>");
+	    0x3,
+	    "0x3<Field=0x3>");
+
+	// new style bit-field, 'F' with non-exhaustive ':'
+	//
+	// A bit-field that does not match any values still generates empty
+	// angle brackets.
 	h_snprintb(
 	    "\177\020"
-	    "F\010\004\0"
+	    "F\000\004\0"
 		":\1one\0"
 		":\2two\0",
-	    0x301,
-	    "0x301<>");
+	    0x3,
+	    "0x3<>");
+
+	// new style bit-field, 'F' with non-exhaustive ':'
+	//
+	// A bit-field that does not match any values still generates empty
+	// angle brackets or adjacent commas.
 	h_snprintb(
 	    "\177\020"
-	    "f\010\004Field\0"
-		"=\1one\0"
-		"=\2two\0"
-	    "b\000separator\0"
-	    "F\010\004\0"
+	    "b\000bit0\0"
+	    "F\000\004\0"
 		":\1one\0"
-		":\2two\0",
-	    0x301,
-	    "0x301<Field=0x3,separator,>");
+		":\2two\0"
+	    "b\001bit1\0",
+	    0x3,
+	    "0x3<bit0,,bit1>");
 
-	// new-style format, two separate bit-fields
+	// new style, two separate bit-fields
 	h_snprintb(
-	    "\177\20"
-	    "f\0\4Field_1\0"
-		"=\1ONE\0"
-		"=\2TWO\0"
-	    "f\4\4Field_2\0"
-		"=\1ONE\0"
-		"=\2TWO\0",
+	    "\177\020"
+	    "f\000\004f1\0"
+		"=\001one\0"
+		"=\002two\0"
+	    "f\004\004f2\0"
+		"=\001one\0"
+		"=\002two\0",
 	    0x12,
-	    "0x12<Field_1=0x2=TWO,Field_2=0x1=ONE>");
+	    "0x12<f1=0x2=two,f2=0x1=one>");
+
+	// new style, mixed named and unnamed bit-fields
+	h_snprintb(
+	    "\177\020"
+	    "f\000\004f1\0"
+		"=\001one\0"
+		"=\002two\0"
+	    "F\010\004\0"
+		":\015thirteen\0"
+	    "f\004\004f2\0"
+		"=\001one\0"
+		"=\002two\0",
+	    0x0d12,
+	    "0xd12<f1=0x2=two,thirteen,f2=0x1=one>");
+
+	// new style bit-field, overlapping
+	h_snprintb(
+	    "\177\020"
+	    "f\000\004lo\0"
+	    "f\002\004mid\0"
+	    "f\004\004hi\0"
+	    "f\000\010all\0",
+	    0x18,
+	    "0x18<lo=0x8,mid=0x6,hi=0x1,all=0x18>");
+
+	// new style bit-field, difference between '=' and ':'
+	//
+	// The ':' directive can almost emulate the '=' directive, without the
+	// numeric output and with a different separator. It's best to use
+	// either 'f' with '=' or 'F' with ':', but not mix them.
+	h_snprintb(
+	    "\177\020"
+	    "f\000\004field\0"
+		"=\010value\0"
+	    "F\000\000\0"
+		":\000field\0"	// Since the description of 'F' is ignored.
+	    "F\000\004\0"
+		":\010value\0",
+	    0x18,
+	    "0x18<field=0x8=value,field,value>");
+
+	// new style bit-field default, fixed string
+	//
+	// The 'f' directive pairs up with the '=' directive,
+	// the 'F' directive pairs up with the ':' directive,
+	// but there's only one 'default' directive for both variants,
+	// so its description should include the '=' when used with 'f' but
+	// not with 'F'.
+	h_snprintb(
+	    "\177\020"
+	    "f\030\010f1\0"
+		"*default\0"
+	    "f\020\010f2\0"
+		"*=default\0"
+	    "F\010\010\0"
+		"*default\0"
+	    "F\010\010\0"
+		"*=default\0",
+	    0x11223344,
+	    "0x11223344<f1=0x11default,f2=0x22=default,default,=default>");
+
+	// new style bit-field default, numeric conversion specifier
+	h_snprintb(
+	    "\177\020"
+	    "f\010\010f\0"
+		"*=f(%ju)\0"
+	    "F\000\010F\0"
+		"*F(%ju)\0",
+	    0x1122,
+	    "0x1122<f=0x11=f(17),F(34)>");
+
+	// new style bit-field default, invalid conversion specifier
+	//
+	// There is no reliable way to make snprintf return an error, as such
+	// errors are defined as undefined behavior in the C standard.
+	// Instead, here's a conversion specifier that produces a literal '%'.
+	h_snprintb(
+	    "\177\020"
+	    "f\000\010f\0"
+		"*=%030ju%%\0",
+	    0xff,
+	    "0xff<f=0xff=000000000000000000000000000255%>");
+
+	// new style unknown directive
+	//
+	// Unknown directives are assumed to have a single byte argument
+	// followed by a description; they are skipped up to the next '\0'.
+	h_snprintb(
+	    "\177\020"
+	    "c\010ignored\0"
+	    "c\000b\0"
+	    "lsb\0"
+	    "b\007msb\0",
+	    0xff,
+	    "0xff<msb>");
+
+	// new style combinations, 'b' '='
+	//
+	// A '=' directive without a preceding 'f' or 'F' directive applies to
+	// the whole value; its description may appear inside or outside the
+	// angle brackets. Having such a format is likely an error.
+	h_snprintb(
+	    "\177\020"
+	    "b\004bit4\0"
+		"=\000clear\0"
+		"=\001set\0"
+		"=\245complete\0"
+	    "b\000bit0\0"
+		"=\000clear\0"
+		"=\001set\0"
+		"=\245complete\0",
+	    0xa5,
+	    "0xa5=complete<bit0=complete>");
+
+	// new style combinations, 'b' ':'
+	//
+	// A ':' directive without a preceding 'f' or 'F' directive applies to
+	// the whole value; its description may appear inside or outside the
+	// angle brackets. Having such a format is likely an error.
+	h_snprintb(
+	    "\177\020"
+	    "b\004bit4\0"
+		":\000clear\0"
+		":\001set\0"
+		":\245complete\0"
+	    "b\000bit0\0"
+		":\000clear\0"
+		":\001set\0"
+		":\245complete\0",
+	    0xa5,
+	    "0xa5complete<bit0complete>");
+
+	// new style combinations, 'b' '*'
+	//
+	// A '*' directive without a preceding 'f' or 'F' directive is ignored.
+	h_snprintb(
+	    "\177\020"
+	    "b\004bit4\0"
+		"*default(%ju)\0"
+	    "b\000bit0\0"
+		"*default(%ju)\0",
+	    0xa5,
+	    "0xa5<bit0>");
+
+	// new style combinations, 'f' 'b' '='
+	//
+	// Between an 'f' and an '=' directive, there may be unrelated 'b'
+	// directives, they do not affect the value of the "previous field".
+	// Formats like these are probably mistakes.
+	h_snprintb(
+	    "\177\020"
+	    "f\000\010f\0"
+	    "b\005bit5\0"
+		"=\xa5match\0",
+	    0xa5,
+	    "0xa5<f=0xa5,bit5=match>");
+
+	// new style combinations, 'f' 'b' ':'
+	//
+	// Between an 'f' and a ':' directive, there may be unrelated 'b'
+	// directives, they do not affect the value of the "previous field".
+	// Formats like these are mistakes, as the output is garbled.
+	h_snprintb(
+	    "\177\020"
+	    "f\000\010f\0"
+	    "b\005bit5\0"
+		":\xa5match\0",
+	    0xa5,
+	    "0xa5<f=0xa5,bit5match>");
+
+	// new style combinations, 'f' ':'
+	h_snprintb(
+	    "\177\20"
+	    "f\000\004nibble\0"
+		":\001one\0",
+	    0x01,
+	    "0x1<nibble=0x1one>");
+
+	// new style combinations, 'F' '='
+	//
+	// Combining the 'F' and '=' directives outputs an isolated '=', which
+	// doesn't look well-formed.
+	h_snprintb(
+	    "\177\20"
+	    "F\000\004\0"
+		"=\001one\0",
+	    0x01,
+	    "0x1<=one>");
+
+	// new style combinations, '='
+	//
+	// A '=' directive without a preceding 'f' or 'F' directive matches on
+	// the complete value. This is not documented in the manual page, and
+	// formats like these are probably mistakes.
+	h_snprintb(
+	    "\177\020"
+		"=\xa5match\0",
+	    0xa5,
+	    "0xa5=match");
+
+	// new style combinations, ':'
+	//
+	// A ':' directive without a preceding 'f' or 'F' directive matches on
+	// the complete value. This is not documented in the manual page, and
+	// formats like these are probably mistakes.
+	h_snprintb(
+	    "\177\020"
+		":\xa5match\0",
+	    0xa5,
+	    "0xa5match");
+
+	// new style combinations, '*'
+	//
+	// A '*' directive without a preceding 'f' or 'F' is skipped. Formats
+	// like these are mistakes.
+	h_snprintb(
+	    "\177\020"
+		"*match\0",
+	    0xa5,
+	    "0xa5");
+
+	// new style combinations, 'f' '*' '='
+	//
+	// A '*' directive may be followed by a '=' directive. Formats like
+	// this are probably a mistake.
+	h_snprintb(
+	    "\177\020"
+	    "f\000\010f\0"
+		"*=default\0"
+		"=\xa5match\0",
+	    0xa5,
+	    "0xa5<f=0xa5=default=match>");
+
+	// new style combinations, 'F' '*' ':'
+	//
+	// A '*' directive may be followed by a ':' directive. Formats like
+	// this are probably a mistake.
+	h_snprintb(
+	    "\177\020"
+	    "F\000\010F\0"
+		"*default\0"
+		":\xa5-match\0",
+	    0xa5,
+	    "0xa5<default-match>");
+
+	// new style combinations, '*' '*'
+	//
+	// The first '*' directive matches everything, so the second '*'
+	// directive cannot match anything and is thus redundant. Formats like
+	// this are a mistake.
+	h_snprintb(
+	    "\177\020"
+	    "f\000\010f\0"
+		"*=default-f\0"
+		"*ignored\0"
+	    "F\000\010\0"
+		"*default-F\0"
+		"*ignored\0",
+	    0xa5,
+	    "0xa5<f=0xa5=default-f,default-F>");
+
+	// manual page, old style octal
+	h_snprintb(
+	    "\10\2BITTWO\1BITONE",
+	    3,
+	    "03<BITTWO,BITONE>");
+
+	// manual page, old style hexadecimal
+	h_snprintb(
+	    "\20"
+	    "\x10NOTBOOT" "\x0f""FPP" "\x0eSDVMA"
+	    "\x0cVIDEO" "\x0bLORES" "\x0a""FPA" "\x09""DIAG"
+	    "\x07""CACHE" "\x06IOCACHE" "\x05LOOPBACK"
+	    "\x04""DBGCACHE",
+	    0xe860,
+	    "0xe860<NOTBOOT,FPP,SDVMA,VIDEO,CACHE,IOCACHE>");
+
+	// manual page, new style bits and fields
+	h_snprintb(
+	    "\177\020"
+	    "b\0LSB\0" "b\1BITONE\0"
+	    "f\4\4NIBBLE2\0"
+	    "f\x10\4BURST\0" "=\4FOUR\0" "=\xf""FIFTEEN\0"
+	    "b\x1fMSB\0",
+	    0x800f0701,
+	    "0x800f0701<LSB,NIBBLE2=0,BURST=0xf=FIFTEEN,MSB>");
 
-	// new-style format, mixed named and unnamed bit-fields
-	h_snprintb(
-	    "\177\20"
-	    "f\0\4Field_1\0"
-		"=\1ONE\0"
-		"=\2TWO\0"
-	    "F\x8\4\0"
-		"*Field_3=%jd\0"
-	    "f\4\4Field_2\0"
-		":\1:ONE\0"
-		":\2:TWO\0",
-	    0xD12,
-	    "0xd12<Field_1=0x2=TWO,Field_3=13,Field_2=0x1:ONE>");
-
-	// new-style format, descriptions with spaces
-	h_snprintb(
-	    "\177\020"
-	    "b\000has std options\0"
-	    "f\010\004std options\0"
-		"=\000no options\0"
-		"=\017all options\0"
-	    "F\020\004ext options\0"
-		":\000no ext options\0"
-		":\017all ext options\0",
-	    0x000001,
-	    "0x1<has std options,std options=0=no options,no ext options>");
-	h_snprintb(
-	    "\177\020"
-	    "f\010\004std options\0"
-		"*=other std options\0"
-	    "F\020\004ext\toptions\0"
-		"*other\text\toptions\0",
-	    0x000001,
-	    "0x1<std options=0=other std options,other\text\toptions>");
+	// manual page, new style mmap
+#define	MAP_FMT				\
+	"\177\020"			\
+	"b\0"  "SHARED\0"		\
+	"b\1"  "PRIVATE\0"		\
+	"b\2"  "COPY\0"			\
+	"b\4"  "FIXED\0"		\
+	"b\5"  "RENAME\0"		\
+	"b\6"  "NORESERVE\0"		\
+	"b\7"  "INHERIT\0"		\
+	"b\11" "HASSEMAPHORE\0"		\
+	"b\12" "TRYFIXED\0"		\
+	"b\13" "WIRED\0"		\
+	"F\14\1\0"			\
+		":\0" "FILE\0"		\
+		":\1" "ANONYMOUS\0"	\
+	"b\15" "STACK\0"		\
+	"F\30\010\0"			\
+		":\000" "ALIGN=NONE\0"	\
+		":\015" "ALIGN=8KB\0"	\
+		"*"     "ALIGN=2^%ju\0"
+	h_snprintb(
+	    MAP_FMT,
+	    0x0d001234,
+	    "0xd001234<COPY,FIXED,RENAME,HASSEMAPHORE,ANONYMOUS,ALIGN=8KB>");
+	h_snprintb(
+	    MAP_FMT,
+	    0x2e000000,
+	    "0x2e000000<FILE,ALIGN=2^46>");
 
 	// It is possible but cumbersome to implement a reduced variant of
 	// rot13 using snprintb, shown here for lowercase letters only.
@@ -595,7 +1044,7 @@ ATF_TC_BODY(snprintb, tc)
 		    expected);
 	}
 
-	// new-style format, small buffers
+	// new style, small buffers
 	h_snprintb_len(
 	    0, "\177\020", 0,
 	    1, "");
@@ -635,29 +1084,33 @@ ATF_TC_BODY(snprintb, tc)
 	h_snprintb_len(
 	    13, "\177\020b\000one\0b\001two\0", 7,
 	    12, "0x7<one,two>");
-
 }
 
 static void
 h_snprintb_m_loc(const char *file, size_t line,
-    size_t bufsize, const char *fmt, size_t fmtlen, uint64_t val, size_t max,
-    size_t exp_rv, const char *res, size_t reslen)
+    size_t bufsize, const char *bitfmt, size_t bitfmtlen, uint64_t val,
+    size_t max,
+    size_t want_rv, const char *want_buf, size_t want_bufsize)
 {
 	char buf[1024];
 
 	ATF_REQUIRE(bufsize > 0);
 	ATF_REQUIRE(bufsize <= sizeof(buf));
-	ATF_REQUIRE(reslen <= sizeof(buf));
+	ATF_REQUIRE(want_bufsize <= sizeof(buf));
+	if (bitfmtlen > 2 && bitfmt[0] == '\177')
+		ATF_REQUIRE_MSG(bitfmt[bitfmtlen - 1] == '\0',
+		    "%s:%zu: missing trailing '\\0' in bitfmt",
+		    file, line);
 
 	memset(buf, 'Z', sizeof(buf));
-	int rv = snprintb_m(buf, bufsize, fmt, val, max);
+	int rv = snprintb_m(buf, bufsize, bitfmt, val, max);
 	ATF_REQUIRE_MSG(rv >= 0,
 	    "formatting %jx with '%s' returns error %d",
-	    (uintmax_t)val, vis_arr(fmt, fmtlen), rv);
+	    (uintmax_t)val, vis_arr(bitfmt, bitfmtlen), rv);
 
 	size_t total = rv;
 	ATF_CHECK_MSG(
-	    total == exp_rv && memcmp(buf, res, reslen) == 0,
+	    total == want_rv && memcmp(buf, want_buf, want_bufsize) == 0,
 	    "failed:\n"
 	    "\ttest case: %s:%zu\n"
 	    "\tformat: %s\n"
@@ -666,20 +1119,21 @@ h_snprintb_m_loc(const char *file, size_
 	    "\twant: %zu bytes %s\n"
 	    "\thave: %zu bytes %s\n",
 	    file, line,
-	    vis_arr(fmt, fmtlen),
+	    vis_arr(bitfmt, bitfmtlen),
 	    (uintmax_t)val,
 	    max,
-	    exp_rv, vis_arr(res, reslen),
-	    total, vis_arr(buf, reslen));
-	check_unmodified_loc(file, line, buf, reslen, sizeof(buf));
+	    want_rv, vis_arr(want_buf, want_bufsize),
+	    total, vis_arr(buf, want_bufsize));
+	check_unmodified_loc(file, line, buf, want_bufsize, sizeof(buf));
 }
 
-#define	h_snprintb_m_len(bufsize, fmt, val, line_max, exp_rv, res)	\
+#define	h_snprintb_m_len(bufsize, bitfmt, val, line_max, want_rv, want_buf) \
 	h_snprintb_m_loc(__FILE__, __LINE__,				\
-	    bufsize, fmt, sizeof(fmt) - 1, val, line_max,		\
-	    exp_rv, res, sizeof(res))
-#define	h_snprintb_m(fmt, val, max, res)				\
-	h_snprintb_m_len(1024, fmt, val, max, sizeof(res) - 1, res)
+	    bufsize, bitfmt, sizeof(bitfmt) - 1, val, line_max,		\
+	    want_rv, want_buf, sizeof(want_buf))
+#define	h_snprintb_m(bitfmt, val, line_max, want_buf)			\
+	h_snprintb_m_len(1024, bitfmt, val, line_max,			\
+	    sizeof(want_buf) - 1, want_buf)
 
 ATF_TC(snprintb_m);
 ATF_TC_HEAD(snprintb_m, tc)
@@ -688,126 +1142,437 @@ ATF_TC_HEAD(snprintb_m, tc)
 }
 ATF_TC_BODY(snprintb_m, tc)
 {
-	// old-style format, small maximum line length
-	h_snprintb_m_len(
-	    68,
+
+	// old style, line_max exceeded by number in line 1
+	h_snprintb_m(
+	    "\020",
+	    0xff,
+	    1,
+	    "0xff\0");		// FIXME: line longer than line_max
+
+	// old style, line_max exceeded by '<' in line 1
+	h_snprintb_m(
+	    "\020",
+	    0xff,
+	    4,
+	    "0xff\0");
+
+	// old style, line_max exceeded by description in line 1
+	h_snprintb_m(
 	    "\020"
 	    "\001bit1"
-	    "\002bit2"
-	    "\003bit3",
-	    0xffff,
-	    6,
-	    143,
-	    "0xffff>\0"
-	    "0xffff<>\0"
-	    "0xffffb>\0"
-	    "0xffffi>\0"
-	    "0xfffft>\0"
-	    "0xffff1>\0"
-	    "0xffff<>\0"
-	    "0xff\0"
-	);
+	    "\002bit2",
+	    0xff,
+	    4,
+	    "0xff>\0"		// FIXME: unbalanced angle brackets
+	    "0xff<>\0"		// FIXME: empty angle brackets
+	    "0xffb>\0"		// FIXME: partial description
+	    "0xffi>\0"
+	    "0xfft>\0"
+	    "0xff1>\0"
+	    "0xff<>\0"		// FIXME: empty angle brackets
+	    "0xffb>\0"		// FIXME: partial description
+	    "0xffi>\0"
+	    "0xfft>\0"
+	    "0xff2>\0");
 
-	// new-style format, small maximum line length
-	h_snprintb_m_len(
-	    68,
-	    "\177\020"
-	    "b\000bit1\0"
-	    "b\001bit2\0"
-	    "b\002bit3\0",
-	    0xffff,
-	    6,
-	    143,
-	    "0xffff>\0"
-	    "0xffff<>\0"
-	    "0xffffb>\0"
-	    "0xffffi>\0"
-	    "0xfffft>\0"
-	    "0xffff1>\0"
-	    "0xffff<>\0"
-	    "0xff\0"
-	);
+	// old style, line_max exceeded by '>' in line 1
+	h_snprintb_m(
+	    "\020"
+	    "\001bit1"
+	    "\0022",
+	    0xff,
+	    9,
+	    "0xff<bit>\0"
+	    "0xff1,2>\0");
 
-	// new-style format, buffer too small for number
-	h_snprintb_m_len(
-	    2,
+	// old style, line_max exceeded by description in line 2
+	h_snprintb_m(
+	    "\020"
+	    "\0011"
+	    "\002bit2",
+	    0xff,
+	    8,
+	    "0xff<1>\0"
+	    "0xff<bi>\0"	// FIXME: incomplete description
+	    "0xfft2>\0");	// FIXME: unbalanced angle brackets
+
+	// old style, line_max exceeded by '>' in line 2
+	h_snprintb_m(
+	    "\020"
+	    "\0011"
+	    "\002bit2",
+	    0xff,
+	    9,
+	    "0xff<1>\0"
+	    "0xff<bit>\0"	// FIXME: incomplete description
+	    "0xff2>\0");	// FIXME: unbalanced angle brackets
+
+	// old style complete
+	h_snprintb_m(
+	    "\020"
+	    "\0011"
+	    "\002bit2",
+	    0xff,
+	    10,
+	    "0xff<1>\0"
+	    "0xff<bit2>\0");
+
+	// new style, line_max exceeded by value in line 1
+	h_snprintb_m(
 	    "\177\020",
-	    0,
-	    64,
-	    2,
-	    "\0"
-	);
+	    0xff,
+	    1,
+	    "0xff\0");		// FIXME: line too long
 
-	// new-style format, buffer too small for '<'
-	h_snprintb_m_len(
-	    6,
+	// new style, line_max exceeded by single-bit '<' in line 1
+	h_snprintb_m(
 	    "\177\020"
-	    "b\000lsb\0",
+	    "b\000bit\0",
 	    0xff,
-	    64,
-	    10,
-	    "0xff\0"
-	);
+	    4,
+	    "0xff>\0"		// FIXME: unbalanced angle brackets
+	    "0xff<>\0"
+	    "0xffb>\0"
+	    "0xffi>\0"
+	    "0xfft>\0");	// FIXME: line too long
 
-	// new-style format, buffer too small for description
-	h_snprintb_m_len(
+	// new style, line_max exceeded by single-bit description in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "b\000bit0\0"
+	    "b\001two\0",
+	    0xff,
+	    8,
+	    "0xff<bi>\0"	// FIXME: incomplete description
+	    "0xfft0>\0"		// FIXME: unbalanced angle brackets
+	    "0xff<tw>\0"	// FIXME: incomplete description
+	    "0xffo>\0");	// FIXME: unbalanced angle brackets
+
+	// new style, line_max exceeded by single-bit '>' in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "b\000bit0\0"
+	    "b\001two\0",
+	    0xff,
+	    9,
+	    "0xff<bit>\0"	// FIXME: incomplete description
+	    "0xff0>\0"		// FIXME: empty angle brackets
+	    "0xff<two>\0");	// FIXME: incomplete description
+
+	// new style, line_max exceeded by single-bit description in line 2
+	h_snprintb_m(
+	    "\177\020"
+	    "b\000one\0"
+	    "b\001three\0",
+	    0xff,
+	    9,
+	    "0xff<one>\0"
+	    "0xff<thr>\0"	// FIXME: incomplete description
+	    "0xffee>\0");	// FIXME: unbalanced angle brackets
+
+	// new style, line_max exceeded by single-bit '>' in line 2
+	h_snprintb_m(
+	    "\177\020"
+	    "b\000one\0"
+	    "b\001four\0",
+	    0xff,
+	    9,
+	    "0xff<one>\0"
+	    "0xff<fou>\0"	// FIXME: incomplete description
+	    "0xffr>\0");	// FIXME: unbalanced angle brackets
+
+	// new style, single-bit complete
+	h_snprintb_m(
+	    "\177\020"
+	    "b\000one\0"
+	    "b\001three\0",
+	    0xff,
+	    11,
+	    "0xff<one>\0"
+	    "0xff<three>\0");
+
+	// new style, line_max exceeded by named bit-field number in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0",
+	    0xff,
+	    3,
+	    "0xff>\0"		// FIXME: unbalanced angle brackets
+	    "0xff<>\0"
+	    "0xffl>\0"		// FIXME: incomplete bit-field description
+	    "0xffo>\0"
+	    "0xff=0xf>\0"	// FIXME: line too long
+	    "0xff#>\0");
+
+	// new style, line_max exceeded by named bit-field '<' in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0",
+	    0xff,
+	    4,
+	    "0xff>\0"		// FIXME: unbalanced angle brackets
+	    "0xff<>\0"
+	    "0xffl>\0"		// FIXME: incomplete bit-field description
+	    "0xffo>\0"
+	    "0xff=0xf>\0"	// FIXME: line too long
+	    "0xff#>\0");
+
+	// new style, line_max exceeded by named bit-field field description in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0",
+	    0xff,
+	    6,
+	    "0xff<>\0"
+	    "0xffl>\0"
+	    "0xffo>\0"		// FIXME: incomplete bit-field description
+	    "0xff=0xf>\0"	// FIXME: line too long
+	    "0xff#>\0");
+
+	// new style, line_max exceeded by named bit-field '=' in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0",
+	    0xff,
 	    7,
+	    "0xff<l>\0"		// FIXME: unbalanced angle brackets
+	    "0xffo=0xf>\0"
+	    "0xff#>\0");
+
+	// new style, line_max exceeded by named bit-field value in line 1
+	h_snprintb_m(
 	    "\177\020"
-	    "b\000lsb\0",
+	    "f\000\004lo\0",
 	    0xff,
-	    64,
 	    10,
-	    "0xff<\0"
-	);
+	    "0xff<lo=0xf>\0"	// FIXME: line too long
+	    "0xff#>\0");	// FIXME: unbalanced angle brackets
 
-	// new-style format, buffer too small for complete description
-	h_snprintb_m_len(
+	// new style, line_max exceeded by named bit-field '=' in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0"
+		"=\017match\0",
+	    0xff,
+	    11,
+	    "0xff<lo=0xf>\0"	// FIXME: line too long
+	    "0xff=match>\0");	// FIXME: unbalanced angle brackets
+
+	// new style, line_max exceeded by named bit-field value description in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0"
+		"=\017match\0",
+	    0xff,
+	    16,
+	    "0xff<lo=0xf=mat>\0"	// FIXME: incomplete field description
+	    "0xffch>\0");		// FIXME: unbalanced angle brackets
+
+	// new style, line_max exceeded by named bit-field '>' in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0"
+		"=\017match\0",
+	    0xff,
+	    17,
+	    "0xff<lo=0xf=matc>\0"	// FIXME: incomplete field description
+	    "0xffh>\0");		// FIXME: unbalanced angle brackets
+
+	// new style, line_max exceeded by named bit-field description in line 2
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0"
+	    "f\000\004low-bits\0"
+		"=\017match\0",
+	    0xff,
+	    12,
+	    "0xff<lo=0xf>\0"
+	    "0xff<low-bi>\0"
+	    "0xffts=0xf=>\0"
+	    "0xffmatch>\0");
+
+	// new style, line_max exceeded by named bit-field '=' in line 2
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0"
+	    "f\000\004low-bits\0"
+		"=\017match\0",
+	    0xff,
+	    13,
+	    "0xff<lo=0xf>\0"
+	    "0xff<low-bit>\0"
+	    "0xffs=0xf=ma>\0"
+	    "0xfftch>\0");
+
+	// new style, line_max exceeded by named bit-field value in line 2
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0"
+	    "f\000\004low-bits\0"
+		"=\017match\0",
+	    0xff,
+	    16,
+	    "0xff<lo=0xf>\0"
+	    "0xff<low-bits=0xf>\0"	// FIXME: line too long
+	    "0xff#=match>\0");
+
+	// new style, line_max exceeded by named bit-field '=' in line 2
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0"
+	    "f\000\004low-bits\0"
+		"=\017match\0",
+	    0xff,
+	    17,
+	    "0xff<lo=0xf>\0"
+	    "0xff<low-bits=0xf>\0"	// FIXME: line too long
+	    "0xff=match>\0");
+
+	// new style, line_max exceeded by named bit-field value description in line 2
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0"
+	    "f\000\004low-bits\0"
+		"=\017match\0",
+	    0xff,
+	    22,
+	    "0xff<lo=0xf>\0"
+	    "0xff<low-bits=0xf=mat>\0"	// FIXME: incomplete description
+	    "0xffch>\0");
+
+	// new style, line_max exceeded by named bit-field '>' in line 2
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0"
+	    "f\000\004low-bits\0"
+		"=\017match\0",
+	    0xff,
+	    23,
+	    "0xff<lo=0xf>\0"
+	    "0xff<low-bits=0xf=matc>\0"	// FIXME: incomplete description
+	    "0xffh>\0");
+
+	// new style, named bit-field complete
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004lo\0"
+	    "f\000\004low-bits\0"
+		"=\017match\0",
+	    0xff,
+	    24,
+	    "0xff<lo=0xf>\0"
+	    "0xfff=match\0");		// FIXME: incomplete
+
+	// new style, line_max exceeded by unnamed bit-field number in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "F\000\004\0",
+	    0xff,
+	    3,
+	    "0xff>\0"			// FIXME: unbalanced angle brackets
+	    "0xff<>\0");		// FIXME: empty angle brackets
+
+	// new style, line_max exceeded by unnamed bit-field '<' in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "F\000\004\0",
+	    0xff,
+	    4,
+	    "0xff>\0"			// FIXME: unbalanced angle brackets
+	    "0xff<>\0");		// FIXME: empty angle brackets
+
+	// new style, line_max exceeded by unnamed bit-field value description in line 1
+	h_snprintb_m(
+	    "\177\020"
+	    "F\000\004\0"
+		":\017match\0",
+	    0xff,
 	    9,
+	    "0xff<mat>\0"
+	    "0xffch>\0");		// FIXME: unbalanced angle brackets
+
+	// new style, line_max exceeded by unnamed bit-field '>' in line 1
+	h_snprintb_m(
 	    "\177\020"
-	    "b\000lsb\0",
+	    "F\000\004\0"
+		":\017match\0",
 	    0xff,
-	    64,
 	    10,
-	    "0xff<ls\0"
-	);
+	    "0xff<matc>\0"		// FIXME: unbalanced angle brackets
+	    "0xffh>\0");		// FIXME: empty angle brackets
 
-	// new-style format, buffer too small for '>'
-	h_snprintb_m_len(
+	// new style, line_max exceeded by unnamed bit-field value description in line 2
+	h_snprintb_m(
+	    "\177\020"
+	    "F\000\004\0"
+		":\017m1\0"
+		":\017match\0",
+	    0xff,
 	    10,
+	    "0xff<m1ma>\0"		// XXX: don't concatenate?
+	    "0xfftch>\0");
+
+	// new style, line_max exceeded by unnamed bit-field '>' in line 2
+	h_snprintb_m(
 	    "\177\020"
-	    "b\000lsb\0",
+	    "F\000\004\0"
+		":\017m1\0"
+		":\017match\0",
 	    0xff,
-	    64,
 	    10,
-	    "0xff<lsb\0"
-	);
+	    "0xff<m1ma>\0"		// XXX: don't concatenate?
+	    "0xfftch>\0");
 
-	// new-style format, buffer too small for second line
-	h_snprintb_m_len(
-	    11,
+	// new style unnamed bit-field complete
+	h_snprintb_m(
 	    "\177\020"
-	    "b\000lsb\0"
-	    "b\001two\0",
+	    "F\000\004\0"
+		":\017m1\0"
+		":\017match\0",
 	    0xff,
 	    11,
-	    20,
-	    "0xff<lsb>\0"
-	);
+	    "0xff<m1mat>\0"		// XXX: don't concatenate?
+	    "0xffch>\0");
 
-	// new-style format, buffer too small for number in line 2
-	h_snprintb_m_len(
-	    12,
+	// new style, line_max exceeded by bit-field default
+	h_snprintb_m(
 	    "\177\020"
-	    "b\000lsb\0"
-	    "b\001two\0",
+	    "f\000\004f\0"
+		"*=default\0",
+	    0xff,
+	    17,
+	    "0xff<f=0xf=default>\0");	// FIXME: line too long
+
+	// new style, line_max exceeded by unmatched field value
+	h_snprintb_m(
+	    "\177\020"
+	    "f\000\004bits\0"
+		":\000other\0",
 	    0xff,
 	    11,
-	    20,
-	    "0xff<lsb>\0"
-	    "\0"
-	);
+	    "0xff<bits=0xf>\0"	// XXX: line too long (14 > 11)
+	    "0xff#>\0");	// XXX: why '#'? unbalanced '<>'
+
+	// manual page, new style bits and fields
+	h_snprintb_m(
+	    "\177\020"
+	    "b\0LSB\0"
+	    "b\1BITONE\0"
+	    "f\4\4NIBBLE2\0"
+	    "f\x10\4BURST\0"
+		"=\4FOUR\0"
+		"=\xf""FIFTEEN\0"
+	    "b\x1fMSB\0",
+	    0x800f0701,
+	    34,
+	    "0x800f0701<LSB,NIBBLE2=0>\0"
+	    // FIXME: The '\020\004' is wrong.
+	    // FIXME: The '=0xf' is missing.
+	    // FIXME: The '<' is in the wrong place.
+	    "0x800f0701f\020\004BURST=FIFTEEN<MSB>\0");
 
-	// new-style format, buffer too small for complete number in line 2
+	// new style, buffer too small for complete number in line 2
 	h_snprintb_m_len(
 	    15,
 	    "\177\020"
@@ -833,56 +1598,15 @@ ATF_TC_BODY(snprintb_m, tc)
 	    "0xff\0"
 	);
 
-	// new-style format, buffer too small for description in line 2
-	h_snprintb_m_len(
-	    17,
-	    "\177\020"
-	    "b\000lsb\0"
-	    "b\001two\0",
-	    0xff,
-	    11,
-	    20,
-	    "0xff<lsb>\0"
-	    "0xff<\0"
-	);
-
-	// new-style format, line too small for unmatched field value
-	h_snprintb_m_len(
-	    30,
-	    "\177\020"
-	    "f\000\004bits\0"
-	        ":\000other\0",
-	    0xff,
-	    11,
-	    22,
-	    "0xff<bits=0xf>\0"	// XXX: line too long (14 > 11)
-	    "0xff#>\0"		// XXX: why '#'? unbalanced '<>'
-	);
-
-	// new-style format, line too small for field value
-	h_snprintb_m_len(
-	    30,
-	    "\177\020"
-	    "f\000\004bits\0"
-		":\017other\0",
-	    0xff,
-	    11,
-	    27,
-	    "0xff<bits=0xf>\0"	// XXX: line too long (14 > 11)
-	    "0xff#other>\0"	// XXX: unbalanced '<>'
-	);
-
 	// new-style format, buffer too small for fallback
-	h_snprintb_m_len(
-	    20,
+	h_snprintb_m(
 	    "\177\020"
 	    "f\000\004bits\0"
 		"*=fallback\0"
 	    "b\0024\0",
 	    0xff,
 	    64,
-	    26,
-	    "0xff<bits=0xf=fall\0"
+	    "0xff<bits=0xf=fallback,4>\0"
 	);
 
 	// new-style format, buffer too small for numeric fallback
@@ -911,6 +1635,7 @@ ATF_TC_BODY(snprintb_m, tc)
 	    "0xff<fallback\0"
 	);
 
+	// new style, bits and fields, line break between fields
 	h_snprintb_m(
 	    "\177\020"
 	    "b\0LSB\0"
@@ -926,6 +1651,7 @@ ATF_TC_BODY(snprintb_m, tc)
 	    "0x800f0701<BURST=0xf=FIFTEEN,MSB>\0"
 	);
 
+	// new style, bits and fields, line break after field description
 	h_snprintb_m(
 	    "\177\020"
 	    "b\0LSB\0"

Reply via email to