1/*-
2 * Copyright (c) 2023 Dag-Erling Sm��rgrav
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <limits.h>
8#include <locale.h>
9#include <stdint.h>
10#include <stdio.h>
11
12#include <atf-c.h>
13
14static const struct sscanf_test_case {
15	char input[8];
16	struct {
17		int ret, val, len;
18	} b, o, d, x, i;
19} sscanf_test_cases[] = {
20//	input		binary		octal		decimal		hexadecimal	automatic
21	// all digits
22	{ "0",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 }, },
23	{ "1",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 }, },
24	{ "2",		{ 0,   0, 0 },	{ 1,   2, 1 },	{ 1,   2, 1 },	{ 1,   2, 1 },	{ 1,   2, 1 }, },
25	{ "3",		{ 0,   0, 0 },	{ 1,   3, 1 },	{ 1,   3, 1 },	{ 1,   3, 1 },	{ 1,   3, 1 }, },
26	{ "4",		{ 0,   0, 0 },	{ 1,   4, 1 },	{ 1,   4, 1 },	{ 1,   4, 1 },	{ 1,   4, 1 }, },
27	{ "5",		{ 0,   0, 0 },	{ 1,   5, 1 },	{ 1,   5, 1 },	{ 1,   5, 1 },	{ 1,   5, 1 }, },
28	{ "6",		{ 0,   0, 0 },	{ 1,   6, 1 },	{ 1,   6, 1 },	{ 1,   6, 1 },	{ 1,   6, 1 }, },
29	{ "7",		{ 0,   0, 0 },	{ 1,   7, 1 },	{ 1,   7, 1 },	{ 1,   7, 1 },	{ 1,   7, 1 }, },
30	{ "8",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,   8, 1 },	{ 1,   8, 1 },	{ 1,   8, 1 }, },
31	{ "9",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,   9, 1 },	{ 1,   9, 1 },	{ 1,   9, 1 }, },
32	{ "A",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  10, 1 },	{ 0,   0, 0 }, },
33	{ "B",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  11, 1 },	{ 0,   0, 0 }, },
34	{ "C",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  12, 1 },	{ 0,   0, 0 }, },
35	{ "D",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  13, 1 },	{ 0,   0, 0 }, },
36	{ "E",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  14, 1 },	{ 0,   0, 0 }, },
37	{ "F",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  15, 1 },	{ 0,   0, 0 }, },
38	{ "X",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 }, },
39	{ "a",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  10, 1 },	{ 0,   0, 0 }, },
40	{ "b",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  11, 1 },	{ 0,   0, 0 }, },
41	{ "c",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  12, 1 },	{ 0,   0, 0 }, },
42	{ "d",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  13, 1 },	{ 0,   0, 0 }, },
43	{ "e",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  14, 1 },	{ 0,   0, 0 }, },
44	{ "f",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 1,  15, 1 },	{ 0,   0, 0 }, },
45	{ "x",		{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 },	{ 0,   0, 0 }, },
46	// all digits with leading zero
47	{ "00",		{ 1,   0, 2 },	{ 1,   0, 2 },	{ 1,   0, 2 },	{ 1,   0, 2 },	{ 1,   0, 2 }, },
48	{ "01",		{ 1,   1, 2 },	{ 1,   1, 2 },	{ 1,   1, 2 },	{ 1,   1, 2 },	{ 1,   1, 2 }, },
49	{ "02",		{ 1,   0, 1 },	{ 1,   2, 2 },	{ 1,   2, 2 },	{ 1,   2, 2 },	{ 1,   2, 2 }, },
50	{ "03",		{ 1,   0, 1 },	{ 1,   3, 2 },	{ 1,   3, 2 },	{ 1,   3, 2 },	{ 1,   3, 2 }, },
51	{ "04",		{ 1,   0, 1 },	{ 1,   4, 2 },	{ 1,   4, 2 },	{ 1,   4, 2 },	{ 1,   4, 2 }, },
52	{ "05",		{ 1,   0, 1 },	{ 1,   5, 2 },	{ 1,   5, 2 },	{ 1,   5, 2 },	{ 1,   5, 2 }, },
53	{ "06",		{ 1,   0, 1 },	{ 1,   6, 2 },	{ 1,   6, 2 },	{ 1,   6, 2 },	{ 1,   6, 2 }, },
54	{ "07",		{ 1,   0, 1 },	{ 1,   7, 2 },	{ 1,   7, 2 },	{ 1,   7, 2 },	{ 1,   7, 2 }, },
55	{ "08",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   8, 2 },	{ 1,   8, 2 },	{ 1,   0, 1 }, },
56	{ "09",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   9, 2 },	{ 1,   9, 2 },	{ 1,   0, 1 }, },
57	{ "0A",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  10, 2 },	{ 1,   0, 1 }, },
58	{ "0B",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  11, 2 },	{ 1,   0, 1 }, },
59	{ "0C",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  12, 2 },	{ 1,   0, 1 }, },
60	{ "0D",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  13, 2 },	{ 1,   0, 1 }, },
61	{ "0E",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  14, 2 },	{ 1,   0, 1 }, },
62	{ "0F",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  15, 2 },	{ 1,   0, 1 }, },
63	{ "0X",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 }, },
64	{ "0a",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  10, 2 },	{ 1,   0, 1 }, },
65	{ "0b",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  11, 2 },	{ 1,   0, 1 }, },
66	{ "0c",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  12, 2 },	{ 1,   0, 1 }, },
67	{ "0d",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  13, 2 },	{ 1,   0, 1 }, },
68	{ "0e",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  14, 2 },	{ 1,   0, 1 }, },
69	{ "0f",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  15, 2 },	{ 1,   0, 1 }, },
70	{ "0x",		{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 }, },
71	// all digits with leading one
72	{ "10",		{ 1,   2, 2 },	{ 1,   8, 2 },	{ 1,  10, 2 },	{ 1,  16, 2 },	{ 1,  10, 2 }, },
73	{ "11",		{ 1,   3, 2 },	{ 1,   9, 2 },	{ 1,  11, 2 },	{ 1,  17, 2 },	{ 1,  11, 2 }, },
74	{ "12",		{ 1,   1, 1 },	{ 1,  10, 2 },	{ 1,  12, 2 },	{ 1,  18, 2 },	{ 1,  12, 2 }, },
75	{ "13",		{ 1,   1, 1 },	{ 1,  11, 2 },	{ 1,  13, 2 },	{ 1,  19, 2 },	{ 1,  13, 2 }, },
76	{ "14",		{ 1,   1, 1 },	{ 1,  12, 2 },	{ 1,  14, 2 },	{ 1,  20, 2 },	{ 1,  14, 2 }, },
77	{ "15",		{ 1,   1, 1 },	{ 1,  13, 2 },	{ 1,  15, 2 },	{ 1,  21, 2 },	{ 1,  15, 2 }, },
78	{ "16",		{ 1,   1, 1 },	{ 1,  14, 2 },	{ 1,  16, 2 },	{ 1,  22, 2 },	{ 1,  16, 2 }, },
79	{ "17",		{ 1,   1, 1 },	{ 1,  15, 2 },	{ 1,  17, 2 },	{ 1,  23, 2 },	{ 1,  17, 2 }, },
80	{ "18",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  18, 2 },	{ 1,  24, 2 },	{ 1,  18, 2 }, },
81	{ "19",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  19, 2 },	{ 1,  25, 2 },	{ 1,  19, 2 }, },
82	{ "1A",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  26, 2 },	{ 1,   1, 1 }, },
83	{ "1B",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  27, 2 },	{ 1,   1, 1 }, },
84	{ "1C",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  28, 2 },	{ 1,   1, 1 }, },
85	{ "1D",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  29, 2 },	{ 1,   1, 1 }, },
86	{ "1E",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  30, 2 },	{ 1,   1, 1 }, },
87	{ "1F",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  31, 2 },	{ 1,   1, 1 }, },
88	{ "1X",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 }, },
89	{ "1a",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  26, 2 },	{ 1,   1, 1 }, },
90	{ "1b",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  27, 2 },	{ 1,   1, 1 }, },
91	{ "1c",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  28, 2 },	{ 1,   1, 1 }, },
92	{ "1d",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  29, 2 },	{ 1,   1, 1 }, },
93	{ "1e",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  30, 2 },	{ 1,   1, 1 }, },
94	{ "1f",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,  31, 2 },	{ 1,   1, 1 }, },
95	{ "1x",		{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 },	{ 1,   1, 1 }, },
96	// all digits with leading binary prefix
97	{ "0b0",	{ 1,   0, 3 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 176, 3 },	{ 1,   0, 3 }, },
98	{ "0b1",	{ 1,   1, 3 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 177, 3 },	{ 1,   1, 3 }, },
99	{ "0b2",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 178, 3 },	{ 1,   0, 1 }, },
100	{ "0b3",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 179, 3 },	{ 1,   0, 1 }, },
101	{ "0b4",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 180, 3 },	{ 1,   0, 1 }, },
102	{ "0b5",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 181, 3 },	{ 1,   0, 1 }, },
103	{ "0b6",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 182, 3 },	{ 1,   0, 1 }, },
104	{ "0b7",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 183, 3 },	{ 1,   0, 1 }, },
105	{ "0b8",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 184, 3 },	{ 1,   0, 1 }, },
106	{ "0b9",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 185, 3 },	{ 1,   0, 1 }, },
107	{ "0bA",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 186, 3 },	{ 1,   0, 1 }, },
108	{ "0bB",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 187, 3 },	{ 1,   0, 1 }, },
109	{ "0bC",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 188, 3 },	{ 1,   0, 1 }, },
110	{ "0bD",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 189, 3 },	{ 1,   0, 1 }, },
111	{ "0bE",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 190, 3 },	{ 1,   0, 1 }, },
112	{ "0bF",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 191, 3 },	{ 1,   0, 1 }, },
113	{ "0bX",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  11, 2 },	{ 1,   0, 1 }, },
114	{ "0ba",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 186, 3 },	{ 1,   0, 1 }, },
115	{ "0bb",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 187, 3 },	{ 1,   0, 1 }, },
116	{ "0bc",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 188, 3 },	{ 1,   0, 1 }, },
117	{ "0bd",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 189, 3 },	{ 1,   0, 1 }, },
118	{ "0be",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 190, 3 },	{ 1,   0, 1 }, },
119	{ "0bf",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1, 191, 3 },	{ 1,   0, 1 }, },
120	{ "0bx",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  11, 2 },	{ 1,   0, 1 }, },
121	// all digits with leading hexadecimal prefix
122	{ "0x0",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 3 },	{ 1,   0, 3 }, },
123	{ "0x1",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   1, 3 },	{ 1,   1, 3 }, },
124	{ "0x2",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   2, 3 },	{ 1,   2, 3 }, },
125	{ "0x3",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   3, 3 },	{ 1,   3, 3 }, },
126	{ "0x4",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   4, 3 },	{ 1,   4, 3 }, },
127	{ "0x5",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   5, 3 },	{ 1,   5, 3 }, },
128	{ "0x6",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   6, 3 },	{ 1,   6, 3 }, },
129	{ "0x7",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   7, 3 },	{ 1,   7, 3 }, },
130	{ "0x8",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   8, 3 },	{ 1,   8, 3 }, },
131	{ "0x9",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   9, 3 },	{ 1,   9, 3 }, },
132	{ "0xA",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  10, 3 },	{ 1,  10, 3 }, },
133	{ "0xB",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  11, 3 },	{ 1,  11, 3 }, },
134	{ "0xC",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  12, 3 },	{ 1,  12, 3 }, },
135	{ "0xD",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  13, 3 },	{ 1,  13, 3 }, },
136	{ "0xE",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  14, 3 },	{ 1,  14, 3 }, },
137	{ "0xF",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  15, 3 },	{ 1,  15, 3 }, },
138	{ "0xX",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 }, },
139	{ "0xa",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  10, 3 },	{ 1,  10, 3 }, },
140	{ "0xb",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  11, 3 },	{ 1,  11, 3 }, },
141	{ "0xc",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  12, 3 },	{ 1,  12, 3 }, },
142	{ "0xd",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  13, 3 },	{ 1,  13, 3 }, },
143	{ "0xe",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  14, 3 },	{ 1,  14, 3 }, },
144	{ "0xf",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,  15, 3 },	{ 1,  15, 3 }, },
145	{ "0xX",	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 },	{ 1,   0, 1 }, },
146	// terminator
147	{ "" }
148};
149
150#define SSCANF_TEST(string, format, expret, expval, explen)		\
151	do {								\
152		int ret = 0, val = 0, len = 0;				\
153		ret = sscanf(string, format "%n", &val, &len);		\
154		ATF_CHECK_EQ(expret, ret);				\
155		if (expret && ret) {					\
156			ATF_CHECK_EQ(expval, val);			\
157			ATF_CHECK_EQ(explen, len);			\
158		}							\
159	} while (0)
160
161ATF_TC_WITHOUT_HEAD(sscanf_b);
162ATF_TC_BODY(sscanf_b, tc)
163{
164	const struct sscanf_test_case *stc;
165	char input[16];
166
167	for (stc = sscanf_test_cases; *stc->input; stc++) {
168		strcpy(input + 1, stc->input);
169		SSCANF_TEST(input + 1, "%b", stc->b.ret, stc->b.val, stc->b.len);
170		input[0] = '+';
171		SSCANF_TEST(input, "%b", stc->b.ret, stc->b.val, stc->b.len ? stc->b.len + 1 : 0);
172		input[0] = '-';
173		SSCANF_TEST(input, "%b", stc->b.ret, -stc->b.val, stc->b.len ? stc->b.len + 1 : 0);
174	}
175}
176
177ATF_TC_WITHOUT_HEAD(sscanf_o);
178ATF_TC_BODY(sscanf_o, tc)
179{
180	const struct sscanf_test_case *stc;
181	char input[16];
182
183	for (stc = sscanf_test_cases; *stc->input; stc++) {
184		strcpy(input + 1, stc->input);
185		SSCANF_TEST(input + 1, "%o", stc->o.ret, stc->o.val, stc->o.len);
186		input[0] = '+';
187		SSCANF_TEST(input, "%o", stc->o.ret, stc->o.val, stc->o.len ? stc->o.len + 1 : 0);
188		input[0] = '-';
189		SSCANF_TEST(input, "%o", stc->o.ret, -stc->o.val, stc->o.len ? stc->o.len + 1 : 0);
190	}
191}
192
193ATF_TC_WITHOUT_HEAD(sscanf_d);
194ATF_TC_BODY(sscanf_d, tc)
195{
196	const struct sscanf_test_case *stc;
197	char input[16];
198
199	for (stc = sscanf_test_cases; *stc->input; stc++) {
200		strcpy(input + 1, stc->input);
201		SSCANF_TEST(input + 1, "%d", stc->d.ret, stc->d.val, stc->d.len);
202		input[0] = '+';
203		SSCANF_TEST(input, "%d", stc->d.ret, stc->d.val, stc->d.len ? stc->d.len + 1 : 0);
204		input[0] = '-';
205		SSCANF_TEST(input, "%d", stc->d.ret, -stc->d.val, stc->d.len ? stc->d.len + 1 : 0);
206	}
207}
208
209ATF_TC_WITHOUT_HEAD(sscanf_x);
210ATF_TC_BODY(sscanf_x, tc)
211{
212	const struct sscanf_test_case *stc;
213	char input[16];
214
215	for (stc = sscanf_test_cases; *stc->input; stc++) {
216		strcpy(input + 1, stc->input);
217		SSCANF_TEST(input + 1, "%x", stc->x.ret, stc->x.val, stc->x.len);
218		input[0] = '+';
219		SSCANF_TEST(input, "%x", stc->x.ret, stc->x.val, stc->x.len ? stc->x.len + 1 : 0);
220		input[0] = '-';
221		SSCANF_TEST(input, "%x", stc->x.ret, -stc->x.val, stc->x.len ? stc->x.len + 1 : 0);
222	}
223}
224
225ATF_TC_WITHOUT_HEAD(sscanf_i);
226ATF_TC_BODY(sscanf_i, tc)
227{
228	const struct sscanf_test_case *stc;
229	char input[16];
230
231	for (stc = sscanf_test_cases; *stc->input; stc++) {
232		strcpy(input + 1, stc->input);
233		SSCANF_TEST(input + 1, "%i", stc->i.ret, stc->i.val, stc->i.len);
234		input[0] = '+';
235		SSCANF_TEST(input, "%i", stc->i.ret, stc->i.val, stc->i.len ? stc->i.len + 1 : 0);
236		input[0] = '-';
237		SSCANF_TEST(input, "%i", stc->i.ret, -stc->i.val, stc->i.len ? stc->i.len + 1 : 0);
238	}
239}
240
241ATF_TC_WITHOUT_HEAD(sscanf_wN);
242ATF_TC_BODY(sscanf_wN, tc)
243{
244	const char x00[] = "0x00";
245	const char x7f[] = "0x7fffffffffffffff";
246	const char xff[] = "0xffffffffffffffff";
247
248#define SSCANF_WN_TEST(N, imin, umax)					\
249	do {								\
250		int##N##_t i;						\
251		uint##N##_t u;						\
252		ATF_CHECK_EQ(1, sscanf(x00, "%w" #N "i", &i));		\
253		ATF_CHECK_EQ(0, i);					\
254		ATF_CHECK_EQ(1, sscanf(x7f, "%w" #N "i", &i));		\
255		ATF_CHECK_EQ(imin, i);					\
256		ATF_CHECK_EQ(1, sscanf(x00, "%w" #N "x", &u));		\
257		ATF_CHECK_EQ(0, u);					\
258		ATF_CHECK_EQ(1, sscanf(xff, "%w" #N "x", &u));		\
259		ATF_CHECK_EQ(umax, u);					\
260	} while (0)
261	SSCANF_WN_TEST(8, -1, UCHAR_MAX);
262	SSCANF_WN_TEST(16, -1, USHRT_MAX);
263	SSCANF_WN_TEST(32, -1, UINT_MAX);
264	SSCANF_WN_TEST(64, LLONG_MAX, ULLONG_MAX);
265#undef SSCANF_WN_TEST
266
267	ATF_CHECK_EQ(0, sscanf(x00, "%wi", (int *)NULL));
268	ATF_CHECK_EQ(0, sscanf(x00, "%w1i", (int *)NULL));
269	ATF_CHECK_EQ(0, sscanf(x00, "%w128i", (int *)NULL));
270}
271
272ATF_TC_WITHOUT_HEAD(sscanf_wfN);
273ATF_TC_BODY(sscanf_wfN, tc)
274{
275	const char x00[] = "0x00";
276	const char x7f[] = "0x7fffffffffffffff";
277	const char xff[] = "0xffffffffffffffff";
278
279#define SSCANF_WFN_TEST(N, imin, umax)					\
280	do {								\
281		int_fast##N##_t i;					\
282		uint_fast##N##_t u;					\
283		ATF_CHECK_EQ(1, sscanf(x00, "%wf" #N "i", &i));		\
284		ATF_CHECK_EQ(0, i);					\
285		ATF_CHECK_EQ(1, sscanf(x7f, "%wf" #N "i", &i));		\
286		ATF_CHECK_EQ(imin, i);					\
287		ATF_CHECK_EQ(1, sscanf(x00, "%wf" #N "x", &u));		\
288		ATF_CHECK_EQ(0, u);					\
289		ATF_CHECK_EQ(1, sscanf(xff, "%wf" #N "x", &u));		\
290		ATF_CHECK_EQ(umax, u);					\
291	} while (0)
292	SSCANF_WFN_TEST(8, -1, UINT_MAX);
293	SSCANF_WFN_TEST(16, -1, UINT_MAX);
294	SSCANF_WFN_TEST(32, -1, UINT_MAX);
295	SSCANF_WFN_TEST(64, LLONG_MAX, ULLONG_MAX);
296#undef SSCANF_WFN_TEST
297
298	ATF_CHECK_EQ(0, sscanf(x00, "%wfi", (int *)NULL));
299	ATF_CHECK_EQ(0, sscanf(x00, "%wf1i", (int *)NULL));
300	ATF_CHECK_EQ(0, sscanf(x00, "%wf128i", (int *)NULL));
301}
302
303/*
304 * Test termination cases: non-numeric character, fixed width, EOF
305 */
306ATF_TC_WITHOUT_HEAD(sscanf_termination);
307ATF_TC_BODY(sscanf_termination, tc)
308{
309	int a = 0, b = 0, c = 0;
310	char d = 0;
311
312	ATF_CHECK_EQ(4, sscanf("3.1415", "%d%c%2d%d", &a, &d, &b, &c));
313	ATF_CHECK_EQ(3, a);
314	ATF_CHECK_EQ(14, b);
315	ATF_CHECK_EQ(15, c);
316	ATF_CHECK_EQ('.', d);
317}
318
319ATF_TP_ADD_TCS(tp)
320{
321	setlocale(LC_NUMERIC, "en_US.UTF-8");
322	ATF_TP_ADD_TC(tp, sscanf_b);
323	ATF_TP_ADD_TC(tp, sscanf_o);
324	ATF_TP_ADD_TC(tp, sscanf_d);
325	ATF_TP_ADD_TC(tp, sscanf_x);
326	ATF_TP_ADD_TC(tp, sscanf_i);
327	ATF_TP_ADD_TC(tp, sscanf_wN);
328	ATF_TP_ADD_TC(tp, sscanf_wfN);
329	ATF_TP_ADD_TC(tp, sscanf_termination);
330	return (atf_no_error());
331}
332