1
2
3
4
5 package strconv
6
7 import "os"
8
9 type NumError struct {
10 Num string
11 Error os.Error
12 }
13
14 func (e *NumError) String() string { return `parsing "` + e.Num + `": ` + e.Error.String() }
15
16 func computeIntsize() uint {
17 siz := uint(8)
18 for 1<<siz != 0 {
19 siz *= 2
20 }
21 return siz
22 }
23
24 var IntSize = computeIntsize()
25
26
27 func cutoff64(base int) uint64 {
28 if base < 2 {
29 return 0
30 }
31 return (1<<64-1)/uint64(base) + 1
32 }
33
34
35
36
37
38
39
40
41
42
43 func Btoui64(s string, b int) (n uint64, err os.Error) {
44 var cutoff uint64
45
46 s0 := s
47 switch {
48 case len(s) < 1:
49 err = os.EINVAL
50 goto Error
51
52 case 2 <= b && b <= 36:
53
54
55 case b == 0:
56
57 switch {
58 case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
59 b = 16
60 s = s[2:]
61 if len(s) < 1 {
62 err = os.EINVAL
63 goto Error
64 }
65 case s[0] == '0':
66 b = 8
67 default:
68 b = 10
69 }
70
71 default:
72 err = os.NewError("invalid base " + Itoa(b))
73 goto Error
74 }
75
76 n = 0
77 cutoff = cutoff64(b)
78
79 for i := 0; i < len(s); i++ {
80 var v byte
81 d := s[i]
82 switch {
83 case '0' <= d && d <= '9':
84 v = d - '0'
85 case 'a' <= d && d <= 'z':
86 v = d - 'a' + 10
87 case 'A' <= d && d <= 'Z':
88 v = d - 'A' + 10
89 default:
90 n = 0
91 err = os.EINVAL
92 goto Error
93 }
94 if int(v) >= b {
95 n = 0
96 err = os.EINVAL
97 goto Error
98 }
99
100 if n >= cutoff {
101
102 n = 1<<64 - 1
103 err = os.ERANGE
104 goto Error
105 }
106 n *= uint64(b)
107
108 n1 := n + uint64(v)
109 if n1 < n {
110
111 n = 1<<64 - 1
112 err = os.ERANGE
113 goto Error
114 }
115 n = n1
116 }
117
118 return n, nil
119
120 Error:
121 return n, &NumError{s0, err}
122 }
123
124
125
126
127
128
129 func Atoui64(s string) (n uint64, err os.Error) {
130 return Btoui64(s, 10)
131 }
132
133
134
135 func Btoi64(s string, base int) (i int64, err os.Error) {
136
137 if len(s) == 0 {
138 return 0, &NumError{s, os.EINVAL}
139 }
140
141
142 s0 := s
143 neg := false
144 if s[0] == '+' {
145 s = s[1:]
146 } else if s[0] == '-' {
147 neg = true
148 s = s[1:]
149 }
150
151
152 var un uint64
153 un, err = Btoui64(s, base)
154 if err != nil && err.(*NumError).Error != os.ERANGE {
155 err.(*NumError).Num = s0
156 return 0, err
157 }
158 if !neg && un >= 1<<63 {
159 return 1<<63 - 1, &NumError{s0, os.ERANGE}
160 }
161 if neg && un > 1<<63 {
162 return -1 << 63, &NumError{s0, os.ERANGE}
163 }
164 n := int64(un)
165 if neg {
166 n = -n
167 }
168 return n, nil
169 }
170
171
172
173 func Atoi64(s string) (i int64, err os.Error) { return Btoi64(s, 10) }
174
175
176 func Atoui(s string) (i uint, err os.Error) {
177 i1, e1 := Atoui64(s)
178 if e1 != nil && e1.(*NumError).Error != os.ERANGE {
179 return 0, e1
180 }
181 i = uint(i1)
182 if uint64(i) != i1 {
183 return ^uint(0), &NumError{s, os.ERANGE}
184 }
185 return i, nil
186 }
187
188
189 func Atoi(s string) (i int, err os.Error) {
190 i1, e1 := Atoi64(s)
191 if e1 != nil && e1.(*NumError).Error != os.ERANGE {
192 return 0, e1
193 }
194 i = int(i1)
195 if int64(i) != i1 {
196 if i1 < 0 {
197 return -1 << (IntSize - 1), &NumError{s, os.ERANGE}
198 }
199 return 1<<(IntSize-1) - 1, &NumError{s, os.ERANGE}
200 }
201 return i, nil
202 }