// SPDX-License-Identifier: GPL-3.0-or-later package config import ( "errors" "fmt" "math" "strconv" "time" ) // ParseSize reads a size: a whole number with an optional K, M, G or T // suffix, in powers of 1024. func ParseSize(s string) (int64, error) { num, mult := s, int64(1) if n := len(s); n > 0 { switch s[n-1] { case 'K': mult = 1 << 10 case 'M': mult = 1 << 20 case 'G': mult = 1 << 30 case 'T': mult = 1 << 40 } if mult > 1 { num = s[:n-1] } } v, err := parseCount(num) if err != nil || v > math.MaxInt64/mult { return 0, fmt.Errorf("bad size %q: want a whole number with an optional K, M, G or T, like 50M", s) } return v * mult, nil } var durationUnits = map[byte]time.Duration{ 's': time.Second, 'm': time.Minute, 'h': time.Hour, 'd': 24 * time.Hour, 'w': 7 * 24 * time.Hour, } // ParseDuration reads a duration: a whole number followed by s, m, h, d or w. func ParseDuration(s string) (time.Duration, error) { bad := fmt.Errorf("bad duration %q: want a whole number followed by s, m, h, d or w, like 30d", s) if len(s) < 2 { return 0, bad } unit, ok := durationUnits[s[len(s)-1]] if !ok { return 0, bad } v, err := parseCount(s[:len(s)-1]) if err != nil || v > int64(math.MaxInt64/unit) { return 0, bad } return time.Duration(v) * unit, nil } // parseCount reads a non-empty run of ASCII digits. func parseCount(s string) (int64, error) { if s == "" { return 0, errors.New("empty number") } for _, c := range s { if c < '0' || c > '9' { return 0, errors.New("not a whole number") } } return strconv.ParseInt(s, 10, 64) }