2008-11-17 13:34:03 -07:00
|
|
|
// 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
|
2009-08-12 14:18:37 -06:00
|
|
|
|
|
|
|
import "os"
|
2009-06-25 21:24:55 -06:00
|
|
|
|
|
|
|
type NumError struct {
|
2009-10-07 12:55:06 -06:00
|
|
|
Num string;
|
|
|
|
Error os.Error;
|
2009-06-25 21:24:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (e *NumError) String() string {
|
|
|
|
return "parsing " + e.Num + ": " + e.Error.String();
|
|
|
|
}
|
|
|
|
|
2008-11-18 18:12:07 -07:00
|
|
|
|
2009-01-15 18:22:17 -07:00
|
|
|
func computeIntsize() uint {
|
2008-11-18 18:12:07 -07:00
|
|
|
siz := uint(8);
|
|
|
|
for 1<<siz != 0 {
|
2009-10-07 12:55:06 -06:00
|
|
|
siz *= 2;
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2009-10-07 12:55:06 -06:00
|
|
|
return siz;
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2009-10-07 12:55:06 -06:00
|
|
|
|
|
|
|
var IntSize = computeIntsize()
|
2008-11-17 13:34:03 -07:00
|
|
|
|
2009-02-16 21:44:21 -07:00
|
|
|
// Return the first number n such that n*base >= 1<<64.
|
|
|
|
func cutoff64(base int) uint64 {
|
|
|
|
if base < 2 {
|
|
|
|
return 0;
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2009-10-07 12:55:06 -06:00
|
|
|
return (1<<64 - 1)/uint64(base) + 1;
|
2009-02-16 21:44:21 -07:00
|
|
|
}
|
2008-11-17 13:34:03 -07:00
|
|
|
|
2009-03-05 16:29:04 -07:00
|
|
|
// Btoui64 interprets a string s in an arbitrary base b (2 to 36)
|
2009-10-12 00:46:11 -06:00
|
|
|
// 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.
|
2009-03-05 16:29:04 -07:00
|
|
|
//
|
2009-06-25 21:24:55 -06:00
|
|
|
// 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.
|
2009-04-17 01:08:24 -06:00
|
|
|
func Btoui64(s string, b int) (n uint64, err os.Error) {
|
2009-10-12 00:46:11 -06:00
|
|
|
s0 := s;
|
|
|
|
switch {
|
|
|
|
case len(s) < 1:
|
2009-06-25 21:24:55 -06:00
|
|
|
err = os.EINVAL;
|
|
|
|
goto Error;
|
2009-10-12 00:46:11 -06:00
|
|
|
|
|
|
|
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:len(s)];
|
|
|
|
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;
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2008-11-18 18:12:07 -07:00
|
|
|
|
2009-02-16 21:44:21 -07:00
|
|
|
n = 0;
|
2009-03-05 16:29:04 -07:00
|
|
|
cutoff := cutoff64(b);
|
2008-11-17 13:34:03 -07:00
|
|
|
|
|
|
|
for i := 0; i < len(s); i++ {
|
2009-02-16 21:44:21 -07:00
|
|
|
var v byte;
|
|
|
|
switch {
|
|
|
|
case '0' <= s[i] && s[i] <= '9':
|
2009-10-07 12:55:06 -06:00
|
|
|
v = s[i]-'0';
|
2009-02-16 21:44:21 -07:00
|
|
|
case 'a' <= s[i] && s[i] <= 'z':
|
2009-10-07 12:55:06 -06:00
|
|
|
v = s[i]-'a'+10;
|
2009-02-16 21:44:21 -07:00
|
|
|
case 'A' <= s[i] && s[i] <= 'Z':
|
2009-10-07 12:55:06 -06:00
|
|
|
v = s[i]-'A'+10;
|
2009-02-16 21:44:21 -07:00
|
|
|
default:
|
2009-06-25 21:24:55 -06:00
|
|
|
n = 0;
|
|
|
|
err = os.EINVAL;
|
|
|
|
goto Error;
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2009-03-05 16:29:04 -07:00
|
|
|
if int(v) >= b {
|
2009-06-25 21:24:55 -06:00
|
|
|
n = 0;
|
|
|
|
err = os.EINVAL;
|
|
|
|
goto Error;
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2009-02-16 21:44:21 -07:00
|
|
|
|
|
|
|
if n >= cutoff {
|
2009-03-05 16:29:04 -07:00
|
|
|
// n*b overflows
|
2009-10-07 12:55:06 -06:00
|
|
|
n = 1<<64 - 1;
|
2009-06-25 21:24:55 -06:00
|
|
|
err = os.ERANGE;
|
|
|
|
goto Error;
|
2009-02-16 21:44:21 -07:00
|
|
|
}
|
2009-03-05 16:29:04 -07:00
|
|
|
n *= uint64(b);
|
2009-02-16 21:44:21 -07:00
|
|
|
|
|
|
|
n1 := n+uint64(v);
|
|
|
|
if n1 < n {
|
|
|
|
// n+v overflows
|
2009-10-07 12:55:06 -06:00
|
|
|
n = 1<<64 - 1;
|
2009-06-25 21:24:55 -06:00
|
|
|
err = os.ERANGE;
|
|
|
|
goto Error;
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2009-02-16 21:44:21 -07:00
|
|
|
n = n1;
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2009-02-16 21:44:21 -07:00
|
|
|
|
|
|
|
return n, nil;
|
2009-06-25 21:24:55 -06:00
|
|
|
|
|
|
|
Error:
|
2009-10-12 00:46:11 -06:00
|
|
|
return n, &NumError{s0, err};
|
2009-02-16 21:44:21 -07:00
|
|
|
}
|
|
|
|
|
2009-10-12 00:46:11 -06:00
|
|
|
// Atoui64 interprets a string s as a decimal number and
|
|
|
|
// returns the corresponding value n.
|
2009-03-05 16:29:04 -07:00
|
|
|
//
|
|
|
|
// 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.
|
2009-04-17 01:08:24 -06:00
|
|
|
func Atoui64(s string) (n uint64, err os.Error) {
|
2009-10-12 00:46:11 -06:00
|
|
|
return Btoui64(s, 10);
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
|
|
|
|
2009-10-12 00:46:11 -06:00
|
|
|
// Btoi64 is like Btoui64 but allows signed numbers and
|
2009-03-05 16:29:04 -07:00
|
|
|
// returns its result in an int64.
|
2009-10-12 00:46:11 -06:00
|
|
|
func Btoi64(s string, base int) (i int64, err os.Error) {
|
2009-02-16 21:44:21 -07:00
|
|
|
// Empty string bad.
|
2008-11-17 13:34:03 -07:00
|
|
|
if len(s) == 0 {
|
2009-10-07 12:55:06 -06:00
|
|
|
return 0, &NumError{s, os.EINVAL};
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
|
|
|
|
2009-02-16 21:44:21 -07:00
|
|
|
// Pick off leading sign.
|
2009-07-02 17:24:44 -06:00
|
|
|
s0 := s;
|
2008-11-17 13:34:03 -07:00
|
|
|
neg := false;
|
|
|
|
if s[0] == '+' {
|
2009-10-07 12:55:06 -06:00
|
|
|
s = s[1:len(s)];
|
2008-11-17 13:34:03 -07:00
|
|
|
} else if s[0] == '-' {
|
|
|
|
neg = true;
|
2009-10-07 12:55:06 -06:00
|
|
|
s = s[1:len(s)];
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
|
|
|
|
2009-02-16 21:44:21 -07:00
|
|
|
// Convert unsigned and check range.
|
2008-11-17 13:34:03 -07:00
|
|
|
var un uint64;
|
2009-10-12 00:46:11 -06:00
|
|
|
un, err = Btoui64(s, base);
|
2009-06-25 21:24:55 -06:00
|
|
|
if err != nil && err.(*NumError).Error != os.ERANGE {
|
2009-07-02 17:24:44 -06:00
|
|
|
err.(*NumError).Num = s0;
|
2009-10-07 12:55:06 -06:00
|
|
|
return 0, err;
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
|
|
|
if !neg && un >= 1<<63 {
|
2009-10-07 12:55:06 -06:00
|
|
|
return 1<<63 - 1, &NumError{s0, os.ERANGE};
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
|
|
|
if neg && un > 1<<63 {
|
2009-10-07 12:55:06 -06:00
|
|
|
return -1 << 63, &NumError{s0, os.ERANGE};
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
|
|
|
n := int64(un);
|
|
|
|
if neg {
|
2009-10-07 12:55:06 -06:00
|
|
|
n = -n;
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2009-10-07 12:55:06 -06:00
|
|
|
return n, nil;
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
|
|
|
|
2009-10-12 00:46:11 -06:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-05 16:29:04 -07:00
|
|
|
// Atoui is like Atoui64 but returns its result as a uint.
|
2009-04-17 01:08:24 -06:00
|
|
|
func Atoui(s string) (i uint, err os.Error) {
|
2009-01-15 18:22:17 -07:00
|
|
|
i1, e1 := Atoui64(s);
|
2009-06-25 21:24:55 -06:00
|
|
|
if e1 != nil && e1.(*NumError).Error != os.ERANGE {
|
2009-10-07 12:55:06 -06:00
|
|
|
return 0, e1;
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
|
|
|
i = uint(i1);
|
|
|
|
if uint64(i) != i1 {
|
2009-10-07 12:55:06 -06:00
|
|
|
return ^uint(0), &NumError{s, os.ERANGE};
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2009-10-07 12:55:06 -06:00
|
|
|
return i, nil;
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
|
|
|
|
2009-03-05 16:29:04 -07:00
|
|
|
// Atoi is like Atoi64 but returns its result as an int.
|
2009-04-17 01:08:24 -06:00
|
|
|
func Atoi(s string) (i int, err os.Error) {
|
2009-01-15 18:22:17 -07:00
|
|
|
i1, e1 := Atoi64(s);
|
2009-06-25 21:24:55 -06:00
|
|
|
if e1 != nil && e1.(*NumError).Error != os.ERANGE {
|
2009-10-07 12:55:06 -06:00
|
|
|
return 0, e1;
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
|
|
|
i = int(i1);
|
|
|
|
if int64(i) != i1 {
|
|
|
|
if i1 < 0 {
|
2009-10-07 12:55:06 -06:00
|
|
|
return -1 << (IntSize-1), &NumError{s, os.ERANGE};
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2009-10-07 12:55:06 -06:00
|
|
|
return 1<<(IntSize-1) - 1, &NumError{s, os.ERANGE};
|
2008-11-18 18:12:07 -07:00
|
|
|
}
|
2009-10-07 12:55:06 -06:00
|
|
|
return i, nil;
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|