diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lj_strscan.c | 57 |
1 files changed, 53 insertions, 4 deletions
diff --git a/src/lj_strscan.c b/src/lj_strscan.c index 568f647d..d3c5ba91 100644 --- a/src/lj_strscan.c +++ b/src/lj_strscan.c | |||
| @@ -140,7 +140,7 @@ static StrScanFmt strscan_hex(const uint8_t *p, TValue *o, | |||
| 140 | break; | 140 | break; |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | /* Reduce range then convert to double. */ | 143 | /* Reduce range, then convert to double. */ |
| 144 | if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } | 144 | if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } |
| 145 | strscan_double(x, o, ex2, neg); | 145 | strscan_double(x, o, ex2, neg); |
| 146 | return fmt; | 146 | return fmt; |
| @@ -326,6 +326,49 @@ static StrScanFmt strscan_dec(const uint8_t *p, TValue *o, | |||
| 326 | return fmt; | 326 | return fmt; |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | /* Parse binary number. */ | ||
| 330 | static StrScanFmt strscan_bin(const uint8_t *p, TValue *o, | ||
| 331 | StrScanFmt fmt, uint32_t opt, | ||
| 332 | int32_t ex2, int32_t neg, uint32_t dig) | ||
| 333 | { | ||
| 334 | uint64_t x = 0; | ||
| 335 | uint32_t i; | ||
| 336 | |||
| 337 | if (ex2 || dig > 64) return STRSCAN_ERROR; | ||
| 338 | |||
| 339 | /* Scan binary digits. */ | ||
| 340 | for (i = dig; i; i--, p++) { | ||
| 341 | if ((*p & ~1) != '0') return STRSCAN_ERROR; | ||
| 342 | x = (x << 1) | (*p & 1); | ||
| 343 | } | ||
| 344 | |||
| 345 | /* Format-specific handling. */ | ||
| 346 | switch (fmt) { | ||
| 347 | case STRSCAN_INT: | ||
| 348 | if (!(opt & STRSCAN_OPT_TONUM) && x < 0x80000000u+neg) { | ||
| 349 | o->i = neg ? -(int32_t)x : (int32_t)x; | ||
| 350 | return STRSCAN_INT; /* Fast path for 32 bit integers. */ | ||
| 351 | } | ||
| 352 | if (!(opt & STRSCAN_OPT_C)) { fmt = STRSCAN_NUM; break; } | ||
| 353 | /* fallthrough */ | ||
| 354 | case STRSCAN_U32: | ||
| 355 | if (dig > 32) return STRSCAN_ERROR; | ||
| 356 | o->i = neg ? -(int32_t)x : (int32_t)x; | ||
| 357 | return STRSCAN_U32; | ||
| 358 | case STRSCAN_I64: | ||
| 359 | case STRSCAN_U64: | ||
| 360 | o->u64 = neg ? (uint64_t)-(int64_t)x : x; | ||
| 361 | return fmt; | ||
| 362 | default: | ||
| 363 | break; | ||
| 364 | } | ||
| 365 | |||
| 366 | /* Reduce range, then convert to double. */ | ||
| 367 | if ((x & U64x(c0000000,0000000))) { x = (x >> 2) | (x & 3); ex2 += 2; } | ||
| 368 | strscan_double(x, o, ex2, neg); | ||
| 369 | return fmt; | ||
| 370 | } | ||
| 371 | |||
| 329 | /* Scan string containing a number. Returns format. Returns value in o. */ | 372 | /* Scan string containing a number. Returns format. Returns value in o. */ |
| 330 | StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) | 373 | StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) |
| 331 | { | 374 | { |
| @@ -364,8 +407,12 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) | |||
| 364 | 407 | ||
| 365 | /* Determine base and skip leading zeros. */ | 408 | /* Determine base and skip leading zeros. */ |
| 366 | if (LJ_UNLIKELY(*p <= '0')) { | 409 | if (LJ_UNLIKELY(*p <= '0')) { |
| 367 | if (*p == '0' && casecmp(p[1], 'x')) | 410 | if (*p == '0') { |
| 368 | base = 16, cmask = LJ_CHAR_XDIGIT, p += 2; | 411 | if (casecmp(p[1], 'x')) |
| 412 | base = 16, cmask = LJ_CHAR_XDIGIT, p += 2; | ||
| 413 | else if (casecmp(p[1], 'b')) | ||
| 414 | base = 2, cmask = LJ_CHAR_DIGIT, p += 2; | ||
| 415 | } | ||
| 369 | for ( ; ; p++) { | 416 | for ( ; ; p++) { |
| 370 | if (*p == '0') { | 417 | if (*p == '0') { |
| 371 | hasdig = 1; | 418 | hasdig = 1; |
| @@ -403,7 +450,7 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) | |||
| 403 | } | 450 | } |
| 404 | 451 | ||
| 405 | /* Parse exponent. */ | 452 | /* Parse exponent. */ |
| 406 | if (casecmp(*p, (uint32_t)(base == 16 ? 'p' : 'e'))) { | 453 | if (base >= 10 && casecmp(*p, (uint32_t)(base == 16 ? 'p' : 'e'))) { |
| 407 | uint32_t xx; | 454 | uint32_t xx; |
| 408 | int negx = 0; | 455 | int negx = 0; |
| 409 | fmt = STRSCAN_NUM; p++; | 456 | fmt = STRSCAN_NUM; p++; |
| @@ -460,6 +507,8 @@ StrScanFmt lj_strscan_scan(const uint8_t *p, TValue *o, uint32_t opt) | |||
| 460 | return strscan_oct(sp, o, fmt, neg, dig); | 507 | return strscan_oct(sp, o, fmt, neg, dig); |
| 461 | if (base == 16) | 508 | if (base == 16) |
| 462 | fmt = strscan_hex(sp, o, fmt, opt, ex, neg, dig); | 509 | fmt = strscan_hex(sp, o, fmt, opt, ex, neg, dig); |
| 510 | else if (base == 2) | ||
| 511 | fmt = strscan_bin(sp, o, fmt, opt, ex, neg, dig); | ||
| 463 | else | 512 | else |
| 464 | fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig); | 513 | fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig); |
| 465 | 514 | ||
