1*c39afc64Skettenis /* $OpenBSD: int.c,v 1.2 2020/07/14 16:40:04 kettenis Exp $ */
2df303251Sschwarze /*
3df303251Sschwarze * Copyright (c) 2020 Ingo Schwarze <schwarze@openbsd.org>
4df303251Sschwarze *
5df303251Sschwarze * Permission to use, copy, modify, and distribute this software for any
6df303251Sschwarze * purpose with or without fee is hereby granted, provided that the above
7df303251Sschwarze * copyright notice and this permission notice appear in all copies.
8df303251Sschwarze *
9df303251Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10df303251Sschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11df303251Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12df303251Sschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13df303251Sschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14df303251Sschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15df303251Sschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16df303251Sschwarze *
17df303251Sschwarze * Test the %c, %lc, %s, and %ls conversion specifiers with all their
18df303251Sschwarze * modifiers, in particular with the minus flag, width, and maxbytes.
19df303251Sschwarze * Also verify that other flags do nothing useful.
20df303251Sschwarze */
21df303251Sschwarze #include <err.h>
22df303251Sschwarze #include <stddef.h>
23df303251Sschwarze #include <stdint.h>
24df303251Sschwarze #include <stdio.h>
25df303251Sschwarze #include <string.h>
26df303251Sschwarze #include <unistd.h>
27df303251Sschwarze
28df303251Sschwarze enum int_size {
29df303251Sschwarze S_CHAR,
30df303251Sschwarze S_SHORT,
31df303251Sschwarze S_INT,
32df303251Sschwarze S_LONG,
33df303251Sschwarze S_LL,
34df303251Sschwarze S_MAX,
35df303251Sschwarze S_PTR,
36df303251Sschwarze S_SIZE
37df303251Sschwarze };
38df303251Sschwarze
39df303251Sschwarze void ti(const char *, enum int_size, long long, const char *);
40df303251Sschwarze void tu(const char *, enum int_size, unsigned long long, const char *);
41df303251Sschwarze
42df303251Sschwarze static int badret, badlen, badout; /* Error counters. */
43df303251Sschwarze static int verbose; /* For debugging. */
44df303251Sschwarze
45df303251Sschwarze
46df303251Sschwarze /*
47df303251Sschwarze * Print the signed integer i with the format fmt,
48df303251Sschwarze * check that the result matches what we want,
49df303251Sschwarze * and report and count the error on failure.
50df303251Sschwarze */
51df303251Sschwarze void
ti(const char * fmt,enum int_size sz,long long i,const char * want)52df303251Sschwarze ti(const char *fmt, enum int_size sz, long long i, const char *want)
53df303251Sschwarze {
54df303251Sschwarze char buf[32];
55df303251Sschwarze size_t len;
56df303251Sschwarze int irc, happy;
57df303251Sschwarze
58df303251Sschwarze happy = 1;
59df303251Sschwarze switch (sz) {
60df303251Sschwarze case S_CHAR:
61df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (signed char)i);
62df303251Sschwarze break;
63df303251Sschwarze case S_SHORT:
64df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (short)i);
65df303251Sschwarze break;
66df303251Sschwarze case S_INT:
67df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (int)i);
68df303251Sschwarze break;
69df303251Sschwarze case S_LONG:
70df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (long)i);
71df303251Sschwarze break;
72df303251Sschwarze case S_LL:
73df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (long long)i);
74df303251Sschwarze break;
75df303251Sschwarze case S_MAX:
76df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (intmax_t)i);
77df303251Sschwarze break;
78df303251Sschwarze case S_PTR:
79df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (ptrdiff_t)i);
80df303251Sschwarze break;
81df303251Sschwarze case S_SIZE:
82df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (ssize_t)i);
83df303251Sschwarze break;
84df303251Sschwarze default:
85df303251Sschwarze warnx("printf(\"%s\", %lld) unknown size code %d",
86df303251Sschwarze fmt, i, sz);
87df303251Sschwarze badret++;
88df303251Sschwarze return;
89df303251Sschwarze }
90df303251Sschwarze len = strlen(want);
91df303251Sschwarze if (irc < 0) {
92df303251Sschwarze warn("printf(\"%s\", %lld) returned %d", fmt, i, irc);
93df303251Sschwarze badret++;
94df303251Sschwarze return;
95df303251Sschwarze }
96df303251Sschwarze if ((unsigned long long)irc != len) {
97df303251Sschwarze warnx("printf(\"%s\", %lld) returned %d (expected %zu)",
98df303251Sschwarze fmt, i, irc, len);
99df303251Sschwarze badlen++;
100df303251Sschwarze happy = 0;
101df303251Sschwarze }
102df303251Sschwarze if (strcmp(buf, want) != 0) {
103df303251Sschwarze warnx("printf(\"%s\", %lld) wrote \"%s\" (expected \"%s\")",
104df303251Sschwarze fmt, i, buf, want);
105df303251Sschwarze badout++;
106df303251Sschwarze happy = 0;
107df303251Sschwarze }
108df303251Sschwarze if (verbose && happy)
109df303251Sschwarze warnx("printf(\"%s\", %lld) wrote \"%s\" length %d (OK)",
110df303251Sschwarze fmt, i, buf, irc);
111df303251Sschwarze }
112df303251Sschwarze
113df303251Sschwarze /*
114df303251Sschwarze * Print the unsigned integer i with the format fmt,
115df303251Sschwarze * check that the result matches what we want,
116df303251Sschwarze * and report and count the error on failure.
117df303251Sschwarze */
118df303251Sschwarze void
tu(const char * fmt,enum int_size sz,unsigned long long i,const char * want)119df303251Sschwarze tu(const char *fmt, enum int_size sz, unsigned long long i, const char *want)
120df303251Sschwarze {
121df303251Sschwarze char buf[32];
122df303251Sschwarze size_t len;
123df303251Sschwarze int irc, happy;
124df303251Sschwarze
125df303251Sschwarze happy = 1;
126df303251Sschwarze switch (sz) {
127df303251Sschwarze case S_CHAR:
128df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (unsigned char)i);
129df303251Sschwarze break;
130df303251Sschwarze case S_SHORT:
131df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (unsigned short)i);
132df303251Sschwarze break;
133df303251Sschwarze case S_INT:
134df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (unsigned int)i);
135df303251Sschwarze break;
136df303251Sschwarze case S_LONG:
137df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (unsigned long)i);
138df303251Sschwarze break;
139df303251Sschwarze case S_LL:
140df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (unsigned long long)i);
141df303251Sschwarze break;
142df303251Sschwarze case S_MAX:
143df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (uintmax_t)i);
144df303251Sschwarze break;
145df303251Sschwarze case S_SIZE:
146df303251Sschwarze irc = snprintf(buf, sizeof(buf), fmt, (size_t)i);
147df303251Sschwarze break;
148df303251Sschwarze default:
149df303251Sschwarze warnx("printf(\"%s\", %llu) unknown size code %d",
150df303251Sschwarze fmt, i, sz);
151df303251Sschwarze badret++;
152df303251Sschwarze return;
153df303251Sschwarze }
154df303251Sschwarze len = strlen(want);
155df303251Sschwarze if (irc < 0) {
156df303251Sschwarze warn("printf(\"%s\", %llu) returned %d", fmt, i, irc);
157df303251Sschwarze badret++;
158df303251Sschwarze return;
159df303251Sschwarze }
160df303251Sschwarze if ((unsigned long long)irc != len) {
161df303251Sschwarze warnx("printf(\"%s\", %llu) returned %d (expected %zu)",
162df303251Sschwarze fmt, i, irc, len);
163df303251Sschwarze badlen++;
164df303251Sschwarze happy = 0;
165df303251Sschwarze }
166df303251Sschwarze if (strcmp(buf, want) != 0) {
167df303251Sschwarze warnx("printf(\"%s\", %llu) wrote \"%s\" (expected \"%s\")",
168df303251Sschwarze fmt, i, buf, want);
169df303251Sschwarze badout++;
170df303251Sschwarze happy = 0;
171df303251Sschwarze }
172df303251Sschwarze if (verbose && happy)
173df303251Sschwarze warnx("printf(\"%s\", %llu) wrote \"%s\" length %d (OK)",
174df303251Sschwarze fmt, i, buf, irc);
175df303251Sschwarze }
176df303251Sschwarze
177df303251Sschwarze int
main(int argc,char * argv[])178df303251Sschwarze main(int argc, char *argv[])
179df303251Sschwarze {
180df303251Sschwarze int badarg, picky;
181*c39afc64Skettenis int ch;
182df303251Sschwarze
183df303251Sschwarze badarg = picky = 0;
184df303251Sschwarze while ((ch = getopt(argc, argv, "pv")) != -1) {
185df303251Sschwarze switch (ch) {
186df303251Sschwarze case 'p':
187df303251Sschwarze picky = 1;
188df303251Sschwarze break;
189df303251Sschwarze case 'v':
190df303251Sschwarze verbose = 1;
191df303251Sschwarze break;
192df303251Sschwarze default:
193df303251Sschwarze badarg = 1;
194df303251Sschwarze break;
195df303251Sschwarze }
196df303251Sschwarze }
197df303251Sschwarze argc -= optind;
198df303251Sschwarze argv += optind;
199df303251Sschwarze if (argc > 0) {
200df303251Sschwarze warnx("unexpected argument \"%s\"", *argv);
201df303251Sschwarze badarg = 1;
202df303251Sschwarze }
203df303251Sschwarze if (badarg) {
204df303251Sschwarze fputs("usage: int [-pv]\n", stderr);
205df303251Sschwarze return 1;
206df303251Sschwarze }
207df303251Sschwarze
208df303251Sschwarze /*
209df303251Sschwarze * Valid use cases of %d.
210df303251Sschwarze */
211df303251Sschwarze
212df303251Sschwarze ti("<%d>", S_INT, 0, "<0>");
213df303251Sschwarze ti("<%d>", S_INT, 1, "<1>");
214df303251Sschwarze ti("<%d>", S_INT, -1, "<-1>");
215df303251Sschwarze ti("<%d>", S_INT, 42, "<42>");
216df303251Sschwarze ti("<%d>", S_INT, INT32_MAX, "<2147483647>");
217df303251Sschwarze ti("<%d>", S_INT, INT32_MIN, "<-2147483648>");
218df303251Sschwarze ti("<% d>", S_INT, 42, "< 42>");
219df303251Sschwarze ti("<% d>", S_INT, -42, "<-42>");
220df303251Sschwarze ti("<%+d>", S_INT, 42, "<+42>");
221df303251Sschwarze ti("<%+d>", S_INT, -42, "<-42>");
222df303251Sschwarze ti("<% +d>", S_INT, 42, "<+42>");
223df303251Sschwarze ti("<% +d>", S_INT, -42, "<-42>");
224df303251Sschwarze ti("<%-4d>", S_INT, 42, "<42 >");
225df303251Sschwarze ti("<% -4d>", S_INT, 42, "< 42 >");
226df303251Sschwarze ti("<%+-4d>", S_INT, 42, "<+42 >");
227df303251Sschwarze ti("<%04d>", S_INT, 42, "<0042>");
228df303251Sschwarze ti("<%-04d>", S_INT, 42, "<42 >");
229df303251Sschwarze ti("<% 04d>", S_INT, 42, "< 042>");
230df303251Sschwarze ti("<%+04d>", S_INT, 42, "<+042>");
231df303251Sschwarze ti("<%4.3d>", S_INT, 42, "< 042>");
232df303251Sschwarze ti("<% 5.3d>", S_INT, 42, "< 042>");
233df303251Sschwarze ti("<%+5.3d>", S_INT, 42, "< +042>");
234df303251Sschwarze ti("<%-4.3d>", S_INT, 42, "<042 >");
235df303251Sschwarze ti("<%04.3d>", S_INT, 42, "< 042>");
236df303251Sschwarze
237df303251Sschwarze ti("<%hhd>", S_CHAR, INT8_MIN, "<-128>");
238df303251Sschwarze ti("<%hhd>", S_CHAR, -1, "<-1>");
239df303251Sschwarze ti("<%hhd>", S_CHAR, 0, "<0>");
240df303251Sschwarze ti("<%hhd>", S_CHAR, 1, "<1>");
241df303251Sschwarze ti("<%hhd>", S_CHAR, INT8_MAX, "<127>");
242df303251Sschwarze ti("<%+.4hhd>", S_CHAR, 42, "<+0042>");
243df303251Sschwarze ti("<% 04hhd>", S_CHAR, 42, "< 042>");
244df303251Sschwarze
245df303251Sschwarze ti("<%hd>", S_SHORT, INT16_MIN, "<-32768>");
246df303251Sschwarze ti("<%hd>", S_SHORT, -1, "<-1>");
247df303251Sschwarze ti("<%hd>", S_SHORT, 0, "<0>");
248df303251Sschwarze ti("<%hd>", S_SHORT, 1, "<1>");
249df303251Sschwarze ti("<%hd>", S_SHORT, INT16_MAX, "<32767>");
250df303251Sschwarze
251df303251Sschwarze ti("<%hld>", S_LONG, INT32_MIN, "<-2147483648>");
252df303251Sschwarze ti("<%hld>", S_LONG, -1, "<-1>");
253df303251Sschwarze ti("<%hld>", S_LONG, 0, "<0>");
254df303251Sschwarze ti("<%hld>", S_LONG, 1, "<1>");
255df303251Sschwarze ti("<%hld>", S_LONG, INT32_MAX, "<2147483647>");
256df303251Sschwarze
257df303251Sschwarze ti("<%hlld>", S_LL, INT64_MIN, "<-9223372036854775808>");
258df303251Sschwarze ti("<%hlld>", S_LL, -1, "<-1>");
259df303251Sschwarze ti("<%hlld>", S_LL, 0, "<0>");
260df303251Sschwarze ti("<%hlld>", S_LL, 1, "<1>");
261df303251Sschwarze ti("<%hlld>", S_LL, INT64_MAX, "<9223372036854775807>");
262df303251Sschwarze ti("<%h-19lld>", S_LL, 123456789123456789LL, "<123456789123456789 >");
263df303251Sschwarze
264df303251Sschwarze ti("<%hjd>", S_MAX, INT64_MIN, "<-9223372036854775808>");
265df303251Sschwarze ti("<%hjd>", S_MAX, -1, "<-1>");
266df303251Sschwarze ti("<%hjd>", S_MAX, 0, "<0>");
267df303251Sschwarze ti("<%hjd>", S_MAX, 1, "<1>");
268df303251Sschwarze ti("<%hjd>", S_MAX, INT64_MAX, "<9223372036854775807>");
269df303251Sschwarze
270df303251Sschwarze ti("<%htd>", S_PTR, INT32_MIN, "<-2147483648>");
271df303251Sschwarze ti("<%htd>", S_PTR, -1, "<-1>");
272df303251Sschwarze ti("<%htd>", S_PTR, 0, "<0>");
273df303251Sschwarze ti("<%htd>", S_PTR, 1, "<1>");
274df303251Sschwarze ti("<%htd>", S_PTR, INT32_MAX, "<2147483647>");
275df303251Sschwarze
276df303251Sschwarze ti("<%hzd>", S_SIZE, INT32_MIN, "<-2147483648>");
277df303251Sschwarze ti("<%hzd>", S_SIZE, -1, "<-1>");
278df303251Sschwarze ti("<%hzd>", S_SIZE, 0, "<0>");
279df303251Sschwarze ti("<%hzd>", S_SIZE, 1, "<1>");
280df303251Sschwarze ti("<%hzd>", S_SIZE, INT32_MAX, "<2147483647>");
281df303251Sschwarze
282df303251Sschwarze /*
283df303251Sschwarze * Undefined behaviour of %d.
284df303251Sschwarze * Do not test by default to avoid noise.
285df303251Sschwarze * But provide the tests anyway to help track down
286df303251Sschwarze * unintended changes of behaviour when needed.
287df303251Sschwarze */
288df303251Sschwarze
289df303251Sschwarze if (picky) {
290df303251Sschwarze ti("<%#d>", S_INT, 42, "<42>");
291df303251Sschwarze ti("<%Ld>", S_INT, 42, "<42>");
292df303251Sschwarze }
293df303251Sschwarze
294df303251Sschwarze /*
295df303251Sschwarze * Valid use cases of %u.
296df303251Sschwarze */
297df303251Sschwarze
298df303251Sschwarze tu("<%u>", S_INT, 0, "<0>");
299df303251Sschwarze tu("<%u>", S_INT, 1, "<1>");
300df303251Sschwarze tu("<%u>", S_INT, 42, "<42>");
301df303251Sschwarze tu("<%u>", S_INT, UINT32_MAX, "<4294967295>");
302df303251Sschwarze tu("<%-4u>", S_INT, 42, "<42 >");
303df303251Sschwarze tu("<%04u>", S_INT, 42, "<0042>");
304df303251Sschwarze tu("<%-04u>", S_INT, 42, "<42 >");
305df303251Sschwarze tu("<%4.3u>", S_INT, 42, "< 042>");
306df303251Sschwarze tu("<%-4.3u>", S_INT, 42, "<042 >");
307df303251Sschwarze tu("<%04.3u>", S_INT, 42, "< 042>");
308df303251Sschwarze
309df303251Sschwarze tu("<%hhu>", S_CHAR, 0, "<0>");
310df303251Sschwarze tu("<%hhu>", S_CHAR, UINT8_MAX, "<255>");
311df303251Sschwarze tu("<%hhu>", S_CHAR, -1, "<255>");
312df303251Sschwarze tu("<%-4hhu>", S_CHAR, 42, "<42 >");
313df303251Sschwarze tu("<%04hhu>", S_CHAR, 42, "<0042>");
314df303251Sschwarze
315df303251Sschwarze tu("<%hu>", S_SHORT, 0, "<0>");
316df303251Sschwarze tu("<%hu>", S_SHORT, UINT16_MAX, "<65535>");
317df303251Sschwarze tu("<%hlu>", S_LONG, 0, "<0>");
318df303251Sschwarze tu("<%hlu>", S_LONG, UINT32_MAX, "<4294967295>");
319df303251Sschwarze tu("<%hllu>", S_LL, 0, "<0>");
320df303251Sschwarze tu("<%hllu>", S_LL, UINT64_MAX, "<18446744073709551615>");
321df303251Sschwarze tu("<%h-19llu>", S_LL, 123456789123456789ULL, "<123456789123456789 >");
322df303251Sschwarze tu("<%hju>", S_MAX, 0, "<0>");
323df303251Sschwarze tu("<%hju>", S_MAX, UINT64_MAX, "<18446744073709551615>");
324df303251Sschwarze tu("<%hzu>", S_SIZE, 0, "<0>");
325df303251Sschwarze tu("<%hzu>", S_SIZE, UINT32_MAX, "<4294967295>");
326df303251Sschwarze
327df303251Sschwarze tu("<%hho>", S_CHAR, 0, "<0>");
328df303251Sschwarze tu("<%#hho>", S_CHAR, 0, "<0>");
329df303251Sschwarze tu("<%hho>", S_CHAR, UINT8_MAX, "<377>");
330df303251Sschwarze tu("<%#hho>", S_CHAR, UINT8_MAX, "<0377>");
331df303251Sschwarze tu("<%hho>", S_CHAR, -1, "<377>");
332df303251Sschwarze tu("<%#hho>", S_CHAR, -1, "<0377>");
333df303251Sschwarze tu("<%-4hho>", S_CHAR, 42, "<52 >");
334df303251Sschwarze tu("<%#-4hho>", S_CHAR, 42, "<052 >");
335df303251Sschwarze tu("<%04hho>", S_CHAR, 42, "<0052>");
336df303251Sschwarze tu("<%#04hho>", S_CHAR, 42, "<0052>");
337df303251Sschwarze
338df303251Sschwarze tu("<%hx>", S_SHORT, 0, "<0>");
339df303251Sschwarze tu("<%#hx>", S_SHORT, 0, "<0>");
340df303251Sschwarze tu("<%hX>", S_SHORT, 0, "<0>");
341df303251Sschwarze tu("<%#hX>", S_SHORT, 0, "<0>");
342df303251Sschwarze tu("<%hx>", S_SHORT, 1, "<1>");
343df303251Sschwarze tu("<%#hx>", S_SHORT, 1, "<0x1>");
344df303251Sschwarze tu("<%hX>", S_SHORT, 1, "<1>");
345df303251Sschwarze tu("<%#hX>", S_SHORT, 1, "<0X1>");
346df303251Sschwarze tu("<%hx>", S_SHORT, 10, "<a>");
347df303251Sschwarze tu("<%#hx>", S_SHORT, 10, "<0xa>");
348df303251Sschwarze tu("<%hX>", S_SHORT, 10, "<A>");
349df303251Sschwarze tu("<%#hX>", S_SHORT, 10, "<0XA>");
350df303251Sschwarze tu("<%hx>", S_SHORT, UINT16_MAX, "<ffff>");
351df303251Sschwarze tu("<%#hx>", S_SHORT, UINT16_MAX, "<0xffff>");
352df303251Sschwarze tu("<%hX>", S_SHORT, UINT16_MAX, "<FFFF>");
353df303251Sschwarze tu("<%#hX>", S_SHORT, UINT16_MAX, "<0XFFFF>");
354df303251Sschwarze
355df303251Sschwarze /*
356df303251Sschwarze * Undefined behaviour of %u.
357df303251Sschwarze */
358df303251Sschwarze
359df303251Sschwarze if (picky) {
360df303251Sschwarze tu("<%#u>", S_INT, 42, "<42>");
361df303251Sschwarze tu("<% u>", S_INT, 42, "<42>");
362df303251Sschwarze tu("<%+u>", S_INT, 42, "<42>");
363df303251Sschwarze tu("<%Lu>", S_INT, 42, "<42>");
364df303251Sschwarze }
365df303251Sschwarze
366df303251Sschwarze /*
367df303251Sschwarze * Summarize the results.
368df303251Sschwarze */
369df303251Sschwarze
370df303251Sschwarze if (badret + badlen + badout)
371df303251Sschwarze errx(1, "ERRORS: %d fail + %d mismatch (incl. %d bad length)",
372df303251Sschwarze badret, badout, badlen);
373df303251Sschwarze else if (verbose)
374df303251Sschwarze warnx("SUCCESS");
375df303251Sschwarze return 0;
376df303251Sschwarze }
377