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