* Generic integer parser that holds 64-bit unsigned values and stores * sign separately. Leading space is not valid. * * Note: this function differs from the type specific parsers like * parse_int64 by not negating the value when there is a sign. It * differs from parse_uint64 by being able to return a negative * UINT64_MAX successfully. * * This parser is used by all type specific integer
| 75 | * Status argument can be null. |
| 76 | */ |
| 77 | static const char *parse_integer(const char *buf, size_t len, uint64_t *value, int *status) |
| 78 | { |
| 79 | uint64_t x0, x = 0; |
| 80 | const char *k, *end = buf + len; |
| 81 | int sign, status_; |
| 82 | |
| 83 | if (!status) { |
| 84 | status = &status_; |
| 85 | } |
| 86 | if (buf == end) { |
| 87 | *status = PARSE_INTEGER_END; |
| 88 | return buf; |
| 89 | } |
| 90 | k = buf; |
| 91 | sign = *buf == '-'; |
| 92 | buf += sign; |
| 93 | while (buf != end && *buf >= '0' && *buf <= '9') { |
| 94 | x0 = x; |
| 95 | x = x * 10 + (uint64_t)(*buf - '0'); |
| 96 | if (x0 > x) { |
| 97 | *status = sign ? PARSE_INTEGER_UNDERFLOW : PARSE_INTEGER_OVERFLOW; |
| 98 | return 0; |
| 99 | } |
| 100 | ++buf; |
| 101 | } |
| 102 | if (buf == k) { |
| 103 | /* No number was matched, but it isn't an invalid number either. */ |
| 104 | *status = PARSE_INTEGER_UNMATCHED; |
| 105 | return buf; |
| 106 | } |
| 107 | if (buf == k + sign) { |
| 108 | *status = PARSE_INTEGER_INVALID; |
| 109 | return 0; |
| 110 | } |
| 111 | if (buf != end) |
| 112 | switch (*buf) { |
| 113 | case 'e': case 'E': case '.': case 'p': case 'P': |
| 114 | *status = PARSE_INTEGER_INVALID; |
| 115 | return 0; |
| 116 | } |
| 117 | *value = x; |
| 118 | *status = sign; |
| 119 | return buf; |
| 120 | } |
| 121 | |
| 122 | /* |
| 123 | * Parse hex values like 0xff, -0xff, 0XdeAdBeaf42, cannot be trailed by '.', 'p', or 'P'. |