// 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 strconvimport// lower(c) is a lower-case letter if and only if// c is either that lower-case letter or the equivalent upper-case letter.// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'.// Note that lower of non-letters can produce other non-letters.func ( byte) byte {return | ('x' - 'X')}// ErrRange indicates that a value is out of range for the target type.varErrRange = errors.New("value out of range")// ErrSyntax indicates that a value does not have the right syntax for the target type.varErrSyntax = errors.New("invalid syntax")// A NumError records a failed conversion.typeNumErrorstruct { Func string// the failing function (ParseBool, ParseInt, ParseUint, ParseFloat, ParseComplex) Num string// the input Err error// the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)}func ( *NumError) () string {return"strconv." + .Func + ": " + "parsing " + Quote(.Num) + ": " + .Err.Error()}func ( *NumError) () error { return .Err }func (, string) *NumError {return &NumError{, , ErrSyntax}}func (, string) *NumError {return &NumError{, , ErrRange}}func (, string, int) *NumError {return &NumError{, , errors.New("invalid base " + Itoa())}}func (, string, int) *NumError {return &NumError{, , errors.New("invalid bit size " + Itoa())}}constintSize = 32 << (^uint(0) >> 63)// IntSize is the size in bits of an int or uint value.constIntSize = intSizeconstmaxUint64 = 1<<64 - 1// ParseUint is like ParseInt but for unsigned numbers.func ( string, int, int) (uint64, error) {const = "ParseUint"if == "" {return0, syntaxError(, ) } := == 0 := switch {case2 <= && <= 36:// valid base; nothing to docase == 0:// Look for octal, hex prefix. = 10if [0] == '0' {switch {caselen() >= 3 && lower([1]) == 'b': = 2 = [2:]caselen() >= 3 && lower([1]) == 'o': = 8 = [2:]caselen() >= 3 && lower([1]) == 'x': = 16 = [2:]default: = 8 = [1:] } }default:return0, baseError(, , ) }if == 0 { = IntSize } elseif < 0 || > 64 {return0, bitSizeError(, , ) }// Cutoff is the smallest number such that cutoff*base > maxUint64. // Use compile-time constants for common cases.varuint64switch {case10: = maxUint64/10 + 1case16: = maxUint64/16 + 1default: = maxUint64/uint64() + 1 } := uint64(1)<<uint() - 1 := falsevaruint64for , := range []byte() {varbyteswitch {case == '_' && : = truecontinuecase'0' <= && <= '9': = - '0'case'a' <= lower() && lower() <= 'z': = lower() - 'a' + 10default:return0, syntaxError(, ) }if >= byte() {return0, syntaxError(, ) }if >= {// n*base overflowsreturn , rangeError(, ) } *= uint64() := + uint64()if < || > {// n+v overflowsreturn , rangeError(, ) } = }if && !underscoreOK() {return0, syntaxError(, ) }return , nil}// ParseInt interprets a string s in the given base (0, 2 to 36) and// bit size (0 to 64) and returns the corresponding value i.//// If the base argument is 0, the true base is implied by the string's// prefix: 2 for "0b", 8 for "0" or "0o", 16 for "0x", and 10 otherwise.// Also, for argument base 0 only, underscore characters are permitted// as defined by the Go syntax for integer literals.//// 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.// If bitSize is below 0 or above 64, an error is returned.//// 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 ( string, int, int) ( int64, error) {const = "ParseInt"if == "" {return0, syntaxError(, ) }// Pick off leading sign. := := falseif [0] == '+' { = [1:] } elseif [0] == '-' { = true = [1:] }// Convert unsigned and check range.varuint64 , = ParseUint(, , )if != nil && .(*NumError).Err != ErrRange { .(*NumError).Func = .(*NumError).Num = return0, }if == 0 { = IntSize } := uint64(1 << uint(-1))if ! && >= {returnint64( - 1), rangeError(, ) }if && > {return -int64(), rangeError(, ) } := int64()if { = - }return , nil}// Atoi is equivalent to ParseInt(s, 10, 0), converted to type int.func ( string) (int, error) {const = "Atoi" := len()ifintSize == 32 && (0 < && < 10) ||intSize == 64 && (0 < && < 19) {// Fast path for small integers that fit int type. := if [0] == '-' || [0] == '+' { = [1:]iflen() < 1 {return0, &NumError{, , ErrSyntax} } } := 0for , := range []byte() { -= '0'if > 9 {return0, &NumError{, , ErrSyntax} } = *10 + int() }if [0] == '-' { = - }return , nil }// Slow path for invalid, big, or underscored integers. , := ParseInt(, 10, 0)if , := .(*NumError); { .Func = }returnint(), }// underscoreOK reports whether the underscores in s are allowed.// Checking them in this one function lets all the parsers skip over them simply.// Underscore must appear only between digits or between a base prefix and a digit.func ( string) bool {// saw tracks the last character (class) we saw: // ^ for beginning of number, // 0 for a digit or base prefix, // _ for an underscore, // ! for none of the above. := '^' := 0// Optional sign.iflen() >= 1 && ([0] == '-' || [0] == '+') { = [1:] }// Optional base prefix. := falseiflen() >= 2 && [0] == '0' && (lower([1]) == 'b' || lower([1]) == 'o' || lower([1]) == 'x') { = 2 = '0'// base prefix counts as a digit for "underscore as digit separator" = lower([1]) == 'x' }// Number proper.for ; < len(); ++ {// Digits are always okay.if'0' <= [] && [] <= '9' || && 'a' <= lower([]) && lower([]) <= 'f' { = '0'continue }// Underscore must follow digit.if [] == '_' {if != '0' {returnfalse } = '_'continue }// Underscore must also be followed by digit.if == '_' {returnfalse }// Saw non-digit, non-underscore. = '!' }return != '_'}