1
0
mirror of https://github.com/golang/go synced 2024-11-22 21:20:03 -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 // 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+d < n {
return 1<<64-1, os.ERANGE
}
n += d;
}
return n, nil
} }
// Convert decimal string to integer. if n >= cutoff {
func Atoi64(s string) (i int64, err *os.Error) { // n*base overflows
// empty string bad 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"
) )
@ -21,12 +22,20 @@ var atoui64tests = []atoui64Test (
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("0x12345", 0x12345, nil),
atoui64Test("0X12345", 0x12345, nil),
atoui64Test("12345x", 0, os.EINVAL), atoui64Test("12345x", 0, os.EINVAL),
atoui64Test("98765432100", 98765432100, nil), atoui64Test("98765432100", 98765432100, nil),
atoui64Test("18446744073709551615", 1<<64-1, nil), atoui64Test("18446744073709551615", 1<<64-1, nil),
atoui64Test("18446744073709551616", 1<<64-1, os.ERANGE), atoui64Test("18446744073709551616", 1<<64-1, os.ERANGE),
atoui64Test("18446744073709551620", 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 {
@ -43,8 +52,10 @@ var atoi64test = []atoi64Test (
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("0x12345", 0x12345, nil),
atoi64Test("-0X12345", -0x12345, nil),
atoi64Test("12345x", 0, os.EINVAL), atoi64Test("12345x", 0, os.EINVAL),
atoi64Test("-12345x", 0, os.EINVAL), atoi64Test("-12345x", 0, os.EINVAL),
atoi64Test("98765432100", 98765432100, nil), atoi64Test("98765432100", 98765432100, nil),
@ -68,7 +79,9 @@ var atoui32tests = []atoui32Test (
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("0x12345", 0x12345, nil),
atoui32Test("0X12345", 0x12345, nil),
atoui32Test("12345x", 0, os.EINVAL), atoui32Test("12345x", 0, os.EINVAL),
atoui32Test("987654321", 987654321, nil), atoui32Test("987654321", 987654321, nil),
atoui32Test("4294967295", 1<<32-1, nil), atoui32Test("4294967295", 1<<32-1, nil),
@ -89,8 +102,10 @@ var atoi32tests = []atoi32Test (
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("0x12345", 0x12345, nil),
atoi32Test("-0X12345", -0x12345, nil),
atoi32Test("12345x", 0, os.EINVAL), atoi32Test("12345x", 0, os.EINVAL),
atoi32Test("-12345x", 0, os.EINVAL), atoi32Test("-12345x", 0, os.EINVAL),
atoi32Test("987654321", 987654321, nil), atoi32Test("987654321", 987654321, nil),