1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package strconv
6
7import "errors"
8
9// ErrRange indicates that a value is out of range for the target type.
10var ErrRange = errors.New("value out of range")
11
12// ErrSyntax indicates that a value does not have the right syntax for the target type.
13var ErrSyntax = errors.New("invalid syntax")
14
15// A NumError records a failed conversion.
16type NumError struct {
17	Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat)
18	Num  string // the input
19	Err  error  // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)
20}
21
22func (e *NumError) Error() string {
23	return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error()
24}
25
26func syntaxError(fn, str string) *NumError {
27	return &NumError{fn, str, ErrSyntax}
28}
29
30func rangeError(fn, str string) *NumError {
31	return &NumError{fn, str, ErrRange}
32}
33
34func baseError(fn, str string, base int) *NumError {
35	return &NumError{fn, str, errors.New("invalid base " + Itoa(base))}
36}
37
38func bitSizeError(fn, str string, bitSize int) *NumError {
39	return &NumError{fn, str, errors.New("invalid bit size " + Itoa(bitSize))}
40}
41
42const intSize = 32 << (^uint(0) >> 63)
43
44// IntSize is the size in bits of an int or uint value.
45const IntSize = intSize
46
47const maxUint64 = 1<<64 - 1
48
49// ParseUint is like ParseInt but for unsigned numbers.
50func ParseUint(s string, base int, bitSize int) (uint64, error) {
51	const fnParseUint = "ParseUint"
52
53	if len(s) == 0 {
54		return 0, syntaxError(fnParseUint, s)
55	}
56
57	s0 := s
58	switch {
59	case 2 <= base && base <= 36:
60		// valid base; nothing to do
61
62	case base == 0:
63		// Look for octal, hex prefix.
64		switch {
65		case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
66			if len(s) < 3 {
67				return 0, syntaxError(fnParseUint, s0)
68			}
69			base = 16
70			s = s[2:]
71		case s[0] == '0':
72			base = 8
73			s = s[1:]
74		default:
75			base = 10
76		}
77
78	default:
79		return 0, baseError(fnParseUint, s0, base)
80	}
81
82	if bitSize == 0 {
83		bitSize = int(IntSize)
84	} else if bitSize < 0 || bitSize > 64 {
85		return 0, bitSizeError(fnParseUint, s0, bitSize)
86	}
87
88	// Cutoff is the smallest number such that cutoff*base > maxUint64.
89	// Use compile-time constants for common cases.
90	var cutoff uint64
91	switch base {
92	case 10:
93		cutoff = maxUint64/10 + 1
94	case 16:
95		cutoff = maxUint64/16 + 1
96	default:
97		cutoff = maxUint64/uint64(base) + 1
98	}
99
100	maxVal := uint64(1)<<uint(bitSize) - 1
101
102	var n uint64
103	for _, c := range []byte(s) {
104		var d byte
105		switch {
106		case '0' <= c && c <= '9':
107			d = c - '0'
108		case 'a' <= c && c <= 'z':
109			d = c - 'a' + 10
110		case 'A' <= c && c <= 'Z':
111			d = c - 'A' + 10
112		default:
113			return 0, syntaxError(fnParseUint, s0)
114		}
115
116		if d >= byte(base) {
117			return 0, syntaxError(fnParseUint, s0)
118		}
119
120		if n >= cutoff {
121			// n*base overflows
122			return maxVal, rangeError(fnParseUint, s0)
123		}
124		n *= uint64(base)
125
126		n1 := n + uint64(d)
127		if n1 < n || n1 > maxVal {
128			// n+v overflows
129			return maxVal, rangeError(fnParseUint, s0)
130		}
131		n = n1
132	}
133
134	return n, nil
135}
136
137// ParseInt interprets a string s in the given base (0, 2 to 36) and
138// bit size (0 to 64) and returns the corresponding value i.
139//
140// If base == 0, the base is implied by the string's prefix:
141// base 16 for "0x", base 8 for "0", and base 10 otherwise.
142// For bases 1, below 0 or above 36 an error is returned.
143//
144// The bitSize argument specifies the integer type
145// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
146// correspond to int, int8, int16, int32, and int64.
147// For a bitSize below 0 or above 64 an error is returned.
148//
149// The errors that ParseInt returns have concrete type *NumError
150// and include err.Num = s. If s is empty or contains invalid
151// digits, err.Err = ErrSyntax and the returned value is 0;
152// if the value corresponding to s cannot be represented by a
153// signed integer of the given size, err.Err = ErrRange and the
154// returned value is the maximum magnitude integer of the
155// appropriate bitSize and sign.
156func ParseInt(s string, base int, bitSize int) (i int64, err error) {
157	const fnParseInt = "ParseInt"
158
159	// Empty string bad.
160	if len(s) == 0 {
161		return 0, syntaxError(fnParseInt, s)
162	}
163
164	// Pick off leading sign.
165	s0 := s
166	neg := false
167	if s[0] == '+' {
168		s = s[1:]
169	} else if s[0] == '-' {
170		neg = true
171		s = s[1:]
172	}
173
174	// Convert unsigned and check range.
175	var un uint64
176	un, err = ParseUint(s, base, bitSize)
177	if err != nil && err.(*NumError).Err != ErrRange {
178		err.(*NumError).Func = fnParseInt
179		err.(*NumError).Num = s0
180		return 0, err
181	}
182
183	if bitSize == 0 {
184		bitSize = int(IntSize)
185	}
186
187	cutoff := uint64(1 << uint(bitSize-1))
188	if !neg && un >= cutoff {
189		return int64(cutoff - 1), rangeError(fnParseInt, s0)
190	}
191	if neg && un > cutoff {
192		return -int64(cutoff), rangeError(fnParseInt, s0)
193	}
194	n := int64(un)
195	if neg {
196		n = -n
197	}
198	return n, nil
199}
200
201// Atoi is equivalent to ParseInt(s, 10, 0), converted to type int.
202func Atoi(s string) (int, error) {
203	const fnAtoi = "Atoi"
204
205	sLen := len(s)
206	if intSize == 32 && (0 < sLen && sLen < 10) ||
207		intSize == 64 && (0 < sLen && sLen < 19) {
208		// Fast path for small integers that fit int type.
209		s0 := s
210		if s[0] == '-' || s[0] == '+' {
211			s = s[1:]
212			if len(s) < 1 {
213				return 0, &NumError{fnAtoi, s0, ErrSyntax}
214			}
215		}
216
217		n := 0
218		for _, ch := range []byte(s) {
219			ch -= '0'
220			if ch > 9 {
221				return 0, &NumError{fnAtoi, s0, ErrSyntax}
222			}
223			n = n*10 + int(ch)
224		}
225		if s0[0] == '-' {
226			n = -n
227		}
228		return n, nil
229	}
230
231	// Slow path for invalid or big integers.
232	i64, err := ParseInt(s, 10, 0)
233	if nerr, ok := err.(*NumError); ok {
234		nerr.Func = fnAtoi
235	}
236	return int(i64), err
237}
238