1
2
3
4
5 package strconv
6
7
8
9
10
11 func lower(c byte) byte {
12 return c | ('x' - 'X')
13 }
14
15 type Error int
16
17 const (
18 _ Error = iota
19 ErrRange
20 ErrSyntax
21 ErrBase
22 ErrBitSize
23 )
24
25 func (e Error) Error() string {
26 switch e {
27 case ErrRange:
28 return "value out of range"
29 case ErrSyntax:
30 return "invalid syntax"
31 case ErrBase:
32 return "invalid base"
33 case ErrBitSize:
34 return "invalid bit size"
35 }
36 return "unknown error"
37 }
38
39 const intSize = 32 << (^uint(0) >> 63)
40
41
42 const IntSize = intSize
43
44
45
46
47 func ParseUint(s string, base int, bitSize int) (uint64, error) {
48 const fnParseUint = "ParseUint"
49
50 if s == "" {
51 return 0, ErrSyntax
52 }
53
54 base0 := base == 0
55
56 s0 := s
57 switch {
58 case 2 <= base && base <= 36:
59
60
61 case base == 0:
62
63 base = 10
64 if s[0] == '0' {
65 switch {
66 case len(s) >= 3 && lower(s[1]) == 'b':
67 base = 2
68 s = s[2:]
69 case len(s) >= 3 && lower(s[1]) == 'o':
70 base = 8
71 s = s[2:]
72 case len(s) >= 3 && lower(s[1]) == 'x':
73 base = 16
74 s = s[2:]
75 default:
76 base = 8
77 s = s[1:]
78 }
79 }
80
81 default:
82 return 0, ErrBase
83 }
84
85 if bitSize == 0 {
86 bitSize = IntSize
87 } else if bitSize < 0 || bitSize > 64 {
88 return 0, ErrBitSize
89 }
90
91
92
93 var cutoff uint64
94 switch base {
95 case 10:
96 cutoff = maxUint64/10 + 1
97 case 16:
98 cutoff = maxUint64/16 + 1
99 default:
100 cutoff = maxUint64/uint64(base) + 1
101 }
102
103 maxVal := uint64(1)<<uint(bitSize) - 1
104
105 underscores := false
106 var n uint64
107 for _, c := range []byte(s) {
108 var d byte
109 switch {
110 case c == '_' && base0:
111 underscores = true
112 continue
113 case '0' <= c && c <= '9':
114 d = c - '0'
115 case 'a' <= lower(c) && lower(c) <= 'z':
116 d = lower(c) - 'a' + 10
117 default:
118 return 0, ErrSyntax
119 }
120
121 if d >= byte(base) {
122 return 0, ErrSyntax
123 }
124
125 if n >= cutoff {
126
127 return maxVal, ErrRange
128 }
129 n *= uint64(base)
130
131 n1 := n + uint64(d)
132 if n1 < n || n1 > maxVal {
133
134 return maxVal, ErrRange
135 }
136 n = n1
137 }
138
139 if underscores && !underscoreOK(s0) {
140 return 0, ErrSyntax
141 }
142
143 return n, nil
144 }
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 func ParseInt(s string, base int, bitSize int) (i int64, err error) {
172 const fnParseInt = "ParseInt"
173
174 if s == "" {
175 return 0, ErrSyntax
176 }
177
178
179 neg := false
180 switch s[0] {
181 case '+':
182 s = s[1:]
183 case '-':
184 s = s[1:]
185 neg = true
186 }
187
188
189 var un uint64
190 un, err = ParseUint(s, base, bitSize)
191 if err != nil && err != ErrRange {
192 return 0, err
193 }
194
195 if bitSize == 0 {
196 bitSize = IntSize
197 }
198
199 cutoff := uint64(1 << uint(bitSize-1))
200 if !neg && un >= cutoff {
201 return int64(cutoff - 1), ErrRange
202 }
203 if neg && un > cutoff {
204 return -int64(cutoff), ErrRange
205 }
206 n := int64(un)
207 if neg {
208 n = -n
209 }
210 return n, nil
211 }
212
213
214 func Atoi(s string) (int, error) {
215 const fnAtoi = "Atoi"
216
217 sLen := len(s)
218 if intSize == 32 && (0 < sLen && sLen < 10) ||
219 intSize == 64 && (0 < sLen && sLen < 19) {
220
221 s0 := s
222 if s[0] == '-' || s[0] == '+' {
223 s = s[1:]
224 if len(s) < 1 {
225 return 0, ErrSyntax
226 }
227 }
228
229 n := 0
230 for _, ch := range []byte(s) {
231 ch -= '0'
232 if ch > 9 {
233 return 0, ErrSyntax
234 }
235 n = n*10 + int(ch)
236 }
237 if s0[0] == '-' {
238 n = -n
239 }
240 return n, nil
241 }
242
243
244 i64, err := ParseInt(s, 10, 0)
245 return int(i64), err
246 }
247
248
249
250
251 func underscoreOK(s string) bool {
252
253
254
255
256
257 saw := '^'
258 i := 0
259
260
261 if len(s) >= 1 && (s[0] == '-' || s[0] == '+') {
262 s = s[1:]
263 }
264
265
266 hex := false
267 if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') {
268 i = 2
269 saw = '0'
270 hex = lower(s[1]) == 'x'
271 }
272
273
274 for ; i < len(s); i++ {
275
276 if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' {
277 saw = '0'
278 continue
279 }
280
281 if s[i] == '_' {
282 if saw != '0' {
283 return false
284 }
285 saw = '_'
286 continue
287 }
288
289 if saw == '_' {
290 return false
291 }
292
293 saw = '!'
294 }
295 return saw != '_'
296 }
297
View as plain text