#ifdef HAVE_CONFIG_H #include #endif #include #include #include "../internal/strtox.h" /* * Shared integer subject-sequence scan (todo 11). See src/internal/strtox.h * for the contract; this file is the engine the strtol/strtoul wrappers and * todo 14's strtoimax/strtoumax build on. * * Prefix rules (C23 7.24.1.4p3-4): * - base 0: "0x"/"0X" followed by a hex digit selects base 16 and the * prefix is consumed; a bare leading 0 selects base 8 and the 0 is the * subject itself ("0" is a valid integer constant, so the subject is * never empty after an octal prefix); anything else is base 10. * - base 16: "0x"/"0X" followed by a hex digit is consumed; without a * hex digit the "0" is itself a valid hex digit and the x terminates * the subject. * - "0x" without a hex digit under base 0 is no integer-constant form, * so there is no subject sequence at all. * * Endptr always lands at the first character that is not part of the * subject sequence, or at nptr when there is no subject (C23 7.24.1.4p5, * even when whitespace or a sign was consumed). */ int __strtox_scan(const char *nptr, char **endptr, int base, int *neg, unsigned long long *mag, int *over) { const char *s = nptr; int sg = 0; int ov = 0; int digits = 0; int consumed_prefix = 0; unsigned long long m = 0; while (strtox_isspace(*s)) { s++; } if (*s == '+' || *s == '-') { sg = (*s == '-'); s++; } if (base != 0 && (base < 2 || base > 36)) { if (endptr) { *endptr = (char *)nptr; } *neg = 0; *mag = 0; *over = 0; return STRTOX_BADBASE; } if (base == 0 || base == 16) { if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { int d2 = strtox_digit(s[2]); if (d2 >= 0 && d2 < 16) { base = 16; s += 2; } else if (base == 0) { /* "0x" with no hex digit is no integer-constant form. */ if (endptr) { *endptr = (char *)nptr; } *neg = 0; *mag = 0; *over = 0; return STRTOX_EMPTY; } /* base 16: the 0 itself is the subject; the x ends it. */ } else if (base == 0 && s[0] == '0') { /* Octal prefix: the 0 opens the subject even when no octal * digit follows ("0" is itself a valid integer constant). */ base = 8; consumed_prefix = 1; s++; } else if (base == 0) { /* No prefix: a decimal subject (base 0 auto-detection). */ base = 10; } } for (;;) { int d = strtox_digit(*s); if (d < 0 || d >= base) { break; } if (ov == 0) { unsigned long long lim = (ULLONG_MAX - (unsigned long long)d) / (unsigned long long)base; if (m > lim) { ov = 1; } else { m = (m * (unsigned long long)base) + (unsigned long long)d; } } digits++; s++; } if (digits == 0 && consumed_prefix == 0) { if (endptr) { *endptr = (char *)nptr; } *neg = 0; *mag = 0; *over = 0; return STRTOX_EMPTY; } if (endptr) { *endptr = (char *)s; } *neg = sg; *mag = m; *over = ov; return STRTOX_OK; }