1 /* Copyright © 2013 Bart Massey */
2 /* This program is licensed under the GPL version 2 or later.
3 Please see the file COPYING.GPL2 in this distribution for
4 license terms. */
5
6 #define _GNU_SOURCE
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <stdint.h>
12 #include <math.h>
13 #include <wchar.h>
14 #include <locale.h>
15
16 #ifndef TINY_STDIO
17 #define printf_float(x) ((double) (x))
18 #ifdef _NANO_FORMATTED_IO
19 #ifndef NO_FLOATING_POINT
20 extern int _printf_float();
21 extern int _scanf_float();
22
23 int (*_reference_printf_float)() = _printf_float;
24 int (*_reference_scanf_float)() = _scanf_float;
25 #define TEST_ASPRINTF
26 #endif
27 #endif
28 #endif
29
30 #define PRINTF_BUF_SIZE 512
31
32 static char buf[PRINTF_BUF_SIZE];
33 static wchar_t wbuf[PRINTF_BUF_SIZE];
34
failmsg(int serial,char * fmt,...)35 static void failmsg(int serial, char *fmt, ...) {
36 va_list ap;
37 va_start(ap, fmt);
38 printf("test %d failed: ", serial);
39 vprintf(fmt, ap);
40 printf("\n");
41 va_end(ap);
42 }
43
44 #ifdef __GNUC__
45 #pragma GCC diagnostic ignored "-Wpragmas"
46 #pragma GCC diagnostic ignored "-Wunknown-warning-option"
47 /* 'bsize' is used directly with malloc/realloc which confuses -fanalyzer */
48 #pragma GCC diagnostic ignored "-Wanalyzer-va-arg-type-mismatch"
49 #pragma GCC diagnostic ignored "-Wanalyzer-va-list-exhausted"
50 #endif
51
test(int serial,char * expect,char * fmt,...)52 static int test(int serial, char *expect, char *fmt, ...) {
53 va_list ap;
54 char *abuf = NULL;
55 va_start(ap, fmt);
56 int n;
57 #ifdef TEST_ASPRINTF
58 int an;
59 va_list aap;
60 va_copy(aap, ap);
61 #endif
62 #ifndef NO_FLOATING_POINT
63 # ifdef _HAS_IO_FLOAT
64 uint32_t dv;
65 # else
66 double dv;
67 # endif
68 #ifndef NO_LONG_DOUBLE
69 long double ldv;
70 #endif
71 char *star;
72 char *long_double;
73 #endif
74 switch (fmt[strlen(fmt)-1]) {
75 case 'e':
76 case 'E':
77 case 'f':
78 case 'F':
79 case 'g':
80 case 'G':
81 case 'a':
82 case 'A':
83 #ifdef NO_FLOATING_POINT
84 return 0;
85 #else
86 star = strchr(fmt, '*');
87 long_double = strchr(fmt, 'L');
88 if (star) {
89 if (strchr(star+1, '*')) {
90 int iv1 = va_arg(ap, int);
91 int iv2 = va_arg(ap, int);
92 #ifndef NO_LONG_DOUBLE
93 if (long_double) {
94 ldv = va_arg(ap, long double);
95 n = snprintf(buf, PRINTF_BUF_SIZE, fmt, iv1, iv2, ldv);
96 #ifdef TEST_ASPRINTF
97 an = asprintf(&abuf, fmt, iv1, iv2, ldv);
98 #endif
99 } else
100 #endif
101 {
102 dv = va_arg(ap, __typeof(dv));
103 n = snprintf(buf, PRINTF_BUF_SIZE, fmt, iv1, iv2, dv);
104 #ifdef TEST_ASPRINTF
105 an = asprintf(&abuf, fmt, iv1, iv2, dv);
106 #endif
107 }
108 } else {
109 int iv = va_arg(ap, int);
110 #ifndef NO_LONG_DOUBLE
111 if (long_double) {
112 ldv = va_arg(ap, long double);
113 n = snprintf(buf, PRINTF_BUF_SIZE, fmt, iv, ldv);
114 #ifdef TEST_ASPRINTF
115 an = asprintf(&abuf, fmt, iv, ldv);
116 #endif
117 } else
118 #endif
119 {
120 dv = va_arg(ap, __typeof(dv));
121 n = snprintf(buf, PRINTF_BUF_SIZE, fmt, iv, dv);
122 #ifdef TEST_ASPRINTF
123 an = asprintf(&abuf, fmt, iv, dv);
124 #endif
125 }
126 }
127 } else {
128 #ifndef NO_LONG_DOUBLE
129 if (long_double) {
130 ldv = va_arg(ap, long double);
131 n = snprintf(buf, PRINTF_BUF_SIZE, fmt, ldv);
132 #ifdef TEST_ASPRINTF
133 an = asprintf(&abuf, fmt, ldv);
134 #endif
135 } else
136 #endif
137 {
138 dv = va_arg(ap, __typeof(dv));
139 n = snprintf(buf, PRINTF_BUF_SIZE, fmt, dv);
140 #ifdef TEST_ASPRINTF
141 an = asprintf(&abuf, fmt, dv);
142 #endif
143 }
144 }
145 break;
146 #endif
147 default:
148 n = vsnprintf(buf, PRINTF_BUF_SIZE, fmt, ap);
149 #ifdef TEST_ASPRINTF
150 an = vasprintf(&abuf, fmt, aap);
151 #endif
152 break;
153 }
154 va_end(ap);
155 #ifdef TEST_ASPRINTF
156 va_end(aap);
157 #endif
158 // printf("serial %d expect \"%s\" got \"%s\"\n", serial, expect, buf);
159 if (n >= PRINTF_BUF_SIZE) {
160 failmsg(serial, "buffer overflow");
161 free(abuf);
162 return 1;
163 }
164 if (n != (int) strlen(expect)) {
165 failmsg(serial, "expected \"%s\" (%d), got \"%s\" (%d)",
166 expect, (int) strlen(expect), buf, n);
167 free(abuf);
168 return 1;
169 }
170 if (strcmp(buf, expect)) {
171 failmsg(serial, "expected \"%s\", got \"%s\"", expect, buf);
172 free(abuf);
173 return 1;
174 }
175 #ifdef TEST_ASPRINTF
176 if (an != n) {
177 failmsg(serial, "asprintf return %d sprintf return %d\n", an, n);
178 free(abuf);
179 return 1;
180 }
181 if (strcmp(abuf, buf)) {
182 failmsg(serial, "sprintf return %s asprintf return %s\n", buf, abuf);
183 free(abuf);
184 return 1;
185 }
186 free(abuf);
187 #endif
188 return 0;
189 }
190
failmsgw(int serial,wchar_t * fmt,...)191 static void failmsgw(int serial, wchar_t *fmt, ...) {
192 va_list ap;
193 va_start(ap, fmt);
194 printf("test %d failed: ", serial);
195 static wchar_t f_wbuf[PRINTF_BUF_SIZE];
196 static char f_buf[PRINTF_BUF_SIZE];
197 vswprintf(f_wbuf, PRINTF_BUF_SIZE, fmt, ap);
198 wcstombs(f_buf, f_wbuf, PRINTF_BUF_SIZE);
199 printf("%s\n", f_buf);
200 va_end(ap);
201 }
202
testw(int serial,wchar_t * expect,wchar_t * fmt,...)203 static int testw(int serial, wchar_t *expect, wchar_t *fmt, ...) {
204 va_list ap;
205 wchar_t *abuf = NULL;
206 va_start(ap, fmt);
207 int n;
208 #ifdef TEST_ASPRINTF
209 int an;
210 va_list aap;
211 va_copy(aap, ap);
212 #endif
213 #ifndef NO_FLOATING_POINT
214 # ifdef _HAS_IO_FLOAT
215 uint32_t dv;
216 # else
217 double dv;
218 # endif
219 wchar_t *star;
220 #endif
221 switch (fmt[wcslen(fmt)-1]) {
222 case 'e':
223 case 'E':
224 case 'f':
225 case 'F':
226 case 'g':
227 case 'G':
228 case 'a':
229 case 'A':
230 #ifdef NO_FLOATING_POINT
231 return 0;
232 #else
233 star = wcschr(fmt, '*');
234 if (star) {
235 if (wcschr(star+1, '*')) {
236 int iv1 = va_arg(ap, int);
237 int iv2 = va_arg(ap, int);
238 dv = va_arg(ap, __typeof(dv));
239 n = swprintf(wbuf, PRINTF_BUF_SIZE, fmt, iv1, iv2, dv);
240 } else {
241 int iv = va_arg(ap, int);
242 dv = va_arg(ap, __typeof(dv));
243 n = swprintf(wbuf, PRINTF_BUF_SIZE, fmt, iv, dv);
244 }
245 } else {
246 dv = va_arg(ap, __typeof(dv));
247 n = swprintf(wbuf, PRINTF_BUF_SIZE, fmt, dv);
248 }
249 break;
250 #endif
251 default:
252 n = vswprintf(wbuf, PRINTF_BUF_SIZE, fmt, ap);
253 break;
254 }
255 va_end(ap);
256 // printf("serial %d expect \"%s\" got \"%s\"\n", serial, expect, wbuf);
257 if (n >= PRINTF_BUF_SIZE) {
258 failmsgw(serial, L"buffer overflow");
259 free(abuf);
260 return 1;
261 }
262 if (n != (int) wcslen(expect)) {
263 failmsgw(serial, L"expected \"%s\" (%d), got \"%s\" (%d)",
264 expect, wcslen(expect), wbuf, n);
265 free(abuf);
266 return 1;
267 }
268 if (wcscmp(wbuf, expect)) {
269 failmsgw(serial, L"expected \"%ls\", got \"%ls\"", expect, wbuf);
270 free(abuf);
271 return 1;
272 }
273 return 0;
274 }
275
main(void)276 int main(void) {
277 int result = 0;
278 #if !defined(__PICOLIBC__) || defined(_MB_CAPABLE)
279 if (!setlocale(LC_CTYPE, "C.UTF-8")) {
280 printf("setlocale(LC_CTYPE, \"C.UTF-8\") failed\n");
281 return 1;
282 }
283 #endif
284 #include "testcases.c"
285 return result;
286 }
287