| 9 | } |
| 10 | |
| 11 | bool |
| 12 | fxp_parse(fxp_t *result, const char *str, char **end) { |
| 13 | /* |
| 14 | * Using malloc_strtoumax in this method isn't as handy as you might |
| 15 | * expect (I tried). In the fractional part, significant leading zeros |
| 16 | * mean that you still need to do your own parsing, now with trickier |
| 17 | * math. In the integer part, the casting (uintmax_t to uint32_t) |
| 18 | * forces more reasoning about bounds than just checking for overflow as |
| 19 | * we parse. |
| 20 | */ |
| 21 | uint32_t integer_part = 0; |
| 22 | |
| 23 | const char *cur = str; |
| 24 | |
| 25 | /* The string must start with a digit or a decimal point. */ |
| 26 | if (*cur != '.' && !fxp_isdigit(*cur)) { |
| 27 | return true; |
| 28 | } |
| 29 | |
| 30 | while ('0' <= *cur && *cur <= '9') { |
| 31 | integer_part *= 10; |
| 32 | integer_part += *cur - '0'; |
| 33 | if (integer_part >= (1U << 16)) { |
| 34 | return true; |
| 35 | } |
| 36 | cur++; |
| 37 | } |
| 38 | |
| 39 | /* |
| 40 | * We've parsed all digits at the beginning of the string, without |
| 41 | * overflow. Either we're done, or there's a fractional part. |
| 42 | */ |
| 43 | if (*cur != '.') { |
| 44 | *result = (integer_part << 16); |
| 45 | if (end != NULL) { |
| 46 | *end = (char *)cur; |
| 47 | } |
| 48 | return false; |
| 49 | } |
| 50 | |
| 51 | /* There's a fractional part. */ |
| 52 | cur++; |
| 53 | if (!fxp_isdigit(*cur)) { |
| 54 | /* Shouldn't end on the decimal point. */ |
| 55 | return true; |
| 56 | } |
| 57 | |
| 58 | /* |
| 59 | * We use a lot of precision for the fractional part, even though we'll |
| 60 | * discard most of it; this lets us get exact values for the important |
| 61 | * special case where the denominator is a small power of 2 (for |
| 62 | * instance, 1/512 == 0.001953125 is exactly representable even with |
| 63 | * only 16 bits of fractional precision). We need to left-shift by 16 |
| 64 | * before dividing so we pick the number of digits to be |
| 65 | * floor(log(2**48)) = 14. |
| 66 | */ |
| 67 | uint64_t fractional_part = 0; |
| 68 | uint64_t frac_div = 1; |
no test coverage detected