Commit 6cc001c3 authored by Russ Cox's avatar Russ Cox

return *os.Error instead of bool from strconv.ato*

R=r
DELTA=137  (56 added, 4 deleted, 77 changed)
OCL=19505
CL=19522
parent 360151d4
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
package strconv package strconv
import "strconv" import (
"os";
"strconv";
)
// TODO(rsc): Better truncation handling. // TODO(rsc): Better truncation handling.
func StringToDecimal(s string) (neg bool, d *Decimal, trunc bool, ok bool) { func StringToDecimal(s string) (neg bool, d *Decimal, trunc bool, ok bool) {
...@@ -314,43 +317,49 @@ func DecimalToFloat32(neg bool, d *Decimal, trunc bool) (f float32, ok bool) { ...@@ -314,43 +317,49 @@ func DecimalToFloat32(neg bool, d *Decimal, trunc bool) (f float32, ok bool) {
// returns f, false, true, where f is the nearest floating point // returns f, false, true, where f is the nearest floating point
// number rounded using IEEE754 unbiased rounding. // number rounded using IEEE754 unbiased rounding.
// //
// If s is not syntactically well-formed, returns ok == false. // If s is not syntactically well-formed, returns err = os.EINVAL.
// //
// If s is syntactically well-formed but is more than 1/2 ULP // If s is syntactically well-formed but is more than 1/2 ULP
// away from the largest floating point number of the given size, // away from the largest floating point number of the given size,
// returns f = ±Inf, overflow = true, ok = true. // returns f = ±Inf, err = os.ERANGE.
export func atof64(s string) (f float64, overflow bool, ok bool) { export func atof64(s string) (f float64, err *os.Error) {
neg, d, trunc, ok1 := StringToDecimal(s); neg, d, trunc, ok := StringToDecimal(s);
if !ok1 { if !ok {
return 0, false, false; return 0, os.EINVAL;
} }
if f, ok := DecimalToFloat64(neg, d, trunc); ok { if f, ok := DecimalToFloat64(neg, d, trunc); ok {
return f, false, true; return f, nil;
} }
b, overflow1 := DecimalToFloatBits(neg, d, trunc, &float64info); b, ovf := DecimalToFloatBits(neg, d, trunc, &float64info);
return sys.float64frombits(b), overflow1, true; f = sys.float64frombits(b);
if ovf {
err = os.ERANGE;
}
return f, err
} }
export func atof32(s string) (f float32, overflow bool, ok bool) { export func atof32(s string) (f float32, err *os.Error) {
neg, d, trunc, ok1 := StringToDecimal(s); neg, d, trunc, ok := StringToDecimal(s);
if !ok1 { if !ok {
return 0, false, false; return 0, os.EINVAL;
} }
if f, ok := DecimalToFloat32(neg, d, trunc); ok { if f, ok := DecimalToFloat32(neg, d, trunc); ok {
return f, false, true; return f, nil;
}
b, ovf := DecimalToFloatBits(neg, d, trunc, &float32info);
f = sys.float32frombits(uint32(b));
if ovf {
err = os.ERANGE;
} }
b, overflow1 := DecimalToFloatBits(neg, d, trunc, &float32info); return f, err
return sys.float32frombits(uint32(b)), overflow1, true;
} }
export func atof(s string) (f float, overflow bool, ok bool) { export func atof(s string) (f float, err *os.Error) {
if floatsize == 32 { if floatsize == 32 {
var f1 float32; f1, err1 := atof32(s);
f1, overflow, ok = atof32(s); return float(f1), err1;
return float(f1), overflow, ok;
} }
var f1 float64; f1, err1 := atof64(s);
f1, overflow, ok = atof64(s); return float(f1), err1;
return float(f1), overflow, ok;
} }
...@@ -3,42 +3,59 @@ ...@@ -3,42 +3,59 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package strconv package strconv
import "os"
func IntSize() uint {
siz := uint(8);
for 1<<siz != 0 {
siz *= 2
}
return siz
}
var intsize = IntSize();
// Convert decimal string to unsigned integer. // Convert decimal string to unsigned integer.
// TODO: Doesn't check for overflow. export func atoui64(s string) (i uint64, err *os.Error) {
export func atoui64(s string) (i uint64, ok bool) {
// empty string bad // empty string bad
if len(s) == 0 { if len(s) == 0 {
return 0, false return 0, os.EINVAL
} }
// pick off zero // pick off zero
if s == "0" { if s == "0" {
return 0, true return 0, nil
} }
// otherwise, leading zero bad // otherwise, leading zero bad:
// don't want to take something intended as octal.
if s[0] == '0' { if s[0] == '0' {
return 0, false return 0, os.EINVAL
} }
// parse number // parse number
n := uint64(0); n := uint64(0);
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
if s[i] < '0' || s[i] > '9' { if s[i] < '0' || s[i] > '9' {
return 0, false return 0, os.EINVAL
}
if n > (1<<64)/10 {
return 1<<64-1, os.ERANGE
} }
n = n*10 + uint64(s[i] - '0') n = n*10;
d := uint64(s[i] - '0');
if n+d < n {
return 1<<64-1, os.ERANGE
}
n += d;
} }
return n, true return n, nil
} }
// Convert decimal string to integer. // Convert decimal string to integer.
// TODO: Doesn't check for overflow. export func atoi64(s string) (i int64, err *os.Error) {
export func atoi64(s string) (i int64, ok bool) {
// empty string bad // empty string bad
if len(s) == 0 { if len(s) == 0 {
return 0, false return 0, os.EINVAL
} }
// pick off leading sign // pick off leading sign
...@@ -51,25 +68,49 @@ export func atoi64(s string) (i int64, ok bool) { ...@@ -51,25 +68,49 @@ export func atoi64(s string) (i int64, ok bool) {
} }
var un uint64; var un uint64;
un, ok = atoui64(s); un, err = atoui64(s);
if !ok { if err != nil && err != os.ERANGE {
return 0, false return 0, err
}
if !neg && un >= 1<<63 {
return 1<<63-1, os.ERANGE
}
if neg && un > 1<<63 {
return -1<<63, os.ERANGE
} }
n := int64(un); n := int64(un);
if neg { if neg {
n = -n n = -n
} }
return n, true return n, nil
} }
export func atoui(s string) (i uint, ok bool) { export func atoui(s string) (i uint, err *os.Error) {
ii, okok := atoui64(s); i1, e1 := atoui64(s);
i = uint(ii); if e1 != nil && e1 != os.ERANGE {
return i, okok 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 i, nil
} }
export func atoi(s string) (i int, ok bool) { export func atoi(s string) (i int, err *os.Error) {
ii, okok := atoi64(s); i1, e1 := atoi64(s);
i = int(ii); if e1 != nil && e1 != os.ERANGE {
return i, okok return 0, e1
}
i = int(i1);
if int64(i) != i1 {
if i1 < 0 {
return -1<<(intsize-1), os.ERANGE
}
return 1<<(intsize-1) - 1, os.ERANGE
}
return i, nil
} }
...@@ -43,8 +43,8 @@ func main() { ...@@ -43,8 +43,8 @@ func main() {
v := strconv.ftoa64(t.f, 'g', -1); v := strconv.ftoa64(t.f, 'g', -1);
if v != t.out { if v != t.out {
println("Bad float64 const:", t.in, "want", t.out, "got", v); println("Bad float64 const:", t.in, "want", t.out, "got", v);
x, overflow, ok := strconv.atof64(t.out); x, err := strconv.atof64(t.out);
if !ok { if err != nil {
panicln("bug120: strconv.atof64", t.out); panicln("bug120: strconv.atof64", t.out);
} }
println("\twant exact:", strconv.ftoa64(x, 'g', 1000)); println("\twant exact:", strconv.ftoa64(x, 'g', 1000));
...@@ -53,6 +53,6 @@ func main() { ...@@ -53,6 +53,6 @@ func main() {
} }
} }
if !ok { if !ok {
panicln("bug120"); sys.exit(1);
} }
} }
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
package main package main
import ( import (
"os";
"strconv"; "strconv";
) )
...@@ -20,9 +21,9 @@ func f(left, right *chan int) { ...@@ -20,9 +21,9 @@ func f(left, right *chan int) {
func main() { func main() {
var n = 10000; var n = 10000;
if sys.argc() > 1 { if sys.argc() > 1 {
var ok bool; var err *os.Error;
n, ok = strconv.atoi(sys.argv(1)); n, err = strconv.atoi(sys.argv(1));
if !ok { if err != nil {
print("bad arg\n"); print("bad arg\n");
sys.exit(1); sys.exit(1);
} }
......
...@@ -125,7 +125,7 @@ BUG: errchk: command succeeded unexpectedly: 6g bugs/bug104.go ...@@ -125,7 +125,7 @@ BUG: errchk: command succeeded unexpectedly: 6g bugs/bug104.go
=========== bugs/bug105.go =========== bugs/bug105.go
bugs/bug105.go:8: P: undefined bugs/bug105.go:8: P: undefined
bugs/bug105.go:9: illegal types for operand: RETURN bugs/bug105.go:8: illegal types for operand: RETURN
int int
BUG: should compile BUG: should compile
...@@ -139,7 +139,7 @@ BUG: bug115 should compile ...@@ -139,7 +139,7 @@ BUG: bug115 should compile
=========== bugs/bug117.go =========== bugs/bug117.go
bugs/bug117.go:9: undefined DOT get on PS bugs/bug117.go:9: undefined DOT get on PS
bugs/bug117.go:10: illegal types for operand: RETURN bugs/bug117.go:9: illegal types for operand: RETURN
int int
BUG: should compile BUG: should compile
...@@ -156,6 +156,7 @@ Bad float64 const: 1e23+8.388608e6 want 1.0000000000000001e+23 got 1e+23 ...@@ -156,6 +156,7 @@ Bad float64 const: 1e23+8.388608e6 want 1.0000000000000001e+23 got 1e+23
Bad float64 const: 1e23+1 want 1.0000000000000001e+23 got 1e+23 Bad float64 const: 1e23+1 want 1.0000000000000001e+23 got 1e+23
want exact: 100000000000000008388608 want exact: 100000000000000008388608
got exact: 99999999999999991611392 got exact: 99999999999999991611392
BUG: bug120
=========== bugs/bug121.go =========== bugs/bug121.go
BUG: compilation succeeds incorrectly BUG: compilation succeeds incorrectly
......
...@@ -35,7 +35,7 @@ func explode(s string) *[]string { ...@@ -35,7 +35,7 @@ func explode(s string) *[]string {
func itoa(i int) string { func itoa(i int) string {
s := strconv.itoa(i); s := strconv.itoa(i);
n, ok := strconv.atoi(s); n, err := strconv.atoi(s);
if n != i { if n != i {
print("itoa: ", i, " ", s, "\n"); print("itoa: ", i, " ", s, "\n");
panic("itoa") panic("itoa")
...@@ -92,20 +92,20 @@ func main() { ...@@ -92,20 +92,20 @@ func main() {
a := split(faces, ""); a := split(faces, "");
if len(a) != 3 || a[0] != "☺" || a[1] != "☻" || a[2] != "☹" { panic("split faces empty") } if len(a) != 3 || a[0] != "☺" || a[1] != "☻" || a[2] != "☹" { panic("split faces empty") }
} }
{ {
n, ok := strconv.atoi("0"); if n != 0 || !ok { panic("atoi 0") } n, err := strconv.atoi("0"); if n != 0 || err != nil { panic("atoi 0") }
n, ok = strconv.atoi("-1"); if n != -1 || !ok { panic("atoi -1") } n, err = strconv.atoi("-1"); if n != -1 || err != nil { panic("atoi -1") }
n, ok = strconv.atoi("+345"); if n != 345 || !ok { panic("atoi +345") } n, err = strconv.atoi("+345"); if n != 345 || err != nil { panic("atoi +345") }
n, ok = strconv.atoi("9999"); if n != 9999 || !ok { panic("atoi 9999") } n, err = strconv.atoi("9999"); if n != 9999 || err != nil { panic("atoi 9999") }
n, ok = strconv.atoi("20ba"); if n != 0 || ok { panic("atoi 20ba") } n, err = strconv.atoi("20ba"); if n != 0 || err == nil { panic("atoi 20ba") }
n, ok = strconv.atoi("hello"); if n != 0 || ok { panic("hello") } n, err = strconv.atoi("hello"); if n != 0 || err == nil { panic("hello") }
} }
if strconv.ftoa(1e6, 'e', 6) != "1.000000e+06" { panic("ftoa 1e6") } if strconv.ftoa(1e6, 'e', 6) != "1.000000e+06" { panic("ftoa 1e6") }
if strconv.ftoa(-1e-6, 'e', 6) != "-1.000000e-06" { panic("ftoa -1e-6") } if strconv.ftoa(-1e-6, 'e', 6) != "-1.000000e-06" { panic("ftoa -1e-6") }
if strconv.ftoa(-1.234567e-6, 'e', 6) != "-1.234567e-06" { panic("ftoa -1.234567e-6") } if strconv.ftoa(-1.234567e-6, 'e', 6) != "-1.234567e-06" { panic("ftoa -1.234567e-6") }
if itoa(0) != "0" { panic("itoa 0") } if itoa(0) != "0" { panic("itoa 0") }
if itoa(12345) != "12345" { panic("itoa 12345") } if itoa(12345) != "12345" { panic("itoa 12345") }
if itoa(-1<<31) != "-2147483648" { panic("itoa 1<<31") } if itoa(-1<<31) != "-2147483648" { panic("itoa 1<<31") }
...@@ -114,7 +114,7 @@ func main() { ...@@ -114,7 +114,7 @@ func main() {
// if itoa(-1<<63) != "-9223372036854775808" { panic("itoa 1<<63") } // if itoa(-1<<63) != "-9223372036854775808" { panic("itoa 1<<63") }
{ {
a, overflow, ok := strconv.atof64("-1.2345e4"); a, err := strconv.atof64("-1.2345e4");
if !ok || a != -12345. { panic(a, "atof64 -1.2345e4") } if err != nil || a != -12345. { panic(a, "atof64 -1.2345e4") }
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment