aboutsummaryrefslogtreecommitdiff
path: root/lib/std/os.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-02-22 15:59:13 -0500
committerAndrew Kelley <andrew@ziglang.org>2020-02-22 15:59:13 -0500
commit936d0b18b116ea126893d2f165f9be72f8bef845 (patch)
tree8481d2c4265d34217e6b045cbf1c7e34c30aab51 /lib/std/os.zig
parent0cd89e9176ab36fc5e267120dc4d75cb79d32684 (diff)
downloadzig-936d0b18b116ea126893d2f165f9be72f8bef845.tar.gz
zig-936d0b18b116ea126893d2f165f9be72f8bef845.zip
update std lib to integrate with libc for environ
closes #3511
Diffstat (limited to 'lib/std/os.zig')
-rw-r--r--lib/std/os.zig49
1 files changed, 44 insertions, 5 deletions
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 766b678c46..a4f148ae00 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -70,6 +70,8 @@ else switch (builtin.os) {
pub usingnamespace @import("os/bits.zig");
/// See also `getenv`. Populated by startup code before main().
+/// TODO this is a footgun because the value will be undefined when using `zig build-lib`.
+/// https://github.com/ziglang/zig/issues/4524
pub var environ: [][*:0]u8 = undefined;
/// Populated by startup code before main().
@@ -922,7 +924,11 @@ pub const execveC = execveZ;
/// Like `execve` except the parameters are null-terminated,
/// matching the syscall API on all targets. This removes the need for an allocator.
/// This function ignores PATH environment variable. See `execvpeZ` for that.
-pub fn execveZ(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError {
+pub fn execveZ(
+ path: [*:0]const u8,
+ child_argv: [*:null]const ?[*:0]const u8,
+ envp: [*:null]const ?[*:0]const u8,
+) ExecveError {
switch (errno(system.execve(path, child_argv, envp))) {
0 => unreachable,
EFAULT => unreachable,
@@ -966,7 +972,7 @@ pub fn execvpeZ_expandArg0(
envp: [*:null]const ?[*:0]const u8,
) ExecveError {
const file_slice = mem.toSliceConst(u8, file);
- if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveC(file, child_argv, envp);
+ if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveZ(file, child_argv, envp);
const PATH = getenvZ("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
var path_buf: [MAX_PATH_BYTES]u8 = undefined;
@@ -993,7 +999,7 @@ pub fn execvpeZ_expandArg0(
.expand => child_argv[0] = full_path,
.no_expand => {},
}
- err = execveC(full_path, child_argv, envp);
+ err = execveZ(full_path, child_argv, envp);
switch (err) {
error.AccessDenied => seen_eacces = true,
error.FileNotFound, error.NotDir => {},
@@ -1007,7 +1013,7 @@ pub fn execvpeZ_expandArg0(
/// Like `execvpe` except the parameters are null-terminated,
/// matching the syscall API on all targets. This removes the need for an allocator.
/// This function also uses the PATH environment variable to get the full path to the executable.
-/// If `file` is an absolute path, this is the same as `execveC`.
+/// If `file` is an absolute path, this is the same as `execveZ`.
pub fn execvpeZ(
file: [*:0]const u8,
argv: [*:null]const ?[*:0]const u8,
@@ -1097,8 +1103,37 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8)
/// Get an environment variable.
/// See also `getenvZ`.
-/// TODO make this go through libc when we have it
pub fn getenv(key: []const u8) ?[]const u8 {
+ if (builtin.os == .windows) {
+ // TODO update this to use the ProcessEnvironmentBlock
+ @compileError("TODO implement std.os.getenv for Windows");
+ }
+ if (builtin.link_libc) {
+ var small_key_buf: [64]u8 = undefined;
+ if (key.len < small_key_buf.len) {
+ mem.copy(u8, &small_key_buf, key);
+ small_key_buf[key.len] = 0;
+ const key0 = small_key_buf[0..key.len :0];
+ return getenvZ(key0);
+ }
+ // Search the entire `environ` because we don't have a null terminated pointer.
+ var ptr = std.c.environ;
+ while (ptr.*) |line| : (ptr += 1) {
+ var line_i: usize = 0;
+ while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
+ const this_key = line[0..line_i];
+
+ if (!mem.eql(u8, this_key, key)) continue;
+
+ var end_i: usize = line_i;
+ while (line[end_i] != 0) : (end_i += 1) {}
+ const value = line[line_i + 1 .. end_i];
+
+ return value;
+ }
+ return null;
+ }
+ // TODO see https://github.com/ziglang/zig/issues/4524
for (environ) |ptr| {
var line_i: usize = 0;
while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
@@ -1120,6 +1155,10 @@ pub const getenvC = getenvZ;
/// Get an environment variable with a null-terminated name.
/// See also `getenv`.
pub fn getenvZ(key: [*:0]const u8) ?[]const u8 {
+ if (builtin.os == .windows) {
+ // TODO update this to use the ProcessEnvironmentBlock
+ @compileError("TODO implement std.os.getenv for Windows");
+ }
if (builtin.link_libc) {
const value = system.getenv(key) orelse return null;
return mem.toSliceConst(u8, value);