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