| author | |
| committer | |
| log | 8ab5313043dad325488d4491a30642696dc7bbcf |
| tree | 462f0b9d7cae35f0bf6277da49b5d0784ab618a2 |
| parent | 55e8bbd1671f9c8e2f195f8f27a4cbe32665253e |
6 files changed, 135 insertions(+), 20 deletions(-)
std/build.zig+13-3| ... | ... | @@ -308,7 +308,7 @@ pub const Builder = struct { |
| 308 | 308 | } |
| 309 | 309 | |
| 310 | 310 | fn processNixOSEnvVars(self: &Builder) { |
| 311 | if (os.getEnv("NIX_CFLAGS_COMPILE")) |nix_cflags_compile| { | |
| 311 | if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| { | |
| 312 | 312 | var it = mem.split(nix_cflags_compile, " "); |
| 313 | 313 | while (true) { |
| 314 | 314 | const word = it.next() ?? break; |
| ... | ... | @@ -323,8 +323,10 @@ pub const Builder = struct { |
| 323 | 323 | break; |
| 324 | 324 | } |
| 325 | 325 | } |
| 326 | } else |err| { | |
| 327 | assert(err == error.EnvironmentVariableNotFound); | |
| 326 | 328 | } |
| 327 | if (os.getEnv("NIX_LDFLAGS")) |nix_ldflags| { | |
| 329 | if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| { | |
| 328 | 330 | var it = mem.split(nix_ldflags, " "); |
| 329 | 331 | while (true) { |
| 330 | 332 | const word = it.next() ?? break; |
| ... | ... | @@ -342,6 +344,8 @@ pub const Builder = struct { |
| 342 | 344 | break; |
| 343 | 345 | } |
| 344 | 346 | } |
| 347 | } else |err| { | |
| 348 | assert(err == error.EnvironmentVariableNotFound); | |
| 345 | 349 | } |
| 346 | 350 | } |
| 347 | 351 | |
| ... | ... | @@ -1248,7 +1252,13 @@ pub const LibExeObjStep = struct { |
| 1248 | 1252 | } |
| 1249 | 1253 | |
| 1250 | 1254 | fn makeC(self: &LibExeObjStep) -> %void { |
| 1251 | const cc = os.getEnv("CC") ?? "cc"; | |
| 1255 | const cc = os.getEnvVarOwned(self.builder.allocator, "CC") %% |err| { | |
| 1256 | if (err == error.EnvironmentVariableNotFound) { | |
| 1257 | ([]const u8)("cc") | |
| 1258 | } else { | |
| 1259 | return err | |
| 1260 | } | |
| 1261 | }; | |
| 1252 | 1262 | const builder = self.builder; |
| 1253 | 1263 | |
| 1254 | 1264 | assert(!self.is_zig); |
std/os/child_process.zig+2-1| ... | ... | @@ -564,7 +564,7 @@ pub const ChildProcess = struct { |
| 564 | 564 | const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null; |
| 565 | 565 | |
| 566 | 566 | const maybe_envp_buf = if (self.env_map) |env_map| { |
| 567 | %return os.createNullDelimitedEnvMap(self.allocator, env_map) | |
| 567 | %return os.createWindowsEnvBlock(self.allocator, env_map) | |
| 568 | 568 | } else { |
| 569 | 569 | null |
| 570 | 570 | }; |
| ... | ... | @@ -578,6 +578,7 @@ pub const ChildProcess = struct { |
| 578 | 578 | const err = windows.GetLastError(); |
| 579 | 579 | return switch (err) { |
| 580 | 580 | windows.ERROR.FILE_NOT_FOUND => error.FileNotFound, |
| 581 | windows.ERROR.INVALID_PARAMETER => unreachable, | |
| 581 | 582 | else => error.Unexpected, |
| 582 | 583 | }; |
| 583 | 584 | } |
std/os/index.zig+77-13| ... | ... | @@ -32,6 +32,7 @@ pub const windowsWrite = windows_util.windowsWrite; |
| 32 | 32 | pub const windowsIsTty = windows_util.windowsIsTty; |
| 33 | 33 | pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty; |
| 34 | 34 | pub const windowsOpen = windows_util.windowsOpen; |
| 35 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; | |
| 35 | 36 | |
| 36 | 37 | const debug = @import("../debug.zig"); |
| 37 | 38 | const assert = debug.assert; |
| ... | ... | @@ -48,6 +49,7 @@ const io = @import("../io.zig"); |
| 48 | 49 | const base64 = @import("../base64.zig"); |
| 49 | 50 | const ArrayList = @import("../array_list.zig").ArrayList; |
| 50 | 51 | const Buffer = @import("../buffer.zig").Buffer; |
| 52 | const math = @import("../index.zig").math; | |
| 51 | 53 | |
| 52 | 54 | error Unexpected; |
| 53 | 55 | error SystemResources; |
| ... | ... | @@ -362,7 +364,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap, |
| 362 | 364 | return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr))); |
| 363 | 365 | } |
| 364 | 366 | |
| 365 | const PATH = getEnv("PATH") ?? "/usr/local/bin:/bin/:/usr/bin"; | |
| 367 | const PATH = getEnvPosix("PATH") ?? "/usr/local/bin:/bin/:/usr/bin"; | |
| 366 | 368 | // PATH.len because it is >= the largest search_path |
| 367 | 369 | // +1 for the / to join the search path and exe_path |
| 368 | 370 | // +1 for the null terminating byte |
| ... | ... | @@ -406,29 +408,55 @@ fn posixExecveErrnoToErr(err: usize) -> error { |
| 406 | 408 | }; |
| 407 | 409 | } |
| 408 | 410 | |
| 409 | pub var environ_raw: []&u8 = undefined; | |
| 411 | pub var posix_environ_raw: []&u8 = undefined; | |
| 410 | 412 | |
| 411 | 413 | /// Caller must free result when done. |
| 412 | 414 | pub fn getEnvMap(allocator: &Allocator) -> %BufMap { |
| 413 | 415 | var result = BufMap.init(allocator); |
| 414 | 416 | %defer result.deinit(); |
| 415 | 417 | |
| 416 | for (environ_raw) |ptr| { | |
| 417 | var line_i: usize = 0; | |
| 418 | while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {} | |
| 419 | const key = ptr[0..line_i]; | |
| 418 | if (is_windows) { | |
| 419 | const ptr = windows.GetEnvironmentStringsA() ?? return error.OutOfMemory; | |
| 420 | defer assert(windows.FreeEnvironmentStringsA(ptr)); | |
| 420 | 421 | |
| 421 | var end_i: usize = line_i; | |
| 422 | while (ptr[end_i] != 0) : (end_i += 1) {} | |
| 423 | const value = ptr[line_i + 1..end_i]; | |
| 422 | var i: usize = 0; | |
| 423 | while (true) { | |
| 424 | if (ptr[i] == 0) | |
| 425 | return result; | |
| 426 | ||
| 427 | const key_start = i; | |
| 428 | ||
| 429 | while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} | |
| 430 | const key = ptr[key_start..i]; | |
| 424 | 431 | |
| 425 | %return result.set(key, value); | |
| 432 | if (ptr[i] == '=') i += 1; | |
| 433 | ||
| 434 | const value_start = i; | |
| 435 | while (ptr[i] != 0) : (i += 1) {} | |
| 436 | const value = ptr[value_start..i]; | |
| 437 | ||
| 438 | i += 1; // skip over null byte | |
| 439 | ||
| 440 | %return result.set(key, value); | |
| 441 | } | |
| 442 | } else { | |
| 443 | for (posix_environ_raw) |ptr| { | |
| 444 | var line_i: usize = 0; | |
| 445 | while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {} | |
| 446 | const key = ptr[0..line_i]; | |
| 447 | ||
| 448 | var end_i: usize = line_i; | |
| 449 | while (ptr[end_i] != 0) : (end_i += 1) {} | |
| 450 | const value = ptr[line_i + 1..end_i]; | |
| 451 | ||
| 452 | %return result.set(key, value); | |
| 453 | } | |
| 454 | return result; | |
| 426 | 455 | } |
| 427 | return result; | |
| 428 | 456 | } |
| 429 | 457 | |
| 430 | pub fn getEnv(key: []const u8) -> ?[]const u8 { | |
| 431 | for (environ_raw) |ptr| { | |
| 458 | pub fn getEnvPosix(key: []const u8) -> ?[]const u8 { | |
| 459 | for (posix_environ_raw) |ptr| { | |
| 432 | 460 | var line_i: usize = 0; |
| 433 | 461 | while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {} |
| 434 | 462 | const this_key = ptr[0..line_i]; |
| ... | ... | @@ -444,6 +472,42 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 { |
| 444 | 472 | return null; |
| 445 | 473 | } |
| 446 | 474 | |
| 475 | error EnvironmentVariableNotFound; | |
| 476 | ||
| 477 | /// Caller must free returned memory. | |
| 478 | pub fn getEnvVarOwned(allocator: &mem.Allocator, key: []const u8) -> %[]u8 { | |
| 479 | if (is_windows) { | |
| 480 | const key_with_null = %return cstr.addNullByte(allocator, key); | |
| 481 | defer allocator.free(key_with_null); | |
| 482 | ||
| 483 | var buf = %return allocator.alloc(u8, 256); | |
| 484 | %defer allocator.free(buf); | |
| 485 | ||
| 486 | while (true) { | |
| 487 | const windows_buf_len = %return math.cast(windows.DWORD, buf.len); | |
| 488 | const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len); | |
| 489 | ||
| 490 | if (result == 0) { | |
| 491 | const err = windows.GetLastError(); | |
| 492 | return switch (err) { | |
| 493 | windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound, | |
| 494 | else => error.Unexpected, | |
| 495 | }; | |
| 496 | } | |
| 497 | ||
| 498 | if (result > buf.len) { | |
| 499 | buf = %return allocator.realloc(u8, buf, result); | |
| 500 | continue; | |
| 501 | } | |
| 502 | ||
| 503 | return allocator.shrink(u8, buf, result); | |
| 504 | } | |
| 505 | } else { | |
| 506 | const result = getEnvPosix(key) ?? return error.EnvironmentVariableNotFound; | |
| 507 | return mem.dupe(u8, allocator, result); | |
| 508 | } | |
| 509 | } | |
| 510 | ||
| 447 | 511 | /// Caller must free the returned memory. |
| 448 | 512 | pub fn getCwd(allocator: &Allocator) -> %[]u8 { |
| 449 | 513 | switch (builtin.os) { |
std/os/windows/index.zig+9-2| ... | ... | @@ -32,12 +32,18 @@ pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) -> bool; |
| 32 | 32 | |
| 33 | 33 | pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) -> noreturn; |
| 34 | 34 | |
| 35 | pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: LPCH) -> BOOL; | |
| 36 | ||
| 35 | 37 | pub extern "kernel32" stdcallcc fn GetCommandLineA() -> LPSTR; |
| 36 | 38 | |
| 37 | 39 | pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool; |
| 38 | 40 | |
| 39 | 41 | pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) -> DWORD; |
| 40 | 42 | |
| 43 | pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() -> ?LPCH; | |
| 44 | ||
| 45 | pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) -> DWORD; | |
| 46 | ||
| 41 | 47 | pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: &DWORD) -> BOOL; |
| 42 | 48 | |
| 43 | 49 | pub extern "kernel32" stdcallcc fn GetLastError() -> DWORD; |
| ... | ... | @@ -49,11 +55,11 @@ pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(in_hFile: HANDLE |
| 49 | 55 | pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpszFilePath: LPSTR, |
| 50 | 56 | cchFilePath: DWORD, dwFlags: DWORD) -> DWORD; |
| 51 | 57 | |
| 52 | pub extern "kernel32" stdcallcc fn GetProcessHeap() -> HANDLE; | |
| 58 | pub extern "kernel32" stdcallcc fn GetProcessHeap() -> ?HANDLE; | |
| 53 | 59 | |
| 54 | 60 | pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE; |
| 55 | 61 | |
| 56 | pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; | |
| 62 | pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> ?LPVOID; | |
| 57 | 63 | |
| 58 | 64 | pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; |
| 59 | 65 | |
| ... | ... | @@ -91,6 +97,7 @@ pub const HCRYPTPROV = ULONG_PTR; |
| 91 | 97 | pub const HINSTANCE = &@OpaqueType(); |
| 92 | 98 | pub const INT = c_int; |
| 93 | 99 | pub const LPBYTE = &BYTE; |
| 100 | pub const LPCH = &CHAR; | |
| 94 | 101 | pub const LPCSTR = &const CHAR; |
| 95 | 102 | pub const LPCTSTR = &const TCHAR; |
| 96 | 103 | pub const LPCVOID = &const c_void; |
std/os/windows/util.zig+33| ... | ... | @@ -3,6 +3,7 @@ const os = std.os; |
| 3 | 3 | const windows = std.os.windows; |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | 5 | const mem = std.mem; |
| 6 | const BufMap = std.BufMap; | |
| 6 | 7 | |
| 7 | 8 | error WaitAbandoned; |
| 8 | 9 | error WaitTimeOut; |
| ... | ... | @@ -111,3 +112,35 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m |
| 111 | 112 | |
| 112 | 113 | return result; |
| 113 | 114 | } |
| 115 | ||
| 116 | /// Caller must free result. | |
| 117 | pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) -> %[]u8 { | |
| 118 | // count bytes needed | |
| 119 | const bytes_needed = { | |
| 120 | var bytes_needed: usize = 1; // 1 for the final null byte | |
| 121 | var it = env_map.iterator(); | |
| 122 | while (it.next()) |pair| { | |
| 123 | // +1 for '=' | |
| 124 | // +1 for null byte | |
| 125 | bytes_needed += pair.key.len + pair.value.len + 2; | |
| 126 | } | |
| 127 | bytes_needed | |
| 128 | }; | |
| 129 | const result = %return allocator.alloc(u8, bytes_needed); | |
| 130 | %defer allocator.free(result); | |
| 131 | ||
| 132 | var it = env_map.iterator(); | |
| 133 | var i: usize = 0; | |
| 134 | while (it.next()) |pair| { | |
| 135 | mem.copy(u8, result[i..], pair.key); | |
| 136 | i += pair.key.len; | |
| 137 | result[i] = '='; | |
| 138 | i += 1; | |
| 139 | mem.copy(u8, result[i..], pair.value); | |
| 140 | i += pair.value.len; | |
| 141 | result[i] = 0; | |
| 142 | i += 1; | |
| 143 | } | |
| 144 | result[i] = 0; | |
| 145 | return result; | |
| 146 | } |
std/special/bootstrap.zig+1-1| ... | ... | @@ -56,7 +56,7 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { |
| 56 | 56 | |
| 57 | 57 | var env_count: usize = 0; |
| 58 | 58 | while (envp[env_count] != null) : (env_count += 1) {} |
| 59 | std.os.environ_raw = @ptrCast(&&u8, envp)[0..env_count]; | |
| 59 | std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count]; | |
| 60 | 60 | |
| 61 | 61 | std.debug.user_main_fn = root.main; |
| 62 | 62 |