| 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 |