1 | /* Test scanf functions with C2X binary integers. |
2 | Copyright (C) 2022-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <inttypes.h> |
20 | #include <stdarg.h> |
21 | #include <stdio.h> |
22 | #include <wchar.h> |
23 | |
24 | #include <libc-diag.h> |
25 | #include <support/check.h> |
26 | #include <support/xstdio.h> |
27 | |
28 | #define CONCAT_(X, Y, Z) X ## Y ## Z |
29 | #define CONCAT(X, Y, Z) CONCAT_ (X, Y, Z) |
30 | #define FNX(FN1, FN2) CONCAT (FN1, FNW, FN2) |
31 | #ifndef STDX |
32 | # define STDX "" |
33 | #endif |
34 | |
35 | #define INFILE OBJPFX "/tst-" STDX "scanf-binary-" STD "-in" |
36 | |
37 | static int |
38 | wrap_vfscanf (FILE *fp, const CHAR *format, ...) |
39 | { |
40 | va_list ap; |
41 | va_start (ap, format); |
42 | int ret = FNX (vf, scanf) (s: fp, format: format, arg: ap); |
43 | va_end (ap); |
44 | return ret; |
45 | } |
46 | |
47 | static int |
48 | wrap_vscanf (const CHAR *format, ...) |
49 | { |
50 | va_list ap; |
51 | va_start (ap, format); |
52 | int ret = FNX (v, scanf) (format: format, arg: ap); |
53 | va_end (ap); |
54 | return ret; |
55 | } |
56 | |
57 | static int |
58 | wrap_vsscanf (const CHAR *s, const CHAR *format, ...) |
59 | { |
60 | va_list ap; |
61 | va_start (ap, format); |
62 | int ret = FNX (vs, scanf) (s: s, format: format, arg: ap); |
63 | va_end (ap); |
64 | return ret; |
65 | } |
66 | |
67 | static void |
68 | one_check (const CHAR *s, int expected, char expected_c) |
69 | { |
70 | int ret; |
71 | FILE *fp; |
72 | int ret_i; |
73 | long int ret_l; |
74 | long long int ret_ll; |
75 | char ret_c; |
76 | fp = xfopen (INFILE, "w" ); |
77 | ret = FNX (fput, s) (s, fp); |
78 | TEST_VERIFY_EXIT (0 <= ret); |
79 | xfclose (fp); |
80 | |
81 | if (!TEST_C2X) |
82 | { |
83 | expected = 0; |
84 | expected_c = s[0] == L_('-') ? s[2] : s[1]; |
85 | } |
86 | |
87 | ret = FNX (s, scanf) (s, L_("%i %c" ), &ret_i, &ret_c); |
88 | TEST_COMPARE (ret, 2); |
89 | TEST_COMPARE (ret_i, expected); |
90 | TEST_COMPARE (ret_c, expected_c); |
91 | fp = xfopen (INFILE, "r" ); |
92 | ret = FNX (f, scanf) (stream: fp, L_("%i %c" ), &ret_i, &ret_c); |
93 | TEST_COMPARE (ret, 2); |
94 | TEST_COMPARE (ret_i, expected); |
95 | TEST_COMPARE (ret_c, expected_c); |
96 | xfclose (fp); |
97 | fp = xfreopen (INFILE, "r" , stdin); |
98 | ret = FNX (, scanf) (L_("%i %c" ), &ret_i, &ret_c); |
99 | TEST_COMPARE (ret, 2); |
100 | TEST_COMPARE (ret_i, expected); |
101 | TEST_COMPARE (ret_c, expected_c); |
102 | ret = wrap_vsscanf (s, L_("%i %c" ), &ret_i, &ret_c); |
103 | TEST_COMPARE (ret, 2); |
104 | TEST_COMPARE (ret_i, expected); |
105 | TEST_COMPARE (ret_c, expected_c); |
106 | fp = xfopen (INFILE, "r" ); |
107 | ret = wrap_vfscanf (fp, L_("%i %c" ), &ret_i, &ret_c); |
108 | TEST_COMPARE (ret, 2); |
109 | TEST_COMPARE (ret_i, expected); |
110 | TEST_COMPARE (ret_c, expected_c); |
111 | xfclose (fp); |
112 | fp = xfreopen (INFILE, "r" , stdin); |
113 | ret = wrap_vscanf (L_("%i %c" ), &ret_i, &ret_c); |
114 | TEST_COMPARE (ret, 2); |
115 | TEST_COMPARE (ret_i, expected); |
116 | TEST_COMPARE (ret_c, expected_c); |
117 | |
118 | ret = FNX (s, scanf) (s, L_("%li %c" ), &ret_l, &ret_c); |
119 | TEST_COMPARE (ret, 2); |
120 | TEST_COMPARE (ret_l, expected); |
121 | TEST_COMPARE (ret_c, expected_c); |
122 | fp = xfopen (INFILE, "r" ); |
123 | ret = FNX (f, scanf) (stream: fp, L_("%li %c" ), &ret_l, &ret_c); |
124 | TEST_COMPARE (ret, 2); |
125 | TEST_COMPARE (ret_l, expected); |
126 | TEST_COMPARE (ret_c, expected_c); |
127 | xfclose (fp); |
128 | fp = xfreopen (INFILE, "r" , stdin); |
129 | ret = FNX (, scanf) (L_("%li %c" ), &ret_l, &ret_c); |
130 | TEST_COMPARE (ret, 2); |
131 | TEST_COMPARE (ret_l, expected); |
132 | TEST_COMPARE (ret_c, expected_c); |
133 | ret = wrap_vsscanf (s, L_("%li %c" ), &ret_l, &ret_c); |
134 | TEST_COMPARE (ret, 2); |
135 | TEST_COMPARE (ret_l, expected); |
136 | TEST_COMPARE (ret_c, expected_c); |
137 | fp = xfopen (INFILE, "r" ); |
138 | ret = wrap_vfscanf (fp, L_("%li %c" ), &ret_l, &ret_c); |
139 | TEST_COMPARE (ret, 2); |
140 | TEST_COMPARE (ret_l, expected); |
141 | TEST_COMPARE (ret_c, expected_c); |
142 | xfclose (fp); |
143 | fp = xfreopen (INFILE, "r" , stdin); |
144 | ret = wrap_vscanf (L_("%li %c" ), &ret_l, &ret_c); |
145 | TEST_COMPARE (ret, 2); |
146 | TEST_COMPARE (ret_l, expected); |
147 | TEST_COMPARE (ret_c, expected_c); |
148 | |
149 | ret = FNX (s, scanf) (s, L_("%lli %c" ), &ret_ll, &ret_c); |
150 | TEST_COMPARE (ret, 2); |
151 | TEST_COMPARE (ret_ll, expected); |
152 | TEST_COMPARE (ret_c, expected_c); |
153 | fp = xfopen (INFILE, "r" ); |
154 | ret = FNX (f, scanf) (stream: fp, L_("%lli %c" ), &ret_ll, &ret_c); |
155 | TEST_COMPARE (ret, 2); |
156 | TEST_COMPARE (ret_ll, expected); |
157 | TEST_COMPARE (ret_c, expected_c); |
158 | xfclose (fp); |
159 | fp = xfreopen (INFILE, "r" , stdin); |
160 | ret = FNX (, scanf) (L_("%lli %c" ), &ret_ll, &ret_c); |
161 | TEST_COMPARE (ret, 2); |
162 | TEST_COMPARE (ret_ll, expected); |
163 | TEST_COMPARE (ret_c, expected_c); |
164 | ret = wrap_vsscanf (s, L_("%lli %c" ), &ret_ll, &ret_c); |
165 | TEST_COMPARE (ret, 2); |
166 | TEST_COMPARE (ret_ll, expected); |
167 | TEST_COMPARE (ret_c, expected_c); |
168 | fp = xfopen (INFILE, "r" ); |
169 | ret = wrap_vfscanf (fp, L_("%lli %c" ), &ret_ll, &ret_c); |
170 | TEST_COMPARE (ret, 2); |
171 | TEST_COMPARE (ret_ll, expected); |
172 | TEST_COMPARE (ret_c, expected_c); |
173 | xfclose (fp); |
174 | fp = xfreopen (INFILE, "r" , stdin); |
175 | ret = wrap_vscanf (L_("%lli %c" ), &ret_ll, &ret_c); |
176 | TEST_COMPARE (ret, 2); |
177 | TEST_COMPARE (ret_ll, expected); |
178 | TEST_COMPARE (ret_c, expected_c); |
179 | } |
180 | |
181 | /* GCC does not know the %b format before GCC 12. */ |
182 | DIAG_PUSH_NEEDS_COMMENT; |
183 | #if !__GNUC_PREREQ (12, 0) |
184 | DIAG_IGNORE_NEEDS_COMMENT (11, "-Wformat" ); |
185 | DIAG_IGNORE_NEEDS_COMMENT (11, "-Wformat-extra-args" ); |
186 | #endif |
187 | |
188 | static void |
189 | one_check_b (const CHAR *s, int expected, char expected_c) |
190 | { |
191 | int ret; |
192 | FILE *fp; |
193 | unsigned int ret_i; |
194 | unsigned long int ret_l; |
195 | unsigned long long int ret_ll; |
196 | char ret_c; |
197 | fp = xfopen (INFILE, "w" ); |
198 | ret = FNX (fput, s) (s, fp); |
199 | TEST_VERIFY_EXIT (0 <= ret); |
200 | xfclose (fp); |
201 | |
202 | ret = FNX (s, scanf) (s, L_("%b %c" ), &ret_i, &ret_c); |
203 | TEST_COMPARE (ret, 2); |
204 | TEST_COMPARE (ret_i, (unsigned int) expected); |
205 | TEST_COMPARE (ret_c, expected_c); |
206 | fp = xfopen (INFILE, "r" ); |
207 | ret = FNX (f, scanf) (stream: fp, L_("%b %c" ), &ret_i, &ret_c); |
208 | TEST_COMPARE (ret, 2); |
209 | TEST_COMPARE (ret_i, (unsigned int) expected); |
210 | TEST_COMPARE (ret_c, expected_c); |
211 | xfclose (fp); |
212 | fp = xfreopen (INFILE, "r" , stdin); |
213 | ret = FNX (, scanf) (L_("%b %c" ), &ret_i, &ret_c); |
214 | TEST_COMPARE (ret, 2); |
215 | TEST_COMPARE (ret_i, (unsigned int) expected); |
216 | TEST_COMPARE (ret_c, expected_c); |
217 | ret = wrap_vsscanf (s, L_("%b %c" ), &ret_i, &ret_c); |
218 | TEST_COMPARE (ret, 2); |
219 | TEST_COMPARE (ret_i, (unsigned int) expected); |
220 | TEST_COMPARE (ret_c, expected_c); |
221 | fp = xfopen (INFILE, "r" ); |
222 | ret = wrap_vfscanf (fp, L_("%b %c" ), &ret_i, &ret_c); |
223 | TEST_COMPARE (ret, 2); |
224 | TEST_COMPARE (ret_i, (unsigned int) expected); |
225 | TEST_COMPARE (ret_c, expected_c); |
226 | xfclose (fp); |
227 | fp = xfreopen (INFILE, "r" , stdin); |
228 | ret = wrap_vscanf (L_("%b %c" ), &ret_i, &ret_c); |
229 | TEST_COMPARE (ret, 2); |
230 | TEST_COMPARE (ret_i, (unsigned int) expected); |
231 | TEST_COMPARE (ret_c, expected_c); |
232 | |
233 | ret = FNX (s, scanf) (s, L_("%lb %c" ), &ret_l, &ret_c); |
234 | TEST_COMPARE (ret, 2); |
235 | TEST_COMPARE (ret_l, (unsigned long int) expected); |
236 | TEST_COMPARE (ret_c, expected_c); |
237 | fp = xfopen (INFILE, "r" ); |
238 | ret = FNX (f, scanf) (stream: fp, L_("%lb %c" ), &ret_l, &ret_c); |
239 | TEST_COMPARE (ret, 2); |
240 | TEST_COMPARE (ret_l, (unsigned long int) expected); |
241 | TEST_COMPARE (ret_c, expected_c); |
242 | xfclose (fp); |
243 | fp = xfreopen (INFILE, "r" , stdin); |
244 | ret = FNX (, scanf) (L_("%lb %c" ), &ret_l, &ret_c); |
245 | TEST_COMPARE (ret, 2); |
246 | TEST_COMPARE (ret_l, (unsigned long int) expected); |
247 | TEST_COMPARE (ret_c, expected_c); |
248 | ret = wrap_vsscanf (s, L_("%lb %c" ), &ret_l, &ret_c); |
249 | TEST_COMPARE (ret, 2); |
250 | TEST_COMPARE (ret_l, (unsigned long int) expected); |
251 | TEST_COMPARE (ret_c, expected_c); |
252 | fp = xfopen (INFILE, "r" ); |
253 | ret = wrap_vfscanf (fp, L_("%lb %c" ), &ret_l, &ret_c); |
254 | TEST_COMPARE (ret, 2); |
255 | TEST_COMPARE (ret_l, (unsigned long int) expected); |
256 | TEST_COMPARE (ret_c, expected_c); |
257 | xfclose (fp); |
258 | fp = xfreopen (INFILE, "r" , stdin); |
259 | ret = wrap_vscanf (L_("%lb %c" ), &ret_l, &ret_c); |
260 | TEST_COMPARE (ret, 2); |
261 | TEST_COMPARE (ret_l, (unsigned long int) expected); |
262 | TEST_COMPARE (ret_c, expected_c); |
263 | |
264 | ret = FNX (s, scanf) (s, L_("%llb %c" ), &ret_ll, &ret_c); |
265 | TEST_COMPARE (ret, 2); |
266 | TEST_COMPARE (ret_ll, (unsigned long long int) expected); |
267 | TEST_COMPARE (ret_c, expected_c); |
268 | fp = xfopen (INFILE, "r" ); |
269 | ret = FNX (f, scanf) (stream: fp, L_("%llb %c" ), &ret_ll, &ret_c); |
270 | TEST_COMPARE (ret, 2); |
271 | TEST_COMPARE (ret_ll, (unsigned long long int) expected); |
272 | TEST_COMPARE (ret_c, expected_c); |
273 | xfclose (fp); |
274 | fp = xfreopen (INFILE, "r" , stdin); |
275 | ret = FNX (, scanf) (L_("%llb %c" ), &ret_ll, &ret_c); |
276 | TEST_COMPARE (ret, 2); |
277 | TEST_COMPARE (ret_ll, (unsigned long long int) expected); |
278 | TEST_COMPARE (ret_c, expected_c); |
279 | ret = wrap_vsscanf (s, L_("%llb %c" ), &ret_ll, &ret_c); |
280 | TEST_COMPARE (ret, 2); |
281 | TEST_COMPARE (ret_ll, (unsigned long long int) expected); |
282 | TEST_COMPARE (ret_c, expected_c); |
283 | fp = xfopen (INFILE, "r" ); |
284 | ret = wrap_vfscanf (fp, L_("%llb %c" ), &ret_ll, &ret_c); |
285 | TEST_COMPARE (ret, 2); |
286 | TEST_COMPARE (ret_ll, (unsigned long long int) expected); |
287 | TEST_COMPARE (ret_c, expected_c); |
288 | xfclose (fp); |
289 | fp = xfreopen (INFILE, "r" , stdin); |
290 | ret = wrap_vscanf (L_("%llb %c" ), &ret_ll, &ret_c); |
291 | TEST_COMPARE (ret, 2); |
292 | TEST_COMPARE (ret_ll, (unsigned long long int) expected); |
293 | TEST_COMPARE (ret_c, expected_c); |
294 | } |
295 | |
296 | #define CHECK_SCNB(TYPE, MACRO, S, EXPECTED, EXPECTED_C) \ |
297 | do \ |
298 | { \ |
299 | int ret; \ |
300 | FILE *fp; \ |
301 | TYPE ret_t; \ |
302 | char ret_c; \ |
303 | fp = xfopen (INFILE, "w"); \ |
304 | ret = FNX (fput, s) (S, fp); \ |
305 | TEST_VERIFY_EXIT (0 <= ret); \ |
306 | xfclose (fp); \ |
307 | ret = FNX (s, scanf) (S, L_("%") MACRO " %c", &ret_t, &ret_c); \ |
308 | TEST_COMPARE (ret, 2); \ |
309 | TEST_COMPARE (ret_t, EXPECTED); \ |
310 | TEST_COMPARE (ret_c, EXPECTED_C); \ |
311 | fp = xfopen (INFILE, "r"); \ |
312 | ret = FNX (f, scanf) (fp, L_("%") MACRO " %c", &ret_t, &ret_c); \ |
313 | TEST_COMPARE (ret, 2); \ |
314 | TEST_COMPARE (ret_t, EXPECTED); \ |
315 | TEST_COMPARE (ret_c, EXPECTED_C); \ |
316 | xfclose (fp); \ |
317 | fp = xfreopen (INFILE, "r", stdin); \ |
318 | ret = FNX (, scanf) (L_("%") MACRO " %c", &ret_t, &ret_c); \ |
319 | TEST_COMPARE (ret, 2); \ |
320 | TEST_COMPARE (ret_t, EXPECTED); \ |
321 | TEST_COMPARE (ret_c, EXPECTED_C); \ |
322 | ret = wrap_vsscanf (S, L_("%") MACRO " %c", &ret_t, &ret_c); \ |
323 | TEST_COMPARE (ret, 2); \ |
324 | TEST_COMPARE (ret_t, EXPECTED); \ |
325 | TEST_COMPARE (ret_c, EXPECTED_C); \ |
326 | fp = xfopen (INFILE, "r"); \ |
327 | ret = wrap_vfscanf (fp, L_("%") MACRO " %c", &ret_t, &ret_c); \ |
328 | TEST_COMPARE (ret, 2); \ |
329 | TEST_COMPARE (ret_t, EXPECTED); \ |
330 | TEST_COMPARE (ret_c, EXPECTED_C); \ |
331 | xfclose (fp); \ |
332 | fp = xfreopen (INFILE, "r", stdin); \ |
333 | ret = wrap_vscanf (L_("%") MACRO " %c", &ret_t, &ret_c); \ |
334 | TEST_COMPARE (ret, 2); \ |
335 | TEST_COMPARE (ret_t, EXPECTED); \ |
336 | TEST_COMPARE (ret_c, EXPECTED_C); \ |
337 | } \ |
338 | while (0) |
339 | |
340 | static void |
341 | one_check_scnb (const CHAR *s, int expected, char expected_c) |
342 | { |
343 | #if TEST_C2X || defined _GNU_SOURCE |
344 | CHECK_SCNB (uint8_t, SCNb8, s, (uint8_t) expected, expected_c); |
345 | CHECK_SCNB (uint16_t, SCNb16, s, (uint16_t) expected, expected_c); |
346 | CHECK_SCNB (uint32_t, SCNb32, s, (uint32_t) expected, expected_c); |
347 | CHECK_SCNB (uint64_t, SCNb64, s, (uint64_t) expected, expected_c); |
348 | CHECK_SCNB (uint_least8_t, SCNbLEAST8, s, (uint_least8_t) expected, |
349 | expected_c); |
350 | CHECK_SCNB (uint_least16_t, SCNbLEAST16, s, (uint_least16_t) expected, |
351 | expected_c); |
352 | CHECK_SCNB (uint_least32_t, SCNbLEAST32, s, (uint_least32_t) expected, |
353 | expected_c); |
354 | CHECK_SCNB (uint_least64_t, SCNbLEAST64, s, (uint_least64_t) expected, |
355 | expected_c); |
356 | CHECK_SCNB (uint_fast8_t, SCNbFAST8, s, (uint_fast8_t) expected, expected_c); |
357 | CHECK_SCNB (uint_fast16_t, SCNbFAST16, s, (uint_fast16_t) expected, |
358 | expected_c); |
359 | CHECK_SCNB (uint_fast32_t, SCNbFAST32, s, (uint_fast32_t) expected, |
360 | expected_c); |
361 | CHECK_SCNB (uint_fast64_t, SCNbFAST64, s, (uint_fast64_t) expected, |
362 | expected_c); |
363 | CHECK_SCNB (uintmax_t, SCNbMAX, s, (uintmax_t) expected, expected_c); |
364 | CHECK_SCNB (uintptr_t, SCNbPTR, s, (uintptr_t) expected, expected_c); |
365 | #endif |
366 | } |
367 | |
368 | DIAG_POP_NEEDS_COMMENT; |
369 | |
370 | static int |
371 | do_test (void) |
372 | { |
373 | one_check (L_("0b101 x" ), expected: 5, expected_c: 'x'); |
374 | one_check (L_("0B101 x" ), expected: 5, expected_c: 'x'); |
375 | one_check (L_("-0b11111 y" ), expected: -31, expected_c: 'y'); |
376 | one_check (L_("-0B11111 y" ), expected: -31, expected_c: 'y'); |
377 | one_check_b (L_("0b101 x" ), expected: 5, expected_c: 'x'); |
378 | one_check_b (L_("0B101 x" ), expected: 5, expected_c: 'x'); |
379 | one_check_b (L_("-0b11111 y" ), expected: -31, expected_c: 'y'); |
380 | one_check_b (L_("-0B11111 y" ), expected: -31, expected_c: 'y'); |
381 | one_check_b (L_("101 x" ), expected: 5, expected_c: 'x'); |
382 | one_check_b (L_("-11111 y" ), expected: -31, expected_c: 'y'); |
383 | one_check_scnb (L_("0b101 x" ), expected: 5, expected_c: 'x'); |
384 | one_check_scnb (L_("0B101 x" ), expected: 5, expected_c: 'x'); |
385 | one_check_scnb (L_("-0b11111 y" ), expected: -31, expected_c: 'y'); |
386 | one_check_scnb (L_("-0B11111 y" ), expected: -31, expected_c: 'y'); |
387 | one_check_scnb (L_("101 x" ), expected: 5, expected_c: 'x'); |
388 | one_check_scnb (L_("-11111 y" ), expected: -31, expected_c: 'y'); |
389 | return 0; |
390 | } |
391 | |
392 | #include <support/test-driver.c> |
393 | |