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 {
}
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 {
......
......@@ -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) {
......
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