refactor headers, especially alltypes.h, and improve C++ ABI compat
[musl] / src / internal / intscan.c
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 */
7 static 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,
13 25,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,
15 25,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
26 unsigned 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         }
87 done:
88         shunget(f);
89         if (y>=lim) {
90                 if (!(lim&1) && !neg) {
91                         errno = ERANGE;
92                         return lim-1;
93                 } else if (y>lim) {
94                         errno = ERANGE;
95                         return lim;
96                 }
97         }
98         return (y^neg)-neg;
99 }