1
0
mirror of https://github.com/golang/go synced 2024-11-22 16:54:48 -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(); var intsize = computeIntsize();
// Convert decimal string to unsigned integer. // Return the first number n such that n*base >= 1<<64.
func Atoui64(s string) (i uint64, err *os.Error) { func cutoff64(base int) uint64 {
// empty string bad if base < 2 {
if len(s) == 0 { return 0;
return 0, os.EINVAL
} }
return (1<<64 - 1) / uint64(base) + 1;
// 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
} }
// Convert decimal string to integer. // Convert arbitrary base string to unsigned integer.
func Atoi64(s string) (i int64, err *os.Error) { func Btoui64(base int, s string) (n uint64, err *os.Error) {
// empty string bad 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 { if len(s) == 0 {
return 0, os.EINVAL 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; neg := false;
if s[0] == '+' { if s[0] == '+' {
s = s[1:len(s)] s = s[1:len(s)]
@ -67,6 +103,7 @@ func Atoi64(s string) (i int64, err *os.Error) {
s = s[1:len(s)] s = s[1:len(s)]
} }
// Convert unsigned and check range.
var un uint64; var un uint64;
un, err = Atoui64(s); un, err = Atoui64(s);
if err != nil && err != os.ERANGE { if err != nil && err != os.ERANGE {
@ -85,6 +122,8 @@ func Atoi64(s string) (i int64, err *os.Error) {
return n, nil return n, nil
} }
// Convert string to uint.
// Use standard prefixes to signal octal, hexadecimal.
func Atoui(s string) (i uint, err *os.Error) { func Atoui(s string) (i uint, err *os.Error) {
i1, e1 := Atoui64(s); i1, e1 := Atoui64(s);
if e1 != nil && e1 != os.ERANGE { if e1 != nil && e1 != os.ERANGE {
@ -99,6 +138,8 @@ func Atoui(s string) (i uint, err *os.Error) {
return i, nil return i, nil
} }
// Convert string to int.
// Use standard prefixes to signal octal, hexadecimal.
func Atoi(s string) (i int, err *os.Error) { func Atoi(s string) (i int, err *os.Error) {
i1, e1 := Atoi64(s); i1, e1 := Atoi64(s);
if e1 != nil && e1 != os.ERANGE { if e1 != nil && e1 != os.ERANGE {

View File

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