|  | // Copyright 2009 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package strconv | 
|  |  | 
|  | import "errors" | 
|  |  | 
|  | // ErrRange indicates that a value is out of range for the target type. | 
|  | var ErrRange = errors.New("value out of range") | 
|  |  | 
|  | // ErrSyntax indicates that a value does not have the right syntax for the target type. | 
|  | var ErrSyntax = errors.New("invalid syntax") | 
|  |  | 
|  | // A NumError records a failed conversion. | 
|  | type NumError struct { | 
|  | Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat) | 
|  | Num  string // the input | 
|  | Err  error  // the reason the conversion failed (ErrRange, ErrSyntax) | 
|  | } | 
|  |  | 
|  | func (e *NumError) Error() string { | 
|  | return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error() | 
|  | } | 
|  |  | 
|  | func syntaxError(fn, str string) *NumError { | 
|  | return &NumError{fn, str, ErrSyntax} | 
|  | } | 
|  |  | 
|  | func rangeError(fn, str string) *NumError { | 
|  | return &NumError{fn, str, ErrRange} | 
|  | } | 
|  |  | 
|  | const intSize = 32 << (^uint(0) >> 63) | 
|  |  | 
|  | // IntSize is the size in bits of an int or uint value. | 
|  | const IntSize = intSize | 
|  |  | 
|  | // Return the first number n such that n*base >= 1<<64. | 
|  | func cutoff64(base int) uint64 { | 
|  | if base < 2 { | 
|  | return 0 | 
|  | } | 
|  | return (1<<64-1)/uint64(base) + 1 | 
|  | } | 
|  |  | 
|  | // ParseUint is like ParseInt but for unsigned numbers. | 
|  | func ParseUint(s string, base int, bitSize int) (n uint64, err error) { | 
|  | var cutoff, maxVal uint64 | 
|  |  | 
|  | if bitSize == 0 { | 
|  | bitSize = int(IntSize) | 
|  | } | 
|  |  | 
|  | s0 := s | 
|  | switch { | 
|  | case len(s) < 1: | 
|  | err = ErrSyntax | 
|  | goto Error | 
|  |  | 
|  | case 2 <= base && base <= 36: | 
|  | // valid base; nothing to do | 
|  |  | 
|  | case base == 0: | 
|  | // Look for octal, hex prefix. | 
|  | switch { | 
|  | case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): | 
|  | base = 16 | 
|  | s = s[2:] | 
|  | if len(s) < 1 { | 
|  | err = ErrSyntax | 
|  | goto Error | 
|  | } | 
|  | case s[0] == '0': | 
|  | base = 8 | 
|  | default: | 
|  | base = 10 | 
|  | } | 
|  |  | 
|  | default: | 
|  | err = errors.New("invalid base " + Itoa(base)) | 
|  | goto Error | 
|  | } | 
|  |  | 
|  | n = 0 | 
|  | cutoff = cutoff64(base) | 
|  | maxVal = 1<<uint(bitSize) - 1 | 
|  |  | 
|  | for i := 0; i < len(s); i++ { | 
|  | var v byte | 
|  | d := s[i] | 
|  | switch { | 
|  | case '0' <= d && d <= '9': | 
|  | v = d - '0' | 
|  | case 'a' <= d && d <= 'z': | 
|  | v = d - 'a' + 10 | 
|  | case 'A' <= d && d <= 'Z': | 
|  | v = d - 'A' + 10 | 
|  | default: | 
|  | n = 0 | 
|  | err = ErrSyntax | 
|  | goto Error | 
|  | } | 
|  | if int(v) >= base { | 
|  | n = 0 | 
|  | err = ErrSyntax | 
|  | goto Error | 
|  | } | 
|  |  | 
|  | if n >= cutoff { | 
|  | // n*base overflows | 
|  | n = 1<<64 - 1 | 
|  | err = ErrRange | 
|  | goto Error | 
|  | } | 
|  | n *= uint64(base) | 
|  |  | 
|  | n1 := n + uint64(v) | 
|  | if n1 < n || n1 > maxVal { | 
|  | // n+v overflows | 
|  | n = 1<<64 - 1 | 
|  | err = ErrRange | 
|  | goto Error | 
|  | } | 
|  | n = n1 | 
|  | } | 
|  |  | 
|  | return n, nil | 
|  |  | 
|  | Error: | 
|  | return n, &NumError{"ParseUint", s0, err} | 
|  | } | 
|  |  | 
|  | // ParseInt interprets a string s in the given base (2 to 36) and | 
|  | // returns the corresponding value i.  If base == 0, the base is | 
|  | // implied by the string's prefix: base 16 for "0x", base 8 for | 
|  | // "0", and base 10 otherwise. | 
|  | // | 
|  | // The bitSize argument specifies the integer type | 
|  | // that the result must fit into.  Bit sizes 0, 8, 16, 32, and 64 | 
|  | // correspond to int, int8, int16, int32, and int64. | 
|  | // | 
|  | // The errors that ParseInt returns have concrete type *NumError | 
|  | // and include err.Num = s.  If s is empty or contains invalid | 
|  | // digits, err.Err = ErrSyntax and the returned value is 0; | 
|  | // if the value corresponding to s cannot be represented by a | 
|  | // signed integer of the given size, err.Err = ErrRange and the | 
|  | // returned value is the maximum magnitude integer of the | 
|  | // appropriate bitSize and sign. | 
|  | func ParseInt(s string, base int, bitSize int) (i int64, err error) { | 
|  | const fnParseInt = "ParseInt" | 
|  |  | 
|  | if bitSize == 0 { | 
|  | bitSize = int(IntSize) | 
|  | } | 
|  |  | 
|  | // Empty string bad. | 
|  | if len(s) == 0 { | 
|  | return 0, syntaxError(fnParseInt, s) | 
|  | } | 
|  |  | 
|  | // Pick off leading sign. | 
|  | s0 := s | 
|  | neg := false | 
|  | if s[0] == '+' { | 
|  | s = s[1:] | 
|  | } else if s[0] == '-' { | 
|  | neg = true | 
|  | s = s[1:] | 
|  | } | 
|  |  | 
|  | // Convert unsigned and check range. | 
|  | var un uint64 | 
|  | un, err = ParseUint(s, base, bitSize) | 
|  | if err != nil && err.(*NumError).Err != ErrRange { | 
|  | err.(*NumError).Func = fnParseInt | 
|  | err.(*NumError).Num = s0 | 
|  | return 0, err | 
|  | } | 
|  | cutoff := uint64(1 << uint(bitSize-1)) | 
|  | if !neg && un >= cutoff { | 
|  | return int64(cutoff - 1), rangeError(fnParseInt, s0) | 
|  | } | 
|  | if neg && un > cutoff { | 
|  | return -int64(cutoff), rangeError(fnParseInt, s0) | 
|  | } | 
|  | n := int64(un) | 
|  | if neg { | 
|  | n = -n | 
|  | } | 
|  | return n, nil | 
|  | } | 
|  |  | 
|  | // Atoi is shorthand for ParseInt(s, 10, 0). | 
|  | func Atoi(s string) (i int, err error) { | 
|  | i64, err := ParseInt(s, 10, 0) | 
|  | return int(i64), err | 
|  | } |