1/* $NetBSD: t_snprintb.c,v 1.36 2024/04/08 21:28:35 rillig Exp $ */
2
3/*
4 * Copyright (c) 2002, 2004, 2008, 2010, 2024 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code was contributed to The NetBSD Foundation by Christos Zoulas and
8 * Roland Illig.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__COPYRIGHT("@(#) Copyright (c) 2008, 2010, 2024\
34 The NetBSD Foundation, inc. All rights reserved.");
35__RCSID("$NetBSD: t_snprintb.c,v 1.36 2024/04/08 21:28:35 rillig Exp $");
36
37#include <stdio.h>
38#include <string.h>
39#include <util.h>
40#include <vis.h>
41
42#include <atf-c.h>
43
44static const char *
45vis_arr(char *buf, size_t bufsize, const char *arr, size_t arrsize)
46{
47	ATF_REQUIRE(bufsize >= 2);
48	int rv = strnvisx(buf + 1, bufsize - 2, arr, arrsize,
49	    VIS_WHITE | VIS_OCTAL);
50	ATF_REQUIRE_MSG(rv >= 0, "buffer too small for size %zu", arrsize);
51	buf[0] = '"';
52	buf[1 + rv] = '"';
53	buf[1 + rv + 1] = '\0';
54	return buf;
55}
56
57static void
58check_snprintb_m(const char *file, size_t line,
59    size_t bufsize, const char *bitfmt, size_t bitfmtlen, uint64_t val,
60    size_t line_max,
61    int want_rv, const char *want_buf, size_t want_bufsize)
62{
63	char buf[1024], vis_bitfmt[1024], vis_want_buf[1024], vis_buf[1024];
64
65	ATF_REQUIRE(bufsize <= sizeof(buf));
66	ATF_REQUIRE(want_bufsize <= sizeof(buf));
67	if (bitfmtlen > 2 && bitfmt[0] == '\177')
68		ATF_REQUIRE_MSG(
69		    bitfmt[bitfmtlen - 1] == '\0',
70		    "%s:%zu: missing trailing '\\0' in new-style bitfmt",
71		    file, line);
72	if (bufsize == 0)
73		want_bufsize = 0;
74	memset(buf, 0x5a, sizeof(buf));
75
76	int rv = snprintb_m(buf, bufsize, bitfmt, val, line_max);
77
78	size_t have_bufsize = sizeof(buf);
79	while (have_bufsize > 0 && buf[have_bufsize - 1] == 0x5a)
80		have_bufsize--;
81	if (rv > 0 && (unsigned)rv < have_bufsize
82	    && buf[rv - 1] == '\0' && buf[rv] == '\0')
83		have_bufsize = rv + 1;
84	if (rv < 0)
85		for (size_t i = have_bufsize; i >= 2; i--)
86			if (buf[i - 2] == '\0' && buf[i - 1] == '\0')
87				have_bufsize = i;
88
89	ATF_CHECK_MSG(
90	    rv == want_rv
91	    && memcmp(buf, want_buf, want_bufsize) == 0
92	    && (line_max == 0 || have_bufsize < 2
93		|| buf[have_bufsize - 2] == '\0')
94	    && (have_bufsize < 1 || buf[have_bufsize - 1] == '\0'),
95	    "failed:\n"
96	    "\ttest case: %s:%zu\n"
97	    "\tformat: %s\n"
98	    "\tvalue: %#jx\n"
99	    "\tline_max: %zu\n"
100	    "\twant: %d bytes %s\n"
101	    "\thave: %d bytes %s\n",
102	    file, line,
103	    vis_arr(vis_bitfmt, sizeof(vis_bitfmt), bitfmt, bitfmtlen),
104	    (uintmax_t)val,
105	    line_max,
106	    want_rv, vis_arr(vis_want_buf, sizeof(vis_want_buf),
107		want_buf, want_bufsize),
108	    rv, vis_arr(vis_buf, sizeof(vis_buf), buf, have_bufsize));
109}
110
111#define	h_snprintb_m_len(bufsize, bitfmt, val, line_max,		\
112	    want_rv, want_buf)						\
113	check_snprintb_m(__FILE__, __LINE__,				\
114	    bufsize, bitfmt, sizeof(bitfmt) - 1, val, line_max,		\
115	    want_rv, want_buf, sizeof(want_buf))
116
117#define	h_snprintb(bitfmt, val, want_buf)				\
118	h_snprintb_m_len(1024, bitfmt, val, 0, sizeof(want_buf) - 1, want_buf)
119
120#define	h_snprintb_len(bufsize, bitfmt, val, want_rv, want_buf)		\
121	h_snprintb_m_len(bufsize, bitfmt, val, 0, want_rv, want_buf)
122
123#define	h_snprintb_error(bitfmt, want_buf)				\
124	h_snprintb_m_len(1024, bitfmt, 0x00, 0, -1, want_buf)
125
126#define	h_snprintb_val_error(bitfmt, val, want_buf)			\
127	h_snprintb_m_len(1024, bitfmt, val, 0, -1, want_buf)
128
129#define	h_snprintb_m(bitfmt, val, line_max, want_buf)			\
130	h_snprintb_m_len(1024, bitfmt, val, line_max,			\
131	    sizeof(want_buf) - 1, want_buf)
132
133ATF_TC(snprintb);
134ATF_TC_HEAD(snprintb, tc)
135{
136	atf_tc_set_md_var(tc, "descr", "Checks snprintb(3)");
137}
138ATF_TC_BODY(snprintb, tc)
139{
140
141	// style and number base, old style, octal, zero value
142	//
143	// The value 0 does not get a leading '0'.
144	h_snprintb(
145	    "\010",
146	    0x00,
147	    "0");
148
149	// style and number base, old style, octal, nonzero value
150	//
151	// Nonzero octal values get a leading '0'.
152	h_snprintb(
153	    "\010",
154	    0xff,
155	    "0377");
156
157	// style and number base, old style, decimal, zero value
158	h_snprintb(
159	    "\012",
160	    0x00,
161	    "0");
162
163	// style and number base, old style, decimal, nonzero value
164	h_snprintb(
165	    "\012",
166	    0xff,
167	    "255");
168
169	// style and number base, old style, hexadecimal, zero value
170	//
171	// The value 0 does not get a leading '0x'.
172	h_snprintb(
173	    "\020",
174	    0x00,
175	    "0");
176
177	// style and number base, old style, hexadecimal, nonzero value
178	//
179	// Nonzero hexadecimal values get a leading '0x'.
180	h_snprintb(
181	    "\177\020",
182	    0xff,
183	    "0xff");
184
185	// style and number base, old style, invalid base 0
186	h_snprintb_error(
187	    "",
188	    "#");
189
190	// style and number base, old style, invalid base 2
191	h_snprintb_error(
192	    "\002",
193	    "#");
194
195	// style and number base, old style, invalid base 255 or -1
196	h_snprintb_error(
197	    "\377",
198	    "#");
199
200	// style and number base, new style, octal, zero value
201	//
202	// The value 0 does not get a leading '0'.
203	h_snprintb(
204	    "\177\010",
205	    0x00,
206	    "0");
207
208	// style and number base, new style, octal, nonzero value
209	//
210	// Nonzero octal values get a leading '0'.
211	h_snprintb(
212	    "\177\010",
213	    0xff,
214	    "0377");
215
216	// style and number base, new style, decimal, zero value
217	h_snprintb(
218	    "\177\012",
219	    0x00,
220	    "0");
221
222	// style and number base, new style, decimal, nonzero value
223	h_snprintb(
224	    "\177\012",
225	    0xff,
226	    "255");
227
228	// style and number base, new style, hexadecimal, zero value
229	//
230	// The value 0 does not get a leading '0x'.
231	h_snprintb(
232	    "\177\020",
233	    0x00,
234	    "0");
235
236	// style and number base, new style, hexadecimal, nonzero value
237	//
238	// Nonzero hexadecimal values get a leading '0x'.
239	h_snprintb(
240	    "\177\020",
241	    0xff,
242	    "0xff");
243
244	// style and number base, new style, invalid number base 0
245	h_snprintb_error(
246	    "\177",
247	    "#");
248
249	// style and number base, new style, invalid number base 2
250	h_snprintb_error(
251	    "\177\002",
252	    "#");
253
254	// style and number base, new style, invalid number base 255 or -1
255	h_snprintb_error(
256	    "\177\377",
257	    "#");
258
259	// old style, from lsb to msb
260	h_snprintb(
261	    "\020"
262	    "\001bit1"
263	    "\002bit2"
264	    "\037bit31"
265	    "\040bit32",
266	    0xffffffff80000001,
267	    "0xffffffff80000001<bit1,bit32>");
268
269	// old style, invalid bit number, at the beginning
270	h_snprintb_error(
271	    "\020"
272	    "\041invalid",
273	    "0#");
274
275	// old style, invalid bit number, in the middle
276	//
277	// The old-style format supports only 32 bits, interpreting the
278	// \041 as part of the text belonging to bit 1.
279	h_snprintb(
280	    "\020"
281	    "\001bit1"
282	    "\041bit33",
283	    0x01,
284	    "0x1<bit1!bit33>");
285
286	// old style, repeated bit numbers
287	//
288	// When a bit number is mentioned more than once,
289	// this is most likely a typo.
290	h_snprintb(
291	    "\020"
292	    "\001once"
293	    "\001again",
294	    0x01,
295	    "0x1<once,again>");
296
297	// old style, non-printable description
298	//
299	// The characters ' ' and '\t' are interpreted as bit numbers,
300	// not as part of the description; the visual arrangement in this
301	// example is intentionally misleading.
302	h_snprintb(
303	    "\020"
304	    "\001least significant"
305	    "\002horizontal\ttab"
306	    "\003\xC3\xA4",
307	    0xff,
308	    "0xff<least,horizontal,\xC3\xA4>");
309
310	// old style, empty description
311	//
312	// The description of a bit in the old format must not be empty,
313	// to prevent multiple commas in a row.
314	h_snprintb_val_error(
315	    "\020"
316	    "\001lsb"
317	    "\004"
318	    "\005"
319	    "\010msb",
320	    0xff,
321	    "0xff<lsb#");
322
323	// old style, buffer size 0, null buffer
324	//
325	// If the buffer size is 0, the buffer is not accessed at all and
326	// may be a null pointer.
327	int null_rv_old = snprintb(NULL, 0, "\020\001lsb", 0x01);
328	ATF_CHECK_MSG(
329	    null_rv_old == 8,
330	    "want length 8, have %d", null_rv_old);
331
332	// old style, buffer too small for value
333	h_snprintb_len(
334	    1, "\020", 0x00,
335	    1, "");
336
337	// old style, buffer large enough for zero value
338	h_snprintb_len(
339	    2, "\020", 0x00,
340	    1, "0");
341
342	// old style, buffer too small for nonzero value
343	h_snprintb_len(
344	    3, "\020", 0x07,
345	    3, "0#");
346
347	// old style, buffer large enough for nonzero value
348	h_snprintb_len(
349	    4, "\020", 0x07,
350	    3, "0x7");
351
352	// old style, buffer too small for '<'
353	h_snprintb_len(
354	    4, "\020\001lsb", 0x07,
355	    8, "0x#");
356
357	// old style, buffer too small for description
358	h_snprintb_len(
359	    7, "\020\001lsb", 0x07,
360	    8, "0x7<l#");
361
362	// old style, buffer too small for '>'
363	h_snprintb_len(
364	    8, "\020\001lsb", 0x07,
365	    8, "0x7<ls#");
366
367	// old style, buffer large enough for '>'
368	h_snprintb_len(
369	    9, "\020\001lsb", 0x07,
370	    8, "0x7<lsb>");
371
372	// old style, buffer too small for second description
373	h_snprintb_len(
374	    9, "\020\001one\002two", 0x07,
375	    12, "0x7<one#");
376
377	// old style, buffer too small for second description
378	h_snprintb_len(
379	    10, "\020\001one\002two", 0x07,
380	    12, "0x7<one,#");
381
382	// old style, buffer too small for '>' after second description
383	h_snprintb_len(
384	    12, "\020\001one\002two", 0x07,
385	    12, "0x7<one,tw#");
386
387	// old style, buffer large enough for '>' after second description
388	h_snprintb_len(
389	    13, "\020\001one\002two", 0x07,
390	    12, "0x7<one,two>");
391
392	// new style, buffer size 0, null buffer
393	//
394	// If the buffer size is 0, the buffer may be NULL.
395	int null_rv_new = snprintb(NULL, 0, "\177\020b\000lsb\0", 0x01);
396	ATF_CHECK_MSG(
397	    null_rv_new == 8,
398	    "want length 8, have %d", null_rv_new);
399
400	// new style single bits
401	h_snprintb(
402	    "\177\020"
403	    "b\000lsb\0"
404	    "b\001above-lsb\0"
405	    "b\037bit31\0"
406	    "b\040bit32\0"
407	    "b\076below-msb\0"
408	    "b\077msb\0",
409	    0x8000000180000001,
410	    "0x8000000180000001<lsb,bit31,bit32,msb>");
411
412	// new style single bits, duplicate bits
413	h_snprintb(
414	    "\177\020"
415	    "b\000lsb\0"
416	    "b\000lsb\0"
417	    "b\000lsb\0",
418	    0xff,
419	    "0xff<lsb,lsb,lsb>");
420
421	// new style single bits, 'b' with empty description
422	//
423	// The description of a 'b' conversion must not be empty, as the
424	// output would contain several commas in a row.
425	h_snprintb_val_error(
426	    "\177\020"
427	    "b\000lsb\0"
428	    "b\001\0"
429	    "b\002\0"
430	    "b\007msb\0",
431	    0xff,
432	    "0xff<lsb#");
433
434	// new style single bits, bit number too large
435	h_snprintb_error(
436	    "\177\020"
437	    "b\100too-high\0",
438	    "0#");
439	h_snprintb_error(
440	    "\177\020"
441	    "b\377too-high\0",
442	    "0#");
443
444	// new style single bits, non-printable description
445	//
446	// Contrary to the old-style format, the new-style format allows
447	// arbitrary characters in the description, even control characters
448	// and non-ASCII characters.
449	h_snprintb(
450	    "\177\020"
451	    "b\000space \t \xC3\xA4\0",
452	    0x1,
453	    "0x1<space \t \xC3\xA4>");
454
455	// new style named bit-field, octal
456	//
457	// The bit-field value gets a leading '0' iff it is nonzero.
458	h_snprintb(
459	    "\177\010"
460	    "f\000\010byte0\0"
461	    "f\010\010byte1\0",
462	    0x0100,
463	    "0400<byte0=0,byte1=01>");
464
465	// new style named bit-field, decimal
466	h_snprintb(
467	    "\177\012"
468	    "f\000\010byte0\0"
469	    "f\010\010byte1\0",
470	    0x0100,
471	    "256<byte0=0,byte1=1>");
472
473	// new style named bit-field, hexadecimal
474	//
475	// The bit-field value gets a leading '0x' iff it is nonzero.
476	h_snprintb(
477	    "\177\020"
478	    "f\000\010byte0\0"
479	    "f\010\010byte1\0",
480	    0x0100,
481	    "0x100<byte0=0,byte1=0x1>");
482
483	// new style bit-field, from 0 width 0
484	h_snprintb(
485	    "\177\020"
486	    "f\000\000zero-width\0"
487		"=\000zero\0",
488	    0xffff,
489	    "0xffff<zero-width=0=zero>");
490
491	// new style bit-field, from 0 width 1
492	h_snprintb(
493	    "\177\020"
494	    "f\000\001lsb\0"
495		"=\000zero\0"
496		"=\001one\0",
497	    0x0,
498	    "0<lsb=0=zero>");
499	h_snprintb(
500	    "\177\020"
501	    "f\000\001lsb\0"
502		"=\000zero\0"
503		"=\001one\0",
504	    0x1,
505	    "0x1<lsb=0x1=one>");
506
507	// new style bit-field, from 0 width 63
508	h_snprintb(
509	    "\177\020"
510	    "f\000\077uint63\0"
511		"=\125match\0",
512	    0xaaaa5555aaaa5555,
513	    "0xaaaa5555aaaa5555<uint63=0x2aaa5555aaaa5555>");
514
515	// new style bit-field, from 0 width 64
516	h_snprintb(
517	    "\177\020"
518	    "f\000\100uint64\0"
519		"=\125match\0",
520	    0xaaaa5555aaaa5555,
521	    "0xaaaa5555aaaa5555<uint64=0xaaaa5555aaaa5555>");
522
523	// new style bit-field, from 0 width 65
524	h_snprintb_error(
525	    "\177\020"
526	    "f\000\101uint65\0",
527	    "0#");
528
529	// new style bit-field, from 1 width 8
530	h_snprintb(
531	    "\177\020"
532	    "f\001\010uint8\0"
533		"=\203match\0",
534	    0x0106,
535	    "0x106<uint8=0x83=match>");
536
537	// new style bit-field, from 1 width 9
538	//
539	// The '=' and ':' directives can match a bit-field value between
540	// 0 and 255, independent of the bit-field's width.
541	h_snprintb(
542	    "\177\020"
543	    "f\001\011uint9\0"
544		"=\203match\0"
545		"*=default-f\0"
546	    "F\001\011\0"
547		":\203match\0"
548		"*default-F\0",
549	    0x0306,
550	    "0x306<uint9=0x183=default-f,default-F>");
551
552	// new style bit-field, from 24 width 32
553	h_snprintb(
554	    "\177\020"
555	    "f\030\040uint32\0",
556	    0xaaaa555500000000,
557	    "0xaaaa555500000000<uint32=0xaa555500>");
558
559	// new style bit-field, from 60 width 4
560	h_snprintb(
561	    "\177\020"
562	    "f\074\004uint4\0",
563	    0xf555555555555555,
564	    "0xf555555555555555<uint4=0xf>");
565
566	// new style bit-field, from 60 width 5
567	//
568	// The end of the bit-field is out of bounds.
569	h_snprintb(
570	    "\177\020"
571	    "f\074\005uint5\0",
572	    0xf555555555555555,
573	    "0xf555555555555555<uint5=0xf>");
574
575	// new style bit-field, from 64 width 0
576	//
577	// The beginning of the bit-field is out of bounds, the end is fine.
578	h_snprintb_error(
579	    "\177\020"
580	    "f\100\000uint0\0",
581	    "0#");
582
583	// new style bit-field, from 65 width 0
584	//
585	// The beginning and end of the bit-field are out of bounds.
586	h_snprintb_error(
587	    "\177\020"
588	    "f\101\000uint0\0",
589	    "0#");
590
591	// new style bit-field, 'f' with empty description
592	//
593	// The description of an 'f' conversion must not be empty, as the
594	// output would contain an isolated '='.
595	h_snprintb_val_error(
596	    "\177\020"
597	    "f\000\004\0"
598		"=\001one\0",
599	    0x1,
600	    "0x1#");
601
602	// new style bit-field, non-printable description
603	//
604	// Contrary to the old-style format, the new-style format allows
605	// arbitrary characters in the description, even control characters
606	// and non-ASCII characters.
607	h_snprintb(
608	    "\177\020"
609	    "f\000\010\t \xC3\xA4\0"
610		"=\001\t \xC3\xA4\0"
611	    "F\000\010\0"
612		":\001\t \xC3\xA4\0"
613	    "F\000\010\0"
614		"*\t \xC3\xA4\0",
615	    0x1,
616	    "0x1<\t \xC3\xA4=0x1=\t \xC3\xA4,\t \xC3\xA4,\t \xC3\xA4>");
617
618	// new style bit-field, '=' with empty description
619	//
620	// The description of a '=' conversion must not be empty, as the
621	// output would contain several '=' in a row.
622	h_snprintb_val_error(
623	    "\177\020"
624	    "f\000\004f\0"
625		"=\001one\0"
626		"=\001\0"
627		"=\001\0",
628	    0x1,
629	    "0x1<f=0x1=one#");
630
631	// new style bit-field, 'F' followed by ':' with empty description
632	//
633	// The description of a ':' conversion must not be empty, as the
634	// output would contain empty angle brackets.
635	h_snprintb_val_error(
636	    "\177\020"
637	    "F\000\004\0"
638		":\001\0"
639		"*default\0",
640	    0x1,
641	    "0x1<#");
642
643	// new style bit-field, 'F', ':' with empty description, '*'
644	//
645	// The description of a ':' conversion must not be empty, as the
646	// output would contain empty angle brackets. Not in this particular
647	// test case, as the value is different, but the structural error is
648	// detected nevertheless.
649	h_snprintb_val_error(
650	    "\177\020"
651	    "F\000\004\0"
652		":\001\0"
653		"*default\0",
654	    0x2,
655	    "0x2<#");
656
657	// new style bit-field, 'f' with non-exhaustive '='
658	h_snprintb(
659	    "\177\020"
660	    "f\000\004Field\0"
661		"=\1one\0"
662		"=\2two\0",
663	    0x3,
664	    "0x3<Field=0x3>");
665
666	// new style bit-field, 'F' with non-exhaustive ':'
667	//
668	// An unnamed bit-field that does not match any values generates empty
669	// angle brackets, which looks confusing. The ':' directives should
670	// either be exhaustive, or there should be a '*' catch-all directive.
671	h_snprintb(
672	    "\177\020"
673	    "F\000\004\0"
674		":\1one\0"
675		":\2two\0",
676	    0x3,
677	    "0x3<>");
678
679	// new style bit-field, 'F' with non-exhaustive ':'
680	//
681	// A bit-field that does not match any values generates multiple commas
682	// in a row, which looks confusing. The ':' conversions should either be
683	// exhaustive, or there should be a '*' catch-all conversion.
684	h_snprintb(
685	    "\177\020"
686	    "b\000bit0\0"
687	    "F\000\004\0"
688		":\1one\0"
689		":\2two\0"
690	    "b\001bit1\0",
691	    0x3,
692	    "0x3<bit0,,bit1>");
693
694	// new style bit-field, '=', can never match
695	//
696	// The extracted value from the bit-field has 7 bits and is thus less
697	// than 128, therefore it can neither match 128 nor 255.
698	h_snprintb(
699	    "\177\020"
700	    "f\000\007f\0"
701		"=\200never\0"
702		"=\377never\0",
703	    0xff,
704	    "0xff<f=0x7f>");
705
706	// new style, two separate bit-fields
707	h_snprintb(
708	    "\177\020"
709	    "f\000\004f1\0"
710		"=\001one\0"
711		"=\002two\0"
712	    "f\004\004f2\0"
713		"=\001one\0"
714		"=\002two\0",
715	    0x12,
716	    "0x12<f1=0x2=two,f2=0x1=one>");
717
718	// new style, mixed named and unnamed bit-fields
719	h_snprintb(
720	    "\177\020"
721	    "f\000\004f1\0"
722		"=\001one\0"
723		"=\002two\0"
724	    "F\010\004\0"
725		":\015thirteen\0"
726	    "f\004\004f2\0"
727		"=\001one\0"
728		"=\002two\0",
729	    0x0d12,
730	    "0xd12<f1=0x2=two,thirteen,f2=0x1=one>");
731
732	// new style bit-field, overlapping
733	h_snprintb(
734	    "\177\020"
735	    "f\000\004lo\0"
736	    "f\002\004mid\0"
737	    "f\004\004hi\0"
738	    "f\000\010all\0",
739	    0x18,
740	    "0x18<lo=0x8,mid=0x6,hi=0x1,all=0x18>");
741
742	// new style bit-field, difference between '=' and ':'
743	//
744	// The ':' conversion can almost emulate the '=' conversion, without the
745	// numeric output and with a different separator. It's best to use
746	// either 'f' with '=', or 'F' with ':', but not mix them.
747	h_snprintb(
748	    "\177\020"
749	    "f\000\004field\0"
750		"=\010f-value\0"
751	    "F\000\000\0"		// Use an empty bit-field
752		":\000separator\0"	// to generate a separator.
753	    "F\000\004\0"
754		":\010F-value\0",
755	    0x18,
756	    "0x18<field=0x8=f-value,separator,F-value>");
757
758	// new style bit-field default, fixed string
759	//
760	// The 'f' conversion pairs up with the '=' conversion,
761	// the 'F' conversion pairs up with the ':' conversion,
762	// but there's only one 'default' conversion for both variants,
763	// so its description should include the '=' when used with 'f' but
764	// not with 'F'.
765	h_snprintb(
766	    "\177\020"
767	    "f\030\010f1\0"
768		"*default\0"
769	    "f\020\010f2\0"
770		"*=default\0"
771	    "F\010\010\0"
772		"*default\0"
773	    "F\010\010\0"
774		"*=default\0",
775	    0x11223344,
776	    "0x11223344<f1=0x11default,f2=0x22=default,default,=default>");
777
778	// new style bit-field default, numeric conversion specifier
779	h_snprintb(
780	    "\177\020"
781	    "f\010\010f\0"
782		"*=f(%ju)\0"
783	    "F\000\010F\0"
784		"*F(%ju)\0",
785	    0x1122,
786	    "0x1122<f=0x11=f(17),F(34)>");
787
788	// new style bit-field default, can never match
789	//
790	// The '=' conversion are exhaustive, making the '*' redundant.
791	h_snprintb(
792	    "\177\020"
793	    "f\010\002f\0"
794		"=\000zero\0"
795		"=\001one\0"
796		"=\002two\0"
797		"=\003three\0"
798		"*default\0",
799	    0xff00,
800	    "0xff00<f=0x3=three>");
801
802	// new style bit-field default, invalid conversion specifier
803	//
804	// There is no reliable way to make snprintf return an error, as such
805	// errors are defined as undefined behavior in the C standard.
806	// Instead, here's a conversion specifier that produces a literal '%'.
807	h_snprintb(
808	    "\177\020"
809	    "f\000\010f\0"
810		"*=%030ju%%\0",
811	    0xff,
812	    "0xff<f=0xff=000000000000000000000000000255%>");
813
814	// new style unknown conversion, at the beginning
815	h_snprintb_val_error(
816	    "\177\020"
817	    "unknown\0",
818	    0xff,
819	    "0xff#");
820
821	// new style unknown conversion, after a known conversion
822	h_snprintb_val_error(
823	    "\177\020"
824	    "b\007msb\0"
825	    "unknown\0",
826	    0xff,
827	    "0xff<msb#");
828
829	// new style combinations, 'b' '='
830	//
831	// A '=' conversion requires a preceding 'f' conversion.
832	h_snprintb_val_error(
833	    "\177\020"
834	    "b\004bit4\0"
835		"=\000clear\0"
836		"=\001set\0"
837		"=\245complete\0"
838	    "b\000bit0\0"
839		"=\000clear\0"
840		"=\001set\0"
841		"=\245complete\0",
842	    0xa5,
843	    "0xa5#");
844
845	// new style combinations, 'b' ':'
846	//
847	// A ':' conversion requires a preceding 'f' or 'F' conversion.
848	h_snprintb_val_error(
849	    "\177\020"
850	    "b\004bit4\0"
851		":\000clear\0"
852		":\001set\0"
853		":\245complete\0"
854	    "b\000bit0\0"
855		":\000clear\0"
856		":\001set\0"
857		":\245complete\0",
858	    0xa5,
859	    "0xa5#");
860
861	// new style combinations, 'b' '*'
862	//
863	// A '*' conversion requires a preceding 'f' or 'F' conversion.
864	h_snprintb_val_error(
865	    "\177\020"
866	    "b\004bit4\0"
867		"*default(%ju)\0"
868	    "b\000bit0\0"
869		"*default(%ju)\0",
870	    0xa5,
871	    "0xa5#");
872
873	// new style combinations, 'f' 'b' '='
874	//
875	// A '=' conversion requires a preceding 'f' conversion, there must
876	// not be a 'b' conversion in between.
877	h_snprintb_val_error(
878	    "\177\020"
879	    "f\000\010f\0"
880	    "b\005bit5\0"
881		"=\245match\0",
882	    0xa5,
883	    "0xa5<f=0xa5,bit5#");
884
885	// new style combinations, 'F' 'b' ':'
886	//
887	// A ':' conversion requires a preceding 'F' conversion, there must
888	// not be a 'b' conversion in between.
889	//
890	// The isolated leading comma is produced by the non-exhaustive 'F'
891	// conversion. Detecting these at runtime would be too costly.
892	h_snprintb_val_error(
893	    "\177\020"
894	    "F\000\010f\0"
895	    "b\005bit5\0"
896		":\245match\0",
897	    0xa5,
898	    "0xa5<,bit5#");
899
900	// new style combinations, 'f' ':'
901	//
902	// The ':' conversion requires a preceding 'F' conversion, not 'f'.
903	h_snprintb_val_error(
904	    "\177\20"
905	    "f\000\004nibble\0"
906		":\001one\0",
907	    0x01,
908	    "0x1<nibble=0x1#");
909
910	// new style combinations, 'F' '='
911	//
912	// A '=' conversion requires a preceding 'f' conversion, not 'F'.
913	h_snprintb_val_error(
914	    "\177\20"
915	    "F\000\004\0"
916		"=\001one\0",
917	    0x01,
918	    "0x1<#");
919
920	// new style combinations, '='
921	//
922	// A '=' conversion requires a preceding 'f' or 'F' conversion.
923	h_snprintb_val_error(
924	    "\177\020"
925		"=\245match\0",
926	    0xa5,
927	    "0xa5#");
928
929	// new style combinations, ':'
930	//
931	// A ':' conversion requires a preceding 'f' or 'F' conversion.
932	h_snprintb_val_error(
933	    "\177\020"
934		":\245match\0",
935	    0xa5,
936	    "0xa5#");
937
938	// new style combinations, '*'
939	//
940	// A '*' conversion requires a preceding 'f' or 'F' conversion.
941	h_snprintb_val_error(
942	    "\177\020"
943		"*match\0",
944	    0xa5,
945	    "0xa5#");
946
947	// new style combinations, 'f' '*' '='
948	//
949	// After a catch-all '*' conversions, there must not be further '='
950	// conversions.
951	h_snprintb_val_error(
952	    "\177\020"
953	    "f\000\010f\0"
954		"*=default\0"
955		"=\245match\0",
956	    0xa5,
957	    "0xa5<f=0xa5=default#");
958
959	// new style combinations, 'F' '*' ':'
960	//
961	// After a catch-all '*' conversion, there must not be further ':'
962	// conversions.
963	h_snprintb_val_error(
964	    "\177\020"
965	    "F\000\010F\0"
966		"*default\0"
967		":\245-match\0",
968	    0xa5,
969	    "0xa5<default#");
970
971	// new style combinations, 'f' '*' '*'
972	//
973	// After a catch-all '*' conversion, there must not be further '=' or
974	// '*' conversions.
975	h_snprintb_val_error(
976	    "\177\020"
977	    "f\000\010f\0"
978		"*=default-f\0"
979		"*ignored\0",
980	    0xa5,
981	    "0xa5<f=0xa5=default-f#");
982
983	// new style combinations, 'F' '*' '*'
984	//
985	// After a catch-all '*' conversion, there must not be further ':' or
986	// '*' conversions.
987	h_snprintb_val_error(
988	    "\177\020"
989	    "F\000\010\0"
990		"*default-F\0"
991		"*ignored\0",
992	    0xa5,
993	    "0xa5<default-F#");
994
995	// example from the manual page, old style octal
996	h_snprintb(
997	    "\010\002BITTWO\001BITONE",
998	    0x03,
999	    "03<BITTWO,BITONE>");
1000
1001	// example from the manual page, old style hexadecimal
1002	//
1003	// When using a hexadecimal escape sequence to encode a bit number,
1004	// the description must not start with a hexadecimal digit, or that
1005	// digit is interpreted as part of the bit number. To prevent this,
1006	// the bit number and the description need to be written as separate
1007	// string literals.
1008	h_snprintb(
1009	    "\x10"
1010	    "\x10" "NOTBOOT"
1011	    "\x0f" "FPP"
1012	    "\x0e" "SDVMA"
1013	    "\x0c" "VIDEO"
1014	    "\x0b" "LORES"
1015	    "\x0a" "FPA"
1016	    "\x09" "DIAG"
1017	    "\x07" "CACHE"
1018	    "\x06" "IOCACHE"
1019	    "\x05" "LOOPBACK"
1020	    "\x04" "DBGCACHE",
1021	    0xe860,
1022	    "0xe860<NOTBOOT,FPP,SDVMA,VIDEO,CACHE,IOCACHE>");
1023
1024	// example from the manual page, new style bits and fields
1025	h_snprintb(
1026	    "\177\020"
1027	    "b\000" "LSB\0"
1028	    "b\001" "BITONE\0"
1029	    "f\004\004" "NIBBLE2\0"
1030	    "f\020\004" "BURST\0"
1031		"=\x04" "FOUR\0"
1032		"=\x0f" "FIFTEEN\0"
1033	    "b\037" "MSB\0",
1034	    0x800f0701,
1035	    "0x800f0701<LSB,NIBBLE2=0,BURST=0xf=FIFTEEN,MSB>");
1036
1037	// example from the manual page, new style mmap
1038#define	MAP_FMT				\
1039	"\177\020"			\
1040	"b\0"  "SHARED\0"		\
1041	"b\1"  "PRIVATE\0"		\
1042	"b\2"  "COPY\0"			\
1043	"b\4"  "FIXED\0"		\
1044	"b\5"  "RENAME\0"		\
1045	"b\6"  "NORESERVE\0"		\
1046	"b\7"  "INHERIT\0"		\
1047	"b\11" "HASSEMAPHORE\0"		\
1048	"b\12" "TRYFIXED\0"		\
1049	"b\13" "WIRED\0"		\
1050	"F\14\1\0"			\
1051		":\0" "FILE\0"		\
1052		":\1" "ANONYMOUS\0"	\
1053	"b\15" "STACK\0"		\
1054	"F\30\010\0"			\
1055		":\000" "ALIGN=NONE\0"	\
1056		":\015" "ALIGN=8KB\0"	\
1057		"*"     "ALIGN=2^%ju\0"
1058	h_snprintb(
1059	    MAP_FMT,
1060	    0x0d001234,
1061	    "0xd001234<COPY,FIXED,RENAME,HASSEMAPHORE,ANONYMOUS,ALIGN=8KB>");
1062	h_snprintb(
1063	    MAP_FMT,
1064	    0x2e000000,
1065	    "0x2e000000<FILE,ALIGN=2^46>");
1066
1067	// It is possible but cumbersome to implement a reduced variant of
1068	// rot13 using snprintb, shown here for lowercase letters only.
1069	for (char ch = 'A'; ch <= '~'; ch++) {
1070		char rot13 = ch >= 'a' && ch <= 'm' ? ch + 13
1071		    : ch >= 'n' && ch <= 'z' ? ch - 13
1072		    : '?';
1073		char expected[8];
1074		ATF_REQUIRE_EQ(7,
1075		    snprintf(expected, sizeof(expected), "%#x<%c>", ch, rot13));
1076		h_snprintb(
1077		    "\177\020"
1078		    "F\000\010\0"
1079		    ":an\0:bo\0:cp\0:dq\0:er\0:fs\0:gt\0:hu\0"
1080		    ":iv\0:jw\0:kx\0:ly\0:mz\0"
1081		    ":na\0:ob\0:pc\0:qd\0:re\0:sf\0:tg\0:uh\0"
1082		    ":vi\0:wj\0:xk\0:yl\0:zm\0"
1083		    // If snprintf accepted "%jc", it would be possible to
1084		    // echo the non-alphabetic characters instead of a
1085		    // catchall question mark.
1086		    "*?\0",
1087		    ch,
1088		    expected);
1089	}
1090
1091	// new style, small buffers
1092	h_snprintb_len(
1093	    0, "\177\020", 0x00,
1094	    1, "");
1095	h_snprintb_len(
1096	    1, "\177\020", 0x00,
1097	    1, "");
1098	h_snprintb_len(
1099	    2, "\177\020", 0x00,
1100	    1, "0");
1101	h_snprintb_len(
1102	    3, "\177\020", 0x00,
1103	    1, "0");
1104	h_snprintb_len(
1105	    3, "\177\020", 0x07,
1106	    3, "0#");
1107	h_snprintb_len(
1108	    4, "\177\020", 0x07,
1109	    3, "0x7");
1110	h_snprintb_len(
1111	    7, "\177\020b\000lsb\0", 0x07,
1112	    8, "0x7<l#");
1113	h_snprintb_len(
1114	    8, "\177\020b\000lsb\0", 0x07,
1115	    8, "0x7<ls#");
1116	h_snprintb_len(
1117	    9, "\177\020b\000lsb\0", 0x07,
1118	    8, "0x7<lsb>");
1119	h_snprintb_len(
1120	    9, "\177\020b\000one\0b\001two\0", 0x07,
1121	    12, "0x7<one#");
1122	h_snprintb_len(
1123	    10, "\177\020b\000one\0b\001two\0", 0x07,
1124	    12, "0x7<one,#");
1125	h_snprintb_len(
1126	    12, "\177\020b\000one\0b\001two\0", 0x07,
1127	    12, "0x7<one,tw#");
1128	h_snprintb_len(
1129	    13, "\177\020b\000one\0b\001two\0", 0x07,
1130	    12, "0x7<one,two>");
1131}
1132
1133ATF_TC(snprintb_m);
1134ATF_TC_HEAD(snprintb_m, tc)
1135{
1136	atf_tc_set_md_var(tc, "descr", "Checks snprintb_m(3)");
1137}
1138ATF_TC_BODY(snprintb_m, tc)
1139{
1140
1141	// old style, line_max exceeded by number in line 1
1142	h_snprintb_m(
1143	    "\020",
1144	    0xff,
1145	    1,
1146	    "#\0");
1147
1148	// old style, line_max exceeded by '<' in line 1
1149	h_snprintb_m(
1150	    "\020"
1151	    "\001lsb",
1152	    0xff,
1153	    4,
1154	    "0xf#\0");
1155
1156	// old style, line_max exceeded by description
1157	h_snprintb_m(
1158	    "\020"
1159	    "\001bit1"
1160	    "\002bit2",
1161	    0xff,
1162	    7,
1163	    "0xff<b#\0"
1164	    "0xff<b#\0");
1165
1166	// old style, line_max exceeded by '>' in line 1
1167	h_snprintb_m(
1168	    "\020"
1169	    "\001bit1"
1170	    "\0022",
1171	    0xff,
1172	    9,
1173	    "0xff<bit#\0"
1174	    "0xff<2>\0");
1175
1176	// old style, line_max exceeded by description in line 2
1177	h_snprintb_m(
1178	    "\020"
1179	    "\0011"
1180	    "\002bit2",
1181	    0xff,
1182	    8,
1183	    "0xff<1>\0"
1184	    "0xff<bi#\0");
1185
1186	// old style, line_max exceeded by '>' in line 2
1187	h_snprintb_m(
1188	    "\020"
1189	    "\0011"
1190	    "\002bit2",
1191	    0xff,
1192	    9,
1193	    "0xff<1>\0"
1194	    "0xff<bit#\0");
1195
1196	// old style, complete
1197	h_snprintb_m(
1198	    "\020"
1199	    "\0011"
1200	    "\002bit2",
1201	    0xff,
1202	    10,
1203	    "0xff<1>\0"
1204	    "0xff<bit2>\0");
1205
1206	// new style, line_max exceeded by value in line 1
1207	h_snprintb_m(
1208	    "\177\020",
1209	    0xff,
1210	    3,
1211	    "0x#\0");
1212
1213	// new style, line_max exceeded by single-bit '<' in line 1
1214	h_snprintb_m(
1215	    "\177\020"
1216	    "b\000bit\0",
1217	    0xff,
1218	    4,
1219	    "0xf#\0");
1220
1221	// new style, line_max exceeded by single-bit description in line 1
1222	h_snprintb_m(
1223	    "\177\020"
1224	    "b\000bit0\0"
1225	    "b\001two\0",
1226	    0xff,
1227	    8,
1228	    "0xff<bi#\0"
1229	    "0xff<tw#\0");
1230
1231	// new style, line_max exceeded by single-bit '>' in line 1
1232	h_snprintb_m(
1233	    "\177\020"
1234	    "b\000bit0\0"
1235	    "b\001two\0",
1236	    0xff,
1237	    9,
1238	    "0xff<bit#\0"
1239	    "0xff<two>\0");
1240
1241	// new style, line_max exceeded by single-bit description in line 2
1242	h_snprintb_m(
1243	    "\177\020"
1244	    "b\000one\0"
1245	    "b\001three\0",
1246	    0xff,
1247	    9,
1248	    "0xff<one>\0"
1249	    "0xff<thr#\0");
1250
1251	// new style, line_max exceeded by single-bit '>' in line 2
1252	h_snprintb_m(
1253	    "\177\020"
1254	    "b\000one\0"
1255	    "b\001three\0",
1256	    0xff,
1257	    10,
1258	    "0xff<one>\0"
1259	    "0xff<thre#\0");
1260
1261	// new style, single-bit complete
1262	h_snprintb_m(
1263	    "\177\020"
1264	    "b\000one\0"
1265	    "b\001three\0",
1266	    0xff,
1267	    11,
1268	    "0xff<one>\0"
1269	    "0xff<three>\0");
1270
1271	// new style, line_max exceeded by named bit-field number in line 1
1272	h_snprintb_m(
1273	    "\177\020"
1274	    "f\000\004lo\0",
1275	    0xff,
1276	    3,
1277	    "0x#\0");
1278
1279	// new style, line_max exceeded by named bit-field '<' in line 1
1280	h_snprintb_m(
1281	    "\177\020"
1282	    "f\000\004lo\0",
1283	    0xff,
1284	    4,
1285	    "0xf#\0");
1286
1287	// new style, line_max exceeded by bit-field description in line 1
1288	h_snprintb_m(
1289	    "\177\020"
1290	    "f\000\004lo\0",
1291	    0xff,
1292	    6,
1293	    "0xff<#\0");
1294
1295	// new style, line_max exceeded by named bit-field '=' in line 1
1296	h_snprintb_m(
1297	    "\177\020"
1298	    "f\000\004lo\0",
1299	    0xff,
1300	    7,
1301	    "0xff<l#\0");
1302
1303	// new style, line_max exceeded by named bit-field value in line 1
1304	h_snprintb_m(
1305	    "\177\020"
1306	    "f\000\004lo\0",
1307	    0xff,
1308	    10,
1309	    "0xff<lo=0#\0");
1310
1311	// new style, line_max exceeded by named bit-field '=' in line 1
1312	h_snprintb_m(
1313	    "\177\020"
1314	    "f\000\004lo\0"
1315		"=\017match\0",
1316	    0xff,
1317	    12,
1318	    "0xff<lo=0xf#\0");
1319
1320	// new style, line_max exceeded by named bit-field value description in
1321	// line 1
1322	h_snprintb_m(
1323	    "\177\020"
1324	    "f\000\004lo\0"
1325		"=\017match\0",
1326	    0xff,
1327	    16,
1328	    "0xff<lo=0xf=mat#\0");
1329
1330	// new style, line_max exceeded by named bit-field '>' in line 1
1331	h_snprintb_m(
1332	    "\177\020"
1333	    "f\000\004lo\0"
1334		"=\017match\0",
1335	    0xff,
1336	    17,
1337	    "0xff<lo=0xf=matc#\0");
1338
1339	// new style, line_max exceeded by named bit-field description in
1340	// line 2
1341	h_snprintb_m(
1342	    "\177\020"
1343	    "f\000\004lo\0"
1344	    "f\000\004low-bits\0"
1345		"=\017match\0",
1346	    0xff,
1347	    12,
1348	    "0xff<lo=0xf>\0"
1349	    "0xff<low-bi#\0");
1350
1351	// new style, line_max exceeded by named bit-field '=' in line 2
1352	h_snprintb_m(
1353	    "\177\020"
1354	    "f\000\004lo\0"
1355	    "f\000\004low-bits\0"
1356		"=\017match\0",
1357	    0xff,
1358	    13,
1359	    "0xff<lo=0xf>\0"
1360	    "0xff<low-bit#\0");
1361
1362	// new style, line_max exceeded by named bit-field value in line 2
1363	h_snprintb_m(
1364	    "\177\020"
1365	    "f\000\004lo\0"
1366	    "f\000\004low-bits\0"
1367		"=\017match\0",
1368	    0xff,
1369	    16,
1370	    "0xff<lo=0xf>\0"
1371	    "0xff<low-bits=0#\0");
1372
1373	// new style, line_max exceeded by named bit-field '=' in line 2
1374	h_snprintb_m(
1375	    "\177\020"
1376	    "f\000\004lo\0"
1377	    "f\000\004low-bits\0"
1378		"=\017match\0",
1379	    0xff,
1380	    18,
1381	    "0xff<lo=0xf>\0"
1382	    "0xff<low-bits=0xf#\0");
1383
1384	// new style, line_max exceeded by named bit-field value description
1385	// in line 2
1386	h_snprintb_m(
1387	    "\177\020"
1388	    "f\000\004lo\0"
1389	    "f\000\004low-bits\0"
1390		"=\017match\0",
1391	    0xff,
1392	    22,
1393	    "0xff<lo=0xf>\0"
1394	    "0xff<low-bits=0xf=mat#\0");
1395
1396	// new style, line_max exceeded by named bit-field '>' in line 2
1397	h_snprintb_m(
1398	    "\177\020"
1399	    "f\000\004lo\0"
1400	    "f\000\004low-bits\0"
1401		"=\017match\0",
1402	    0xff,
1403	    23,
1404	    "0xff<lo=0xf>\0"
1405	    "0xff<low-bits=0xf=matc#\0");
1406
1407	// new style, named bit-field complete
1408	h_snprintb_m(
1409	    "\177\020"
1410	    "f\000\004lo\0"
1411	    "f\000\004low-bits\0"
1412		"=\017match\0",
1413	    0xff,
1414	    24,
1415	    "0xff<lo=0xf>\0"
1416	    "0xff<low-bits=0xf=match>\0");
1417
1418	// new style, line_max exceeded by unnamed bit-field number in line 1
1419	h_snprintb_m(
1420	    "\177\020"
1421	    "F\000\004\0",
1422	    0xff,
1423	    3,
1424	    "0x#\0");
1425
1426	// new style, line_max exceeded by unnamed bit-field '<' in line 1
1427	h_snprintb_m(
1428	    "\177\020"
1429	    "F\000\004\0",
1430	    0xff,
1431	    4,
1432	    "0xf#\0");
1433
1434	// new style, line_max exceeded by unnamed bit-field value description
1435	// in line 1
1436	h_snprintb_m(
1437	    "\177\020"
1438	    "F\000\004\0"
1439		":\017match\0",
1440	    0xff,
1441	    9,
1442	    "0xff<mat#\0");
1443
1444	// new style, line_max exceeded by unnamed bit-field '>' in line 1
1445	h_snprintb_m(
1446	    "\177\020"
1447	    "F\000\004\0"
1448		":\017match\0",
1449	    0xff,
1450	    10,
1451	    "0xff<matc#\0");
1452
1453	// new style, line_max exceeded by unnamed bit-field value description
1454	// in line 2
1455	h_snprintb_m(
1456	    "\177\020"
1457	    "F\000\004\0"
1458		":\017m1\0"
1459		":\017match\0",
1460	    0xff,
1461	    10,
1462	    "0xff<m1ma#\0");
1463
1464	// new style, line_max exceeded by unnamed bit-field '>' in line 2
1465	h_snprintb_m(
1466	    "\177\020"
1467	    "F\000\004\0"
1468		":\017m1\0"
1469		":\017match\0",
1470	    0xff,
1471	    10,
1472	    "0xff<m1ma#\0");
1473
1474	// new style unnamed bit-field complete
1475	h_snprintb_m(
1476	    "\177\020"
1477	    "F\000\004\0"
1478		":\017m1\0"
1479		":\017match\0",
1480	    0xff,
1481	    13,
1482	    "0xff<m1match>\0");
1483
1484	// new style, line_max exceeded by bit-field default
1485	h_snprintb_m(
1486	    "\177\020"
1487	    "f\000\004f\0"
1488		"*=default\0",
1489	    0xff,
1490	    17,
1491	    "0xff<f=0xf=defau#\0");
1492
1493	// new style, line_max exceeded by unmatched field value
1494	h_snprintb_m(
1495	    "\177\020"
1496	    "f\000\004bits\0"
1497		"=\000zero\0",
1498	    0xff,
1499	    11,
1500	    "0xff<bits=#\0");
1501
1502	// example from the manual page, new style bits and fields
1503	h_snprintb_m(
1504	    "\177\020"
1505	    "b\000" "LSB\0"
1506	    "b\001" "BITONE\0"
1507	    "f\004\004" "NIBBLE2\0"
1508	    "f\020\004" "BURST\0"
1509		"=\x04" "FOUR\0"
1510		"=\x0f" "FIFTEEN\0"
1511	    "b\037" "MSB\0",
1512	    0x800f0701,
1513	    34,
1514	    "0x800f0701<LSB,NIBBLE2=0>\0"
1515	    "0x800f0701<BURST=0xf=FIFTEEN,MSB>\0");
1516
1517	// new style, missing number base
1518	h_snprintb_m_len(
1519	    1024,
1520	    "\177",
1521	    0xff,
1522	    128,
1523	    -1,
1524	    "#\0");
1525
1526	// new style, buffer too small for complete number in line 2
1527	h_snprintb_m_len(
1528	    15,
1529	    "\177\020"
1530	    "b\000lsb\0"
1531	    "b\001two\0",
1532	    0xff,
1533	    11,
1534	    20,
1535	    "0xff<lsb>\0"
1536	    "0x#\0");
1537
1538	// new-style format, buffer too small for '<' in line 2
1539	h_snprintb_m_len(
1540	    16,
1541	    "\177\020"
1542	    "b\000lsb\0"
1543	    "b\001two\0",
1544	    0xff,
1545	    11,
1546	    20,
1547	    "0xff<lsb>\0"
1548	    "0xf#\0");
1549
1550	// new-style format, buffer too small for textual fallback
1551	h_snprintb_m_len(
1552	    24,
1553	    "\177\020"
1554	    "f\000\004bits\0"
1555		"*=fallback\0"
1556	    "b\0024\0",
1557	    0xff,
1558	    64,
1559	    26,
1560	    "0xff<bits=0xf=fallbac#\0");
1561
1562	// new-style format, buffer too small for numeric fallback
1563	h_snprintb_m_len(
1564	    20,
1565	    "\177\020"
1566	    "F\000\004\0"
1567		"*fallback(%040jd)\0",
1568	    0xff,
1569	    64,
1570	    57,
1571	    "0xff<fallback(000#\0");
1572
1573	// new-style format, buffer too small for numeric fallback past buffer
1574	h_snprintb_m_len(
1575	    15,
1576	    "\177\020"
1577	    "F\000\004\0"
1578		"*fallback(%010jd)\0"
1579	    "F\004\004\0"
1580		"*fallback(%010jd)\0",
1581	    0xff,
1582	    64,
1583	    48,
1584	    "0xff<fallbac#\0");
1585
1586	// new style, bits and fields, line break between fields
1587	h_snprintb_m(
1588	    "\177\020"
1589	    "b\0LSB\0"
1590	    "b\1_BITONE\0"
1591	    "f\4\4NIBBLE2\0"
1592	    "f\x10\4BURST\0"
1593		"=\04FOUR\0"
1594		"=\17FIFTEEN\0"
1595	    "b\x1fMSB\0",
1596	    0x800f0701,
1597	    33,
1598	    "0x800f0701<LSB,NIBBLE2=0>\0"
1599	    "0x800f0701<BURST=0xf=FIFTEEN,MSB>\0");
1600
1601	// new style, bits and fields, line break after field description
1602	h_snprintb_m(
1603	    "\177\020"
1604	    "b\0LSB\0"
1605	    "b\1_BITONE\0"
1606	    "f\4\4NIBBLE2\0"
1607	    "f\020\4BURST\0"
1608		"=\04FOUR\0"
1609		"=\17FIFTEEN\0"
1610	    "b\037MSB\0",
1611	    0x800f0701,
1612	    32,
1613	    "0x800f0701<LSB,NIBBLE2=0>\0"
1614	    "0x800f0701<BURST=0xf=FIFTEEN>\0"
1615	    "0x800f0701<MSB>\0");
1616}
1617
1618ATF_TP_ADD_TCS(tp)
1619{
1620
1621	ATF_TP_ADD_TC(tp, snprintb);
1622	ATF_TP_ADD_TC(tp, snprintb_m);
1623
1624	return atf_no_error();
1625}
1626