github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/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 {"", 1}, // no suffix is still a valid suffix 42 } 43 44 strSize = strings.ToLower(strSize) 45 for _, unit := range units { 46 if strings.HasSuffix(strSize, unit.suffix) { 47 r, ok := new(big.Rat).SetString(strings.TrimSuffix(strSize, unit.suffix)) 48 if !ok { 49 return "", errUnableToParseSize 50 } 51 r.Mul(r, new(big.Rat).SetInt(big.NewInt(unit.multiplier))) 52 if !r.IsInt() { 53 f, _ := r.Float64() 54 return fmt.Sprintf("%d", int64(f)), nil 55 } 56 return r.RatString(), nil 57 } 58 } 59 60 return "", errUnableToParseSize 61 } 62 63 // parsePeriod converts a number of weeks to a number of blocks. 64 func parsePeriod(period string) (string, error) { 65 var weeks float64 66 _, err := fmt.Sscan(period, &weeks) 67 if err != nil { 68 return "", errUnableToParseSize 69 } 70 blocks := int(weeks * 1008) // 1008 blocks per week 71 return fmt.Sprint(blocks), nil 72 } 73 74 // currencyUnits converts a types.Currency to a string with human-readable 75 // units. The unit used will be the largest unit that results in a value 76 // greater than 1. The value is rounded to 4 significant digits. 77 func currencyUnits(c types.Currency) string { 78 pico := types.SiacoinPrecision.Div64(1e12) 79 if c.Cmp(pico) < 0 { 80 return c.String() + " H" 81 } 82 83 // iterate until we find a unit greater than c 84 mag := pico 85 unit := "" 86 for _, unit = range []string{"pS", "nS", "uS", "mS", "SC", "KS", "MS", "GS", "TS"} { 87 if c.Cmp(mag.Mul64(1e3)) < 0 { 88 break 89 } else if unit != "TS" { 90 // don't want to perform this multiply on the last iter; that 91 // would give us 1.235 TS instead of 1235 TS 92 mag = mag.Mul64(1e3) 93 } 94 } 95 96 num := new(big.Rat).SetInt(c.Big()) 97 denom := new(big.Rat).SetInt(mag.Big()) 98 res, _ := new(big.Rat).Mul(num, denom.Inv(denom)).Float64() 99 100 return fmt.Sprintf("%.4g %s", res, unit) 101 } 102 103 // parseCurrency converts a siacoin amount to base units. 104 func parseCurrency(amount string) (string, error) { 105 units := []string{"pS", "nS", "uS", "mS", "SC", "KS", "MS", "GS", "TS"} 106 for i, unit := range units { 107 if strings.HasSuffix(amount, unit) { 108 // scan into big.Rat 109 r, ok := new(big.Rat).SetString(strings.TrimSuffix(amount, unit)) 110 if !ok { 111 return "", errors.New("malformed amount") 112 } 113 // convert units 114 exp := 24 + 3*(int64(i)-4) 115 mag := new(big.Int).Exp(big.NewInt(10), big.NewInt(exp), nil) 116 r.Mul(r, new(big.Rat).SetInt(mag)) 117 // r must be an integer at this point 118 if !r.IsInt() { 119 return "", errors.New("non-integer number of hastings") 120 } 121 return r.RatString(), nil 122 } 123 } 124 // check for hastings separately 125 if strings.HasSuffix(amount, "H") { 126 return strings.TrimSuffix(amount, "H"), nil 127 } 128 129 return "", errors.New("amount is missing units; run 'wallet --help' for a list of units") 130 }