1
0
mirror of https://github.com/golang/go synced 2024-11-22 12:04:46 -07:00

allow hex, octal in Atoi, etc.

R=r
DELTA=169  (79 added, 23 deleted, 67 changed)
OCL=25079
CL=25083
This commit is contained in:
Russ Cox 2009-02-16 20:44:21 -08:00
parent 9e3e61627d
commit eb3823a44d
2 changed files with 152 additions and 96 deletions

View File

@ -14,51 +14,87 @@ func computeIntsize() uint {
}
var intsize = computeIntsize();
// Convert decimal string to unsigned integer.
func Atoui64(s string) (i uint64, err *os.Error) {
// empty string bad
if len(s) == 0 {
return 0, os.EINVAL
// Return the first number n such that n*base >= 1<<64.
func cutoff64(base int) uint64 {
if base < 2 {
return 0;
}
// pick off zero
if s == "0" {
return 0, nil
}
// otherwise, leading zero bad:
// don't want to take something intended as octal.
if s[0] == '0' {
return 0, os.EINVAL
}
// parse number
n := uint64(0);
for i := 0; i < len(s); i++ {
if s[i] < '0' || s[i] > '9' {
return 0, os.EINVAL
}
if n > (1<<64)/10 {
return 1<<64-1, os.ERANGE
}
n = n*10;
d := uint64(s[i] - '0');
if n+d < n {
return 1<<64-1, os.ERANGE
}
n += d;
}
return n, nil
return (1<<64 - 1) / uint64(base) + 1;
}
// Convert decimal string to integer.
func Atoi64(s string) (i int64, err *os.Error) {
// empty string bad
// Convert arbitrary base string to unsigned integer.
func Btoui64(base int, s string) (n uint64, err *os.Error) {
if base < 2 || base > 36 || len(s) < 1 {
return 0, os.EINVAL;
}
n = 0;
cutoff := cutoff64(base);
for i := 0; i < len(s); i++ {
var v byte;
switch {
case '0' <= s[i] && s[i] <= '9':
v = s[i] - '0';
case 'a' <= s[i] && s[i] <= 'z':
v = s[i] - 'a' + 10;
case 'A' <= s[i] && s[i] <= 'Z':
v = s[i] - 'A' + 10;
default:
return 0, os.EINVAL;
}
if int(v) >= base {
return 0, os.EINVAL;
}
if n >= cutoff {
// n*base overflows
return 1<<64-1, os.ERANGE;
}
n *= uint64(base);
n1 := n+uint64(v);
if n1 < n {
// n+v overflows
return 1<<64-1, os.ERANGE;
}
n = n1;
}
return n, nil;
}
// Convert string to uint64.
// Use standard prefixes to signal octal, hexadecimal.
func Atoui64(s string) (i uint64, err *os.Error) {
// Empty string bad.
if len(s) == 0 {
return 0, os.EINVAL
}
// pick off leading sign
// Look for octal, hex prefix.
if s[0] == '0' && len(s) > 1 {
if s[1] == 'x' || s[1] == 'X' {
// hex
return Btoui64(16, s[2:len(s)]);
}
// octal
return Btoui64(8, s[1:len(s)]);
}
// decimal
return Btoui64(10, s);
}
// Convert string to int64.
// Use standard prefixes to signal octal, hexadecimal.
func Atoi64(s string) (i int64, err *os.Error) {
// Empty string bad.
if len(s) == 0 {
return 0, os.EINVAL
}
// Pick off leading sign.
neg := false;
if s[0] == '+' {
s = s[1:len(s)]
@ -67,6 +103,7 @@ func Atoi64(s string) (i int64, err *os.Error) {
s = s[1:len(s)]
}
// Convert unsigned and check range.
var un uint64;
un, err = Atoui64(s);
if err != nil && err != os.ERANGE {
@ -85,6 +122,8 @@ func Atoi64(s string) (i int64, err *os.Error) {
return n, nil
}
// Convert string to uint.
// Use standard prefixes to signal octal, hexadecimal.
func Atoui(s string) (i uint, err *os.Error) {
i1, e1 := Atoui64(s);
if e1 != nil && e1 != os.ERANGE {
@ -99,6 +138,8 @@ func Atoui(s string) (i uint, err *os.Error) {
return i, nil
}
// Convert string to int.
// Use standard prefixes to signal octal, hexadecimal.
func Atoi(s string) (i int, err *os.Error) {
i1, e1 := Atoi64(s);
if e1 != nil && e1 != os.ERANGE {

View File

@ -3,9 +3,10 @@
// license that can be found in the LICENSE file.
package strconv
import (
"os";
"fmt";
"os";
"strconv";
"testing"
)
@ -17,16 +18,24 @@ type atoui64Test struct {
}
var atoui64tests = []atoui64Test (
atoui64Test( "", 0, os.EINVAL ),
atoui64Test( "0", 0, nil ),
atoui64Test( "1", 1, nil ),
atoui64Test( "12345", 12345, nil ),
atoui64Test( "012345", 0, os.EINVAL ),
atoui64Test( "12345x", 0, os.EINVAL ),
atoui64Test( "98765432100", 98765432100, nil ),
atoui64Test( "18446744073709551615", 1<<64-1, nil ),
atoui64Test( "18446744073709551616", 1<<64-1, os.ERANGE ),
atoui64Test( "18446744073709551620", 1<<64-1, os.ERANGE ),
atoui64Test("", 0, os.EINVAL),
atoui64Test("0", 0, nil),
atoui64Test("1", 1, nil),
atoui64Test("12345", 12345, nil),
atoui64Test("012345", 012345, nil),
atoui64Test("0x12345", 0x12345, nil),
atoui64Test("0X12345", 0x12345, nil),
atoui64Test("12345x", 0, os.EINVAL),
atoui64Test("98765432100", 98765432100, nil),
atoui64Test("18446744073709551615", 1<<64-1, nil),
atoui64Test("18446744073709551616", 1<<64-1, os.ERANGE),
atoui64Test("18446744073709551620", 1<<64-1, os.ERANGE),
atoui64Test("0xFFFFFFFFFFFFFFFF", 1<<64-1, nil),
atoui64Test("0x10000000000000000", 1<<64-1, os.ERANGE),
atoui64Test("01777777777777777777777", 1<<64-1, nil),
atoui64Test("01777777777777777777778", 0, os.EINVAL),
atoui64Test("02000000000000000000000", 1<<64-1, os.ERANGE),
atoui64Test("0200000000000000000000", 1<<61, nil),
)
type atoi64Test struct {
@ -36,25 +45,27 @@ type atoi64Test struct {
}
var atoi64test = []atoi64Test (
atoi64Test( "", 0, os.EINVAL ),
atoi64Test( "0", 0, nil ),
atoi64Test( "-0", 0, nil ),
atoi64Test( "1", 1, nil ),
atoi64Test( "-1", -1, nil ),
atoi64Test( "12345", 12345, nil ),
atoi64Test( "-12345", -12345, nil ),
atoi64Test( "012345", 0, os.EINVAL ),
atoi64Test( "-012345", 0, os.EINVAL ),
atoi64Test( "12345x", 0, os.EINVAL ),
atoi64Test( "-12345x", 0, os.EINVAL ),
atoi64Test( "98765432100", 98765432100, nil ),
atoi64Test( "-98765432100", -98765432100, nil ),
atoi64Test( "9223372036854775807", 1<<63-1, nil ),
atoi64Test( "-9223372036854775807", -(1<<63-1), nil ),
atoi64Test( "9223372036854775808", 1<<63-1, os.ERANGE ),
atoi64Test( "-9223372036854775808", -1<<63, nil ),
atoi64Test( "9223372036854775809", 1<<63-1, os.ERANGE ),
atoi64Test( "-9223372036854775809", -1<<63, os.ERANGE ),
atoi64Test("", 0, os.EINVAL),
atoi64Test("0", 0, nil),
atoi64Test("-0", 0, nil),
atoi64Test("1", 1, nil),
atoi64Test("-1", -1, nil),
atoi64Test("12345", 12345, nil),
atoi64Test("-12345", -12345, nil),
atoi64Test("012345", 012345, nil),
atoi64Test("-012345", -012345, nil),
atoi64Test("0x12345", 0x12345, nil),
atoi64Test("-0X12345", -0x12345, nil),
atoi64Test("12345x", 0, os.EINVAL),
atoi64Test("-12345x", 0, os.EINVAL),
atoi64Test("98765432100", 98765432100, nil),
atoi64Test("-98765432100", -98765432100, nil),
atoi64Test("9223372036854775807", 1<<63-1, nil),
atoi64Test("-9223372036854775807", -(1<<63-1), nil),
atoi64Test("9223372036854775808", 1<<63-1, os.ERANGE),
atoi64Test("-9223372036854775808", -1<<63, nil),
atoi64Test("9223372036854775809", 1<<63-1, os.ERANGE),
atoi64Test("-9223372036854775809", -1<<63, os.ERANGE),
)
type atoui32Test struct {
@ -64,15 +75,17 @@ type atoui32Test struct {
}
var atoui32tests = []atoui32Test (
atoui32Test( "", 0, os.EINVAL ),
atoui32Test( "0", 0, nil ),
atoui32Test( "1", 1, nil ),
atoui32Test( "12345", 12345, nil ),
atoui32Test( "012345", 0, os.EINVAL ),
atoui32Test( "12345x", 0, os.EINVAL ),
atoui32Test( "987654321", 987654321, nil ),
atoui32Test( "4294967295", 1<<32-1, nil ),
atoui32Test( "4294967296", 1<<32-1, os.ERANGE ),
atoui32Test("", 0, os.EINVAL),
atoui32Test("0", 0, nil),
atoui32Test("1", 1, nil),
atoui32Test("12345", 12345, nil),
atoui32Test("012345", 012345, nil),
atoui32Test("0x12345", 0x12345, nil),
atoui32Test("0X12345", 0x12345, nil),
atoui32Test("12345x", 0, os.EINVAL),
atoui32Test("987654321", 987654321, nil),
atoui32Test("4294967295", 1<<32-1, nil),
atoui32Test("4294967296", 1<<32-1, os.ERANGE),
)
type atoi32Test struct {
@ -82,25 +95,27 @@ type atoi32Test struct {
}
var atoi32tests = []atoi32Test (
atoi32Test( "", 0, os.EINVAL ),
atoi32Test( "0", 0, nil ),
atoi32Test( "-0", 0, nil ),
atoi32Test( "1", 1, nil ),
atoi32Test( "-1", -1, nil ),
atoi32Test( "12345", 12345, nil ),
atoi32Test( "-12345", -12345, nil ),
atoi32Test( "012345", 0, os.EINVAL ),
atoi32Test( "-012345", 0, os.EINVAL ),
atoi32Test( "12345x", 0, os.EINVAL ),
atoi32Test( "-12345x", 0, os.EINVAL ),
atoi32Test( "987654321", 987654321, nil ),
atoi32Test( "-987654321", -987654321, nil ),
atoi32Test( "2147483647", 1<<31-1, nil ),
atoi32Test( "-2147483647", -(1<<31-1), nil ),
atoi32Test( "2147483648", 1<<31-1, os.ERANGE ),
atoi32Test( "-2147483648", -1<<31, nil ),
atoi32Test( "2147483649", 1<<31-1, os.ERANGE ),
atoi32Test( "-2147483649", -1<<31, os.ERANGE ),
atoi32Test("", 0, os.EINVAL),
atoi32Test("0", 0, nil),
atoi32Test("-0", 0, nil),
atoi32Test("1", 1, nil),
atoi32Test("-1", -1, nil),
atoi32Test("12345", 12345, nil),
atoi32Test("-12345", -12345, nil),
atoi32Test("012345", 012345, nil),
atoi32Test("-012345", -012345, nil),
atoi32Test("0x12345", 0x12345, nil),
atoi32Test("-0X12345", -0x12345, nil),
atoi32Test("12345x", 0, os.EINVAL),
atoi32Test("-12345x", 0, os.EINVAL),
atoi32Test("987654321", 987654321, nil),
atoi32Test("-987654321", -987654321, nil),
atoi32Test("2147483647", 1<<31-1, nil),
atoi32Test("-2147483647", -(1<<31-1), nil),
atoi32Test("2147483648", 1<<31-1, os.ERANGE),
atoi32Test("-2147483648", -1<<31, nil),
atoi32Test("2147483649", 1<<31-1, os.ERANGE),
atoi32Test("-2147483649", -1<<31, os.ERANGE),
)
func TestAtoui64(t *testing.T) {