| // 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 "os" | 
 |  | 
 | type NumError struct { | 
 | 	Num   string | 
 | 	Error os.Error | 
 | } | 
 |  | 
 | func (e *NumError) String() string { return "parsing " + e.Num + ": " + e.Error.String() } | 
 |  | 
 |  | 
 | func computeIntsize() uint { | 
 | 	siz := uint(8) | 
 | 	for 1<<siz != 0 { | 
 | 		siz *= 2 | 
 | 	} | 
 | 	return siz | 
 | } | 
 |  | 
 | var IntSize = computeIntsize() | 
 |  | 
 | // 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 | 
 | } | 
 |  | 
 | // Btoui64 interprets a string s in an arbitrary base b (2 to 36) | 
 | // and returns the corresponding value n.  If b == 0, the base | 
 | // is taken from the string prefix: base 16 for "0x", base 8 for "0", | 
 | // and base 10 otherwise. | 
 | // | 
 | // The errors that Btoui64 returns have concrete type *NumError | 
 | // and include err.Num = s.  If s is empty or contains invalid | 
 | // digits, err.Error = os.EINVAL; if the value corresponding | 
 | // to s cannot be represented by a uint64, err.Error = os.ERANGE. | 
 | func Btoui64(s string, b int) (n uint64, err os.Error) { | 
 | 	s0 := s | 
 | 	switch { | 
 | 	case len(s) < 1: | 
 | 		err = os.EINVAL | 
 | 		goto Error | 
 |  | 
 | 	case 2 <= b && b <= 36: | 
 | 		// valid base; nothing to do | 
 |  | 
 | 	case b == 0: | 
 | 		// Look for octal, hex prefix. | 
 | 		switch { | 
 | 		case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): | 
 | 			b = 16 | 
 | 			s = s[2:] | 
 | 			if len(s) < 1 { | 
 | 				err = os.EINVAL | 
 | 				goto Error | 
 | 			} | 
 | 		case s[0] == '0': | 
 | 			b = 8 | 
 | 		default: | 
 | 			b = 10 | 
 | 		} | 
 |  | 
 | 	default: | 
 | 		err = os.ErrorString("invalid base " + Itoa(b)) | 
 | 		goto Error | 
 | 	} | 
 |  | 
 | 	n = 0 | 
 | 	cutoff := cutoff64(b) | 
 |  | 
 | 	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 = os.EINVAL | 
 | 			goto Error | 
 | 		} | 
 | 		if int(v) >= b { | 
 | 			n = 0 | 
 | 			err = os.EINVAL | 
 | 			goto Error | 
 | 		} | 
 |  | 
 | 		if n >= cutoff { | 
 | 			// n*b overflows | 
 | 			n = 1<<64 - 1 | 
 | 			err = os.ERANGE | 
 | 			goto Error | 
 | 		} | 
 | 		n *= uint64(b) | 
 |  | 
 | 		n1 := n + uint64(v) | 
 | 		if n1 < n { | 
 | 			// n+v overflows | 
 | 			n = 1<<64 - 1 | 
 | 			err = os.ERANGE | 
 | 			goto Error | 
 | 		} | 
 | 		n = n1 | 
 | 	} | 
 |  | 
 | 	return n, nil | 
 |  | 
 | Error: | 
 | 	return n, &NumError{s0, err} | 
 | } | 
 |  | 
 | // Atoui64 interprets a string s as a decimal number and | 
 | // returns the corresponding value n. | 
 | // | 
 | // Atoui64 returns err == os.EINVAL if s is empty or contains invalid digits. | 
 | // It returns err == os.ERANGE if s cannot be represented by a uint64. | 
 | func Atoui64(s string) (n uint64, err os.Error) { | 
 | 	return Btoui64(s, 10) | 
 | } | 
 |  | 
 | // Btoi64 is like Btoui64 but allows signed numbers and | 
 | // returns its result in an int64. | 
 | func Btoi64(s string, base int) (i int64, err os.Error) { | 
 | 	// Empty string bad. | 
 | 	if len(s) == 0 { | 
 | 		return 0, &NumError{s, os.EINVAL} | 
 | 	} | 
 |  | 
 | 	// 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 = Btoui64(s, base) | 
 | 	if err != nil && err.(*NumError).Error != os.ERANGE { | 
 | 		err.(*NumError).Num = s0 | 
 | 		return 0, err | 
 | 	} | 
 | 	if !neg && un >= 1<<63 { | 
 | 		return 1<<63 - 1, &NumError{s0, os.ERANGE} | 
 | 	} | 
 | 	if neg && un > 1<<63 { | 
 | 		return -1 << 63, &NumError{s0, os.ERANGE} | 
 | 	} | 
 | 	n := int64(un) | 
 | 	if neg { | 
 | 		n = -n | 
 | 	} | 
 | 	return n, nil | 
 | } | 
 |  | 
 | // Atoi64 is like Atoui64 but allows signed numbers and | 
 | // returns its result in an int64. | 
 | func Atoi64(s string) (i int64, err os.Error) { return Btoi64(s, 10) } | 
 |  | 
 |  | 
 | // Atoui is like Atoui64 but returns its result as a uint. | 
 | func Atoui(s string) (i uint, err os.Error) { | 
 | 	i1, e1 := Atoui64(s) | 
 | 	if e1 != nil && e1.(*NumError).Error != os.ERANGE { | 
 | 		return 0, e1 | 
 | 	} | 
 | 	i = uint(i1) | 
 | 	if uint64(i) != i1 { | 
 | 		return ^uint(0), &NumError{s, os.ERANGE} | 
 | 	} | 
 | 	return i, nil | 
 | } | 
 |  | 
 | // Atoi is like Atoi64 but returns its result as an int. | 
 | func Atoi(s string) (i int, err os.Error) { | 
 | 	i1, e1 := Atoi64(s) | 
 | 	if e1 != nil && e1.(*NumError).Error != os.ERANGE { | 
 | 		return 0, e1 | 
 | 	} | 
 | 	i = int(i1) | 
 | 	if int64(i) != i1 { | 
 | 		if i1 < 0 { | 
 | 			return -1 << (IntSize - 1), &NumError{s, os.ERANGE} | 
 | 		} | 
 | 		return 1<<(IntSize-1) - 1, &NumError{s, os.ERANGE} | 
 | 	} | 
 | 	return i, nil | 
 | } |