#include "stdlib_p.h" #include #include #include #include #include #include #include #include /* ** In the following conversions, the significant digits are represented in an ** integer and multiplied at the last moment by a suitable power of 10 (decimal ** representation) or 2 (hexadecimal representation). An integer of a suitable ** size needs to be used; that size is the size of the long double type. ** ** TODO: vhex-x86: Using 128-bit long double is untested! */ #if __SIZEOF_LONG_DOUBLE__ == 8 # define SIGNIFICAND_TYPE uint64_t # define SIGNIFICAND_DIGITS 17 #elif __SIZEOF_LONG_DOUBLE__ <= 16 # define SIGNIFICAND_TYPE unsigned __int128 # define SIGNIFICAND_DIGITS 38 #else # error long double larger than 128 bits is not supported #endif /* ** Parse digits and exponent into integers, in decimal or hexadecimal notation. ** ** -> In decimal notation; we read up to 19 (64-bit) or 38 (128-bit) digits, * which is enough to fill the mantissa of a long double, and later multiply ** the digits by a power of 10. The main approximation is the power of 10. ** ** -> In hexadecimal notation, we read as many bits as the mantissa of a long ** double, then later multiply by a power of 2. There are no approximations. */ static bool parse_digits(struct __scanf_input *input, SIGNIFICAND_TYPE *digits, long *exponent, bool hexadecimal) { bool dot_found = false; int digits_found=0, c=0; *digits = 0; *exponent = 0; int max_digits = hexadecimal ? LDBL_MANT_DIG / 4 : SIGNIFICAND_DIGITS; /* TODO: locale: use a locale-aware decimal separator */ int dot_character = '.'; int exp_character = (hexadecimal ? 'p' : 'e'); for(int i = 0; true; i++) { c = __scanf_peek(input); if(!(isdigit(c) || (hexadecimal && isxdigit(c)) || (c == dot_character && !dot_found))) break; __scanf_in(input); if(c == dot_character) { dot_found = true; continue; } /* Count digits only until SIGNIFICAND_DIGITS */ if(digits_found < max_digits) { if(hexadecimal) { int v = c - '0'; if(!isdigit(c)) v = tolower(c) - 'a' + 10; *digits = (*digits << 4) + v; } else { *digits = (*digits * 10) + (c - '0'); } } else (*exponent)++; if(dot_found) (*exponent)--; /* But also round at the first discarded one */ if(digits_found == max_digits && c >= '5') (*digits)++; digits_found++; } /* Require at least one digit to be present; if not, the whole string is considered invalid */ if(!digits_found) return false; /* In hexadecimal, each character is worth 4 bits of exponent */ if(hexadecimal) (*exponent) *= 4; /* Parse exponent */ if(tolower(__scanf_peek(input)) == exp_character) { /* Hack: Restore the str pointer if this fails (which we cannot determine with a single lookahead) so that *endptr is set correctly */ struct __scanf_input backup = *input; __scanf_in(input); long e = 0; if(__strto_int(input, 10, &e, NULL, false) == 0) *exponent += e; else *input = backup; } return true; } static bool expect(struct __scanf_input *input, char const *sequence) { for(int i = 0; sequence[i]; i++) { int c = __scanf_in(input); if(tolower(c) != tolower(sequence[i])) return false; } return true; } int __strto_fp(struct __scanf_input *input, double *out, float *outf, long double *outl) { /* Skip initial whitespace */ while(isspace(__scanf_peek(input))) __scanf_in(input); /* Read optional sign */ bool negative = false; int sign = __scanf_peek(input); if(sign == '-') negative = true; if(sign == '-' || sign == '+') __scanf_in(input); int errno_value = 0; bool valid = false; /* Result variable */ if(out) *out = 0.0; if(outf) *outf = 0.0f; if(outl) *outl = 0.0l; /* NaN possibly with an argument */ if(tolower(__scanf_peek(input)) == 'n') { if(!expect(input, "nan")) return EINVAL; /* Get the argument for up to 32 bytes */ char arg[32]; int i = 0; if(__scanf_peek(input) == '(') { while(i < 31) { int c = __scanf_in(input); if(c == ')') break; arg[i++] = c; } arg[i] = 0; } if(out) *out = __builtin_nan(arg); if(outf) *outf = __builtin_nanf(arg); if(outl) *outl = __builtin_nanl(arg); valid = true; } else if(tolower(__scanf_peek(input)) == 'i') { if(!expect(input, "inf")) return EINVAL; if(tolower(__scanf_peek(input)) == 'i' && !expect(input, "inity")) return EINVAL; if(out) *out = __builtin_inf(); if(outf) *outf = __builtin_inff(); if(outl) *outl = __builtin_infl(); valid = true; } else { SIGNIFICAND_TYPE digits = 0; long e = 0; /* Check for the 0x prefix. Skipping a 0 if we start with 0 but not 0x isn't a problem. */ bool hexa = false; if(__scanf_peek(input) == '0') { __scanf_in(input); if(tolower(__scanf_peek(input)) == 'x') { __scanf_in(input); hexa = true; } /* Count the 0 as a digit */ else valid = true; } if(hexa) { valid |= parse_digits(input, &digits, &e, true); if(out) *out = (double)digits * exp2(e); if(outf) *outf = (float)digits * exp2f(e); if(outl) *outl = (long double)digits * exp2l(e); } else { valid |= parse_digits(input, &digits, &e, false); if(out) *out = (double)digits * pow(10, e); if(outf) *outf = (float)digits * powf(10, e); if(outl) *outl = (long double)digits * powl(10, e); } /* ** Detect overflow, somewhat. Implementation is not required to ** set errno on underflow, which makes things much easier for ** us as underflow gives 0 (7.20.1.3§10). */ if((out && *out == HUGE_VAL) || (outf && *outf == HUGE_VALF) || (outl && *outl == HUGE_VALL)) { errno_value = ERANGE; } } /* Apply sign; this method is allowed by 7.20.1.3§4.249 */ if(negative) { if(out) *out = -(*out); if(outf) *outf = -(*outf); if(outl) *outl = -(*outl); } return valid ? errno_value : EINVAL; }