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