1 // ----------------------------------------------------------------------
2 // Copyright © 2005-2014 Rich Felker, et al.
3 // Copyright 2014 The Android Open Source Project.
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 // ----------------------------------------------------------------------
24
25 #include <limits.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include "shgetc.h"
29
30 // ANDROID: Redefine FILE to use our custom stream abstraction.
31 #undef FILE
32 #define FILE struct fake_file_t
33
34 /* Lookup table for digit values. -1==255>=36 -> invalid */
35 static const unsigned char table[] = { -1,
36 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
37 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
38 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
39 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
40 -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
41 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
42 -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
43 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
44 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
45 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
46 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
47 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
48 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
49 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
50 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
51 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
52 };
53
__intscan(FILE * f,unsigned base,int pok,unsigned long long lim)54 unsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long lim)
55 {
56 const unsigned char *val = table+1;
57 int c, neg=0;
58 unsigned x;
59 unsigned long long y;
60 if (base > 36) {
61 errno = EINVAL;
62 return 0;
63 }
64 while (isspace((c=shgetc(f))));
65 if (c=='+' || c=='-') {
66 neg = -(c=='-');
67 c = shgetc(f);
68 }
69 if ((base == 0 || base == 16) && c=='0') {
70 c = shgetc(f);
71 if ((c|32)=='x') {
72 c = shgetc(f);
73 if (val[c]>=16) {
74 shunget(f);
75 if (pok) shunget(f);
76 else shlim(f, 0);
77 return 0;
78 }
79 base = 16;
80 } else if (base == 0) {
81 base = 8;
82 }
83 } else {
84 if (base == 0) base = 10;
85 if (val[c] >= base) {
86 shunget(f);
87 shlim(f, 0);
88 errno = EINVAL;
89 return 0;
90 }
91 }
92 if (base == 10) {
93 for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f))
94 x = x*10 + (c-'0');
95 for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f))
96 y = y*10 + (c-'0');
97 if (c-'0'>=10U) goto done;
98 } else if (!(base & base-1)) {
99 int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7];
100 for (x=0; val[c]<base && x<=UINT_MAX/32; c=shgetc(f))
101 x = x<<bs | val[c];
102 for (y=x; val[c]<base && y<=ULLONG_MAX>>bs; c=shgetc(f))
103 y = y<<bs | val[c];
104 } else {
105 for (x=0; val[c]<base && x<=UINT_MAX/36-1; c=shgetc(f))
106 x = x*base + val[c];
107 for (y=x; val[c]<base && y<=ULLONG_MAX/base && base*y<=ULLONG_MAX-val[c]; c=shgetc(f))
108 y = y*base + val[c];
109 }
110 if (val[c]<base) {
111 for (; val[c]<base; c=shgetc(f));
112 errno = ERANGE;
113 y = lim;
114 }
115 done:
116 shunget(f);
117 if (y>=lim) {
118 if (!(lim&1) && !neg) {
119 errno = ERANGE;
120 return lim-1;
121 } else if (y>lim) {
122 errno = ERANGE;
123 return lim;
124 }
125 }
126 return (y^neg)-neg;
127 }
128