t_strtoi.c revision 1.5 1 /* $NetBSD: t_strtoi.c,v 1.5 2024/07/24 09:26:06 kre Exp $ */
2
3 /*-
4 * Copyright (c) 2015 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jukka Ruohonen.
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 /*
33 * Created by Kamil Rytarowski, based on ID:
34 * NetBSD: t_strtol.c,v 1.5 2011/06/14 02:45:58 jruoho Exp
35 */
36
37 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: t_strtoi.c,v 1.5 2024/07/24 09:26:06 kre Exp $");
39
40 #include <atf-c.h>
41 #include <errno.h>
42 #include <inttypes.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <limits.h>
46
47 struct test {
48 const char *str;
49 intmax_t res;
50 int base;
51 const char *end;
52 intmax_t lo;
53 intmax_t hi;
54 int rstatus;
55 };
56
57 static void check(struct test *, intmax_t, char *, int);
58
59 static void
60 check(struct test *t, intmax_t rv, char *end, int rstatus)
61 {
62
63 if (rv != t->res)
64 atf_tc_fail_nonfatal("strtoi(\"%s\", &end, %d, %jd, %jd, "
65 "&rstatus) failed (rv = %jd)", t->str, t->base,
66 t->lo, t->hi, rv);
67
68 if (rstatus != t->rstatus) {
69 char *emsg;
70
71 if (rstatus != 0) {
72 emsg = strerror(rstatus);
73 if (emsg != NULL) {
74 emsg = strdup(emsg);
75 if (emsg == NULL) {
76 atf_tc_fail("Out of Memory");
77 return;
78 }
79 }
80 } else
81 emsg = NULL;
82
83 atf_tc_fail_nonfatal("strtoi(\"%s\", &end, %d, %jd, %jd, &rstatus)"
84 " failed (rstatus: %d %s%s%sexpected %d%s%s%s)",
85 t->str, t->base, t->lo, t->hi, rstatus, rstatus ? "('" : "",
86 emsg != NULL ? emsg : "", rstatus ? "') " : "", t->rstatus,
87 t->rstatus ? " ('" : "", t->rstatus ? strerror(t->rstatus)
88 : "", t->rstatus ? "')" : "");
89
90 free(emsg);
91 }
92
93 if ((t->end != NULL && strcmp(t->end, end) != 0) ||
94 (t->end == NULL && *end != '\0'))
95 atf_tc_fail_nonfatal("invalid end pointer ('%s') from "
96 "strtoi(\"%s\", &end, %d, %jd, %jd, &rstatus), "
97 "expected '%s'", end, t->str, t->base, t->lo, t->hi,
98 t->end != NULL ? t->end : "\\0");
99 }
100
101 static void
102 check_errno(int e)
103 {
104 if (e != 0)
105 atf_tc_fail("strtoi(3) changed errno to %d ('%s')",
106 e, strerror(e));
107 }
108
109 ATF_TC(strtoi_base);
110 ATF_TC_HEAD(strtoi_base, tc)
111 {
112 atf_tc_set_md_var(tc, "descr", "Test strtoi(3) with different bases");
113 }
114
115 ATF_TC_BODY(strtoi_base, tc)
116 {
117 struct test t[] = {
118 { "123456789", 123456789, 0, NULL,
119 INTMAX_MIN, INTMAX_MAX, 0 },
120 { "111010110111100110100010101",123456789, 2, NULL,
121 INTMAX_MIN, INTMAX_MAX, 0 },
122 { "22121022020212200", 123456789, 3, NULL,
123 INTMAX_MIN, INTMAX_MAX, 0 },
124 { "13112330310111", 123456789, 4, NULL,
125 INTMAX_MIN, INTMAX_MAX, 0 },
126 { "223101104124", 123456789, 5, NULL,
127 INTMAX_MIN, INTMAX_MAX, 0 },
128 { "20130035113", 123456789, 6, NULL,
129 INTMAX_MIN, INTMAX_MAX, 0 },
130 { "3026236221", 123456789, 7, NULL,
131 INTMAX_MIN, INTMAX_MAX, 0 },
132 { "726746425", 123456789, 8, NULL,
133 INTMAX_MIN, INTMAX_MAX, 0 },
134 { "277266780", 123456789, 9, NULL,
135 INTMAX_MIN, INTMAX_MAX, 0 },
136 { "123456789", 123456789, 10, NULL,
137 INTMAX_MIN, INTMAX_MAX, 0 },
138 { "63762A05", 123456789, 11, NULL,
139 INTMAX_MIN, INTMAX_MAX, 0 },
140 { "35418A99", 123456789, 12, NULL,
141 INTMAX_MIN, INTMAX_MAX, 0 },
142 { "1C767471", 123456789, 13, NULL,
143 INTMAX_MIN, INTMAX_MAX, 0 },
144 { "12579781", 123456789, 14, NULL,
145 INTMAX_MIN, INTMAX_MAX, 0 },
146 { "AC89BC9", 123456789, 15, NULL,
147 INTMAX_MIN, INTMAX_MAX, 0 },
148 { "75BCD15", 123456789, 16, NULL,
149 INTMAX_MIN, INTMAX_MAX, 0 },
150 { "1234567", 342391, 8, NULL,
151 INTMAX_MIN, INTMAX_MAX, 0 },
152 { "01234567", 342391, 0, NULL,
153 INTMAX_MIN, INTMAX_MAX, 0 },
154 { "0123456789", 123456789, 10, NULL,
155 INTMAX_MIN, INTMAX_MAX, 0 },
156 { "0x75bcd15", 123456789, 0, NULL,
157 INTMAX_MIN, INTMAX_MAX, 0 },
158 };
159 struct test f[] = {
160 { "1", 0, 1, "1",
161 INTMAX_MIN, INTMAX_MAX, EINVAL },
162 { "2", 0, -1, "2",
163 INTMAX_MIN, INTMAX_MAX, EINVAL },
164 { "3", 0, 37, "3",
165 INTMAX_MIN, INTMAX_MAX, EINVAL },
166 { "4", 0, -1, "4",
167 INTMAX_MIN, INTMAX_MAX, EINVAL },
168 { "0x", 0, 0, "x",
169 INTMAX_MIN, INTMAX_MAX, ENOTSUP },
170 };
171
172 intmax_t rv;
173 char *end;
174 int e;
175 size_t i;
176
177 for (i = 0; i < __arraycount(t); i++) {
178
179 errno = 0;
180 rv = strtoi(t[i].str, &end, t[i].base, t[i].lo, t[i].hi, &e);
181
182 check_errno(errno);
183
184 check(&t[i], rv, end, e);
185 }
186
187 for (i = 0; i < __arraycount(f); i++) {
188
189 end = NULL;
190 errno = 0;
191 e = -99;
192
193 rv = strtoi(f[i].str, &end, f[i].base, f[i].lo, f[i].hi, &e);
194
195 check_errno(errno);
196
197 check(&f[i], rv, end, e);
198 }
199 }
200
201 ATF_TC(strtoi_case);
202 ATF_TC_HEAD(strtoi_case, tc)
203 {
204 atf_tc_set_md_var(tc, "descr", "Case insensitivity with strtoi(3)");
205 }
206
207 ATF_TC_BODY(strtoi_case, tc)
208 {
209 struct test t[] = {
210 { "abcd", 0xabcd, 16, NULL,
211 INTMAX_MIN, INTMAX_MAX, 0 },
212 { " dcba", 0xdcba, 16, NULL,
213 INTMAX_MIN, INTMAX_MAX, 0 },
214 { "abcd dcba", 0xabcd, 16, " dcba",
215 INTMAX_MIN, INTMAX_MAX, ENOTSUP },
216 { "abc0x123", 0xabc0, 16, "x123",
217 INTMAX_MIN, INTMAX_MAX, ENOTSUP },
218 { "abcd\0x123", 0xabcd, 16, "\0x123",
219 INTMAX_MIN, INTMAX_MAX, 0 },
220 { "ABCD", 0xabcd, 16, NULL,
221 INTMAX_MIN, INTMAX_MAX, 0 },
222 { "aBcD", 0xabcd, 16, NULL,
223 INTMAX_MIN, INTMAX_MAX, 0 },
224 { "0xABCD", 0xabcd, 16, NULL,
225 INTMAX_MIN, INTMAX_MAX, 0 },
226 { "0xABCDX", 0xabcd, 16, "X",
227 INTMAX_MIN, INTMAX_MAX, ENOTSUP},
228 };
229
230 intmax_t rv;
231 char *end;
232 int e;
233 size_t i;
234
235 for (i = 0; i < __arraycount(t); i++) {
236
237 errno = 0;
238 rv = strtoi(t[i].str, &end, t[i].base, t[i].lo, t[i].hi, &e);
239
240 check_errno(errno);
241
242 check(&t[i], rv, end, e);
243 }
244 }
245
246 ATF_TC(strtoi_range);
247 ATF_TC_HEAD(strtoi_range, tc)
248 {
249 atf_tc_set_md_var(tc, "descr", "Test ERANGE from strtoi(3)");
250 }
251
252 ATF_TC_BODY(strtoi_range, tc)
253 {
254 struct test t[] = {
255 #if INTMAX_MAX == 0x7fffffffffffffff
256 { "1000000000000000000000", INTMAX_MAX, 8, NULL,
257 INTMAX_MIN, INTMAX_MAX, ERANGE },
258 { "9223372036854775808", INTMAX_MAX, 10, NULL,
259 INTMAX_MIN, INTMAX_MAX, ERANGE },
260 { "8000000000000000", INTMAX_MAX, 16, NULL,
261 INTMAX_MIN, INTMAX_MAX, ERANGE },
262 #else
263 #error extend this test to your platform!
264 #endif
265 { "10", 1, 10, NULL,
266 -1, 1, ERANGE },
267 { "10", 11, 10, NULL,
268 11, 20, ERANGE },
269 { "7", 7, 0, NULL,
270 7, 7, 0 },
271 { "6", 7, 0, NULL,
272 7, 7, ERANGE },
273 { "8", 7, 0, NULL,
274 7, 7, ERANGE },
275 { "7x", 7, 0, "x",
276 7, 7, ENOTSUP },
277 { "8x", 7, 0, "x",
278 7, 7, ERANGE },
279 { "Z", 11, 10, "Z",
280 11, 20, ECANCELED },
281 };
282
283 intmax_t rv;
284 char *end;
285 int e;
286 size_t i;
287
288 for (i = 0; i < __arraycount(t); i++) {
289
290 errno = 0;
291 rv = strtoi(t[i].str, &end, t[i].base, t[i].lo, t[i].hi, &e);
292
293 if (errno != 0)
294 atf_tc_fail("Range test %zd set errno=%d", i, errno);
295 check_errno(errno);
296
297 check(&t[i], rv, end, e);
298 }
299 }
300
301 ATF_TC(strtoi_range_trail);
302 ATF_TC_HEAD(strtoi_range_trail, tc)
303 {
304 atf_tc_set_md_var(tc, "descr", "Test ERANGE from strtoi(3) "
305 "with trailing characters");
306 }
307
308 ATF_TC_BODY(strtoi_range_trail, tc)
309 {
310 struct test t[] = {
311 { "11x", 9, 10, "x", 0, 9, ERANGE },
312 { " -3y", -2, 10, "y", -2, 1, ERANGE },
313 { "11111z", 9, 10, "z", 0, 9, ERANGE },
314 { "+0xAq", 9, 16, "q", 0, 9, ERANGE },
315 { "-0xBAr", 0, 16, "r", 0, 9, ERANGE },
316 };
317
318 intmax_t rv;
319 char *end;
320 int e;
321 size_t i;
322
323 for (i = 0; i < __arraycount(t); i++) {
324
325 errno = 0;
326 rv = strtoi(t[i].str, &end, t[i].base, t[i].lo, t[i].hi, &e);
327
328 check_errno(errno);
329
330 check(&t[i], rv, end, e);
331 }
332 }
333
334 ATF_TC(strtoi_signed);
335 ATF_TC_HEAD(strtoi_signed, tc)
336 {
337 atf_tc_set_md_var(tc, "descr", "A basic test of strtoi(3)");
338 }
339
340 ATF_TC_BODY(strtoi_signed, tc)
341 {
342 struct test t[] = {
343 { "1", 1, 0, NULL,
344 INTMAX_MIN, INTMAX_MAX, 0 },
345 { " 2", 2, 0, NULL,
346 INTMAX_MIN, INTMAX_MAX, 0 },
347 { " 3", 3, 0, NULL,
348 INTMAX_MIN, INTMAX_MAX, 0 },
349 { " -3", -3, 0, NULL,
350 INTMAX_MIN, INTMAX_MAX, 0 },
351 { "--1", 0, 0, "--1",
352 INTMAX_MIN, INTMAX_MAX, ECANCELED },
353 { "+-2", 0, 0, "+-2",
354 INTMAX_MIN, INTMAX_MAX, ECANCELED },
355 { "++3", 0, 0, "++3",
356 INTMAX_MIN, INTMAX_MAX, ECANCELED },
357 { "+9", 9, 0, NULL,
358 INTMAX_MIN, INTMAX_MAX, 0 },
359 { "+123", 123, 0, NULL,
360 INTMAX_MIN, INTMAX_MAX, 0 },
361 { "-1 3", -1, 0, " 3",
362 INTMAX_MIN, INTMAX_MAX, ENOTSUP },
363 { "-1.3", -1, 0, ".3",
364 INTMAX_MIN, INTMAX_MAX, ENOTSUP },
365 { "- 3", 0, 0, "- 3",
366 INTMAX_MIN, INTMAX_MAX, ECANCELED },
367 { "+33.", 33, 0, ".",
368 INTMAX_MIN, INTMAX_MAX, ENOTSUP },
369 { "30x0", 30, 0, "x0",
370 INTMAX_MIN, INTMAX_MAX, ENOTSUP },
371 };
372
373 intmax_t rv;
374 char *end;
375 int e;
376 size_t i;
377
378 for (i = 0; i < __arraycount(t); i++) {
379
380 errno = 0;
381 rv = strtoi(t[i].str, &end, t[i].base, t[i].lo, t[i].hi, &e);
382
383 check_errno(errno);
384
385 check(&t[i], rv, end, e);
386 }
387 }
388
389 ATF_TP_ADD_TCS(tp)
390 {
391
392 ATF_TP_ADD_TC(tp, strtoi_base);
393 ATF_TP_ADD_TC(tp, strtoi_case);
394 ATF_TP_ADD_TC(tp, strtoi_range);
395 ATF_TP_ADD_TC(tp, strtoi_range_trail);
396 ATF_TP_ADD_TC(tp, strtoi_signed);
397
398 return atf_no_error();
399 }
400