// strings — operations over the immutable str type ({ *u8, len }). use os; export fn len(s: str) i32 = { return s.len; }; export fn isempty(s: str) bool = { return s.len == 0; }; export fn equal(a: str, b: str) bool = { if (a.len != b.len) { return false; }; let i: i32 = 0; for (i < a.len) { if (a[i] != b[i]) { return false; }; i += 1; }; return true; }; export fn hasprefix(s: str, p: str) bool = { if (p.len > s.len) { return false; }; let i: i32 = 0; for (i < p.len) { if (s[i] != p[i]) { return false; }; i += 1; }; return true; }; export fn hassuffix(s: str, suf: str) bool = { if (suf.len > s.len) { return false; }; let off: i32 = s.len - suf.len; let i: i32 = 0; for (i < suf.len) { if (s[off + i] != suf[i]) { return false; }; i += 1; }; return true; }; // indexbyte — first index of `c` in `s`, or -1 if absent. Plan 9- // style sentinel return; callers that prefer a fallible shape can // wrap this in their own (i32 | str). No allocation. export fn indexbyte(s: str, c: u8) i32 = { let i: i32 = 0; for (i < s.len) { if (s[i] == c) { return i; }; i += 1; }; return -1; }; // index — first index of `sub` in `s`, or -1. Naive scan; fine for // short patterns and small strings, which dominate config and CLI // parsing. Empty `sub` matches at 0. export fn index(s: str, sub: str) i32 = { if (sub.len == 0) { return 0; }; if (sub.len > s.len) { return -1; }; let last: i32 = s.len - sub.len; let i: i32 = 0; for (i <= last) { let j: i32 = 0; let ok: bool = true; for (j < sub.len) { if (s[i + j] != sub[j]) { ok = false; j = sub.len; } else { j += 1; }; }; if (ok) { return i; }; i += 1; }; return -1; }; export fn contains(s: str, sub: str) bool = { return index(s, sub) >= 0; }; // concat — joins two strings into a fresh str. Caller owns the // returned str's storage; release via `os.free(r.ptr, r.len)`. Mirrors // Hare's strings::concat shape. export fn concat(a: str, b: str) str = { let total: i32 = a.len + b.len; let buf: *u8 = os.alloc(total: u64): *u8; let i: i32 = 0; for (i < a.len) { buf[i] = a[i]; i += 1; }; let j: i32 = 0; for (j < b.len) { buf[a.len + j] = b[j]; j += 1; }; let r: str; r.ptr = buf; r.len = total; return r; };