1570af302Sopenharmony_ci#include <limits.h>
2570af302Sopenharmony_ci#include <errno.h>
3570af302Sopenharmony_ci#include <ctype.h>
4570af302Sopenharmony_ci#include "shgetc.h"
5570af302Sopenharmony_ci
6570af302Sopenharmony_ci/* Lookup table for digit values. -1==255>=36 -> invalid */
7570af302Sopenharmony_cistatic const unsigned char table[] = { -1,
8570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
9570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
10570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
11570af302Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
12570af302Sopenharmony_ci-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
13570af302Sopenharmony_ci25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
14570af302Sopenharmony_ci-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
15570af302Sopenharmony_ci25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
16570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
17570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
18570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
19570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
20570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
21570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
22570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
23570af302Sopenharmony_ci-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
24570af302Sopenharmony_ci};
25570af302Sopenharmony_ci
26570af302Sopenharmony_ciunsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long lim)
27570af302Sopenharmony_ci{
28570af302Sopenharmony_ci	const unsigned char *val = table+1;
29570af302Sopenharmony_ci	int c, neg=0;
30570af302Sopenharmony_ci	unsigned x;
31570af302Sopenharmony_ci	unsigned long long y;
32570af302Sopenharmony_ci	if (base > 36 || base == 1) {
33570af302Sopenharmony_ci		errno = EINVAL;
34570af302Sopenharmony_ci		return 0;
35570af302Sopenharmony_ci	}
36570af302Sopenharmony_ci	while (isspace((c=shgetc(f))));
37570af302Sopenharmony_ci	if (c=='+' || c=='-') {
38570af302Sopenharmony_ci		neg = -(c=='-');
39570af302Sopenharmony_ci		c = shgetc(f);
40570af302Sopenharmony_ci	}
41570af302Sopenharmony_ci	if ((base == 0 || base == 16) && c=='0') {
42570af302Sopenharmony_ci		c = shgetc(f);
43570af302Sopenharmony_ci		if ((c|32)=='x') {
44570af302Sopenharmony_ci			c = shgetc(f);
45570af302Sopenharmony_ci			if (val[c]>=16) {
46570af302Sopenharmony_ci				shunget(f);
47570af302Sopenharmony_ci				if (pok) shunget(f);
48570af302Sopenharmony_ci				else shlim(f, 0);
49570af302Sopenharmony_ci				return 0;
50570af302Sopenharmony_ci			}
51570af302Sopenharmony_ci			base = 16;
52570af302Sopenharmony_ci		} else if (base == 0) {
53570af302Sopenharmony_ci			base = 8;
54570af302Sopenharmony_ci		}
55570af302Sopenharmony_ci	} else {
56570af302Sopenharmony_ci		if (base == 0) base = 10;
57570af302Sopenharmony_ci		if (val[c] >= base) {
58570af302Sopenharmony_ci			shunget(f);
59570af302Sopenharmony_ci			shlim(f, 0);
60570af302Sopenharmony_ci			errno = EINVAL;
61570af302Sopenharmony_ci			return 0;
62570af302Sopenharmony_ci		}
63570af302Sopenharmony_ci	}
64570af302Sopenharmony_ci	if (base == 10) {
65570af302Sopenharmony_ci		for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f))
66570af302Sopenharmony_ci			x = x*10 + (c-'0');
67570af302Sopenharmony_ci		for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f))
68570af302Sopenharmony_ci			y = y*10 + (c-'0');
69570af302Sopenharmony_ci		if (c-'0'>=10U) goto done;
70570af302Sopenharmony_ci	} else if (!(base & base-1)) {
71570af302Sopenharmony_ci		int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7];
72570af302Sopenharmony_ci		for (x=0; val[c]<base && x<=UINT_MAX/32; c=shgetc(f))
73570af302Sopenharmony_ci			x = x<<bs | val[c];
74570af302Sopenharmony_ci		for (y=x; val[c]<base && y<=ULLONG_MAX>>bs; c=shgetc(f))
75570af302Sopenharmony_ci			y = y<<bs | val[c];
76570af302Sopenharmony_ci	} else {
77570af302Sopenharmony_ci		for (x=0; val[c]<base && x<=UINT_MAX/36-1; c=shgetc(f))
78570af302Sopenharmony_ci			x = x*base + val[c];
79570af302Sopenharmony_ci		for (y=x; val[c]<base && y<=ULLONG_MAX/base && base*y<=ULLONG_MAX-val[c]; c=shgetc(f))
80570af302Sopenharmony_ci			y = y*base + val[c];
81570af302Sopenharmony_ci	}
82570af302Sopenharmony_ci	if (val[c]<base) {
83570af302Sopenharmony_ci		for (; val[c]<base; c=shgetc(f));
84570af302Sopenharmony_ci		errno = ERANGE;
85570af302Sopenharmony_ci		y = lim;
86570af302Sopenharmony_ci		if (lim&1) neg = 0;
87570af302Sopenharmony_ci	}
88570af302Sopenharmony_cidone:
89570af302Sopenharmony_ci	shunget(f);
90570af302Sopenharmony_ci	if (y>=lim) {
91570af302Sopenharmony_ci		if (!(lim&1) && !neg) {
92570af302Sopenharmony_ci			errno = ERANGE;
93570af302Sopenharmony_ci			return lim-1;
94570af302Sopenharmony_ci		} else if (y>lim) {
95570af302Sopenharmony_ci			errno = ERANGE;
96570af302Sopenharmony_ci			return lim;
97570af302Sopenharmony_ci		}
98570af302Sopenharmony_ci	}
99570af302Sopenharmony_ci	return (y^neg)-neg;
100570af302Sopenharmony_ci}
101