diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-11 14:47:10 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-11 15:01:57 +0200 |
| commit | 42b02c47be9b285099203e44a2570636d4ca6f03 (patch) | |
| tree | 82bcb9e19bd886f36e1ca7b2d94a204c988f1fd1 /internal/config/units.go | |
| download | krino-42b02c47be9b285099203e44a2570636d4ca6f03.tar.gz krino-42b02c47be9b285099203e44a2570636d4ca6f03.zip | |
krino: foundation — sexp reader, config language, init/new/check
Diffstat (limited to 'internal/config/units.go')
| -rw-r--r-- | internal/config/units.go | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/internal/config/units.go b/internal/config/units.go new file mode 100644 index 0000000..ea61dee --- /dev/null +++ b/internal/config/units.go @@ -0,0 +1,71 @@ +// 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) +} |
