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