Ember Sawady: 1 os: add setenv and unsetenv 7 files changed, 71 insertions(+), 84 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~sircmpwn/hare-dev/patches/41703/mbox | git am -3Learn more about email & git
Signed-off-by: Ember Sawady <ecs@d2evs.net> --- v3: improve docs and check for nul. name validity checks in setenv() are already handled by the unsetenv() call, like how os::exec:: does it os/+freebsd/dirfdfs.ha | 1 - .../{environ.ha => platform_environ.ha} | 39 ++-------------- os/+linux/dirfdfs.ha | 1 - os/+linux/{environ.ha => platform_environ.ha} | 39 ++-------------- os/environ.ha | 45 +++++++++++++++++++ scripts/gen-stdlib | 10 +++-- stdlib.mk | 20 +++++---- 7 files changed, 71 insertions(+), 84 deletions(-) rename os/+freebsd/{environ.ha => platform_environ.ha} (72%) rename os/+linux/{environ.ha => platform_environ.ha} (71%) create mode 100644 os/environ.ha diff --git a/os/+freebsd/dirfdfs.ha b/os/+freebsd/dirfdfs.ha index 13903709..50c41c83 100644 --- a/os/+freebsd/dirfdfs.ha +++ b/os/+freebsd/dirfdfs.ha @@ -2,7 +2,6 @@ // (c) 2021-2022 Drew DeVault <sir@cmpwn.com> // (c) 2021 Ember Sawady <ecs@d2evs.net> // (c) 2022 Jon Eskin <eskinjp@gmail.com> -use bytes; use errors; use encoding::utf8; use fs; diff --git a/os/+freebsd/environ.ha b/os/+freebsd/platform_environ.ha similarity index 72% rename from os/+freebsd/environ.ha rename to os/+freebsd/platform_environ.ha index 9dd81a94..931a49b2 100644 --- a/os/+freebsd/environ.ha +++ b/os/+freebsd/platform_environ.ha @@ -1,7 +1,6 @@ // License: MPL-2.0 // (c) 2021 Drew DeVault <sir@cmpwn.com> // (c) 2021 Ember Sawady <ecs@d2evs.net> -use bytes; use errors; use rt; use strings; @@ -15,7 +14,7 @@ export let args: []str = []; // syscall if we don't need it. let args_static: [32]str = [""...]; -@init fn init_environ() void = { +@init fn args() void = { if (rt::argc < len(args_static)) { args = args_static[..rt::argc]; for (let i = 0z; i < rt::argc; i += 1) { @@ -30,50 +29,20 @@ let args_static: [32]str = [""...]; }; -@fini fn fini_environ() void = { +@fini fn args() void = { if (rt::argc >= len(args_static)) { free(args); }; - free(envp); }; -// Looks up an environment variable and returns its value, or void if unset. -export fn getenv(name: const str) (str | void) = { - const name_b = strings::toutf8(name); - for (let i = 0z; rt::envp[i] != null; i += 1) { - const item = rt::envp[i]: *[*]u8; - const ln = c::strlen(item: *c::char); - const eq: size = match (bytes::index(item[..ln], '=')) { - case void => - abort("Environment violates System-V invariants"); - case let i: size => - yield i; - }; - if (bytes::equal(name_b, item[..eq])) { - const ln = c::strlen(item: *const c::char); - return strings::fromutf8(item[eq+1..ln])!; - }; - }; -}; - -// Looks up an environment variable and returns its value, or a default value if -// unset. -export fn tryenv(name: const str, default: str) str = match (getenv(name)) { -case let s: str => - yield s; -case void => - yield default; -}; - -let envp: []str = []; - // Returns a slice of the environment strings in the form KEY=VALUE. export fn getenvs() []str = { if (len(envp) != 0) { return envp; }; for (let i = 0z; rt::envp[i] != null; i += 1) { - append(envp, c::tostr(rt::envp[i]: *const c::char)!); + let s = c::tostr(rt::envp[i]: *const c::char)!; + append(envp, strings::dup(s)); }; return envp; }; diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha index c7fcd451..bd658100 100644 --- a/os/+linux/dirfdfs.ha +++ b/os/+linux/dirfdfs.ha @@ -4,7 +4,6 @@ // (c) 2021-2022 Drew DeVault <sir@cmpwn.com> // (c) 2021 Ember Sawady <ecs@d2evs.net> // (c) 2022 Jon Eskin <eskinjp@gmail.com> -use bytes; use errors; use encoding::utf8; use fs; diff --git a/os/+linux/environ.ha b/os/+linux/platform_environ.ha similarity index 71% rename from os/+linux/environ.ha rename to os/+linux/platform_environ.ha index 6acd0507..c14fb914 100644 --- a/os/+linux/environ.ha +++ b/os/+linux/platform_environ.ha @@ -1,7 +1,6 @@ // License: MPL-2.0 // (c) 2021 Drew DeVault <sir@cmpwn.com> // (c) 2021 Ember Sawady <ecs@d2evs.net> -use bytes; use errors; use math; use rt; @@ -16,7 +15,7 @@ export let args: []str = []; // syscall if we don't need it. let args_static: [32]str = [""...]; -@init fn init_environ() void = { +@init fn args() void = { if (rt::argc < len(args_static)) { args = args_static[..rt::argc]; for (let i = 0z; i < rt::argc; i += 1) { @@ -31,50 +30,20 @@ let args_static: [32]str = [""...]; }; -@fini fn fini_environ() void = { +@fini fn args() void = { if (rt::argc >= len(args_static)) { free(args); }; - free(envp); }; -// Looks up an environment variable and returns its value, or void if unset. -export fn getenv(name: const str) (str | void) = { - const name_b = strings::toutf8(name); - for (let i = 0z; rt::envp[i] != null; i += 1) { - const item = rt::envp[i]: *[*]u8; - const ln = c::strlen(item: *c::char); - const eq: size = match (bytes::index(item[..ln], '=')) { - case void => - abort("Environment violates System-V invariants"); - case let i: size => - yield i; - }; - if (bytes::equal(name_b, item[..eq])) { - const ln = c::strlen(item: *const c::char); - return strings::fromutf8(item[eq+1..ln])!; - }; - }; -}; - -// Looks up an environment variable and returns its value, or a default value if -// unset. -export fn tryenv(name: const str, default: str) str = match (getenv(name)) { -case let s: str => - yield s; -case void => - yield default; -}; - -let envp: []str = []; - // Returns a slice of the environment strings in the form KEY=VALUE. export fn getenvs() []str = { if (len(envp) != 0) { return envp; }; for (let i = 0z; rt::envp[i] != null; i += 1) { - append(envp, c::tostr(rt::envp[i]: *const c::char)!); + let s = c::tostr(rt::envp[i]: *const c::char)!; + append(envp, strings::dup(s)); }; return envp; }; diff --git a/os/environ.ha b/os/environ.ha new file mode 100644 index 00000000..9551516a --- /dev/null +++ b/os/environ.ha @@ -0,0 +1,45 @@ +use errors; +use strings; + +let envp: []str = []; + +@fini fn envp() void = strings::freeall(envp); + +// Looks up an environment variable and returns its value, or void if unset. +export fn getenv(name: const str) (str | void) = { + getenvs(); // populate envp + for (let i = 0z; i < len(envp); i += 1) { + let (key, value) = strings::cut(envp[i], "="); + if (key == name) return value; + }; +}; + +// Looks up an environment variable and returns its value, or a default value if +// unset. +export fn tryenv(name: const str, default: str) str = match (getenv(name)) { +case let s: str => return s; +case void => return default; +}; + +// Sets an environment variable, overwriting it if it's already set. The name +// may not contain '=' or '\0', and the value may not contain '\0'. +export fn setenv(name: const str, value: const str) (void | errors::invalid) = { + if (strings::contains(value, '\0')) return errors::invalid; + unsetenv(name)?; + append(envp, strings::join("=", name, value)); +}; + +// Unsets an environment variable. Does nothing if the variable isn't set. The +// name may not contain '=' or '\0'. +export fn unsetenv(name: const str) (void | errors::invalid) = { + if (strings::contains(name, '=', '\0')) return errors::invalid; + getenvs(); // populate envp + for (let i = 0z; i < len(envp); i += 1) { + if (strings::cut(envp[i], "=").0 == name) { + free(envp[i]); + delete(envp[i]); + break; + }; + }; +}; + diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib index 544af061..460a21c4 100755 --- a/scripts/gen-stdlib +++ b/scripts/gen-stdlib @@ -1186,25 +1186,27 @@ os() { gen_srcs -plinux os \ +linux/dirfdfs.ha \ - +linux/environ.ha \ + +linux/platform_environ.ha \ +linux/$exit \ +linux/fs.ha \ +linux/memory.ha \ +linux/status.ha \ +linux/stdfd.ha \ + environ.ha \ os.ha - gen_ssa -plinux os io strings fs encoding::utf8 bytes bufio \ + gen_ssa -plinux os io strings fs encoding::utf8 bufio \ errors math types::c gen_srcs -pfreebsd os \ - +freebsd/environ.ha \ + +freebsd/platform_environ.ha \ +freebsd/$exit \ +freebsd/dirfdfs.ha \ +freebsd/status.ha \ +freebsd/stdfd.ha \ +freebsd/fs.ha \ + environ.ha \ os.ha - gen_ssa -pfreebsd os io strings fs encoding::utf8 bytes bufio \ + gen_ssa -pfreebsd os io strings fs encoding::utf8 bufio \ errors types::c } diff --git a/stdlib.mk b/stdlib.mk index c5c49937..9c8483ab 100644 --- a/stdlib.mk +++ b/stdlib.mk @@ -1923,15 +1923,16 @@ $(HARECACHE)/net/uri/net_uri-any.ssa: $(stdlib_net_uri_any_srcs) $(stdlib_rt) $( # os (+linux) stdlib_os_linux_srcs = \ $(STDLIB)/os/+linux/dirfdfs.ha \ - $(STDLIB)/os/+linux/environ.ha \ + $(STDLIB)/os/+linux/platform_environ.ha \ $(STDLIB)/os/+linux/exit.ha \ $(STDLIB)/os/+linux/fs.ha \ $(STDLIB)/os/+linux/memory.ha \ $(STDLIB)/os/+linux/status.ha \ $(STDLIB)/os/+linux/stdfd.ha \ + $(STDLIB)/os/environ.ha \ $(STDLIB)/os/os.ha -$(HARECACHE)/os/os-linux.ssa: $(stdlib_os_linux_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_math_$(PLATFORM)) $(stdlib_types_c_$(PLATFORM)) +$(HARECACHE)/os/os-linux.ssa: $(stdlib_os_linux_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_math_$(PLATFORM)) $(stdlib_types_c_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/os @$(stdlib_env) $(HAREC) $(HAREFLAGS) -o $@ -Nos \ @@ -1939,15 +1940,16 @@ $(HARECACHE)/os/os-linux.ssa: $(stdlib_os_linux_srcs) $(stdlib_rt) $(stdlib_io_$ # os (+freebsd) stdlib_os_freebsd_srcs = \ - $(STDLIB)/os/+freebsd/environ.ha \ + $(STDLIB)/os/+freebsd/platform_environ.ha \ $(STDLIB)/os/+freebsd/exit.ha \ $(STDLIB)/os/+freebsd/dirfdfs.ha \ $(STDLIB)/os/+freebsd/status.ha \ $(STDLIB)/os/+freebsd/stdfd.ha \ $(STDLIB)/os/+freebsd/fs.ha \ + $(STDLIB)/os/environ.ha \ $(STDLIB)/os/os.ha -$(HARECACHE)/os/os-freebsd.ssa: $(stdlib_os_freebsd_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_types_c_$(PLATFORM)) +$(HARECACHE)/os/os-freebsd.ssa: $(stdlib_os_freebsd_srcs) $(stdlib_rt) $(stdlib_io_$(PLATFORM)) $(stdlib_strings_$(PLATFORM)) $(stdlib_fs_$(PLATFORM)) $(stdlib_encoding_utf8_$(PLATFORM)) $(stdlib_bufio_$(PLATFORM)) $(stdlib_errors_$(PLATFORM)) $(stdlib_types_c_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/os @$(stdlib_env) $(HAREC) $(HAREFLAGS) -o $@ -Nos \ @@ -4416,15 +4418,16 @@ $(TESTCACHE)/net/uri/net_uri-any.ssa: $(testlib_net_uri_any_srcs) $(testlib_rt) # os (+linux) testlib_os_linux_srcs = \ $(STDLIB)/os/+linux/dirfdfs.ha \ - $(STDLIB)/os/+linux/environ.ha \ + $(STDLIB)/os/+linux/platform_environ.ha \ $(STDLIB)/os/+linux/exit+test.ha \ $(STDLIB)/os/+linux/fs.ha \ $(STDLIB)/os/+linux/memory.ha \ $(STDLIB)/os/+linux/status.ha \ $(STDLIB)/os/+linux/stdfd.ha \ + $(STDLIB)/os/environ.ha \ $(STDLIB)/os/os.ha -$(TESTCACHE)/os/os-linux.ssa: $(testlib_os_linux_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_math_$(PLATFORM)) $(testlib_types_c_$(PLATFORM)) +$(TESTCACHE)/os/os-linux.ssa: $(testlib_os_linux_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_math_$(PLATFORM)) $(testlib_types_c_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/os @$(testlib_env) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nos \ @@ -4432,15 +4435,16 @@ $(TESTCACHE)/os/os-linux.ssa: $(testlib_os_linux_srcs) $(testlib_rt) $(testlib_i # os (+freebsd) testlib_os_freebsd_srcs = \ - $(STDLIB)/os/+freebsd/environ.ha \ + $(STDLIB)/os/+freebsd/platform_environ.ha \ $(STDLIB)/os/+freebsd/exit+test.ha \ $(STDLIB)/os/+freebsd/dirfdfs.ha \ $(STDLIB)/os/+freebsd/status.ha \ $(STDLIB)/os/+freebsd/stdfd.ha \ $(STDLIB)/os/+freebsd/fs.ha \ + $(STDLIB)/os/environ.ha \ $(STDLIB)/os/os.ha -$(TESTCACHE)/os/os-freebsd.ssa: $(testlib_os_freebsd_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_bytes_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_types_c_$(PLATFORM)) +$(TESTCACHE)/os/os-freebsd.ssa: $(testlib_os_freebsd_srcs) $(testlib_rt) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) $(testlib_fs_$(PLATFORM)) $(testlib_encoding_utf8_$(PLATFORM)) $(testlib_bufio_$(PLATFORM)) $(testlib_errors_$(PLATFORM)) $(testlib_types_c_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/os @$(testlib_env) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nos \ -- 2.41.0
Thanks! To gitsrht:~sircmpwn/hare ccf63b91..e0ed8fa3 master -> master
builds.sr.ht <builds@sr.ht>hare/patches: SUCCESS in 1m44s [os: add setenv and unsetenv][0] v3 from [Ember Sawady][1] [0]: https://lists.sr.ht/~sircmpwn/hare-dev/patches/41703 [1]: mailto:ecs@d2evs.net ✓ #1003046 SUCCESS hare/patches/freebsd.yml https://builds.sr.ht/~sircmpwn/job/1003046 ✓ #1003045 SUCCESS hare/patches/alpine.yml https://builds.sr.ht/~sircmpwn/job/1003045