diff options
author | Russ Cox <rsc@golang.org> | 2009-06-25 20:24:55 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-06-25 20:24:55 -0700 |
commit | b26cd1bfcd7107d8208595614ba45f54d5efacf6 (patch) | |
tree | 1596fd2f89c1d896cdf5772aebc910f4e0ff5bda /src/pkg/strconv | |
parent | 37fd11a43607dc5f7ff5c38311b060ada2a0e7a5 (diff) | |
download | golang-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/Makefile | 9 | ||||
-rw-r--r-- | src/pkg/strconv/atof.go | 15 | ||||
-rw-r--r-- | src/pkg/strconv/atof_test.go | 18 | ||||
-rw-r--r-- | src/pkg/strconv/atoi.go | 73 | ||||
-rw-r--r-- | src/pkg/strconv/atoi_test.go | 60 |
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); } |