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