#include "shgetc.h" #include #include #include /* Lookup table for digit values. -1==255>=36 -> invalid */ static const unsigned char table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; unsigned long long __intscan(FILE* f, unsigned base, int pok, unsigned long long lim) { const unsigned char* val = table + 1; int c, neg = 0; unsigned x; unsigned long long y; if (base > 36) { errno = EINVAL; return 0; } while (isspace((c = shgetc(f)))) ; if (c == '+' || c == '-') { neg = -(c == '-'); c = shgetc(f); } if ((base == 0 || base == 16) && c == '0') { c = shgetc(f); if ((c | 32) == 'x') { c = shgetc(f); if (val[c] >= 16) { shunget(f); if (pok) shunget(f); else shlim(f, 0); return 0; } base = 16; } else if (base == 0) { base = 8; } } else { if (base == 0) base = 10; if (val[c] >= base) { shunget(f); shlim(f, 0); errno = EINVAL; return 0; } } if (base == 10) { for (x = 0; c >= '0' && c <= '9' && x <= UINT_MAX / 10 - 1; c = shgetc(f)) x = x * 10 + (c - '0'); for (y = x; c >= '0' && c <= '9' && y <= ULLONG_MAX / 10 && 10 * y <= ULLONG_MAX - (c - '0'); c = shgetc(f)) y = y * 10 + (c - '0'); if (c < '0' || c > '9') goto done; } else if (!(base & (base - 1))) { int bs = "\0\1\2\4\7\3\6\5"[(0x17 * base) >> 5 & 7]; for (x = 0; val[c] < base && x <= UINT_MAX / 32; c = shgetc(f)) x = x << bs | val[c]; for (y = x; val[c] < base && y <= ULLONG_MAX >> bs; c = shgetc(f)) y = y << bs | val[c]; } else { for (x = 0; val[c] < base && x <= UINT_MAX / 36 - 1; c = shgetc(f)) x = x * base + val[c]; for (y = x; val[c] < base && y <= ULLONG_MAX / base && base * y <= ULLONG_MAX - val[c]; c = shgetc(f)) y = y * base + val[c]; } if (val[c] < base) { for (; val[c] < base; c = shgetc(f)) ; errno = ERANGE; y = lim; if (lim & 1) neg = 0; } done: shunget(f); if (y >= lim) { if (!(lim & 1) && !neg) { errno = ERANGE; return lim - 1; } else if (y > lim) { errno = ERANGE; return lim; } } return (y ^ neg) - neg; }