Commit 8ab5313043
Changed files (6)
std
std/os/windows/index.zig
@@ -32,12 +32,18 @@ pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) -> bool;
pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) -> noreturn;
+pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: LPCH) -> BOOL;
+
pub extern "kernel32" stdcallcc fn GetCommandLineA() -> LPSTR;
pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool;
pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) -> DWORD;
+pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() -> ?LPCH;
+
+pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) -> DWORD;
+
pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: &DWORD) -> BOOL;
pub extern "kernel32" stdcallcc fn GetLastError() -> DWORD;
@@ -49,11 +55,11 @@ pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(in_hFile: HANDLE
pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpszFilePath: LPSTR,
cchFilePath: DWORD, dwFlags: DWORD) -> DWORD;
-pub extern "kernel32" stdcallcc fn GetProcessHeap() -> HANDLE;
+pub extern "kernel32" stdcallcc fn GetProcessHeap() -> ?HANDLE;
pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE;
-pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
+pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> ?LPVOID;
pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
@@ -91,6 +97,7 @@ pub const HCRYPTPROV = ULONG_PTR;
pub const HINSTANCE = &@OpaqueType();
pub const INT = c_int;
pub const LPBYTE = &BYTE;
+pub const LPCH = &CHAR;
pub const LPCSTR = &const CHAR;
pub const LPCTSTR = &const TCHAR;
pub const LPCVOID = &const c_void;
std/os/windows/util.zig
@@ -3,6 +3,7 @@ const os = std.os;
const windows = std.os.windows;
const assert = std.debug.assert;
const mem = std.mem;
+const BufMap = std.BufMap;
error WaitAbandoned;
error WaitTimeOut;
@@ -111,3 +112,35 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
return result;
}
+
+/// Caller must free result.
+pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 {
+ // count bytes needed
+ const bytes_needed = {
+ var bytes_needed: usize = 1; // 1 for the final null byte
+ var it = env_map.iterator();
+ while (it.next()) |pair| {
+ // +1 for '='
+ // +1 for null byte
+ bytes_needed += pair.key.len + pair.value.len + 2;
+ }
+ bytes_needed
+ };
+ const result = %return allocator.alloc(u8, bytes_needed);
+ %defer allocator.free(result);
+
+ var it = env_map.iterator();
+ var i: usize = 0;
+ while (it.next()) |pair| {
+ mem.copy(u8, result[i..], pair.key);
+ i += pair.key.len;
+ result[i] = '=';
+ i += 1;
+ mem.copy(u8, result[i..], pair.value);
+ i += pair.value.len;
+ result[i] = 0;
+ i += 1;
+ }
+ result[i] = 0;
+ return result;
+}
std/os/child_process.zig
@@ -564,7 +564,7 @@ pub const ChildProcess = struct {
const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;
const maybe_envp_buf = if (self.env_map) |env_map| {
- %return os.createNullDelimitedEnvMap(self.allocator, env_map)
+ %return os.createWindowsEnvBlock(self.allocator, env_map)
} else {
null
};
@@ -578,6 +578,7 @@ pub const ChildProcess = struct {
const err = windows.GetLastError();
return switch (err) {
windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,
+ windows.ERROR.INVALID_PARAMETER => unreachable,
else => error.Unexpected,
};
}
std/os/index.zig
@@ -32,6 +32,7 @@ pub const windowsWrite = windows_util.windowsWrite;
pub const windowsIsTty = windows_util.windowsIsTty;
pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
pub const windowsOpen = windows_util.windowsOpen;
+pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
const debug = @import("../debug.zig");
const assert = debug.assert;
@@ -48,6 +49,7 @@ const io = @import("../io.zig");
const base64 = @import("../base64.zig");
const ArrayList = @import("../array_list.zig").ArrayList;
const Buffer = @import("../buffer.zig").Buffer;
+const math = @import("../index.zig").math;
error Unexpected;
error SystemResources;
@@ -362,7 +364,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr)));
}
- const PATH = getEnv("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
+ const PATH = getEnvPosix("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
// PATH.len because it is >= the largest search_path
// +1 for the / to join the search path and exe_path
// +1 for the null terminating byte
@@ -406,29 +408,55 @@ fn posixExecveErrnoToErr(err: usize) -> error {
};
}
-pub var environ_raw: []&u8 = undefined;
+pub var posix_environ_raw: []&u8 = undefined;
/// Caller must free result when done.
pub fn getEnvMap(allocator: &Allocator) -> %BufMap {
var result = BufMap.init(allocator);
%defer result.deinit();
- for (environ_raw) |ptr| {
- var line_i: usize = 0;
- while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
- const key = ptr[0..line_i];
+ if (is_windows) {
+ const ptr = windows.GetEnvironmentStringsA() ?? return error.OutOfMemory;
+ defer assert(windows.FreeEnvironmentStringsA(ptr));
- var end_i: usize = line_i;
- while (ptr[end_i] != 0) : (end_i += 1) {}
- const value = ptr[line_i + 1..end_i];
+ var i: usize = 0;
+ while (true) {
+ if (ptr[i] == 0)
+ return result;
+
+ const key_start = i;
+
+ while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
+ const key = ptr[key_start..i];
- %return result.set(key, value);
+ if (ptr[i] == '=') i += 1;
+
+ const value_start = i;
+ while (ptr[i] != 0) : (i += 1) {}
+ const value = ptr[value_start..i];
+
+ i += 1; // skip over null byte
+
+ %return result.set(key, value);
+ }
+ } else {
+ for (posix_environ_raw) |ptr| {
+ var line_i: usize = 0;
+ while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
+ const key = ptr[0..line_i];
+
+ var end_i: usize = line_i;
+ while (ptr[end_i] != 0) : (end_i += 1) {}
+ const value = ptr[line_i + 1..end_i];
+
+ %return result.set(key, value);
+ }
+ return result;
}
- return result;
}
-pub fn getEnv(key: []const u8) -> ?[]const u8 {
- for (environ_raw) |ptr| {
+pub fn getEnvPosix(key: []const u8) -> ?[]const u8 {
+ for (posix_environ_raw) |ptr| {
var line_i: usize = 0;
while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
const this_key = ptr[0..line_i];
@@ -444,6 +472,42 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 {
return null;
}
+error EnvironmentVariableNotFound;
+
+/// Caller must free returned memory.
+pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) -> %[]u8 {
+ if (is_windows) {
+ const key_with_null = %return cstr.addNullByte(allocator, key);
+ defer allocator.free(key_with_null);
+
+ var buf = %return allocator.alloc(u8, 256);
+ %defer allocator.free(buf);
+
+ while (true) {
+ const windows_buf_len = %return math.cast(windows.DWORD, buf.len);
+ const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len);
+
+ if (result == 0) {
+ const err = windows.GetLastError();
+ return switch (err) {
+ windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
+ else => error.Unexpected,
+ };
+ }
+
+ if (result > buf.len) {
+ buf = %return allocator.realloc(u8, buf, result);
+ continue;
+ }
+
+ return allocator.shrink(u8, buf, result);
+ }
+ } else {
+ const result = getEnvPosix(key) ?? return error.EnvironmentVariableNotFound;
+ return mem.dupe(u8, allocator, result);
+ }
+}
+
/// Caller must free the returned memory.
pub fn getCwd(allocator: &Allocator) -> %[]u8 {
switch (builtin.os) {
std/special/bootstrap.zig
@@ -56,7 +56,7 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
var env_count: usize = 0;
while (envp[env_count] != null) : (env_count += 1) {}
- std.os.environ_raw = @ptrCast(&&u8, envp)[0..env_count];
+ std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];
std.debug.user_main_fn = root.main;
std/build.zig
@@ -308,7 +308,7 @@ pub const Builder = struct {
}
fn processNixOSEnvVars(self: &Builder) {
- if (os.getEnv("NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
+ if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
var it = mem.split(nix_cflags_compile, " ");
while (true) {
const word = it.next() ?? break;
@@ -323,8 +323,10 @@ pub const Builder = struct {
break;
}
}
+ } else |err| {
+ assert(err == error.EnvironmentVariableNotFound);
}
- if (os.getEnv("NIX_LDFLAGS")) |nix_ldflags| {
+ if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
var it = mem.split(nix_ldflags, " ");
while (true) {
const word = it.next() ?? break;
@@ -342,6 +344,8 @@ pub const Builder = struct {
break;
}
}
+ } else |err| {
+ assert(err == error.EnvironmentVariableNotFound);
}
}
@@ -1248,7 +1252,13 @@ pub const LibExeObjStep = struct {
}
fn makeC(self: &LibExeObjStep) -> %void {
- const cc = os.getEnv("CC") ?? "cc";
+ const cc = os.getEnvVarOwned(self.builder.allocator, "CC") %% |err| {
+ if (err == error.EnvironmentVariableNotFound) {
+ ([]const u8)("cc")
+ } else {
+ return err
+ }
+ };
const builder = self.builder;
assert(!self.is_zig);