summaryrefslogtreecommitdiff
path: root/libgo/go/strconv/atoi.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/strconv/atoi.go')
-rw-r--r--libgo/go/strconv/atoi.go202
1 files changed, 202 insertions, 0 deletions
diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go
new file mode 100644
index 000000000..f7b845672
--- /dev/null
+++ b/libgo/go/strconv/atoi.go
@@ -0,0 +1,202 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+import "os"
+
+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)
+ for 1<<siz != 0 {
+ siz *= 2
+ }
+ return siz
+}
+
+var IntSize = computeIntsize()
+
+// 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
+}
+
+// Btoui64 interprets a string s in an arbitrary base b (2 to 36)
+// 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) {
+ 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:]
+ 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
+ cutoff := cutoff64(b)
+
+ for i := 0; i < len(s); i++ {
+ var v byte
+ d := s[i]
+ switch {
+ case '0' <= d && d <= '9':
+ v = d - '0'
+ case 'a' <= d && d <= 'z':
+ v = d - 'a' + 10
+ case 'A' <= d && d <= 'Z':
+ v = d - 'A' + 10
+ default:
+ n = 0
+ err = os.EINVAL
+ goto Error
+ }
+ if int(v) >= b {
+ n = 0
+ err = os.EINVAL
+ goto Error
+ }
+
+ if n >= cutoff {
+ // n*b overflows
+ n = 1<<64 - 1
+ err = os.ERANGE
+ goto Error
+ }
+ n *= uint64(b)
+
+ n1 := n + uint64(v)
+ if n1 < n {
+ // n+v overflows
+ n = 1<<64 - 1
+ err = os.ERANGE
+ goto Error
+ }
+ n = n1
+ }
+
+ return n, nil
+
+Error:
+ return n, &NumError{s0, err}
+}
+
+// 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) {
+ return Btoui64(s, 10)
+}
+
+// Btoi64 is like Btoui64 but allows signed numbers and
+// returns its result in an int64.
+func Btoi64(s string, base int) (i int64, err os.Error) {
+ // Empty string bad.
+ if len(s) == 0 {
+ return 0, &NumError{s, os.EINVAL}
+ }
+
+ // Pick off leading sign.
+ s0 := s
+ neg := false
+ if s[0] == '+' {
+ s = s[1:]
+ } else if s[0] == '-' {
+ neg = true
+ s = s[1:]
+ }
+
+ // Convert unsigned and check range.
+ var un uint64
+ un, err = Btoui64(s, base)
+ if err != nil && err.(*NumError).Error != os.ERANGE {
+ err.(*NumError).Num = s0
+ return 0, err
+ }
+ if !neg && un >= 1<<63 {
+ return 1<<63 - 1, &NumError{s0, os.ERANGE}
+ }
+ if neg && un > 1<<63 {
+ return -1 << 63, &NumError{s0, os.ERANGE}
+ }
+ n := int64(un)
+ if neg {
+ n = -n
+ }
+ 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)
+ if e1 != nil && e1.(*NumError).Error != os.ERANGE {
+ return 0, e1
+ }
+ i = uint(i1)
+ if uint64(i) != i1 {
+ return ^uint(0), &NumError{s, os.ERANGE}
+ }
+ return i, nil
+}
+
+// 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.(*NumError).Error != os.ERANGE {
+ return 0, e1
+ }
+ i = int(i1)
+ if int64(i) != i1 {
+ if i1 < 0 {
+ return -1 << (IntSize - 1), &NumError{s, os.ERANGE}
+ }
+ return 1<<(IntSize-1) - 1, &NumError{s, os.ERANGE}
+ }
+ return i, nil
+}