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