Commit eb3823a4 authored by Russ Cox's avatar Russ Cox

allow hex, octal in Atoi, etc.

R=r
DELTA=169  (79 added, 23 deleted, 67 changed)
OCL=25079
CL=25083
parent 9e3e6162
...@@ -14,51 +14,87 @@ func computeIntsize() uint { ...@@ -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 // Convert arbitrary base string to unsigned integer.
if s == "0" { func Btoui64(base int, s string) (n uint64, err *os.Error) {
return 0, nil if base < 2 || base > 36 || len(s) < 1 {
return 0, os.EINVAL;
} }
// otherwise, leading zero bad: n = 0;
// don't want to take something intended as octal. cutoff := cutoff64(base);
if s[0] == '0' {
return 0, os.EINVAL
}
// parse number
n := uint64(0);
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
if s[i] < '0' || s[i] > '9' { var v byte;
return 0, os.EINVAL 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 { if int(v) >= base {
return 1<<64-1, os.ERANGE return 0, os.EINVAL;
} }
n = n*10;
d := uint64(s[i] - '0'); if n >= cutoff {
if n+d < n { // n*base overflows
return 1<<64-1, os.ERANGE 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) { func Atoi64(s string) (i int64, err *os.Error) {
// empty string bad // Empty string bad.
if len(s) == 0 { if len(s) == 0 {
return 0, os.EINVAL return 0, os.EINVAL
} }
// pick off leading sign // 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) { ...@@ -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) { ...@@ -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) { ...@@ -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 {
......
...@@ -3,9 +3,10 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment