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 
15 #ifndef TINY_STDIO
16 #define printf_float(x) x
17 #ifdef _NANO_FORMATTED_IO
18 #ifndef NO_FLOATING_POINT
19 extern int _printf_float();
20 extern int _scanf_float();
21 
22 int (*_reference_printf_float)() = _printf_float;
23 int (*_reference_scanf_float)() = _scanf_float;
24 #define TEST_ASPRINTF
25 #endif
26 #endif
27 #endif
28 
29 #define PRINTF_BUF_SIZE 512
30 
31 static char buf[PRINTF_BUF_SIZE];
32 static wchar_t wbuf[PRINTF_BUF_SIZE];
33 
failmsg(int serial,char * fmt,...)34 static void failmsg(int serial, char *fmt, ...) {
35     va_list ap;
36     va_start(ap, fmt);
37     printf("test %d failed: ", serial);
38     vprintf(fmt, ap);
39     printf("\n");
40     va_end(ap);
41 }
42 
43 #ifdef __GNUC__
44 #pragma GCC diagnostic ignored "-Wpragmas"
45 #pragma GCC diagnostic ignored "-Wunknown-warning-option"
46 /* 'bsize' is used directly with malloc/realloc which confuses -fanalyzer */
47 #pragma GCC diagnostic ignored "-Wanalyzer-va-arg-type-mismatch"
48 #pragma GCC diagnostic ignored "-Wanalyzer-va-list-exhausted"
49 #endif
50 
test(int serial,char * expect,char * fmt,...)51 static int test(int serial, char *expect, char *fmt, ...) {
52     va_list ap;
53     char *abuf = NULL;
54     va_start(ap, fmt);
55     int n;
56 #ifdef TEST_ASPRINTF
57     int an;
58     va_list aap;
59     va_copy(aap, ap);
60 #endif
61 #ifndef NO_FLOATING_POINT
62     double dv;
63     char *star;
64 #endif
65     switch (fmt[strlen(fmt)-1]) {
66     case 'e':
67     case 'E':
68     case 'f':
69     case 'F':
70     case 'g':
71     case 'G':
72     case 'a':
73     case 'A':
74 #ifdef NO_FLOATING_POINT
75 	    return 0;
76 #else
77 	    star = strchr(fmt, '*');
78 	    if (star) {
79 		    if (strchr(star+1, '*')) {
80 			    int iv1 = va_arg(ap, int);
81 			    int iv2 = va_arg(ap, int);
82 			    dv = va_arg(ap, double);
83 			    n = snprintf(buf, PRINTF_BUF_SIZE, fmt, iv1, iv2, printf_float(dv));
84 #ifdef TEST_ASPRINTF
85 			    an = asprintf(&abuf, fmt, iv1, iv2, printf_float(dv));
86 #endif
87 		    } else  {
88 			    int iv = va_arg(ap, int);
89 			    dv = va_arg(ap, double);
90 			    n = snprintf(buf, PRINTF_BUF_SIZE, fmt, iv, printf_float(dv));
91 #ifdef TEST_ASPRINTF
92 			    an = asprintf(&abuf, fmt, iv, printf_float(dv));
93 #endif
94 		    }
95 	    } else {
96 		    dv = va_arg(ap, double);
97 		    n = snprintf(buf, PRINTF_BUF_SIZE, fmt, printf_float(dv));
98 #ifdef TEST_ASPRINTF
99 		    an = asprintf(&abuf, fmt, printf_float(dv));
100 #endif
101 	    }
102 	    break;
103 #endif
104     default:
105 	    n = vsnprintf(buf, PRINTF_BUF_SIZE, fmt, ap);
106 #ifdef TEST_ASPRINTF
107 	    an = vasprintf(&abuf, fmt, aap);
108 #endif
109 	    break;
110     }
111     va_end(ap);
112 #ifdef TEST_ASPRINTF
113     va_end(aap);
114 #endif
115 //    printf("serial %d expect \"%s\" got \"%s\"\n", serial, expect, buf);
116     if (n >= PRINTF_BUF_SIZE) {
117         failmsg(serial, "buffer overflow");
118 	free(abuf);
119         return 1;
120     }
121     if (n != (int) strlen(expect)) {
122         failmsg(serial, "expected \"%s\" (%d), got \"%s\" (%d)",
123 		expect, (int) strlen(expect), buf, n);
124 	free(abuf);
125         return 1;
126     }
127     if (strcmp(buf, expect)) {
128         failmsg(serial, "expected \"%s\", got \"%s\"", expect, buf);
129 	free(abuf);
130         return 1;
131     }
132 #ifdef TEST_ASPRINTF
133     if (an != n) {
134 	failmsg(serial, "asprintf return %d sprintf return %d\n", an, n);
135 	free(abuf);
136 	return 1;
137     }
138     if (strcmp(abuf, buf)) {
139 	failmsg(serial, "sprintf return %s asprintf return %s\n", buf, abuf);
140 	free(abuf);
141 	return 1;
142     }
143     free(abuf);
144 #endif
145     return 0;
146 }
147 
failmsgw(int serial,wchar_t * fmt,...)148 static void failmsgw(int serial, wchar_t *fmt, ...) {
149     va_list ap;
150     va_start(ap, fmt);
151     printf("test %d failed: ", serial);
152     static wchar_t f_wbuf[PRINTF_BUF_SIZE];
153     static char f_buf[PRINTF_BUF_SIZE];
154     vswprintf(f_wbuf, PRINTF_BUF_SIZE, fmt, ap);
155     wcstombs(f_buf, f_wbuf, PRINTF_BUF_SIZE);
156     printf("%s\n", f_buf);
157     va_end(ap);
158 }
159 
testw(int serial,wchar_t * expect,wchar_t * fmt,...)160 static int testw(int serial, wchar_t *expect, wchar_t *fmt, ...) {
161     va_list ap;
162     wchar_t *abuf = NULL;
163     va_start(ap, fmt);
164     int n;
165 #ifdef TEST_ASPRINTF
166     int an;
167     va_list aap;
168     va_copy(aap, ap);
169 #endif
170 #ifndef NO_FLOATING_POINT
171     double dv;
172     wchar_t *star;
173 #endif
174     switch (fmt[wcslen(fmt)-1]) {
175     case 'e':
176     case 'E':
177     case 'f':
178     case 'F':
179     case 'g':
180     case 'G':
181     case 'a':
182     case 'A':
183 #ifdef NO_FLOATING_POINT
184 	    return 0;
185 #else
186 	    star = wcschr(fmt, '*');
187 	    if (star) {
188 		    if (wcschr(star+1, '*')) {
189 			    int iv1 = va_arg(ap, int);
190 			    int iv2 = va_arg(ap, int);
191 			    dv = va_arg(ap, double);
192 			    n = swprintf(wbuf, PRINTF_BUF_SIZE, fmt, iv1, iv2, printf_float(dv));
193 		    } else  {
194 			    int iv = va_arg(ap, int);
195 			    dv = va_arg(ap, double);
196 			    n = swprintf(wbuf, PRINTF_BUF_SIZE, fmt, iv, printf_float(dv));
197 		    }
198 	    } else {
199 		    dv = va_arg(ap, double);
200 		    n = swprintf(wbuf, PRINTF_BUF_SIZE, fmt, printf_float(dv));
201 	    }
202 	    break;
203 #endif
204     default:
205 	    n = vswprintf(wbuf, PRINTF_BUF_SIZE, fmt, ap);
206 	    break;
207     }
208     va_end(ap);
209 //    printf("serial %d expect \"%s\" got \"%s\"\n", serial, expect, wbuf);
210     if (n >= PRINTF_BUF_SIZE) {
211         failmsgw(serial, L"buffer overflow");
212 	free(abuf);
213         return 1;
214     }
215     if (n != (int) wcslen(expect)) {
216         failmsgw(serial, L"expected \"%s\" (%d), got \"%s\" (%d)",
217 		expect, wcslen(expect), wbuf, n);
218 	free(abuf);
219         return 1;
220     }
221     if (wcscmp(wbuf, expect)) {
222         failmsgw(serial, L"expected \"%ls\", got \"%ls\"", expect, wbuf);
223 	free(abuf);
224         return 1;
225     }
226     return 0;
227 }
228 
main(void)229 int main(void) {
230     int result = 0;
231 #include "testcases.c"
232     return result;
233 }
234