t_snprintb.c revision 1.9 1 1.9 rillig /* $NetBSD: t_snprintb.c,v 1.9 2024/01/25 18:13:14 rillig Exp $ */
2 1.1 jmmv
3 1.1 jmmv /*
4 1.9 rillig * Copyright (c) 2002, 2004, 2008, 2010, 2024 The NetBSD Foundation, Inc.
5 1.1 jmmv * All rights reserved.
6 1.1 jmmv *
7 1.9 rillig * This code was contributed to The NetBSD Foundation by Christos Zoulas and
8 1.9 rillig * Roland Illig.
9 1.1 jmmv *
10 1.1 jmmv * Redistribution and use in source and binary forms, with or without
11 1.1 jmmv * modification, are permitted provided that the following conditions
12 1.1 jmmv * are met:
13 1.1 jmmv * 1. Redistributions of source code must retain the above copyright
14 1.1 jmmv * notice, this list of conditions and the following disclaimer.
15 1.1 jmmv * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 jmmv * notice, this list of conditions and the following disclaimer in the
17 1.1 jmmv * documentation and/or other materials provided with the distribution.
18 1.1 jmmv *
19 1.1 jmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 jmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 jmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 jmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 jmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 jmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 jmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 jmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 jmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 jmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 jmmv * POSSIBILITY OF SUCH DAMAGE.
30 1.1 jmmv */
31 1.1 jmmv
32 1.1 jmmv #include <sys/cdefs.h>
33 1.1 jmmv __COPYRIGHT("@(#) Copyright (c) 2008, 2010\
34 1.1 jmmv The NetBSD Foundation, inc. All rights reserved.");
35 1.9 rillig __RCSID("$NetBSD: t_snprintb.c,v 1.9 2024/01/25 18:13:14 rillig Exp $");
36 1.1 jmmv
37 1.9 rillig #include <stdio.h>
38 1.1 jmmv #include <string.h>
39 1.1 jmmv #include <util.h>
40 1.9 rillig #include <vis.h>
41 1.1 jmmv
42 1.1 jmmv #include <atf-c.h>
43 1.1 jmmv
44 1.9 rillig static const char *
45 1.9 rillig vis_fmt(const char *fmt, size_t fmtlen)
46 1.9 rillig {
47 1.9 rillig static char buf[4][1024];
48 1.9 rillig static size_t i;
49 1.9 rillig
50 1.9 rillig i = (i + 1) % 4;
51 1.9 rillig ATF_REQUIRE_MSG(
52 1.9 rillig strnvisx(buf[i], sizeof(buf[i]), fmt, fmtlen, VIS_WHITE | VIS_OCTAL) >= 0,
53 1.9 rillig "strnvisx failed for length %zu", fmtlen);
54 1.9 rillig return buf[i];
55 1.9 rillig }
56 1.9 rillig
57 1.1 jmmv static void
58 1.9 rillig h_snprintb(const char *file, size_t line, const char *fmt, size_t fmtlen, uint64_t val,
59 1.9 rillig const char *res, size_t reslen)
60 1.1 jmmv {
61 1.9 rillig char buf[1024];
62 1.9 rillig
63 1.9 rillig int rv = snprintb(buf, sizeof(buf), fmt, val);
64 1.1 jmmv
65 1.9 rillig ATF_REQUIRE_MSG(rv > 0, "formatting %jx with '%s' returns error %d",
66 1.9 rillig (uintmax_t)val, vis_fmt(fmt, fmtlen), rv);
67 1.1 jmmv
68 1.9 rillig size_t buflen = rv;
69 1.9 rillig ATF_CHECK_MSG(
70 1.9 rillig buflen == reslen && memcmp(buf, res, reslen) == 0,
71 1.9 rillig "failed:\n"
72 1.9 rillig "\ttest case: %s:%zu\n"
73 1.9 rillig "\tformat: %s\n"
74 1.9 rillig "\tvalue: %#jx\n"
75 1.9 rillig "\twant: %3zu bytes %s\n"
76 1.9 rillig "\thave: %3zu bytes %s\n",
77 1.9 rillig file, line,
78 1.9 rillig vis_fmt(fmt, fmtlen), (uintmax_t)val,
79 1.9 rillig reslen, vis_fmt(res, reslen),
80 1.9 rillig buflen, vis_fmt(buf, buflen));
81 1.1 jmmv }
82 1.1 jmmv
83 1.9 rillig #define h_snprintb(fmt, val, res) \
84 1.9 rillig h_snprintb(__FILE__, __LINE__, fmt, sizeof(fmt) - 1, \
85 1.9 rillig val, res, sizeof(res) - 1)
86 1.9 rillig
87 1.1 jmmv ATF_TC(snprintb);
88 1.1 jmmv ATF_TC_HEAD(snprintb, tc)
89 1.1 jmmv {
90 1.1 jmmv atf_tc_set_md_var(tc, "descr", "Checks snprintb(3)");
91 1.1 jmmv }
92 1.1 jmmv ATF_TC_BODY(snprintb, tc)
93 1.1 jmmv {
94 1.9 rillig h_snprintb(
95 1.9 rillig "\010"
96 1.9 rillig "\002BITTWO"
97 1.9 rillig "\001BITONE",
98 1.9 rillig 3,
99 1.9 rillig "03<BITTWO,BITONE>");
100 1.9 rillig
101 1.9 rillig h_snprintb(
102 1.9 rillig "\177\20"
103 1.9 rillig "b\0A\0",
104 1.9 rillig 0,
105 1.9 rillig "0");
106 1.9 rillig
107 1.9 rillig h_snprintb(
108 1.9 rillig "\177\020"
109 1.9 rillig "b\05NOTBOOT\0"
110 1.9 rillig "b\06FPP\0"
111 1.9 rillig "b\13SDVMA\0"
112 1.9 rillig "b\15VIDEO\0"
113 1.9 rillig "b\20LORES\0"
114 1.9 rillig "b\21FPA\0"
115 1.9 rillig "b\22DIAG\0"
116 1.9 rillig "b\16CACHE\0"
117 1.9 rillig "b\17IOCACHE\0"
118 1.9 rillig "b\22LOOPBACK\0"
119 1.9 rillig "b\04DBGCACHE\0",
120 1.9 rillig 0xe860,
121 1.9 rillig "0xe860<NOTBOOT,FPP,SDVMA,VIDEO,CACHE,IOCACHE>");
122 1.9 rillig
123 1.9 rillig h_snprintb(
124 1.9 rillig "\177\20"
125 1.9 rillig "f\0\4FOO\0"
126 1.9 rillig "=\1ONE\0"
127 1.9 rillig "=\2TWO\0",
128 1.9 rillig 1,
129 1.5 ryo "0x1<FOO=0x1=ONE>");
130 1.9 rillig h_snprintb(
131 1.9 rillig "\177\20"
132 1.9 rillig "f\0\4X\0"
133 1.9 rillig "=\1ONE\0"
134 1.9 rillig "=\2TWO\0",
135 1.9 rillig 1,
136 1.5 ryo "0x1<X=0x1=ONE>");
137 1.9 rillig h_snprintb(
138 1.9 rillig "\177\20"
139 1.9 rillig "F\0\4\0"
140 1.9 rillig ":\1ONE\0"
141 1.9 rillig ":\2TWO\0",
142 1.9 rillig 1,
143 1.6 kre "0x1<ONE>");
144 1.5 ryo
145 1.9 rillig h_snprintb(
146 1.9 rillig "\177\20"
147 1.9 rillig "f\0\4FOO\0"
148 1.9 rillig "=\1ONE\0"
149 1.9 rillig "=\2TWO\0",
150 1.9 rillig 2,
151 1.6 kre "0x2<FOO=0x2=TWO>");
152 1.9 rillig h_snprintb(
153 1.9 rillig "\177\20"
154 1.9 rillig "f\0\4X\0"
155 1.9 rillig "=\1ONE\0"
156 1.9 rillig "=\2TWO\0",
157 1.9 rillig 2,
158 1.6 kre "0x2<X=0x2=TWO>");
159 1.9 rillig h_snprintb(
160 1.9 rillig "\177\020"
161 1.9 rillig "F\0\4\0"
162 1.9 rillig ":\1ONE\0"
163 1.9 rillig ":\2TWO\0",
164 1.9 rillig 2,
165 1.6 kre "0x2<TWO>");
166 1.6 kre
167 1.9 rillig h_snprintb(
168 1.9 rillig "\177\20"
169 1.9 rillig "f\0\4FOO\0"
170 1.9 rillig "=\1ONE\0"
171 1.9 rillig "=\2TWO\0"
172 1.9 rillig "*=OTHER\0",
173 1.9 rillig 3,
174 1.6 kre "0x3<FOO=0x3=OTHER>");
175 1.9 rillig h_snprintb(
176 1.9 rillig "\177\20"
177 1.9 rillig "f\0\4X\0"
178 1.9 rillig "=\1ONE\0"
179 1.9 rillig "=\2TWO\0"
180 1.9 rillig "*=Other(%jd)\0",
181 1.9 rillig 3,
182 1.6 kre "0x3<X=0x3=Other(3)>");
183 1.9 rillig h_snprintb(
184 1.9 rillig "\177\20"
185 1.9 rillig "f\0\x8X\0"
186 1.9 rillig "=\1ONE\0"
187 1.9 rillig "=\2TWO\0"
188 1.9 rillig "*=other(%jo)\0",
189 1.9 rillig 0x20,
190 1.6 kre "0x20<X=0x20=other(40)>");
191 1.9 rillig h_snprintb(
192 1.9 rillig "\177\020"
193 1.9 rillig "F\0\4\0"
194 1.9 rillig ":\1ONE\0"
195 1.9 rillig ":\2TWO\0",
196 1.9 rillig 3,
197 1.6 kre "0x3<>");
198 1.6 kre
199 1.9 rillig h_snprintb(
200 1.9 rillig "\177\20"
201 1.9 rillig "f\0\4Field_1\0"
202 1.9 rillig "=\1ONE\0"
203 1.9 rillig "=\2TWO\0"
204 1.9 rillig "f\4\4Field_2\0"
205 1.9 rillig "=\1ONE\0"
206 1.9 rillig "=\2TWO\0",
207 1.9 rillig 0x12,
208 1.6 kre "0x12<Field_1=0x2=TWO,Field_2=0x1=ONE>");
209 1.6 kre
210 1.9 rillig h_snprintb(
211 1.9 rillig "\177\20"
212 1.9 rillig "f\0\4Field_1\0"
213 1.9 rillig "=\1ONE\0"
214 1.9 rillig "=\2TWO\0"
215 1.9 rillig "F\x8\4\0"
216 1.9 rillig "*Field_3=%jd\0"
217 1.9 rillig "f\4\4Field_2\0"
218 1.9 rillig ":\1:ONE\0"
219 1.9 rillig ":\2:TWO\0",
220 1.9 rillig 0xD12,
221 1.6 kre "0xd12<Field_1=0x2=TWO,Field_3=13,Field_2=0x1:ONE>");
222 1.9 rillig
223 1.9 rillig // It is possible but cumbersome to implement a reduced variant of
224 1.9 rillig // rot13 using snprintb, shown here for lowercase letters only.
225 1.9 rillig for (char ch = 'A'; ch <= '~'; ch++) {
226 1.9 rillig char rot13 = ch >= 'a' && ch <= 'm' ? ch + 13
227 1.9 rillig : ch >= 'n' && ch <= 'z' ? ch - 13
228 1.9 rillig : '?';
229 1.9 rillig char expected[8];
230 1.9 rillig ATF_REQUIRE_EQ(7,
231 1.9 rillig snprintf(expected, sizeof(expected), "%#x<%c>", ch, rot13));
232 1.9 rillig h_snprintb(
233 1.9 rillig "\177\020"
234 1.9 rillig "F\000\010\0"
235 1.9 rillig ":an\0:bo\0:cp\0:dq\0:er\0:fs\0:gt\0:hu\0"
236 1.9 rillig ":iv\0:jw\0:kx\0:ly\0:mz\0"
237 1.9 rillig ":na\0:ob\0:pc\0:qd\0:re\0:sf\0:tg\0:uh\0"
238 1.9 rillig ":vi\0:wj\0:xk\0:yl\0:zm\0"
239 1.9 rillig // If snprintf accepted "%jc", it would be possible to
240 1.9 rillig // echo the non-alphabetic characters instead of a
241 1.9 rillig // catchall question mark.
242 1.9 rillig "*?\0",
243 1.9 rillig ch,
244 1.9 rillig expected);
245 1.9 rillig }
246 1.1 jmmv }
247 1.1 jmmv
248 1.2 pgoyette static void
249 1.9 rillig h_snprintb_m(const char *file, size_t line, const char *fmt, size_t fmtlen, uint64_t val, int line_max,
250 1.9 rillig const char *res, size_t reslen)
251 1.2 pgoyette {
252 1.2 pgoyette char buf[1024];
253 1.2 pgoyette
254 1.9 rillig int rv = snprintb_m(buf, sizeof(buf), fmt, val, line_max);
255 1.2 pgoyette
256 1.9 rillig ATF_REQUIRE_MSG(rv >= 0, "formatting %jx with '%s' returns error %d",
257 1.9 rillig (uintmax_t)val, vis_fmt(fmt, fmtlen), rv);
258 1.9 rillig
259 1.9 rillig size_t buflen = rv;
260 1.9 rillig ATF_CHECK_MSG(
261 1.9 rillig buflen == reslen && memcmp(buf, res, reslen) == 0,
262 1.9 rillig "failed:\n"
263 1.9 rillig "\ttest case: %s:%zu\n"
264 1.9 rillig "\tformat: %s\n"
265 1.9 rillig "\tvalue: %#jx\n"
266 1.9 rillig "\twant: %zu bytes %s\n"
267 1.9 rillig "\thave: %zu bytes %s\n",
268 1.9 rillig file, line,
269 1.9 rillig vis_fmt(fmt, fmtlen), (uintmax_t)val,
270 1.9 rillig reslen, vis_fmt(res, reslen),
271 1.9 rillig buflen, vis_fmt(buf, buflen));
272 1.2 pgoyette }
273 1.2 pgoyette
274 1.9 rillig #define h_snprintb_m(fmt, val, line_max, res) \
275 1.9 rillig h_snprintb_m(__FILE__, __LINE__, fmt, sizeof(fmt) - 1, \
276 1.9 rillig val, line_max, res, sizeof(res) - 1)
277 1.9 rillig
278 1.2 pgoyette ATF_TC(snprintb_m);
279 1.2 pgoyette ATF_TC_HEAD(snprintb_m, tc)
280 1.2 pgoyette {
281 1.2 pgoyette atf_tc_set_md_var(tc, "descr", "Checks snprintb_m(3)");
282 1.2 pgoyette }
283 1.2 pgoyette ATF_TC_BODY(snprintb_m, tc)
284 1.2 pgoyette {
285 1.9 rillig h_snprintb_m(
286 1.9 rillig "\177\020"
287 1.9 rillig "b\0LSB\0"
288 1.9 rillig "b\1_BITONE\0"
289 1.9 rillig "f\4\4NIBBLE2\0"
290 1.9 rillig "f\x10\4BURST\0"
291 1.9 rillig "=\04FOUR\0"
292 1.9 rillig "=\17FIFTEEN\0"
293 1.9 rillig "b\x1fMSB\0",
294 1.9 rillig 0x800f0701,
295 1.9 rillig 33,
296 1.9 rillig "0x800f0701<LSB,NIBBLE2=0>\0"
297 1.9 rillig "0x800f0701<BURST=0xf=FIFTEEN,MSB>\0");
298 1.9 rillig
299 1.9 rillig h_snprintb_m(
300 1.9 rillig "\177\020"
301 1.9 rillig "b\0LSB\0"
302 1.9 rillig "b\1_BITONE\0"
303 1.9 rillig "f\4\4NIBBLE2\0"
304 1.9 rillig "f\x10\4BURST\0"
305 1.9 rillig "=\04FOUR\0"
306 1.9 rillig "=\17FIFTEEN\0"
307 1.9 rillig "b\x1fMSB\0",
308 1.9 rillig 0x800f0701,
309 1.9 rillig 32,
310 1.9 rillig "0x800f0701<LSB,NIBBLE2=0>\0"
311 1.9 rillig "0x800f0701<BURST=0xf=FIFTEEN>\0"
312 1.9 rillig "0x800f0701<MSB>\0");
313 1.2 pgoyette }
314 1.2 pgoyette
315 1.1 jmmv ATF_TP_ADD_TCS(tp)
316 1.1 jmmv {
317 1.1 jmmv
318 1.1 jmmv ATF_TP_ADD_TC(tp, snprintb);
319 1.2 pgoyette ATF_TP_ADD_TC(tp, snprintb_m);
320 1.1 jmmv
321 1.1 jmmv return atf_no_error();
322 1.1 jmmv }
323