commit aef0a97bedd46608db499196f239c1a529801432
parent 25c165ad428a6eb5d2942c782eda8b128a8f5cff
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 6 Mar 2021 14:48:03 -0500
os::exec: add setenv
Diffstat:
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 = {