summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-10-11 23:46:11 -0700
committerRuss Cox <rsc@golang.org>2009-10-11 23:46:11 -0700
commit12b5a55f4a94341ea7e1ad00ffa6f295cb4268d5 (patch)
tree3253bc73bc49592e082524241c3aaafeed9038de
parent83595b457cfaa39092df0129b400b6733e604d4d (diff)
downloadgolang-12b5a55f4a94341ea7e1ad00ffa6f295cb4268d5.tar.gz
correct a design flaw: Atoi etc should not guess the base.
leave that for Btoi with base == 0. R=r DELTA=146 (101 added, 29 deleted, 16 changed) OCL=35584 CL=35593
-rw-r--r--src/pkg/strconv/atoi.go77
-rw-r--r--src/pkg/strconv/atoi_test.go77
2 files changed, 113 insertions, 41 deletions
diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
index f31632eff..2f1d5dec6 100644
--- a/src/pkg/strconv/atoi.go
+++ b/src/pkg/strconv/atoi.go
@@ -35,20 +35,43 @@ func cutoff64(base int) uint64 {
}
// Btoui64 interprets a string s in an arbitrary base b (2 to 36)
-// and returns the corresponding value n.
+// and returns the corresponding value n. If b == 0, the base
+// is taken from the string prefix: base 16 for "0x", base 8 for "0",
+// and base 10 otherwise.
//
// The errors that Btoui64 returns have concrete type *NumError
// and include err.Num = s. If s is empty or contains invalid
// digits, err.Error = os.EINVAL; if the value corresponding
// to s cannot be represented by a uint64, err.Error = os.ERANGE.
func Btoui64(s string, b int) (n uint64, err os.Error) {
- if b < 2 || b > 36 {
- err = os.ErrorString("invalid base " + Itoa(b));
- goto Error;
- }
- if len(s) < 1 {
+ s0 := s;
+ switch {
+ case len(s) < 1:
err = os.EINVAL;
goto Error;
+
+ case 2 <= b && b <= 36:
+ // valid base; nothing to do
+
+ case b == 0:
+ // Look for octal, hex prefix.
+ switch {
+ case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
+ b = 16;
+ s = s[2:len(s)];
+ if len(s) < 1 {
+ err = os.EINVAL;
+ goto Error;
+ }
+ case s[0] == '0':
+ b = 8;
+ default:
+ b = 10;
+ }
+
+ default:
+ err = os.ErrorString("invalid base " + Itoa(b));
+ goto Error;
}
n = 0;
@@ -95,42 +118,21 @@ func Btoui64(s string, b int) (n uint64, err os.Error) {
return n, nil;
Error:
- return n, &NumError{s, err};
+ return n, &NumError{s0, err};
}
-// Atoui64 interprets a string s as an unsigned decimal, octal, or
-// hexadecimal number and returns the corresponding value n.
-// The default base is decimal. Strings beginning with 0x are
-// hexadecimal; strings beginning with 0 are octal.
+// Atoui64 interprets a string s as a decimal number and
+// returns the corresponding value n.
//
// Atoui64 returns err == os.EINVAL if s is empty or contains invalid digits.
// It returns err == os.ERANGE if s cannot be represented by a uint64.
func Atoui64(s string) (n uint64, err os.Error) {
- // Empty string bad.
- if len(s) == 0 {
- return 0, &NumError{s, os.EINVAL};
- }
-
- // Look for octal, hex prefix.
- switch {
- case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
- n, err = Btoui64(s[2:len(s)], 16);
- case s[0] == '0':
- n, err = Btoui64(s, 8);
- default:
- n, err = Btoui64(s, 10);
- }
-
- if err != nil {
- err.(*NumError).Num = s;
- }
- return;
+ return Btoui64(s, 10);
}
-
-// Atoi64 is like Atoui64 but allows signed numbers and
+// Btoi64 is like Btoui64 but allows signed numbers and
// returns its result in an int64.
-func Atoi64(s string) (i int64, err os.Error) {
+func Btoi64(s string, base int) (i int64, err os.Error) {
// Empty string bad.
if len(s) == 0 {
return 0, &NumError{s, os.EINVAL};
@@ -148,7 +150,7 @@ func Atoi64(s string) (i int64, err os.Error) {
// Convert unsigned and check range.
var un uint64;
- un, err = Atoui64(s);
+ un, err = Btoui64(s, base);
if err != nil && err.(*NumError).Error != os.ERANGE {
err.(*NumError).Num = s0;
return 0, err;
@@ -166,6 +168,13 @@ func Atoi64(s string) (i int64, err os.Error) {
return n, nil;
}
+// Atoi64 is like Atoui64 but allows signed numbers and
+// returns its result in an int64.
+func Atoi64(s string) (i int64, err os.Error) {
+ return Btoi64(s, 10);
+}
+
+
// Atoui is like Atoui64 but returns its result as a uint.
func Atoui(s string) (i uint, err os.Error) {
i1, e1 := Atoui64(s);
diff --git a/src/pkg/strconv/atoi_test.go b/src/pkg/strconv/atoi_test.go
index adbf7f5c3..34eadaad5 100644
--- a/src/pkg/strconv/atoi_test.go
+++ b/src/pkg/strconv/atoi_test.go
@@ -22,6 +22,19 @@ var atoui64tests = []atoui64Test{
atoui64Test{"0", 0, nil},
atoui64Test{"1", 1, nil},
atoui64Test{"12345", 12345, nil},
+ atoui64Test{"012345", 12345, 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},
+}
+
+var btoui64tests = []atoui64Test{
+ 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},
@@ -52,6 +65,26 @@ var atoi64tests = []atoi64Test{
atoi64Test{"-1", -1, nil},
atoi64Test{"12345", 12345, nil},
atoi64Test{"-12345", -12345, nil},
+ atoi64Test{"012345", 12345, nil},
+ atoi64Test{"-012345", -12345, nil},
+ 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},
+}
+
+var btoi64tests = []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", 012345, nil},
atoi64Test{"-012345", -012345, nil},
atoi64Test{"0x12345", 0x12345, nil},
@@ -79,9 +112,7 @@ var atoui32tests = []atoui32Test{
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{"012345", 12345, nil},
atoui32Test{"12345x", 0, os.EINVAL},
atoui32Test{"987654321", 987654321, nil},
atoui32Test{"4294967295", 1<<32 - 1, nil},
@@ -102,10 +133,8 @@ var atoi32tests = []atoi32Test{
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{"012345", 12345, nil},
+ atoi32Test{"-012345", -12345, nil},
atoi32Test{"12345x", 0, os.EINVAL},
atoi32Test{"-12345x", 0, os.EINVAL},
atoi32Test{"987654321", 987654321, nil},
@@ -127,12 +156,24 @@ func init() {
test.err = &NumError{test.in, test.err};
}
}
+ for i := range btoui64tests {
+ test := &btoui64tests[i];
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err};
+ }
+ }
for i := range atoi64tests {
test := &atoi64tests[i];
if test.err != nil {
test.err = &NumError{test.in, test.err};
}
}
+ for i := range btoi64tests {
+ test := &btoi64tests[i];
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err};
+ }
+ }
for i := range atoui32tests {
test := &atoui32tests[i];
if test.err != nil {
@@ -158,6 +199,17 @@ func TestAtoui64(t *testing.T) {
}
}
+func TestBtoui64(t *testing.T) {
+ for i := range btoui64tests {
+ test := &btoui64tests[i];
+ out, err := Btoui64(test.in, 0);
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Btoui64(%q) = %v, %v want %v, %v\n",
+ test.in, out, err, test.out, test.err);
+ }
+ }
+}
+
func TestAtoi64(t *testing.T) {
for i := range atoi64tests {
test := &atoi64tests[i];
@@ -169,6 +221,17 @@ func TestAtoi64(t *testing.T) {
}
}
+func TestBtoi64(t *testing.T) {
+ for i := range btoi64tests {
+ test := &btoi64tests[i];
+ out, err := Btoi64(test.in, 0);
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
+ t.Errorf("Btoi64(%q) = %v, %v want %v, %v\n",
+ test.in, out, err, test.out, test.err);
+ }
+ }
+}
+
func TestAtoui(t *testing.T) {
switch IntSize {
case 32: