master
1#include <stdlib.h>
2#include <stdarg.h>
3#include <ctype.h>
4#include <wchar.h>
5#include <wctype.h>
6#include <limits.h>
7#include <string.h>
8#include <stdint.h>
9#ifdef __wasilibc_unmodified_upstream // Changes to optimize printf/scanf when long double isn't needed
10#else
11#include "printscan.h"
12#endif
13
14#include "stdio_impl.h"
15#include "shgetc.h"
16#include "intscan.h"
17#include "floatscan.h"
18
19#define SIZE_hh -2
20#define SIZE_h -1
21#define SIZE_def 0
22#define SIZE_l 1
23#define SIZE_L 2
24#define SIZE_ll 3
25
26static void store_int(void *dest, int size, unsigned long long i)
27{
28 if (!dest) return;
29 switch (size) {
30 case SIZE_hh:
31 *(char *)dest = i;
32 break;
33 case SIZE_h:
34 *(short *)dest = i;
35 break;
36 case SIZE_def:
37 *(int *)dest = i;
38 break;
39 case SIZE_l:
40 *(long *)dest = i;
41 break;
42 case SIZE_ll:
43 *(long long *)dest = i;
44 break;
45 }
46}
47
48static void *arg_n(va_list ap, unsigned int n)
49{
50 void *p;
51 unsigned int i;
52 va_list ap2;
53 va_copy(ap2, ap);
54 for (i=n; i>1; i--) va_arg(ap2, void *);
55 p = va_arg(ap2, void *);
56 va_end(ap2);
57 return p;
58}
59
60int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap)
61{
62 int width;
63 int size;
64 int alloc = 0;
65 int base;
66 const unsigned char *p;
67 int c, t;
68 char *s;
69 wchar_t *wcs;
70 mbstate_t st;
71 void *dest=NULL;
72 int invert;
73 int matches=0;
74 unsigned long long x;
75#if defined(__wasilibc_printscan_no_long_double)
76 long_double y;
77#else
78 long double y;
79#endif
80 off_t pos = 0;
81 unsigned char scanset[257];
82 size_t i, k;
83 wchar_t wc;
84
85 FLOCK(f);
86
87 if (!f->rpos) __toread(f);
88 if (!f->rpos) goto input_fail;
89
90 for (p=(const unsigned char *)fmt; *p; p++) {
91
92 alloc = 0;
93
94 if (isspace(*p)) {
95 while (isspace(p[1])) p++;
96 shlim(f, 0);
97 while (isspace(shgetc(f)));
98 shunget(f);
99 pos += shcnt(f);
100 continue;
101 }
102 if (*p != '%' || p[1] == '%') {
103 shlim(f, 0);
104 if (*p == '%') {
105 p++;
106 while (isspace((c=shgetc(f))));
107 } else {
108 c = shgetc(f);
109 }
110 if (c!=*p) {
111 shunget(f);
112 if (c<0) goto input_fail;
113 goto match_fail;
114 }
115 pos += shcnt(f);
116 continue;
117 }
118
119 p++;
120 if (*p=='*') {
121 dest = 0; p++;
122 } else if (isdigit(*p) && p[1]=='$') {
123 dest = arg_n(ap, *p-'0'); p+=2;
124 } else {
125 dest = va_arg(ap, void *);
126 }
127
128 for (width=0; isdigit(*p); p++) {
129 width = 10*width + *p - '0';
130 }
131
132 if (*p=='m') {
133 wcs = 0;
134 s = 0;
135 alloc = !!dest;
136 p++;
137 } else {
138 alloc = 0;
139 }
140
141 size = SIZE_def;
142 switch (*p++) {
143 case 'h':
144 if (*p == 'h') p++, size = SIZE_hh;
145 else size = SIZE_h;
146 break;
147 case 'l':
148 if (*p == 'l') p++, size = SIZE_ll;
149 else size = SIZE_l;
150 break;
151 case 'j':
152 size = SIZE_ll;
153 break;
154 case 'z':
155 case 't':
156 size = SIZE_l;
157 break;
158 case 'L':
159 size = SIZE_L;
160 break;
161 case 'd': case 'i': case 'o': case 'u': case 'x':
162 case 'a': case 'e': case 'f': case 'g':
163 case 'A': case 'E': case 'F': case 'G': case 'X':
164 case 's': case 'c': case '[':
165 case 'S': case 'C':
166 case 'p': case 'n':
167 p--;
168 break;
169 default:
170 goto fmt_fail;
171 }
172
173 t = *p;
174
175 /* C or S */
176 if ((t&0x2f) == 3) {
177 t |= 32;
178 size = SIZE_l;
179 }
180
181 switch (t) {
182 case 'c':
183 if (width < 1) width = 1;
184 case '[':
185 break;
186 case 'n':
187 store_int(dest, size, pos);
188 /* do not increment match count, etc! */
189 continue;
190 default:
191 shlim(f, 0);
192 while (isspace(shgetc(f)));
193 shunget(f);
194 pos += shcnt(f);
195 }
196
197 shlim(f, width);
198 if (shgetc(f) < 0) goto input_fail;
199 shunget(f);
200
201 switch (t) {
202 case 's':
203 case 'c':
204 case '[':
205 if (t == 'c' || t == 's') {
206 memset(scanset, -1, sizeof scanset);
207 scanset[0] = 0;
208 if (t == 's') {
209 scanset[1+'\t'] = 0;
210 scanset[1+'\n'] = 0;
211 scanset[1+'\v'] = 0;
212 scanset[1+'\f'] = 0;
213 scanset[1+'\r'] = 0;
214 scanset[1+' '] = 0;
215 }
216 } else {
217 if (*++p == '^') p++, invert = 1;
218 else invert = 0;
219 memset(scanset, invert, sizeof scanset);
220 scanset[0] = 0;
221 if (*p == '-') p++, scanset[1+'-'] = 1-invert;
222 else if (*p == ']') p++, scanset[1+']'] = 1-invert;
223 for (; *p != ']'; p++) {
224 if (!*p) goto fmt_fail;
225 if (*p=='-' && p[1] && p[1] != ']')
226 for (c=p++[-1]; c<*p; c++)
227 scanset[1+c] = 1-invert;
228 scanset[1+*p] = 1-invert;
229 }
230 }
231 wcs = 0;
232 s = 0;
233 i = 0;
234 k = t=='c' ? width+1U : 31;
235 if (size == SIZE_l) {
236 if (alloc) {
237 wcs = malloc(k*sizeof(wchar_t));
238 if (!wcs) goto alloc_fail;
239 } else {
240 wcs = dest;
241 }
242 st = (mbstate_t){0};
243 while (scanset[(c=shgetc(f))+1]) {
244 switch (mbrtowc(&wc, &(char){c}, 1, &st)) {
245 case -1:
246 goto input_fail;
247 case -2:
248 continue;
249 }
250 if (wcs) wcs[i++] = wc;
251 if (alloc && i==k) {
252 k+=k+1;
253 wchar_t *tmp = realloc(wcs, k*sizeof(wchar_t));
254 if (!tmp) goto alloc_fail;
255 wcs = tmp;
256 }
257 }
258 if (!mbsinit(&st)) goto input_fail;
259 } else if (alloc) {
260 s = malloc(k);
261 if (!s) goto alloc_fail;
262 while (scanset[(c=shgetc(f))+1]) {
263 s[i++] = c;
264 if (i==k) {
265 k+=k+1;
266 char *tmp = realloc(s, k);
267 if (!tmp) goto alloc_fail;
268 s = tmp;
269 }
270 }
271 } else if ((s = dest)) {
272 while (scanset[(c=shgetc(f))+1])
273 s[i++] = c;
274 } else {
275 while (scanset[(c=shgetc(f))+1]);
276 }
277 shunget(f);
278 if (!shcnt(f)) goto match_fail;
279 if (t == 'c' && shcnt(f) != width) goto match_fail;
280 if (alloc) {
281 if (size == SIZE_l) *(wchar_t **)dest = wcs;
282 else *(char **)dest = s;
283 }
284 if (t != 'c') {
285 if (wcs) wcs[i] = 0;
286 if (s) s[i] = 0;
287 }
288 break;
289 case 'p':
290 case 'X':
291 case 'x':
292 base = 16;
293 goto int_common;
294 case 'o':
295 base = 8;
296 goto int_common;
297 case 'd':
298 case 'u':
299 base = 10;
300 goto int_common;
301 case 'i':
302 base = 0;
303 int_common:
304 x = __intscan(f, base, 0, ULLONG_MAX);
305 if (!shcnt(f)) goto match_fail;
306 if (t=='p' && dest) *(void **)dest = (void *)(uintptr_t)x;
307 else store_int(dest, size, x);
308 break;
309 case 'a': case 'A':
310 case 'e': case 'E':
311 case 'f': case 'F':
312 case 'g': case 'G':
313 y = __floatscan(f, size, 0);
314 if (!shcnt(f)) goto match_fail;
315 if (dest) switch (size) {
316 case SIZE_def:
317 *(float *)dest = y;
318 break;
319 case SIZE_l:
320 *(double *)dest = y;
321 break;
322 case SIZE_L:
323#if defined(__wasilibc_printscan_no_long_double)
324 long_double_not_supported();
325#else
326 *(long double *)dest = y;
327#endif
328 break;
329 }
330 break;
331 }
332
333 pos += shcnt(f);
334 if (dest) matches++;
335 }
336 if (0) {
337fmt_fail:
338alloc_fail:
339input_fail:
340 if (!matches) matches--;
341match_fail:
342 if (alloc) {
343 free(s);
344 free(wcs);
345 }
346 }
347 FUNLOCK(f);
348 return matches;
349}
350
351weak_alias(vfscanf,__isoc99_vfscanf);