1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
package main
import (
"errors"
"fmt"
"math"
"math/big"
"strings"
"github.com/NebulousLabs/Sia/types"
)
var errUnableToParseSize = errors.New("unable to parse size")
// filesize returns a string that displays a filesize in human-readable units.
func filesizeUnits(size int64) string {
if size == 0 {
return "0 B"
}
sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
i := int(math.Log10(float64(size)) / 3)
return fmt.Sprintf("%.*f %s", i, float64(size)/math.Pow10(3*i), sizes[i])
}
// parseFilesize converts strings of form 10GB to a size in bytes. Fractional
// sizes are truncated at the byte size.
func parseFilesize(strSize string) (string, error) {
units := []struct {
suffix string
multiplier int64
}{
{"kb", 1e3},
{"mb", 1e6},
{"gb", 1e9},
{"tb", 1e12},
{"kib", 1 << 10},
{"mib", 1 << 20},
{"gib", 1 << 30},
{"tib", 1 << 40},
{"b", 1}, // must be after others else it'll match on them all
}
strSize = strings.ToLower(strSize)
for _, unit := range units {
if strings.HasSuffix(strSize, unit.suffix) {
r, ok := new(big.Rat).SetString(strings.TrimSuffix(strSize, unit.suffix))
if !ok {
return "", errUnableToParseSize
}
r.Mul(r, new(big.Rat).SetInt(big.NewInt(unit.multiplier)))
if !r.IsInt() {
f, _ := r.Float64()
return fmt.Sprintf("%d", int64(f)), nil
}
return r.RatString(), nil
}
}
return "", errUnableToParseSize
}
// periodUnits turns a period in terms of blocks to a number of weeks.
func periodUnits(blocks types.BlockHeight) string {
return fmt.Sprint(blocks / 1008) // 1008 blocks per week
}
// parsePeriod converts a duration specified in blocks, hours, or weeks to a
// number of blocks.
func parsePeriod(period string) (string, error) {
units := []struct {
suffix string
multiplier float64
}{
{"b", 1}, // blocks
{"block", 1}, // blocks
{"blocks", 1}, // blocks
{"h", 6}, // hours
{"hour", 6}, // hours
{"hours", 6}, // hours
{"d", 144}, // days
{"day", 144}, // days
{"days", 144}, // days
{"w", 1008}, // weeks
{"week", 1008}, // weeks
{"weeks", 1008}, // weeks
}
period = strings.ToLower(period)
for _, unit := range units {
if strings.HasSuffix(period, unit.suffix) {
var base float64
_, err := fmt.Sscan(strings.TrimSuffix(period, unit.suffix), &base)
if err != nil {
return "", errUnableToParseSize
}
blocks := int(base * unit.multiplier)
return fmt.Sprint(blocks), nil
}
}
return "", errUnableToParseSize
}
// currencyUnits converts a types.Currency to a string with human-readable
// units. The unit used will be the largest unit that results in a value
// greater than 1. The value is rounded to 4 significant digits.
func currencyUnits(c types.Currency) string {
pico := types.SiacoinPrecision.Div64(1e12)
if c.Cmp(pico) < 0 {
return c.String() + " H"
}
// iterate until we find a unit greater than c
mag := pico
unit := ""
for _, unit = range []string{"pS", "nS", "uS", "mS", "SC", "KS", "MS", "GS", "TS"} {
if c.Cmp(mag.Mul64(1e3)) < 0 {
break
} else if unit != "TS" {
// don't want to perform this multiply on the last iter; that
// would give us 1.235 TS instead of 1235 TS
mag = mag.Mul64(1e3)
}
}
num := new(big.Rat).SetInt(c.Big())
denom := new(big.Rat).SetInt(mag.Big())
res, _ := new(big.Rat).Mul(num, denom.Inv(denom)).Float64()
return fmt.Sprintf("%.4g %s", res, unit)
}
// parseCurrency converts a siacoin amount to base units.
func parseCurrency(amount string) (string, error) {
units := []string{"pS", "nS", "uS", "mS", "SC", "KS", "MS", "GS", "TS"}
for i, unit := range units {
if strings.HasSuffix(amount, unit) {
// scan into big.Rat
r, ok := new(big.Rat).SetString(strings.TrimSuffix(amount, unit))
if !ok {
return "", errors.New("malformed amount")
}
// convert units
exp := 24 + 3*(int64(i)-4)
mag := new(big.Int).Exp(big.NewInt(10), big.NewInt(exp), nil)
r.Mul(r, new(big.Rat).SetInt(mag))
// r must be an integer at this point
if !r.IsInt() {
return "", errors.New("non-integer number of hastings")
}
return r.RatString(), nil
}
}
// check for hastings separately
if strings.HasSuffix(amount, "H") {
return strings.TrimSuffix(amount, "H"), nil
}
return "", errors.New("amount is missing units; run 'wallet --help' for a list of units")
}
// yesNo returns "Yes" if b is true, and "No" if b is false.
func yesNo(b bool) string {
if b {
return "Yes"
}
return "No"
}
|