Skip to content

Commit ea73d5d

Browse files
author
morphqdd
committed
feat(stdlib): env.getenv(name) — value of an env var (buf)
Iterates envp, returns the bytes after KEY= for a matching entry, empty buf if unset. Lets Lake tools read config from the environment (used by lake-house to locate the toolchain portably).
1 parent f990fb0 commit ea73d5d

1 file changed

Lines changed: 78 additions & 0 deletions

File tree

std/env.lake

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
// `rt_cstr_to_buf` copies each null-terminated entry into a Lake-owned
55
// `buf`, returned as an `{atom buf}` tuple.
66

7+
+std.bytes.{ at size }
8+
+std.process.{ alloc_or_die }
9+
710
@rt(rt_argc_raw)
811
@rt(rt_argv_raw)
912
@rt(rt_envp_raw)
1013
@rt(rt_load_ptr_raw)
1114
@rt(rt_cstr_to_buf)
1215
@rt(rt_cstr_len)
16+
@rt(rt_copy_bytes)
1317

1418
// Number of command-line arguments, including argv[0].
1519
pub argc is {
@@ -46,3 +50,77 @@ pub envp_at is {
4650

4751
// For entry length, callers use `std.bytes.size(b)` (re-exporting it
4852
// here would collide — bug #97).
53+
54+
// ── getenv (#97) ────────────────────────────────────────────────
55+
//
56+
// `getenv(name)` returns the value of environment variable `name` (the
57+
// bytes after `=`), or an empty buf when the variable is absent. An
58+
// env var set to the empty string is reported as absent too — fine for
59+
// path-style lookups (LAKEC / LAKE_STDLIB) where empty == unset.
60+
61+
// 1 iff the first `nn` bytes of `e` equal `name`.
62+
env_prefix_eq is {
63+
e buf name buf nn i64 i i64 -> ret i64 {
64+
when i >= nn {
65+
true -> { ret 1 }
66+
false -> {
67+
when at(e i) == at(name i) {
68+
true -> { self(e name nn i + 1) }
69+
false -> { ret 0 }
70+
}
71+
}
72+
}
73+
}
74+
}
75+
76+
// If `e` is `name=<value>`, return a fresh buf with `<value>`, else empty.
77+
env_match is {
78+
e buf name buf -> ret buf {
79+
let en = size(e)
80+
let nn = size(name)
81+
when en < nn + 1 {
82+
true -> { ret alloc_or_die(0) }
83+
false -> {
84+
let pm = env_prefix_eq(e name nn 0)
85+
when pm == 1 {
86+
true -> {
87+
let eq = at(e nn)
88+
when eq == 61 {
89+
true -> {
90+
let vlen = en - nn - 1
91+
let out = alloc_or_die(vlen)
92+
rt_copy_bytes(out 0 e nn + 1 vlen)
93+
ret out
94+
}
95+
false -> { ret alloc_or_die(0) }
96+
}
97+
}
98+
false -> { ret alloc_or_die(0) }
99+
}
100+
}
101+
}
102+
}
103+
}
104+
105+
getenv_at is {
106+
name buf i i64 -> ret buf {
107+
let base = rt_envp_raw()
108+
let p = rt_load_ptr_raw(base i)
109+
when p == 0 {
110+
true -> { ret alloc_or_die(0) }
111+
false -> {
112+
let entry = rt_cstr_to_buf(p)
113+
let val = env_match(entry.1 name)
114+
when size(val) > 0 {
115+
true -> { ret val }
116+
false -> { self(name i + 1) }
117+
}
118+
}
119+
}
120+
}
121+
}
122+
123+
// Value of env var `name`, or an empty buf if unset / empty.
124+
pub getenv is {
125+
name buf -> ret buf { ret getenv_at(name 0) }
126+
}

0 commit comments

Comments
 (0)