summaryrefslogtreecommitdiff
path: root/src/pkg/strconv
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-06-25 20:24:55 -0700
committerRuss Cox <rsc@golang.org>2009-06-25 20:24:55 -0700
commitb26cd1bfcd7107d8208595614ba45f54d5efacf6 (patch)
tree1596fd2f89c1d896cdf5772aebc910f4e0ff5bda /src/pkg/strconv
parent37fd11a43607dc5f7ff5c38311b060ada2a0e7a5 (diff)
downloadgolang-b26cd1bfcd7107d8208595614ba45f54d5efacf6.tar.gz
Change os.Error convention:
echo back context of call in error if likely to be useful. For example, if os.Open("/etc/passwd", os.O_RDONLY) fails with syscall.EPERM, it returns as the os.Error &PathError{ Op: "open", Path: "/etc/passwd" Error: os.EPERM } which formats as open /etc/passwd: permission denied Not converted: datafmt go/... google/... regexp tabwriter template R=r DELTA=1153 (561 added, 156 deleted, 436 changed) OCL=30738 CL=30781
Diffstat (limited to 'src/pkg/strconv')
-rw-r--r--src/pkg/strconv/Makefile9
-rw-r--r--src/pkg/strconv/atof.go15
-rw-r--r--src/pkg/strconv/atof_test.go18
-rw-r--r--src/pkg/strconv/atoi.go73
-rw-r--r--src/pkg/strconv/atoi_test.go60
5 files changed, 124 insertions, 51 deletions
diff --git a/src/pkg/strconv/Makefile b/src/pkg/strconv/Makefile
index 499f8c1c1..f29521844 100644
--- a/src/pkg/strconv/Makefile
+++ b/src/pkg/strconv/Makefile
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
+
# DO NOT EDIT. Automatically generated by gobuild.
# gobuild -m >Makefile
@@ -20,7 +21,7 @@ test: packages
coverage: packages
gotest
- 6cov -g `pwd` | grep -v '_test\.go:'
+ 6cov -g $$(pwd) | grep -v '_test\.go:'
%.$O: %.go
$(GC) -I_obj $*.go
@@ -32,12 +33,12 @@ coverage: packages
$(AS) $*.s
O1=\
- atoi.$O\
decimal.$O\
itoa.$O\
quote.$O\
O2=\
+ atoi.$O\
ftoa.$O\
O3=\
@@ -48,11 +49,11 @@ phases: a1 a2 a3
_obj$D/strconv.a: phases
a1: $(O1)
- $(AR) grc _obj$D/strconv.a atoi.$O decimal.$O itoa.$O quote.$O
+ $(AR) grc _obj$D/strconv.a decimal.$O itoa.$O quote.$O
rm -f $(O1)
a2: $(O2)
- $(AR) grc _obj$D/strconv.a ftoa.$O
+ $(AR) grc _obj$D/strconv.a atoi.$O ftoa.$O
rm -f $(O2)
a3: $(O3)
diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go
index c257b2a33..6d6ec562c 100644
--- a/src/pkg/strconv/atof.go
+++ b/src/pkg/strconv/atof.go
@@ -316,15 +316,18 @@ func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) {
// Atof32 returns the nearest floating point number rounded
// using IEEE754 unbiased rounding.
//
-// If s is not syntactically well-formed, Atof32 returns err = os.EINVAL.
+// The errors that Atof32 returns have concrete type *NumError
+// and include err.Num = s.
+//
+// If s is not syntactically well-formed, Atof32 returns err.Error = os.EINVAL.
//
// If s is syntactically well-formed but is more than 1/2 ULP
// away from the largest floating point number of the given size,
-// Atof32 returns f = ±Inf, err = os.ERANGE.
+// Atof32 returns f = ±Inf, err.Error = os.ERANGE.
func Atof32(s string) (f float32, err os.Error) {
neg, d, trunc, ok := stringToDecimal(s);
if !ok {
- return 0, os.EINVAL;
+ return 0, &NumError{s, os.EINVAL};
}
if optimize {
if f, ok := decimalAtof32(neg, d, trunc); ok {
@@ -334,7 +337,7 @@ func Atof32(s string) (f float32, err os.Error) {
b, ovf := decimalToFloatBits(neg, d, trunc, &float32info);
f = math.Float32frombits(uint32(b));
if ovf {
- err = os.ERANGE;
+ err = &NumError{s, os.ERANGE};
}
return f, err
}
@@ -345,7 +348,7 @@ func Atof32(s string) (f float32, err os.Error) {
func Atof64(s string) (f float64, err os.Error) {
neg, d, trunc, ok := stringToDecimal(s);
if !ok {
- return 0, os.EINVAL;
+ return 0, &NumError{s, os.EINVAL};
}
if optimize {
if f, ok := decimalAtof64(neg, d, trunc); ok {
@@ -355,7 +358,7 @@ func Atof64(s string) (f float64, err os.Error) {
b, ovf := decimalToFloatBits(neg, d, trunc, &float64info);
f = math.Float64frombits(b);
if ovf {
- err = os.ERANGE;
+ err = &NumError{s, os.ERANGE};
}
return f, err
}
diff --git a/src/pkg/strconv/atof_test.go b/src/pkg/strconv/atof_test.go
index 6782f274a..ecccab79b 100644
--- a/src/pkg/strconv/atof_test.go
+++ b/src/pkg/strconv/atof_test.go
@@ -6,6 +6,7 @@ package strconv
import (
"fmt";
"os";
+ "reflect";
"strconv";
"testing"
)
@@ -91,6 +92,17 @@ var atoftests = []atofTest {
atofTest{ ".e-1", "0", os.EINVAL },
}
+func init() {
+ // The atof routines return NumErrors wrapping
+ // the error and the string. Convert the table above.
+ for i := range atoftests {
+ test := &atoftests[i];
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+}
+
func testAtof(t *testing.T, opt bool) {
oldopt := strconv.optimize;
strconv.optimize = opt;
@@ -98,7 +110,7 @@ func testAtof(t *testing.T, opt bool) {
test := &atoftests[i];
out, err := strconv.Atof64(test.in);
outs := strconv.Ftoa64(out, 'g', -1);
- if outs != test.out || err != test.err {
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
t.Errorf("strconv.Atof64(%v) = %v, %v want %v, %v\n",
test.in, out, err, test.out, test.err);
}
@@ -106,7 +118,7 @@ func testAtof(t *testing.T, opt bool) {
if float64(float32(out)) == out {
out32, err := strconv.Atof32(test.in);
outs := strconv.Ftoa32(out32, 'g', -1);
- if outs != test.out || err != test.err {
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
t.Errorf("strconv.Atof32(%v) = %v, %v want %v, %v # %v\n",
test.in, out32, err, test.out, test.err, out);
}
@@ -115,7 +127,7 @@ func testAtof(t *testing.T, opt bool) {
if FloatSize == 64 || float64(float32(out)) == out {
outf, err := strconv.Atof(test.in);
outs := strconv.Ftoa(outf, 'g', -1);
- if outs != test.out || err != test.err {
+ if outs != test.out || !reflect.DeepEqual(err, test.err) {
t.Errorf("strconv.Ftoa(%v) = %v, %v want %v, %v # %v\n",
test.in, outf, err, test.out, test.err, out);
}
diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
index a5d896a05..857b1afe6 100644
--- a/src/pkg/strconv/atoi.go
+++ b/src/pkg/strconv/atoi.go
@@ -3,7 +3,20 @@
// license that can be found in the LICENSE file.
package strconv
-import "os"
+import (
+ "os";
+ "strconv"
+)
+
+type NumError struct {
+ Num string;
+ Error os.Error;
+}
+
+func (e *NumError) String() string {
+ return "parsing " + e.Num + ": " + e.Error.String();
+}
+
func computeIntsize() uint {
siz := uint(8);
@@ -25,13 +38,18 @@ func cutoff64(base int) uint64 {
// Btoui64 interprets a string s in an arbitrary base b (2 to 36)
// and returns the corresponding value n.
//
-// Btoui64 returns err == os.EINVAL if b is out of
-// range or s is empty or contains invalid digits.
-// It returns err == os.ERANGE if the value corresponding
-// to s cannot be represented by a uint64.
+// 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 || len(s) < 1 {
- return 0, os.EINVAL;
+ if b < 2 || b > 36 {
+ err = os.ErrorString("invalid base " + Itoa(b));
+ goto Error;
+ }
+ if len(s) < 1 {
+ err = os.EINVAL;
+ goto Error;
}
n = 0;
@@ -47,27 +65,38 @@ func Btoui64(s string, b int) (n uint64, err os.Error) {
case 'A' <= s[i] && s[i] <= 'Z':
v = s[i] - 'A' + 10;
default:
- return 0, os.EINVAL;
+ n = 0;
+ err = os.EINVAL;
+ goto Error;
}
if int(v) >= b {
- return 0, os.EINVAL;
+ n = 0;
+ err = os.EINVAL;
+ goto Error;
}
if n >= cutoff {
// n*b overflows
- return 1<<64-1, os.ERANGE;
+ n = 1<<64-1;
+ err = os.ERANGE;
+ goto Error;
}
n *= uint64(b);
n1 := n+uint64(v);
if n1 < n {
// n+v overflows
- return 1<<64-1, os.ERANGE;
+ n = 1<<64-1;
+ err = os.ERANGE;
+ goto Error;
}
n = n1;
}
return n, nil;
+
+Error:
+ return n, &NumError{s, err};
}
// Atoui64 interprets a string s as an unsigned decimal, octal, or
@@ -80,7 +109,7 @@ func Btoui64(s string, b int) (n uint64, err os.Error) {
func Atoui64(s string) (n uint64, err os.Error) {
// Empty string bad.
if len(s) == 0 {
- return 0, os.EINVAL
+ return 0, &NumError{s, os.EINVAL}
}
// Look for octal, hex prefix.
@@ -102,7 +131,7 @@ func Atoui64(s string) (n uint64, err os.Error) {
func Atoi64(s string) (i int64, err os.Error) {
// Empty string bad.
if len(s) == 0 {
- return 0, os.EINVAL
+ return 0, &NumError{s, os.EINVAL}
}
// Pick off leading sign.
@@ -117,14 +146,14 @@ func Atoi64(s string) (i int64, err os.Error) {
// Convert unsigned and check range.
var un uint64;
un, err = Atoui64(s);
- if err != nil && err != os.ERANGE {
+ if err != nil && err.(*NumError).Error != os.ERANGE {
return 0, err
}
if !neg && un >= 1<<63 {
- return 1<<63-1, os.ERANGE
+ return 1<<63-1, &NumError{s, os.ERANGE}
}
if neg && un > 1<<63 {
- return -1<<63, os.ERANGE
+ return -1<<63, &NumError{s, os.ERANGE}
}
n := int64(un);
if neg {
@@ -136,14 +165,12 @@ func Atoi64(s string) (i int64, err os.Error) {
// Atoui is like Atoui64 but returns its result as a uint.
func Atoui(s string) (i uint, err os.Error) {
i1, e1 := Atoui64(s);
- if e1 != nil && e1 != os.ERANGE {
+ if e1 != nil && e1.(*NumError).Error != os.ERANGE {
return 0, e1
}
i = uint(i1);
if uint64(i) != i1 {
- // TODO: return uint(^0), os.ERANGE.
- i1 = 1<<64-1;
- return uint(i1), os.ERANGE
+ return ^uint(0), &NumError{s, os.ERANGE}
}
return i, nil
}
@@ -151,15 +178,15 @@ func Atoui(s string) (i uint, err os.Error) {
// Atoi is like Atoi64 but returns its result as an int.
func Atoi(s string) (i int, err os.Error) {
i1, e1 := Atoi64(s);
- if e1 != nil && e1 != os.ERANGE {
+ if e1 != nil && e1.(*NumError).Error != os.ERANGE {
return 0, e1
}
i = int(i1);
if int64(i) != i1 {
if i1 < 0 {
- return -1<<(intsize-1), os.ERANGE
+ return -1<<(intsize-1), &NumError{s, os.ERANGE}
}
- return 1<<(intsize-1) - 1, os.ERANGE
+ return 1<<(intsize-1) - 1, &NumError{s, os.ERANGE}
}
return i, nil
}
diff --git a/src/pkg/strconv/atoi_test.go b/src/pkg/strconv/atoi_test.go
index e4a9f955d..2483a6ff4 100644
--- a/src/pkg/strconv/atoi_test.go
+++ b/src/pkg/strconv/atoi_test.go
@@ -7,6 +7,7 @@ package strconv
import (
"fmt";
"os";
+ "reflect";
"strconv";
"testing"
)
@@ -44,7 +45,7 @@ type atoi64Test struct {
err os.Error;
}
-var atoi64test = []atoi64Test {
+var atoi64tests = []atoi64Test {
atoi64Test{"", 0, os.EINVAL},
atoi64Test{"0", 0, nil},
atoi64Test{"-0", 0, nil},
@@ -118,11 +119,40 @@ var atoi32tests = []atoi32Test {
atoi32Test{"-2147483649", -1<<31, os.ERANGE},
}
+func init() {
+ // The atoi routines return NumErrors wrapping
+ // the error and the string. Convert the tables above.
+ for i := range atoui64tests {
+ test := &atoui64tests[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 atoui32tests {
+ test := &atoui32tests[i];
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+ for i := range atoi32tests {
+ test := &atoi32tests[i];
+ if test.err != nil {
+ test.err = &NumError{test.in, test.err}
+ }
+ }
+}
+
func TestAtoui64(t *testing.T) {
- for i := 0; i < len(atoui64tests); i++ {
+ for i := range atoui64tests {
test := &atoui64tests[i];
out, err := strconv.Atoui64(test.in);
- if test.out != out || test.err != err {
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
t.Errorf("strconv.Atoui64(%v) = %v, %v want %v, %v\n",
test.in, out, err, test.out, test.err);
}
@@ -130,10 +160,10 @@ func TestAtoui64(t *testing.T) {
}
func TestAtoi64(t *testing.T) {
- for i := 0; i < len(atoi64test); i++ {
- test := &atoi64test[i];
+ for i := range atoi64tests {
+ test := &atoi64tests[i];
out, err := strconv.Atoi64(test.in);
- if test.out != out || test.err != err {
+ if test.out != out || !reflect.DeepEqual(test.err, err) {
t.Errorf("strconv.Atoi64(%v) = %v, %v want %v, %v\n",
test.in, out, err, test.out, test.err);
}
@@ -143,19 +173,19 @@ func TestAtoi64(t *testing.T) {
func TestAtoui(t *testing.T) {
switch intsize {
case 32:
- for i := 0; i < len(atoui32tests); i++ {
+ for i := range atoui32tests {
test := &atoui32tests[i];
out, err := strconv.Atoui(test.in);
- if test.out != uint32(out) || test.err != err {
+ if test.out != uint32(out) || !reflect.DeepEqual(test.err, err) {
t.Errorf("strconv.Atoui(%v) = %v, %v want %v, %v\n",
test.in, out, err, test.out, test.err);
}
}
case 64:
- for i := 0; i < len(atoui64tests); i++ {
+ for i := range atoui64tests {
test := &atoui64tests[i];
out, err := strconv.Atoui(test.in);
- if test.out != uint64(out) || test.err != err {
+ if test.out != uint64(out) || !reflect.DeepEqual(test.err, err) {
t.Errorf("strconv.Atoui(%v) = %v, %v want %v, %v\n",
test.in, out, err, test.out, test.err);
}
@@ -166,19 +196,19 @@ func TestAtoui(t *testing.T) {
func TestAtoi(t *testing.T) {
switch intsize {
case 32:
- for i := 0; i < len(atoi32tests); i++ {
+ for i := range atoi32tests {
test := &atoi32tests[i];
out, err := strconv.Atoi(test.in);
- if test.out != int32(out) || test.err != err {
+ if test.out != int32(out) || !reflect.DeepEqual(test.err, err) {
t.Errorf("strconv.Atoi(%v) = %v, %v want %v, %v\n",
test.in, out, err, test.out, test.err);
}
}
case 64:
- for i := 0; i < len(atoi64test); i++ {
- test := &atoi64test[i];
+ for i := range atoi64tests {
+ test := &atoi64tests[i];
out, err := strconv.Atoi(test.in);
- if test.out != int64(out) || test.err != err {
+ if test.out != int64(out) || !reflect.DeepEqual(test.err, err) {
t.Errorf("strconv.Atoi(%v) = %v, %v want %v, %v\n",
test.in, out, err, test.out, test.err);
}