authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-10-15 01:23:10-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-10-15 01:23:10-04:00
log8ab5313043dad325488d4491a30642696dc7bbcf
tree462f0b9d7cae35f0bf6277da49b5d0784ab618a2
parent55e8bbd1671f9c8e2f195f8f27a4cbe32665253e

implement environment variables for windows


6 files changed, 135 insertions(+), 20 deletions(-)

std/build.zig+13-3
......@@ -308,7 +308,7 @@ pub const Builder = struct {
308308 }
309309
310310 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| {
312312 var it = mem.split(nix_cflags_compile, " ");
313313 while (true) {
314314 const word = it.next() ?? break;
......@@ -323,8 +323,10 @@ pub const Builder = struct {
323323 break;
324324 }
325325 }
326 } else |err| {
327 assert(err == error.EnvironmentVariableNotFound);
326328 }
327 if (os.getEnv("NIX_LDFLAGS")) |nix_ldflags| {
329 if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
328330 var it = mem.split(nix_ldflags, " ");
329331 while (true) {
330332 const word = it.next() ?? break;
......@@ -342,6 +344,8 @@ pub const Builder = struct {
342344 break;
343345 }
344346 }
347 } else |err| {
348 assert(err == error.EnvironmentVariableNotFound);
345349 }
346350 }
347351
......@@ -1248,7 +1252,13 @@ pub const LibExeObjStep = struct {
12481252 }
12491253
12501254 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 };
12521262 const builder = self.builder;
12531263
12541264 assert(!self.is_zig);
std/os/child_process.zig+2-1
......@@ -564,7 +564,7 @@ pub const ChildProcess = struct {
564564 const cwd_ptr = if (cwd_slice) |cwd| cwd.ptr else null;
565565
566566 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)
568568 } else {
569569 null
570570 };
......@@ -578,6 +578,7 @@ pub const ChildProcess = struct {
578578 const err = windows.GetLastError();
579579 return switch (err) {
580580 windows.ERROR.FILE_NOT_FOUND => error.FileNotFound,
581 windows.ERROR.INVALID_PARAMETER => unreachable,
581582 else => error.Unexpected,
582583 };
583584 }
std/os/index.zig+77-13
......@@ -32,6 +32,7 @@ pub const windowsWrite = windows_util.windowsWrite;
3232pub const windowsIsTty = windows_util.windowsIsTty;
3333pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
3434pub const windowsOpen = windows_util.windowsOpen;
35pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
3536
3637const debug = @import("../debug.zig");
3738const assert = debug.assert;
......@@ -48,6 +49,7 @@ const io = @import("../io.zig");
4849const base64 = @import("../base64.zig");
4950const ArrayList = @import("../array_list.zig").ArrayList;
5051const Buffer = @import("../buffer.zig").Buffer;
52const math = @import("../index.zig").math;
5153
5254error Unexpected;
5355error SystemResources;
......@@ -362,7 +364,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
362364 return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr)));
363365 }
364366
365 const PATH = getEnv("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
367 const PATH = getEnvPosix("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
366368 // PATH.len because it is >= the largest search_path
367369 // +1 for the / to join the search path and exe_path
368370 // +1 for the null terminating byte
......@@ -406,29 +408,55 @@ fn posixExecveErrnoToErr(err: usize) -> error {
406408 };
407409}
408410
409pub var environ_raw: []&u8 = undefined;
411pub var posix_environ_raw: []&u8 = undefined;
410412
411413/// Caller must free result when done.
412414pub fn getEnvMap(allocator: &Allocator) -> %BufMap {
413415 var result = BufMap.init(allocator);
414416 %defer result.deinit();
415417
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));
420421
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];
424431
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;
426455 }
427 return result;
428456}
429457
430pub fn getEnv(key: []const u8) -> ?[]const u8 {
431 for (environ_raw) |ptr| {
458pub fn getEnvPosix(key: []const u8) -> ?[]const u8 {
459 for (posix_environ_raw) |ptr| {
432460 var line_i: usize = 0;
433461 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
434462 const this_key = ptr[0..line_i];
......@@ -444,6 +472,42 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 {
444472 return null;
445473}
446474
475error EnvironmentVariableNotFound;
476
477/// Caller must free returned memory.
478pub 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
447511/// Caller must free the returned memory.
448512pub fn getCwd(allocator: &Allocator) -> %[]u8 {
449513 switch (builtin.os) {
std/os/windows/index.zig+9-2
......@@ -32,12 +32,18 @@ pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) -> bool;
3232
3333pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) -> noreturn;
3434
35pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: LPCH) -> BOOL;
36
3537pub extern "kernel32" stdcallcc fn GetCommandLineA() -> LPSTR;
3638
3739pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: &DWORD) -> bool;
3840
3941pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) -> DWORD;
4042
43pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() -> ?LPCH;
44
45pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) -> DWORD;
46
4147pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: &DWORD) -> BOOL;
4248
4349pub extern "kernel32" stdcallcc fn GetLastError() -> DWORD;
......@@ -49,11 +55,11 @@ pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(in_hFile: HANDLE
4955pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(hFile: HANDLE, lpszFilePath: LPSTR,
5056 cchFilePath: DWORD, dwFlags: DWORD) -> DWORD;
5157
52pub extern "kernel32" stdcallcc fn GetProcessHeap() -> HANDLE;
58pub extern "kernel32" stdcallcc fn GetProcessHeap() -> ?HANDLE;
5359
5460pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) -> ?HANDLE;
5561
56pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
62pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> ?LPVOID;
5763
5864pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
5965
......@@ -91,6 +97,7 @@ pub const HCRYPTPROV = ULONG_PTR;
9197pub const HINSTANCE = &@OpaqueType();
9298pub const INT = c_int;
9399pub const LPBYTE = &BYTE;
100pub const LPCH = &CHAR;
94101pub const LPCSTR = &const CHAR;
95102pub const LPCTSTR = &const TCHAR;
96103pub const LPCVOID = &const c_void;
std/os/windows/util.zig+33
......@@ -3,6 +3,7 @@ const os = std.os;
33const windows = std.os.windows;
44const assert = std.debug.assert;
55const mem = std.mem;
6const BufMap = std.BufMap;
67
78error WaitAbandoned;
89error WaitTimeOut;
......@@ -111,3 +112,35 @@ pub fn windowsOpen(file_path: []const u8, desired_access: windows.DWORD, share_m
111112
112113 return result;
113114}
115
116/// Caller must free result.
117pub 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 {
5656
5757 var env_count: usize = 0;
5858 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];
6060
6161 std.debug.user_main_fn = root.main;
6262