| #include <limits.h> |
| #include <errno.h> |
| #include <ctype.h> |
| #include "shgetc.h" |
| |
| /* 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' < 10U && x <= UINT_MAX / 10 - 1; c = shgetc(f)) |
| x = x * 10 + (c - '0'); |
| for (y = x; c - '0' < 10U && y <= ULLONG_MAX / 10 && |
| 10 * y <= ULLONG_MAX - (c - '0'); |
| c = shgetc(f)) |
| y = y * 10 + (c - '0'); |
| if (c - '0' >= 10U) |
| 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; |
| } |