summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-02-16 20:44:21 -0800
committerRuss Cox <rsc@golang.org>2009-02-16 20:44:21 -0800
commite181dd601698cad04e5a7fa2815f01fd9c88fbae (patch)
tree37cf29dbf4c83a94e5f2347166b55f2caa7f577c
parent48f2e283eccf29c2247c23063ab998ea1c9416bf (diff)
downloadgolang-e181dd601698cad04e5a7fa2815f01fd9c88fbae.tar.gz
allow hex, octal in Atoi, etc.
R=r DELTA=169 (79 added, 23 deleted, 67 changed) OCL=25079 CL=25083
-rw-r--r--src/lib/strconv/atoi.go97
-rw-r--r--src/lib/strconv/atoi_test.go131
2 files changed, 142 insertions, 86 deletions
diff --git a/src/lib/strconv/atoi.go b/src/lib/strconv/atoi.go
index b41d08e14..337c32777 100644
--- a/src/lib/strconv/atoi.go
+++ b/src/lib/strconv/atoi.go
@@ -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;
}
+ return (1<<64 - 1) / uint64(base) + 1;
+}
- // pick off zero
- if s == "0" {
- return 0, nil
+// 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;
}
- // otherwise, leading zero bad:
- // don't want to take something intended as octal.
- if s[0] == '0' {
- return 0, os.EINVAL
- }
+ n = 0;
+ cutoff := cutoff64(base);
- // parse number
- n := uint64(0);
for i := 0; i < len(s); i++ {
- if s[i] < '0' || s[i] > '9' {
- return 0, os.EINVAL
+ 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 n > (1<<64)/10 {
- return 1<<64-1, os.ERANGE
+ if int(v) >= base {
+ return 0, os.EINVAL;
}
- n = n*10;
- d := uint64(s[i] - '0');
- if n+d < n {
- return 1<<64-1, os.ERANGE
+
+ 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 += d;
+ n = n1;
}
- return n, nil
+
+ 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
+ }
+
+ // 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 decimal string to integer.
+// Convert string to int64.
+// Use standard prefixes to signal octal, hexadecimal.
func Atoi64(s string) (i int64, err *os.Error) {
- // empty string bad
+ // Empty string bad.
if len(s) == 0 {
return 0, os.EINVAL
}
- // pick off leading sign
+ // 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 {
diff --git a/src/lib/strconv/atoi_test.go b/src/lib/strconv/atoi_test.go
index d57846d23..0128eb70b 100644
--- a/src/lib/strconv/atoi_test.go
+++ b/src/lib/strconv/atoi_test.go
@@ -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) {