]> Cypherpunks repositories - gostls13.git/commitdiff
allow hex, octal in Atoi, etc.
authorRuss Cox <rsc@golang.org>
Tue, 17 Feb 2009 04:44:21 +0000 (20:44 -0800)
committerRuss Cox <rsc@golang.org>
Tue, 17 Feb 2009 04:44:21 +0000 (20:44 -0800)
R=r
DELTA=169  (79 added, 23 deleted, 67 changed)
OCL=25079
CL=25083

src/lib/strconv/atoi.go
src/lib/strconv/atoi_test.go

index b41d08e147cca28b861d02ef653106ded4ac36e9..337c32777e03cb05974eeb4983e12645609c3ba8 100644 (file)
@@ -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 {
index d57846d23320750d970e64d030f675cfcb12c1a6..0128eb70b69f07f933e07156bcd222f375426782 100644 (file)
@@ -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) {