diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-02-22 15:59:13 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-02-22 15:59:13 -0500 |
| commit | 936d0b18b116ea126893d2f165f9be72f8bef845 (patch) | |
| tree | 8481d2c4265d34217e6b045cbf1c7e34c30aab51 /lib/std/os.zig | |
| parent | 0cd89e9176ab36fc5e267120dc4d75cb79d32684 (diff) | |
| download | zig-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.zig | 49 |
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); |
