1#include "shgetc.h"
2#include <ctype.h>
3#include <errno.h>
4#include <limits.h>
5
6/* Lookup table for digit values. -1==255>=36 -> invalid */
7static const unsigned char table[] = {
8    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
9    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
10    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15,
11    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1,
12    -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
13    32, 33, 34, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
14    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
15    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
16    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
17    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
19};
20
21unsigned long long __intscan(FILE* f, unsigned base, int pok, unsigned long long lim) {
22    const unsigned char* val = table + 1;
23    int c, neg = 0;
24    unsigned x;
25    unsigned long long y;
26    if (base > 36) {
27        errno = EINVAL;
28        return 0;
29    }
30    while (isspace((c = shgetc(f))))
31        ;
32    if (c == '+' || c == '-') {
33        neg = -(c == '-');
34        c = shgetc(f);
35    }
36    if ((base == 0 || base == 16) && c == '0') {
37        c = shgetc(f);
38        if ((c | 32) == 'x') {
39            c = shgetc(f);
40            if (val[c] >= 16) {
41                shunget(f);
42                if (pok)
43                    shunget(f);
44                else
45                    shlim(f, 0);
46                return 0;
47            }
48            base = 16;
49        } else if (base == 0) {
50            base = 8;
51        }
52    } else {
53        if (base == 0)
54            base = 10;
55        if (val[c] >= base) {
56            shunget(f);
57            shlim(f, 0);
58            errno = EINVAL;
59            return 0;
60        }
61    }
62    if (base == 10) {
63        for (x = 0; c >= '0' && c <= '9' && x <= UINT_MAX / 10 - 1; c = shgetc(f))
64            x = x * 10 + (c - '0');
65        for (y = x; c >= '0' && c <= '9' && y <= ULLONG_MAX / 10 && 10 * y <= ULLONG_MAX - (c - '0');
66             c = shgetc(f))
67            y = y * 10 + (c - '0');
68        if (c < '0' || c > '9')
69            goto done;
70    } else if (!(base & (base - 1))) {
71        int bs = "\0\1\2\4\7\3\6\5"[(0x17 * base) >> 5 & 7];
72        for (x = 0; val[c] < base && x <= UINT_MAX / 32; c = shgetc(f))
73            x = x << bs | val[c];
74        for (y = x; val[c] < base && y <= ULLONG_MAX >> bs; c = shgetc(f))
75            y = y << bs | val[c];
76    } else {
77        for (x = 0; val[c] < base && x <= UINT_MAX / 36 - 1; c = shgetc(f))
78            x = x * base + val[c];
79        for (y = x; val[c] < base && y <= ULLONG_MAX / base && base * y <= ULLONG_MAX - val[c];
80             c = shgetc(f))
81            y = y * base + val[c];
82    }
83    if (val[c] < base) {
84        for (; val[c] < base; c = shgetc(f))
85            ;
86        errno = ERANGE;
87        y = lim;
88        if (lim & 1)
89            neg = 0;
90    }
91done:
92    shunget(f);
93    if (y >= lim) {
94        if (!(lim & 1) && !neg) {
95            errno = ERANGE;
96            return lim - 1;
97        } else if (y > lim) {
98            errno = ERANGE;
99            return lim;
100        }
101    }
102    return (y ^ neg) - neg;
103}
104