|
4 | 4 | // `rt_cstr_to_buf` copies each null-terminated entry into a Lake-owned |
5 | 5 | // `buf`, returned as an `{atom buf}` tuple. |
6 | 6 |
|
| 7 | ++std.bytes.{ at size } |
| 8 | ++std.process.{ alloc_or_die } |
| 9 | + |
7 | 10 | @rt(rt_argc_raw) |
8 | 11 | @rt(rt_argv_raw) |
9 | 12 | @rt(rt_envp_raw) |
10 | 13 | @rt(rt_load_ptr_raw) |
11 | 14 | @rt(rt_cstr_to_buf) |
12 | 15 | @rt(rt_cstr_len) |
| 16 | +@rt(rt_copy_bytes) |
13 | 17 |
|
14 | 18 | // Number of command-line arguments, including argv[0]. |
15 | 19 | pub argc is { |
@@ -46,3 +50,77 @@ pub envp_at is { |
46 | 50 |
|
47 | 51 | // For entry length, callers use `std.bytes.size(b)` (re-exporting it |
48 | 52 | // 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