hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit aef0a97bedd46608db499196f239c1a529801432
parent 25c165ad428a6eb5d2942c782eda8b128a8f5cff
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat,  6 Mar 2021 14:48:03 -0500

os::exec: add setenv

Diffstat:
Mos/exec/cmd+linux.ha | 8++++----
Mos/exec/cmd.ha | 33++++++++++++++++++++++++++++++---
Mos/exec/types.ha | 8++++----
3 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/os/exec/cmd+linux.ha b/os/exec/cmd+linux.ha @@ -48,10 +48,10 @@ fn platform_exec(cmd: *command) os_error = { append(argv, null); let envp: nullable *[*]nullable *const char = null; - if (len(cmd.envp) != 0) { - let env: []nullable *const char = alloc([], len(cmd.envp) + 1); - for (let i = 0z; i < len(cmd.envp); i += 1) { - append(env, strings::to_c(cmd.envp[i])); + if (len(cmd.env) != 0) { + let env: []nullable *const char = alloc([], len(cmd.env) + 1); + for (let i = 0z; i < len(cmd.env); i += 1) { + append(env, strings::to_c(cmd.env[i])); }; append(env, null); envp = env: *[*]nullable *const char; diff --git a/os/exec/cmd.ha b/os/exec/cmd.ha @@ -1,3 +1,4 @@ +use ascii; use os; use strings; @@ -26,11 +27,11 @@ export fn cmd(name: str, args: str...) (command | error) = { p: platform_cmd => p, }, argv = alloc([], len(args) + 1z), - envp = alloc([], len(env)), + env = alloc([], len(env)), ... }; append(cmd.argv, name, ...args); - append(cmd.envp, ...env); + append(cmd.env, ...env); return cmd; }; @@ -61,7 +62,33 @@ export fn start(cmd: *command) (error | process) = { // Empties the environment variables for the command. By default, the command // inherits the environment of the parent process. export fn clearenv(cmd: *command) void = { - cmd.envp = []; + cmd.env = []; +}; + +// Adds or sets a variable in the command environment. This does not affect the +// current process environment. The 'key' must be a valid environment variable +// name per POSIX definition 3.235. This includes underscores and alphanumeric +// ASCII characters, and cannot begin with a number. +export fn setenv(cmd: *command, key: str, value: str) void = { + let iter = strings::iter(key); + for (let i = 0z; true; i += 1) match (strings::next(&iter)) { + void => break, + r: rune => if (i == 0) assert(r == '_' || ascii::isalpha(r), + "Invalid environment variable") + else assert(r == '_' || ascii::isalnum(r), + "Invalid environment variable"), + }; + + // XXX: This can be a binary search + let fullkey = strings::concat(key, "="); + defer free(fullkey); + for (let i = 0z; i < len(cmd.env); i += 1) { + if (strings::has_prefix(cmd.env[i], fullkey)) { + delete(cmd.env[i]); + break; + }; + }; + append(cmd.env, strings::concat(fullkey, value)); }; fn lookup(name: str) (platform_cmd | void) = { diff --git a/os/exec/types.ha b/os/exec/types.ha @@ -2,20 +2,20 @@ export type command = struct { platform: platform_cmd, argv: []str, - envp: []str, + env: []str, }; // Returned when path resolution fails to find a command by its name. -export type nocmd = void; +export type nocmd = void!; // An error provided by the operating system. export type os_error = struct { string: *fn(data: *void) str, data: *void, -}; +}!; // All errors that can be returned from os::exec. -export type error = (nocmd | os_error); +export type error = (nocmd | os_error)!; // Returns a human-readable message for the given error. export fn errstr(err: error) const str = {