aboutsummaryrefslogtreecommitdiff
path: root/internal/config/units.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-11 14:47:10 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-11 15:01:57 +0200
commit42b02c47be9b285099203e44a2570636d4ca6f03 (patch)
tree82bcb9e19bd886f36e1ca7b2d94a204c988f1fd1 /internal/config/units.go
downloadkrino-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.go71
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)
+}