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