From 42b02c47be9b285099203e44a2570636d4ca6f03 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Fri, 11 Sep 2026 14:47:10 +0200 Subject: krino: foundation — sexp reader, config language, init/new/check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/config/units.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 internal/config/units.go (limited to 'internal/config/units.go') 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) +} -- cgit v1.3